2026-04-29 13:34:50 +00:00
|
|
|
import { Agent } from "@/agent/agent"
|
|
|
|
|
import { Command } from "@/command"
|
|
|
|
|
import * as InstanceState from "@/effect/instance-state"
|
|
|
|
|
import { Format } from "@/format"
|
|
|
|
|
import { Global } from "@opencode-ai/core/global"
|
|
|
|
|
import { LSP } from "@/lsp/lsp"
|
|
|
|
|
import { Vcs } from "@/project/vcs"
|
|
|
|
|
import { Skill } from "@/skill"
|
|
|
|
|
import { Effect } from "effect"
|
|
|
|
|
import { HttpApiBuilder } from "effect/unstable/httpapi"
|
|
|
|
|
import { InstanceHttpApi } from "../api"
|
2026-05-07 14:24:17 +00:00
|
|
|
import { ApiVcsApplyError } from "../groups/instance"
|
2026-04-29 13:34:50 +00:00
|
|
|
import { markInstanceForDisposal } from "../lifecycle"
|
|
|
|
|
|
|
|
|
|
export const instanceHandlers = HttpApiBuilder.group(InstanceHttpApi, "instance", (handlers) =>
|
2026-04-29 13:36:05 +00:00
|
|
|
Effect.gen(function* () {
|
|
|
|
|
const agent = yield* Agent.Service
|
|
|
|
|
const command = yield* Command.Service
|
|
|
|
|
const format = yield* Format.Service
|
|
|
|
|
const lsp = yield* LSP.Service
|
|
|
|
|
const skill = yield* Skill.Service
|
|
|
|
|
const vcs = yield* Vcs.Service
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
const dispose = Effect.fn("InstanceHttpApi.dispose")(function* () {
|
|
|
|
|
yield* markInstanceForDisposal(yield* InstanceState.context)
|
|
|
|
|
return true
|
|
|
|
|
})
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
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,
|
|
|
|
|
}
|
|
|
|
|
})
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
const getVcs = Effect.fn("InstanceHttpApi.vcs")(function* () {
|
2026-05-14 00:31:27 +00:00
|
|
|
const [branch, default_branch] = yield* Effect.all([vcs.branch(), vcs.defaultBranch()], {
|
|
|
|
|
concurrency: "unbounded",
|
|
|
|
|
})
|
2026-04-29 13:36:05 +00:00
|
|
|
return { branch, default_branch }
|
|
|
|
|
})
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-05-07 14:24:17 +00:00
|
|
|
const getVcsStatus = Effect.fn("InstanceHttpApi.vcsStatus")(function* () {
|
|
|
|
|
return yield* vcs.status()
|
|
|
|
|
})
|
|
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
const getVcsDiff = Effect.fn("InstanceHttpApi.vcsDiff")(function* (ctx: { query: { mode: Vcs.Mode } }) {
|
|
|
|
|
return yield* vcs.diff(ctx.query.mode)
|
|
|
|
|
})
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-05-07 14:24:17 +00:00
|
|
|
const getVcsDiffRaw = Effect.fn("InstanceHttpApi.vcsDiffRaw")(function* () {
|
|
|
|
|
return yield* vcs.diffRaw()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const applyVcs = Effect.fn("InstanceHttpApi.vcsApply")(function* (ctx: { payload: Vcs.ApplyInput }) {
|
|
|
|
|
return yield* vcs.apply(ctx.payload).pipe(
|
|
|
|
|
Effect.mapError(
|
|
|
|
|
(error) =>
|
|
|
|
|
new ApiVcsApplyError({
|
|
|
|
|
name: "VcsApplyError",
|
|
|
|
|
data: {
|
|
|
|
|
message: error.message,
|
|
|
|
|
reason: error.reason,
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
const getCommand = Effect.fn("InstanceHttpApi.command")(function* () {
|
|
|
|
|
return yield* command.list()
|
|
|
|
|
})
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
const getAgent = Effect.fn("InstanceHttpApi.agent")(function* () {
|
|
|
|
|
return yield* agent.list()
|
|
|
|
|
})
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
const getSkill = Effect.fn("InstanceHttpApi.skill")(function* () {
|
|
|
|
|
return yield* skill.all()
|
|
|
|
|
})
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
const getLsp = Effect.fn("InstanceHttpApi.lsp")(function* () {
|
|
|
|
|
return yield* lsp.status()
|
|
|
|
|
})
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
const getFormatter = Effect.fn("InstanceHttpApi.formatter")(function* () {
|
|
|
|
|
return yield* format.status()
|
|
|
|
|
})
|
2026-04-29 13:34:50 +00:00
|
|
|
|
2026-04-29 13:36:05 +00:00
|
|
|
return handlers
|
|
|
|
|
.handle("dispose", dispose)
|
|
|
|
|
.handle("path", getPath)
|
|
|
|
|
.handle("vcs", getVcs)
|
2026-05-07 14:24:17 +00:00
|
|
|
.handle("vcsStatus", getVcsStatus)
|
2026-04-29 13:36:05 +00:00
|
|
|
.handle("vcsDiff", getVcsDiff)
|
2026-05-07 14:24:17 +00:00
|
|
|
.handle("vcsDiffRaw", getVcsDiffRaw)
|
|
|
|
|
.handle("vcsApply", applyVcs)
|
2026-04-29 13:36:05 +00:00
|
|
|
.handle("command", getCommand)
|
|
|
|
|
.handle("agent", getAgent)
|
|
|
|
|
.handle("skill", getSkill)
|
|
|
|
|
.handle("lsp", getLsp)
|
|
|
|
|
.handle("formatter", getFormatter)
|
|
|
|
|
}),
|
2026-04-29 13:34:50 +00:00
|
|
|
)
|