1import * as Schema from "effect/Schema";
2
3import { TrimmedNonEmptyString } from "./baseSchemas.ts";
4
5/**
6 * The desktop app renders browser tabs for the server it launched, and the
7 * server drives them with the same engine as its headless tabs. Messages
8 * travel as newline-delimited JSON over two bootstrap file descriptors, so
9 * only that one server can reach the desktop's pages; nothing listens on a port.
10 *
11 * Each tab carries one CDP connection, multiplexed by `tabId`. CDP frames pass
12 * through untouched; the desktop answers them with `CdpRelay`.
13 */
14
15const TabKey = {
16 threadId: TrimmedNonEmptyString,
17 tabId: TrimmedNonEmptyString,
18};
19
20/** Desktop -> server. */
21export const DesktopBrowserEvent = Schema.Union([
22 /** A desktop `<webview>` for this server tab is attached and can be driven. */
23 Schema.Struct({ type: Schema.Literal("attached"), ...TabKey }),
24 /** Its `<webview>` went away: closed, crashed, swapped, or devtools took the debugger. */
25 Schema.Struct({ type: Schema.Literal("detached"), ...TabKey }),
26 /** One CDP message from the tab's relay. */
27 Schema.Struct({ type: Schema.Literal("cdp"), ...TabKey, message: Schema.String }),
28]);
29export type DesktopBrowserEvent = typeof DesktopBrowserEvent.Type;
30
31/** Server -> desktop. */
32export const DesktopBrowserCommand = Schema.Union([
33 /** One CDP message for the tab's relay. */
34 Schema.Struct({ type: Schema.Literal("cdp"), ...TabKey, message: Schema.String }),
35 /** The server stopped driving this tab, so the relay can drop its sessions. */
36 Schema.Struct({ type: Schema.Literal("release"), ...TabKey }),
37 /** Where an agent action is about to land, so the desktop draws its cursor there. */
38 Schema.Struct({
39 type: Schema.Literal("pointer"),
40 ...TabKey,
41 phase: Schema.Literals(["move", "click"]),
42 x: Schema.Finite,
43 y: Schema.Finite,
44 }),
45]);
46export type DesktopBrowserCommand = typeof DesktopBrowserCommand.Type;