import { Schema, Struct } from "effect"; import { TrimmedNonEmptyString } from "./baseSchemas"; import { ClientOrchestrationCommand, OrchestrationGetFullThreadDiffInput, ORCHESTRATION_WS_METHODS, OrchestrationGetSnapshotInput, OrchestrationGetTurnDiffInput, OrchestrationReplayEventsInput, } from "./orchestration"; import { GitCheckoutInput, GitCreateBranchInput, GitCreateWorktreeInput, GitInitInput, GitListBranchesInput, GitPullInput, GitRemoveWorktreeInput, GitRunStackedActionInput, GitStatusInput, } from "./git"; import { TerminalClearInput, TerminalCloseInput, TerminalOpenInput, TerminalResizeInput, TerminalRestartInput, TerminalWriteInput, } from "./terminal"; import { KeybindingRule } from "./keybindings"; import { ProjectSearchEntriesInput } from "./project"; import { OpenInEditorInput } from "./editor"; // ── WebSocket RPC Method Names ─────────────────────────────────────── export const WS_METHODS = { // Project registry methods projectsList: "projects.list", projectsAdd: "projects.add", projectsRemove: "projects.remove", projectsSearchEntries: "projects.searchEntries", // Shell methods shellOpenInEditor: "shell.openInEditor", // Git methods gitPull: "git.pull", gitStatus: "git.status", gitRunStackedAction: "git.runStackedAction", gitListBranches: "git.listBranches", gitCreateWorktree: "git.createWorktree", gitRemoveWorktree: "git.removeWorktree", gitCreateBranch: "git.createBranch", gitCheckout: "git.checkout", gitInit: "git.init", // Terminal methods terminalOpen: "terminal.open", terminalWrite: "terminal.write", terminalResize: "terminal.resize", terminalClear: "terminal.clear", terminalRestart: "terminal.restart", terminalClose: "terminal.close", // Server meta serverGetConfig: "server.getConfig", serverUpsertKeybinding: "server.upsertKeybinding", } as const; // ── Push Event Channels ────────────────────────────────────────────── export const WS_CHANNELS = { terminalEvent: "terminal.event", serverWelcome: "server.welcome", serverConfigUpdated: "server.configUpdated", } as const; // -- Tagged Union of all request body schemas ───────────────────────── const tagRequestBody = ( tag: Tag, schema: Schema.Struct, ) => schema.mapFields( Struct.assign({ _tag: Schema.tag(tag) }), // PreserveChecks is safe here. No existing schema should have checks depending on the tag { unsafePreserveChecks: true }, ); export const WebSocketRequestBody = Schema.Union([ // Orchestration methods tagRequestBody( ORCHESTRATION_WS_METHODS.dispatchCommand, Schema.Struct({ command: ClientOrchestrationCommand }), ), tagRequestBody(ORCHESTRATION_WS_METHODS.getSnapshot, OrchestrationGetSnapshotInput), tagRequestBody(ORCHESTRATION_WS_METHODS.getTurnDiff, OrchestrationGetTurnDiffInput), tagRequestBody(ORCHESTRATION_WS_METHODS.getFullThreadDiff, OrchestrationGetFullThreadDiffInput), tagRequestBody(ORCHESTRATION_WS_METHODS.replayEvents, OrchestrationReplayEventsInput), // Project Search tagRequestBody(WS_METHODS.projectsSearchEntries, ProjectSearchEntriesInput), // Shell methods tagRequestBody(WS_METHODS.shellOpenInEditor, OpenInEditorInput), // Git methods tagRequestBody(WS_METHODS.gitPull, GitPullInput), tagRequestBody(WS_METHODS.gitStatus, GitStatusInput), tagRequestBody(WS_METHODS.gitRunStackedAction, GitRunStackedActionInput), tagRequestBody(WS_METHODS.gitListBranches, GitListBranchesInput), tagRequestBody(WS_METHODS.gitCreateWorktree, GitCreateWorktreeInput), tagRequestBody(WS_METHODS.gitRemoveWorktree, GitRemoveWorktreeInput), tagRequestBody(WS_METHODS.gitCreateBranch, GitCreateBranchInput), tagRequestBody(WS_METHODS.gitCheckout, GitCheckoutInput), tagRequestBody(WS_METHODS.gitInit, GitInitInput), // Terminal methods tagRequestBody(WS_METHODS.terminalOpen, TerminalOpenInput), tagRequestBody(WS_METHODS.terminalWrite, TerminalWriteInput), tagRequestBody(WS_METHODS.terminalResize, TerminalResizeInput), tagRequestBody(WS_METHODS.terminalClear, TerminalClearInput), tagRequestBody(WS_METHODS.terminalRestart, TerminalRestartInput), tagRequestBody(WS_METHODS.terminalClose, TerminalCloseInput), // Server meta tagRequestBody(WS_METHODS.serverGetConfig, Schema.Struct({})), tagRequestBody(WS_METHODS.serverUpsertKeybinding, KeybindingRule), ]); export const WebSocketRequest = Schema.Struct({ id: TrimmedNonEmptyString, body: WebSocketRequestBody, }); export type WebSocketRequest = typeof WebSocketRequest.Type; export const WebSocketResponse = Schema.Struct({ id: TrimmedNonEmptyString, result: Schema.optional(Schema.Unknown), error: Schema.optional( Schema.Struct({ message: Schema.String, }), ), }); export type WebSocketResponse = typeof WebSocketResponse.Type; export const WsPush = Schema.Struct({ type: Schema.Literal("push"), channel: TrimmedNonEmptyString, data: Schema.Unknown, }); export type WsPush = typeof WsPush.Type; // ── Union of all server → client messages ───────────────────────────── export const WsResponse = Schema.Union([WebSocketResponse, WsPush]); export type WsResponse = typeof WsResponse.Type; // ── Server welcome payload ─────────────────────────────────────────── export const WsWelcomePayload = Schema.Struct({ cwd: TrimmedNonEmptyString, projectName: TrimmedNonEmptyString, }); export type WsWelcomePayload = typeof WsWelcomePayload.Type;