import { EventV2Bridge } from "@/event-v2-bridge" import { TuiEvent } from "@/cli/cmd/tui/event" import { Session } from "@/session/session" import { Effect } from "effect" import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi" import { nextTuiRequest, submitTuiResponse } from "@/server/shared/tui-control" import { InstanceHttpApi } from "../api" import { CommandPayload, TuiPublishPayload } from "../groups/tui" import * as SessionError from "./session-errors" const commandAliases = { session_new: "session.new", session_share: "session.share", session_interrupt: "session.interrupt", session_compact: "session.compact", messages_page_up: "session.page.up", messages_page_down: "session.page.down", messages_line_up: "session.line.up", messages_line_down: "session.line.down", messages_half_page_up: "session.half.page.up", messages_half_page_down: "session.half.page.down", messages_first: "session.first", messages_last: "session.last", agent_cycle: "agent.cycle", } as const export const tuiHandlers = HttpApiBuilder.group(InstanceHttpApi, "tui", (handlers) => Effect.gen(function* () { const events = yield* EventV2Bridge.Service const session = yield* Session.Service const publishCommand = (command: typeof TuiEvent.CommandExecute.data.Type.command | undefined) => events.publish(TuiEvent.CommandExecute, { command } as typeof TuiEvent.CommandExecute.data.Type) const appendPrompt = Effect.fn("TuiHttpApi.appendPrompt")(function* (ctx: { payload: typeof TuiEvent.PromptAppend.data.Type }) { yield* events.publish(TuiEvent.PromptAppend, ctx.payload) return true }) const openHelp = Effect.fn("TuiHttpApi.openHelp")(function* () { yield* publishCommand("help.show") return true }) const openSessions = Effect.fn("TuiHttpApi.openSessions")(function* () { yield* publishCommand("session.list") return true }) const openThemes = Effect.fn("TuiHttpApi.openThemes")(function* () { yield* publishCommand("session.list") return true }) const openModels = Effect.fn("TuiHttpApi.openModels")(function* () { yield* publishCommand("model.list") return true }) const submitPrompt = Effect.fn("TuiHttpApi.submitPrompt")(function* () { yield* publishCommand("prompt.submit") return true }) const clearPrompt = Effect.fn("TuiHttpApi.clearPrompt")(function* () { yield* publishCommand("prompt.clear") return true }) const executeCommand = Effect.fn("TuiHttpApi.executeCommand")(function* (ctx: { payload: typeof CommandPayload.Type }) { // Legacy only publishes known aliases; unknown commands become undefined. yield* publishCommand(commandAliases[ctx.payload.command as keyof typeof commandAliases]) return true }) const showToast = Effect.fn("TuiHttpApi.showToast")(function* (ctx: { payload: typeof TuiEvent.ToastShow.data.Type }) { yield* events.publish(TuiEvent.ToastShow, ctx.payload) return true }) const publish = Effect.fn("TuiHttpApi.publish")(function* (ctx: { payload: typeof TuiPublishPayload.Type }) { if (ctx.payload.type === TuiEvent.PromptAppend.type) yield* events.publish(TuiEvent.PromptAppend, ctx.payload.properties) if (ctx.payload.type === TuiEvent.CommandExecute.type) yield* events.publish(TuiEvent.CommandExecute, ctx.payload.properties) if (ctx.payload.type === TuiEvent.ToastShow.type) yield* events.publish(TuiEvent.ToastShow, ctx.payload.properties) if (ctx.payload.type === TuiEvent.SessionSelect.type) yield* events.publish(TuiEvent.SessionSelect, ctx.payload.properties) return true }) const selectSession = Effect.fn("TuiHttpApi.selectSession")(function* (ctx: { payload: typeof TuiEvent.SessionSelect.data.Type }) { if (!ctx.payload.sessionID.startsWith("ses")) return yield* new HttpApiError.BadRequest({}) yield* SessionError.mapStorageNotFound(session.get(ctx.payload.sessionID)) yield* events.publish(TuiEvent.SessionSelect, ctx.payload) return true }) const controlNext = Effect.fn("TuiHttpApi.controlNext")(function* () { return yield* Effect.promise(() => nextTuiRequest()) }) const controlResponse = Effect.fn("TuiHttpApi.controlResponse")(function* (ctx: { payload: unknown }) { submitTuiResponse(ctx.payload) return true }) return handlers .handle("appendPrompt", appendPrompt) .handle("openHelp", openHelp) .handle("openSessions", openSessions) .handle("openThemes", openThemes) .handle("openModels", openModels) .handle("submitPrompt", submitPrompt) .handle("clearPrompt", clearPrompt) .handle("executeCommand", executeCommand) .handle("showToast", showToast) .handle("publish", publish) .handle("selectSession", selectSession) .handle("controlNext", controlNext) .handle("controlResponse", controlResponse) }), )