mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-23 10:45:33 -04:00
167 lines
6.5 KiB
TypeScript
167 lines
6.5 KiB
TypeScript
import { describe, expect } from "bun:test"
|
|
import fs from "fs/promises"
|
|
import path from "path"
|
|
import { Effect, Exit, Layer } from "effect"
|
|
import { make } from "effect/unstable/process/ChildProcessSpawner"
|
|
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
|
import { Location } from "@opencode-ai/core/location"
|
|
import { Project } from "@opencode-ai/core/project"
|
|
import { AbsolutePath } from "@opencode-ai/core/schema"
|
|
import { WorkspaceV2 } from "@opencode-ai/core/workspace"
|
|
import { WorkspaceEnvironment } from "@opencode-ai/core/workspace/environment"
|
|
import { tmpdir } from "./fixture/tmpdir"
|
|
import { testEffect } from "./lib/effect"
|
|
|
|
const workspaceID = WorkspaceV2.ID.make("wrk_test")
|
|
const ref = { directory: AbsolutePath.make("/repo/packages/app") }
|
|
const projectLayer = Layer.succeed(
|
|
Project.Service,
|
|
Project.Service.of({
|
|
list: () => Effect.succeed([]),
|
|
directories: () => Effect.succeed([]),
|
|
resolve: () =>
|
|
Effect.succeed({
|
|
id: Project.ID.make("project"),
|
|
directory: AbsolutePath.make("/repo"),
|
|
vcs: { type: "git", store: AbsolutePath.make("/repo/.git") },
|
|
}),
|
|
commit: () => Effect.void,
|
|
}),
|
|
)
|
|
const it = testEffect(AppNodeBuilder.build(Location.boundNode(ref), [[Project.node, projectLayer]]))
|
|
|
|
describe("Location", () => {
|
|
it.effect("resolves the current project and vcs information", () =>
|
|
Effect.gen(function* () {
|
|
const location = yield* Location.Service
|
|
|
|
expect(location.directory).toBe(AbsolutePath.make("/repo/packages/app"))
|
|
expect(location.workspaceID).toBeUndefined()
|
|
expect(location.project.id).toBe(Project.ID.make("project"))
|
|
expect(location.project.directory).toBe(AbsolutePath.make("/repo"))
|
|
expect(location.vcs).toEqual({
|
|
type: "git",
|
|
store: AbsolutePath.make("/repo/.git"),
|
|
})
|
|
}),
|
|
)
|
|
|
|
it.live("resolves hosted metadata without reading the host path", () =>
|
|
Effect.acquireRelease(
|
|
Effect.promise(() => tmpdir()),
|
|
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
|
).pipe(
|
|
Effect.flatMap((tmp) => {
|
|
const directory = AbsolutePath.make(path.join(tmp.path, "hosted-checkout"))
|
|
const connections = { count: 0 }
|
|
const reads = { count: 0 }
|
|
const unsupported = () => Effect.die("Unsupported fake environment operation")
|
|
const providerEnvironment = WorkspaceEnvironment.Service.of({
|
|
platform: "linux",
|
|
directory,
|
|
process: make(() => unsupported()),
|
|
shell: {
|
|
executable: "/bin/sh",
|
|
args: (command) => ["-c", command],
|
|
environmentOverrides: {},
|
|
detached: false,
|
|
},
|
|
ripgrep: Effect.succeed("/usr/bin/rg"),
|
|
files: {
|
|
resolve: (target) =>
|
|
Effect.succeed({
|
|
canonical: target.includes("symlink") ? "/outside/secret" : target,
|
|
directory: path.posix.dirname(target),
|
|
type: "File",
|
|
}),
|
|
inspect: unsupported,
|
|
read: () =>
|
|
Effect.sync(() => {
|
|
reads.count++
|
|
return new Uint8Array([1])
|
|
}),
|
|
list: unsupported,
|
|
ensureDirectory: unsupported,
|
|
createExclusive: unsupported,
|
|
write: unsupported,
|
|
writeIfUnchanged: unsupported,
|
|
remove: unsupported,
|
|
},
|
|
})
|
|
const workspaceLayer = Layer.succeed(
|
|
WorkspaceV2.Service,
|
|
WorkspaceV2.Service.of({
|
|
create: () => Effect.die("Unsupported fake Workspace operation"),
|
|
get: () =>
|
|
Effect.succeed(
|
|
WorkspaceV2.Info.make({
|
|
id: workspaceID,
|
|
name: "Hosted",
|
|
directory,
|
|
project: {
|
|
id: Project.ID.make("hosted-project"),
|
|
directory,
|
|
},
|
|
}),
|
|
),
|
|
borrow: () =>
|
|
Effect.sync(() => {
|
|
connections.count++
|
|
return providerEnvironment
|
|
}),
|
|
connect: () => Effect.die("Unsupported fake Workspace operation"),
|
|
suspend: () => Effect.die("Unsupported fake Workspace operation"),
|
|
remove: () => Effect.die("Unsupported fake Workspace operation"),
|
|
}),
|
|
)
|
|
const hostedRef = { directory, workspaceID }
|
|
const layer = AppNodeBuilder.build(LayerNode.group([Location.node, WorkspaceEnvironment.node]), [
|
|
[Location.node, Location.boundNode(hostedRef)],
|
|
[WorkspaceEnvironment.node, WorkspaceEnvironment.boundNode(hostedRef)],
|
|
[WorkspaceV2.node, workspaceLayer],
|
|
])
|
|
const invalidLayer = AppNodeBuilder.build(
|
|
Location.boundNode({ directory: AbsolutePath.make(path.join(tmp.path, "outside")), workspaceID }),
|
|
[[WorkspaceV2.node, workspaceLayer]],
|
|
)
|
|
return Effect.gen(function* () {
|
|
expect(
|
|
yield* Effect.promise(() =>
|
|
fs.stat(directory).then(
|
|
() => true,
|
|
() => false,
|
|
),
|
|
),
|
|
).toBe(false)
|
|
|
|
const location = yield* Location.Service
|
|
const environment = yield* WorkspaceEnvironment.Service
|
|
expect(location.directory).toBe(directory)
|
|
expect(location.workspaceID).toBe(workspaceID)
|
|
expect(location.project).toEqual({
|
|
id: Project.ID.make("hosted-project"),
|
|
directory,
|
|
})
|
|
expect(environment.directory).toBe(directory)
|
|
expect(environment.platform).toBe("linux")
|
|
expect(connections.count).toBe(0)
|
|
|
|
expect(yield* environment.files.read(path.posix.join(directory, "file.txt"))).toEqual(new Uint8Array([1]))
|
|
expect(connections.count).toBe(1)
|
|
expect(reads.count).toBe(1)
|
|
|
|
const outsideFile = yield* environment.files.read("/outside/secret").pipe(Effect.flip)
|
|
expect(outsideFile.operation).toBe("containment")
|
|
const symlink = yield* environment.files.read(path.posix.join(directory, "symlink")).pipe(Effect.flip)
|
|
expect(symlink.operation).toBe("containment")
|
|
expect(reads.count).toBe(1)
|
|
|
|
const invalid = yield* Location.Service.pipe(Effect.provide(invalidLayer), Effect.exit)
|
|
expect(Exit.isFailure(invalid)).toBe(true)
|
|
}).pipe(Effect.provide(layer))
|
|
}),
|
|
),
|
|
)
|
|
})
|