import { Global } from "@opencode-ai/core/global" import { Vcs } from "@/project" import * as InstanceState from "@/effect/instance-state" import { Effect, Layer, Schema } from "effect" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" import { Authorization } from "./auth" const PathInfo = Schema.Struct({ home: Schema.String, state: Schema.String, config: Schema.String, worktree: Schema.String, directory: Schema.String, }).annotate({ identifier: "Path" }) const VcsDiffQuery = Schema.Struct({ mode: Vcs.Mode, }) export const InstancePaths = { path: "/path", vcs: "/vcs", vcsDiff: "/vcs/diff", } as const export const InstanceApi = HttpApi.make("instance") .add( HttpApiGroup.make("instance") .add( HttpApiEndpoint.get("path", InstancePaths.path, { success: PathInfo, }).annotateMerge( OpenApi.annotations({ identifier: "path.get", summary: "Get paths", description: "Retrieve the current working directory and related path information for the OpenCode instance.", }), ), HttpApiEndpoint.get("vcs", InstancePaths.vcs, { success: Vcs.Info, }).annotateMerge( OpenApi.annotations({ identifier: "vcs.get", summary: "Get VCS info", description: "Retrieve version control system (VCS) information for the current project, such as git branch.", }), ), HttpApiEndpoint.get("vcsDiff", InstancePaths.vcsDiff, { query: VcsDiffQuery, success: Schema.Array(Vcs.FileDiff), }).annotateMerge( OpenApi.annotations({ identifier: "vcs.diff", summary: "Get VCS diff", description: "Retrieve the current git diff for the working tree or against the default branch.", }), ), ) .annotateMerge( OpenApi.annotations({ title: "instance", description: "Experimental HttpApi instance read routes.", }), ) .middleware(Authorization), ) .annotateMerge( OpenApi.annotations({ title: "opencode experimental HttpApi", version: "0.0.1", description: "Experimental HttpApi surface for selected instance routes.", }), ) export const instanceHandlers = Layer.unwrap( Effect.gen(function* () { const vcs = yield* Vcs.Service const getPath = Effect.fn("InstanceHttpApi.path")(function* () { const ctx = yield* InstanceState.context return { home: Global.Path.home, state: Global.Path.state, config: Global.Path.config, worktree: ctx.worktree, directory: ctx.directory, } }) const getVcs = Effect.fn("InstanceHttpApi.vcs")(function* () { const [branch, default_branch] = yield* Effect.all([vcs.branch(), vcs.defaultBranch()], { concurrency: 2 }) return { branch, default_branch } }) const getVcsDiff = Effect.fn("InstanceHttpApi.vcsDiff")(function* (ctx: { query: { mode: Vcs.Mode } }) { return yield* vcs.diff(ctx.query.mode) }) return HttpApiBuilder.group(InstanceApi, "instance", (handlers) => handlers.handle("path", getPath).handle("vcs", getVcs).handle("vcsDiff", getVcsDiff), ) }), ).pipe(Layer.provide(Vcs.defaultLayer))