@braedonsaunders/appkit-desk 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/events.d.ts +1 -0
- package/events.d.ts.map +1 -1
- package/events.js.map +1 -1
- package/host.d.ts +1 -1
- package/host.d.ts.map +1 -1
- package/host.js +27 -3
- package/host.js.map +1 -1
- package/package.json +1 -1
- package/protocol.d.ts +1 -0
- package/protocol.d.ts.map +1 -1
- package/protocol.js +8 -0
- package/protocol.js.map +1 -1
package/events.d.ts
CHANGED
package/events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3D,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACtE,QAAQ,EAAE,SAAS,QAAQ,EAAE,CAAA;CAC9B;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,MAAM,CAAA;AAE5C;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,CAAA;AAEjD,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAAA;AAElD,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;AAEnE;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IACE,IAAI,EAAE,eAAe,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB,GACD;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
package/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG","sourcesContent":["/**\n * The typed desk event stream and the ports a consumer supplies.\n *\n * AppKit owns the mechanism of running a desk; the consumer owns the record.\n * Every governed thing that happens on a desk is delivered to `onEvent` as one\n * member of a closed union so the consumer's append-only ledger can persist it\n * without inventing its own taxonomy. Handover boundaries additionally reach\n * the `audit` port — and, while a handover is active, they are the *only*\n * thing that reaches any port. See the masking contract on `DeskPorts`.\n */\n\nexport type DeskPointerButton = 'left' | 'middle' | 'right'\n\nexport interface DeskPoint {\n x: number\n y: number\n}\n\nexport interface WindowInfo {\n id: string\n title: string\n appId: string | null\n}\n\n/**\n * One node of the focused application's AT-SPI accessibility tree, when the\n * application exposes one. Perception is pixels-primary; the tree is\n * opportunistic and may be `null` at any time.\n */\nexport interface A11yNode {\n id: string\n role: string\n name: string | null\n actions: readonly string[]\n bounds: { x: number; y: number; width: number; height: number } | null\n children: readonly A11yNode[]\n}\n\n/**\n * How the pixels of a live frame are encoded on the wire.\n *\n * Two jobs, two formats. `observe()` is always lossless PNG because it feeds a\n * model's vision and anchors coordinates, and it is asked for rarely. The\n * `frames()` stream feeds a human driving the screen: there the scarce\n * resource is bytes on the transport, not fidelity, so a lossy `jpeg` is\n * roughly an order of magnitude smaller per frame and is what makes a live\n * view feel like a remote desktop rather than a slideshow.\n */\nexport type DeskFrameFormat = 'png' | 'jpeg'\n\n/**\n * The two kinds of unit a video stream is made of.\n *\n * `init` is the header a decoder needs before it can make sense of anything —\n * for fragmented MP4, `ftyp` plus `moov`. It arrives once per encoder start and\n * a consumer that never receives it decodes nothing at all, silently. `media`\n * is one fragment of pictures. Ordering is load-bearing: init first, then media\n * from a keyframe onwards.\n */\nexport type DeskVideoChunkKind = 'init' | 'media'\n\nexport type DeskHandoverScope = 'view' | 'control'\n\nexport type DeskHandoverEndReason = 'ended' | 'expired' | 'revoked'\n\n/**\n * The closed union of recordable desk activity. The consumer's ledger stores\n * these rows; the union is defined here so the mechanism and the record agree\n * on the taxonomy without the package ever touching a database.\n */\nexport type DeskEventDetail =\n | {\n kind: 'shell_command'\n command: string\n args: readonly string[]\n cwd: string | null\n exitCode: number | null\n signal: string | null\n }\n | { kind: 'app_launch'; appId: string; args: readonly string[] }\n | { kind: 'click'; x: number; y: number; button: DeskPointerButton }\n | { kind: 'type'; text: string }\n | { kind: 'key'; combo: string }\n | { kind: 'scroll'; x: number; y: number; dx: number; dy: number }\n | { kind: 'drag'; from: DeskPoint; to: DeskPoint }\n | { kind: 'window_focus'; window: WindowInfo }\n | { kind: 'screen_open'; width: number; height: number }\n | { kind: 'screen_close' }\n | { kind: 'handover_begin'; actor: string | null; scope: DeskHandoverScope }\n | { kind: 'handover_end'; actor: string | null; durationMs: number }\n | { kind: 'job_start'; jobId: string; command: string; args: readonly string[] }\n | { kind: 'job_exit'; jobId: string; exitCode: number | null; signal: string | null }\n\nexport type DeskEventKind = DeskEventDetail['kind']\n\nexport type DeskEvent = DeskEventDetail & { deskId: string; at: string }\n\n/**\n * Handover boundaries as the audit port sees them: who took over, under what\n * scope, and for how long — never what they typed.\n */\nexport type DeskAuditEntry =\n | {\n kind: 'handover_begin'\n deskId: string\n actor: string | null\n scope: DeskHandoverScope\n ttlMs: number\n at: string\n }\n | {\n kind: 'handover_end'\n deskId: string\n actor: string | null\n durationMs: number\n reason: DeskHandoverEndReason\n at: string\n }\n\n/**\n * Consumer-supplied policy. Absent hooks allow: the package is mechanism, and\n * a deployment that wants governance supplies it here. A hook returning\n * `false` makes the corresponding call throw before anything reaches the\n * guest.\n */\nexport interface DeskPolicyPort {\n allowExec?(request: {\n deskId: string\n command: string\n args: readonly string[]\n keepAlive: boolean\n }): boolean\n allowScreen?(request: { deskId: string; width: number; height: number }): boolean\n allowHandover?(request: {\n deskId: string\n scope: DeskHandoverScope\n ttlMs: number\n }): boolean\n}\n\n/**\n * The ports a consumer supplies to `createDeskHost`.\n *\n * Masking contract (load-bearing): while a handover is active, input events —\n * `click`, `type`, `key`, `scroll`, `drag` — and the screen-derived events\n * `window_focus` and `app_launch` never reach `onEvent`, and frames are never\n * emitted to `frames()` consumers. Only `handover_begin` and `handover_end`\n * cross the boundary, carrying actor and duration. Getting this wrong leaks\n * credentials into an append-only record.\n */\nexport interface DeskPorts {\n policy?: DeskPolicyPort\n onEvent: (event: DeskEvent) => void\n audit: (entry: DeskAuditEntry) => void\n}\n"]}
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG","sourcesContent":["/**\n * The typed desk event stream and the ports a consumer supplies.\n *\n * AppKit owns the mechanism of running a desk; the consumer owns the record.\n * Every governed thing that happens on a desk is delivered to `onEvent` as one\n * member of a closed union so the consumer's append-only ledger can persist it\n * without inventing its own taxonomy. Handover boundaries additionally reach\n * the `audit` port — and, while a handover is active, they are the *only*\n * thing that reaches any port. See the masking contract on `DeskPorts`.\n */\n\nexport type DeskPointerButton = 'left' | 'middle' | 'right'\n\nexport interface DeskPoint {\n x: number\n y: number\n}\n\nexport interface WindowInfo {\n id: string\n title: string\n appId: string | null\n}\n\n/**\n * One node of the focused application's AT-SPI accessibility tree, when the\n * application exposes one. Perception is pixels-primary; the tree is\n * opportunistic and may be `null` at any time.\n */\nexport interface A11yNode {\n id: string\n role: string\n name: string | null\n actions: readonly string[]\n bounds: { x: number; y: number; width: number; height: number } | null\n children: readonly A11yNode[]\n}\n\n/**\n * How the pixels of a live frame are encoded on the wire.\n *\n * Two jobs, two formats. `observe()` is always lossless PNG because it feeds a\n * model's vision and anchors coordinates, and it is asked for rarely. The\n * `frames()` stream feeds a human driving the screen: there the scarce\n * resource is bytes on the transport, not fidelity, so a lossy `jpeg` is\n * roughly an order of magnitude smaller per frame and is what makes a live\n * view feel like a remote desktop rather than a slideshow.\n */\nexport type DeskFrameFormat = 'png' | 'jpeg'\n\n/**\n * The two kinds of unit a video stream is made of.\n *\n * `init` is the header a decoder needs before it can make sense of anything —\n * for fragmented MP4, `ftyp` plus `moov`. It arrives once per encoder start and\n * a consumer that never receives it decodes nothing at all, silently. `media`\n * is one fragment of pictures. Ordering is load-bearing: init first, then media\n * from a keyframe onwards.\n */\nexport type DeskVideoChunkKind = 'init' | 'media'\n\nexport type DeskHandoverScope = 'view' | 'control'\n\nexport type DeskHandoverEndReason = 'ended' | 'expired' | 'revoked'\n\n/**\n * The closed union of recordable desk activity. The consumer's ledger stores\n * these rows; the union is defined here so the mechanism and the record agree\n * on the taxonomy without the package ever touching a database.\n */\nexport type DeskEventDetail =\n | {\n kind: 'shell_command'\n command: string\n args: readonly string[]\n cwd: string | null\n exitCode: number | null\n signal: string | null\n }\n | { kind: 'app_launch'; appId: string; args: readonly string[] }\n | { kind: 'click'; x: number; y: number; button: DeskPointerButton; clicks: 1 | 2 }\n | { kind: 'type'; text: string }\n | { kind: 'key'; combo: string }\n | { kind: 'scroll'; x: number; y: number; dx: number; dy: number }\n | { kind: 'drag'; from: DeskPoint; to: DeskPoint }\n | { kind: 'window_focus'; window: WindowInfo }\n | { kind: 'screen_open'; width: number; height: number }\n | { kind: 'screen_close' }\n | { kind: 'handover_begin'; actor: string | null; scope: DeskHandoverScope }\n | { kind: 'handover_end'; actor: string | null; durationMs: number }\n | { kind: 'job_start'; jobId: string; command: string; args: readonly string[] }\n | { kind: 'job_exit'; jobId: string; exitCode: number | null; signal: string | null }\n\nexport type DeskEventKind = DeskEventDetail['kind']\n\nexport type DeskEvent = DeskEventDetail & { deskId: string; at: string }\n\n/**\n * Handover boundaries as the audit port sees them: who took over, under what\n * scope, and for how long — never what they typed.\n */\nexport type DeskAuditEntry =\n | {\n kind: 'handover_begin'\n deskId: string\n actor: string | null\n scope: DeskHandoverScope\n ttlMs: number\n at: string\n }\n | {\n kind: 'handover_end'\n deskId: string\n actor: string | null\n durationMs: number\n reason: DeskHandoverEndReason\n at: string\n }\n\n/**\n * Consumer-supplied policy. Absent hooks allow: the package is mechanism, and\n * a deployment that wants governance supplies it here. A hook returning\n * `false` makes the corresponding call throw before anything reaches the\n * guest.\n */\nexport interface DeskPolicyPort {\n allowExec?(request: {\n deskId: string\n command: string\n args: readonly string[]\n keepAlive: boolean\n }): boolean\n allowScreen?(request: { deskId: string; width: number; height: number }): boolean\n allowHandover?(request: {\n deskId: string\n scope: DeskHandoverScope\n ttlMs: number\n }): boolean\n}\n\n/**\n * The ports a consumer supplies to `createDeskHost`.\n *\n * Masking contract (load-bearing): while a handover is active, input events —\n * `click`, `type`, `key`, `scroll`, `drag` — and the screen-derived events\n * `window_focus` and `app_launch` never reach `onEvent`, and frames are never\n * emitted to `frames()` consumers. Only `handover_begin` and `handover_end`\n * cross the boundary, carrying actor and duration. Getting this wrong leaks\n * credentials into an append-only record.\n */\nexport interface DeskPorts {\n policy?: DeskPolicyPort\n onEvent: (event: DeskEvent) => void\n audit: (entry: DeskAuditEntry) => void\n}\n"]}
|
package/host.d.ts
CHANGED
|
@@ -163,7 +163,7 @@ export interface DeskVideoChunk {
|
|
|
163
163
|
}
|
|
164
164
|
export interface DeskScreenInput {
|
|
165
165
|
move(x: number, y: number): Promise<void>;
|
|
166
|
-
click(x: number, y: number, button?: DeskPointerButton): Promise<void>;
|
|
166
|
+
click(x: number, y: number, button?: DeskPointerButton, clicks?: 1 | 2): Promise<void>;
|
|
167
167
|
type(text: string): Promise<void>;
|
|
168
168
|
key(combo: string): Promise<void>;
|
|
169
169
|
scroll(x: number, y: number, dx: number, dy: number): Promise<void>;
|
package/host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
|
package/host.js
CHANGED
|
@@ -489,8 +489,15 @@ export function createDeskHost(options) {
|
|
|
489
489
|
// space of a screen that no longer exists lands somewhere nobody chose.
|
|
490
490
|
// Input then refuses until the caller observes again — the existing
|
|
491
491
|
// contract, not a new one.
|
|
492
|
-
if (record.screen)
|
|
492
|
+
if (record.screen) {
|
|
493
493
|
record.screen.lastObservation = null;
|
|
494
|
+
// The reconnected channel proves the machine is alive, not that the
|
|
495
|
+
// guest compositor survived. Treat the screen as needing an explicit
|
|
496
|
+
// restart so screen.start() reaches the guest instead of returning the
|
|
497
|
+
// stale handle forever. Keep ScreenState itself so an active handover
|
|
498
|
+
// remains masked in the safe direction until its explicit/TTL end.
|
|
499
|
+
record.screen.running = false;
|
|
500
|
+
}
|
|
494
501
|
// A handover is deliberately NOT ended here. If a human is still on that
|
|
495
502
|
// screen, dropping the mask would start recording them; letting the TTL
|
|
496
503
|
// expire it fails in the safe direction.
|
|
@@ -596,6 +603,21 @@ export function createDeskHost(options) {
|
|
|
596
603
|
}
|
|
597
604
|
touch(record);
|
|
598
605
|
await machine.request({ op: 'screen-start', width: cleanWidth, height: cleanHeight });
|
|
606
|
+
const existing = record.screen;
|
|
607
|
+
if (existing) {
|
|
608
|
+
// A guest-agent reconnect invalidates what the host knew about the
|
|
609
|
+
// compositor without necessarily ending an active handover. Reuse
|
|
610
|
+
// the same handle so existing consumers can recover, and retain the
|
|
611
|
+
// handover mask until its explicit/TTL end rather than briefly
|
|
612
|
+
// exposing a human's private input while the screen restarts.
|
|
613
|
+
existing.running = true;
|
|
614
|
+
existing.width = cleanWidth;
|
|
615
|
+
existing.height = cleanHeight;
|
|
616
|
+
existing.lastObservation = null;
|
|
617
|
+
existing.lastFocusedId = null;
|
|
618
|
+
emit(record, { kind: 'screen_open', width: cleanWidth, height: cleanHeight });
|
|
619
|
+
return existing.handle;
|
|
620
|
+
}
|
|
599
621
|
const handle = makeScreenHandle(record, epoch);
|
|
600
622
|
record.screen = {
|
|
601
623
|
running: true,
|
|
@@ -679,10 +701,12 @@ export function createDeskHost(options) {
|
|
|
679
701
|
assertCoordinates(record, [{ x, y }]);
|
|
680
702
|
await sendInput(null, { type: 'move', x, y });
|
|
681
703
|
},
|
|
682
|
-
async click(x, y, button = 'left') {
|
|
704
|
+
async click(x, y, button = 'left', clicks = 1) {
|
|
683
705
|
requireScreen(record, epoch);
|
|
684
706
|
assertCoordinates(record, [{ x, y }]);
|
|
685
|
-
|
|
707
|
+
if (clicks !== 1 && clicks !== 2)
|
|
708
|
+
throw new DeskError('clicks must be 1 or 2.');
|
|
709
|
+
await sendInput({ kind: 'click', x, y, button, clicks }, { type: 'click', x, y, button, clicks });
|
|
686
710
|
},
|
|
687
711
|
async type(text) {
|
|
688
712
|
requireScreen(record, epoch);
|
package/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The desk host: lifecycle, leases, and the screen service over a backend.\n *\n * One host manages many desks against one capacity budget. A desk is\n * headless by default; the screen is a service started on demand on the\n * machine the agent is already using. The host owns lease accounting (idle\n * suspend, a hard concurrency cap with a FIFO queue beyond it), event\n * emission to the consumer's ports, and the handover masking contract. It\n * never touches a database and knows nothing about tenants or approvals.\n */\nimport { existsSync } from 'node:fs'\nimport { execFile } from 'node:child_process'\nimport { rm, statfs, writeFile } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport { Buffer } from 'node:buffer'\nimport {\n buildDeskLaunchPlan,\n cleanDeskId,\n DEFAULT_KVM_PATH,\n DEFAULT_VMM_PATH,\n DeskError,\n type DeskLauncherIdentity,\n} from './plan'\nimport {\n cloudHypervisorBackend,\n type DeskBackend,\n type DeskConnectionChange,\n type DeskMachine,\n} from './backend'\nimport {\n parseCapabilities,\n parseClipboardText,\n parseExecResult,\n parseHandoverBegun,\n parseJobStarted,\n parseObservation,\n type GuestEventMessage,\n type GuestInput,\n} from './protocol'\nimport type {\n A11yNode,\n DeskEventDetail,\n DeskEventKind,\n DeskFrameFormat,\n DeskHandoverEndReason,\n DeskHandoverScope,\n DeskPoint,\n DeskPointerButton,\n DeskPorts,\n DeskVideoChunkKind,\n WindowInfo,\n} from './events'\n\nexport const DEFAULT_CAPACITY = 4\nexport const DEFAULT_IDLE_SUSPEND_MS = 5 * 60_000\nexport const DEFAULT_LEASE_MS = 15 * 60_000\n/** The in-guest trim run before a desk suspends — see `trimGuest`. */\nexport const DEFAULT_TRIM_COMMAND = '/usr/sbin/fstrim'\nexport const DEFAULT_TRIM_ARGS: readonly string[] = ['/']\nexport const DEFAULT_TRIM_TIMEOUT_MS = 60_000\nexport const DEFAULT_CID_BASE = 100\nconst MAX_BUFFERED_FRAMES = 60\n/**\n * Video chunks a slow consumer may fall behind by before its stream is ended.\n * Larger than the frame bound because a fragment is a fraction of a frame's\n * bytes, and enforced by ENDING rather than by dropping — see the comment at\n * the overrun.\n */\nconst MAX_BUFFERED_VIDEO_CHUNKS = 600\nconst MIN_TIMER_DELAY_MS = 25\n\n/**\n * Event kinds that must never reach the recording port while a handover is\n * active. Human input and everything derived from watching the human act is\n * masked; only the handover boundaries themselves cross.\n */\nconst HANDOVER_MASKED_KINDS: ReadonlySet<DeskEventKind> = new Set([\n 'click',\n 'type',\n 'key',\n 'scroll',\n 'drag',\n 'window_focus',\n 'app_launch',\n])\n\nexport interface DeskHostOptions {\n /** Root of the golden base image and per-desk assets. */\n imageRoot: string\n vmmPath?: string\n kvmPath?: string\n /** Guest kernel; defaults to `<imageRoot>/vmlinux`. */\n kernelPath?: string\n /**\n * Initramfs the guest kernel boots with. A modular distro cloud kernel needs\n * one to mount root; omit only for a kernel with virtio/ext4 built in. When\n * unset it defaults to `<imageRoot>/initrd` if that file exists, else none.\n */\n initramfsPath?: string\n /**\n * Kernel command line every desk boots with. Defaults to\n * `DEFAULT_KERNEL_CMDLINE`; override it for partitioned cloud images whose\n * root is not `/dev/vda` (e.g. `root=/dev/vda3 rw quiet`).\n */\n kernelCmdline?: string\n /** Directory holding vsock and API control sockets. */\n runtimeDir?: string\n launcherIdentity?: DeskLauncherIdentity\n backend?: DeskBackend\n ports: DeskPorts\n /** Hard cap on concurrently resident desks; starts beyond it queue FIFO. */\n capacity?: number\n idleSuspendMs?: number\n defaultLeaseMs?: number\n /** First guest vsock CID handed out; each boot takes the next one. */\n cidBase?: number\n now?: () => number\n pathExists?: (path: string) => boolean\n deviceExists?: (path: string) => boolean\n /**\n * Delete a destroyed desk's overlay. Injectable so the destroy path is\n * testable without a filesystem; defaults to `rm(path, { force: true })`.\n */\n removeOverlay?: (path: string) => Promise<void>\n /**\n * Bytes that must remain free on the overlay filesystem AFTER admitting a\n * desk. A desk whose overlay cannot be grown fails deep inside the guest —\n * ENOSPC surfaces as a corrupt filesystem or a boot that hangs, which reads\n * as a product bug rather than as a full disk. Refusing the lease up front\n * turns that into one clear error. Zero disables the check.\n */\n minFreeBytes?: number\n /**\n * Free bytes on the filesystem holding `path`. Injectable for tests;\n * defaults to `statfs`.\n */\n freeBytes?: (path: string) => Promise<number>\n /**\n * Run `fstrim` in the guest just before it suspends, returning the blocks it\n * has freed to the host filesystem. On by default: an overlay that is never\n * trimmed only grows. Set false for a guest without the binary, or one whose\n * filesystem should never be discarded.\n */\n trimOnSuspend?: boolean\n /** The in-guest trim binary. */\n trimCommand?: string\n /** Arguments for the trim binary; defaults to trimming the guest root. */\n trimArgs?: readonly string[]\n /** Bound on the trim; a slow trim must not hold up a suspend indefinitely. */\n trimTimeoutMs?: number\n}\n\nexport interface DeskStartOptions {\n deskId: string\n /** Absolute path of the golden base image this desk boots from. */\n baseImage: string\n /** Absolute path of this desk's copy-on-write overlay. */\n overlayPath: string\n memoryMb?: number\n vcpus?: number\n leaseMs?: number\n network?: { tapDevice?: string; macAddress?: string }\n}\n\nexport interface DeskExecOptions {\n command: string\n args?: readonly string[]\n cwd?: string\n env?: Readonly<Record<string, string>>\n timeoutMs?: number\n /** Survive the call as a background job; the job dies with the lease. */\n keepAlive?: boolean\n}\n\nexport interface DeskExecSnapshot {\n deskId: string\n command: string\n args: readonly string[]\n exitCode: number | null\n signal: string | null\n stdout: string\n stderr: string\n truncated: boolean\n startedAt: string\n finishedAt: string\n}\n\nexport interface DeskJob {\n jobId: string\n deskId: string\n command: string\n args: readonly string[]\n startedAt: string\n status: 'running' | 'exited'\n exitCode: number | null\n signal: string | null\n}\n\nexport interface DeskObservation {\n png: Buffer\n width: number\n height: number\n a11y: A11yNode | null\n windows: readonly WindowInfo[]\n focused: WindowInfo | null\n}\n\nexport interface DeskFrame {\n seq: number\n width: number\n height: number\n data: Buffer\n /**\n * How `data` is encoded. A consumer must not assume PNG — it builds the\n * media type it hands on (a `data:` URL, a decoder) from this.\n */\n format: DeskFrameFormat\n at: string\n}\n\n/**\n * One unit of the live video stream: the init segment, or one media fragment.\n *\n * Video is deliberately NOT modelled as a kind of frame. A frame is a picture\n * that stands alone; a video chunk is meaningless without the init segment\n * before it and, for a media chunk, without the keyframe its group of pictures\n * began at. Pretending otherwise produces a consumer that appends bytes in any\n * order and renders black with no error to explain it.\n */\nexport interface DeskVideoChunk {\n seq: number\n kind: DeskVideoChunkKind\n /** RFC 6381, e.g. `avc1.42C020`. What a MediaSource must be told. */\n codec: string\n width: number\n height: number\n /** True when a `media` chunk begins at a sync sample. Always false on `init`. */\n keyframe: boolean\n data: Buffer\n at: string\n}\n\nexport interface DeskScreenInput {\n move(x: number, y: number): Promise<void>\n click(x: number, y: number, button?: DeskPointerButton): Promise<void>\n type(text: string): Promise<void>\n key(combo: string): Promise<void>\n scroll(x: number, y: number, dx: number, dy: number): Promise<void>\n drag(from: DeskPoint, to: DeskPoint): Promise<void>\n}\n\nexport interface DeskScreenHandle {\n observe(): Promise<DeskObservation>\n /**\n * Coordinate contract: all coordinates are in the pixel space of the most\n * recent view of the screen — an `observe()`, a frame from `frames()`, or a\n * chunk from `video()` — one to one. All three anchor it, because the caller\n * aims at whatever it was last shown, and a live viewer is shown a stream\n * rather than an observation. That holds whatever the encoding is: a lossy\n * frame and an H.264 fragment are both true-size views of the screen, so they\n * anchor exactly as a lossless PNG does. Input before any view, or outside\n * its bounds, throws.\n */\n input: DeskScreenInput\n a11y: { invoke(nodeId: string, action: string): Promise<void> }\n launch(appId: string, args?: readonly string[]): Promise<void>\n clipboard: { read(): Promise<string>; write(text: string): Promise<void> }\n /**\n * The live frame stream. `format` picks how the guest encodes each frame and\n * is a bytes-for-fidelity trade: `jpeg` is roughly an order of magnitude\n * smaller per frame, which is what a human driving the screen needs, while\n * `png` stays exact. Omitted leaves the choice to the guest. `observe()` is\n * unaffected and always lossless.\n *\n * The stream also ends when the desk reconnects to its guest agent: the\n * capture behind it did not survive, so the iterator completes rather than\n * waiting on frames that are never coming. Start another one to resume.\n */\n frames(options?: {\n fps?: number\n width?: number\n height?: number\n format?: DeskFrameFormat\n }): AsyncIterable<DeskFrame>\n /**\n * The live screen as encoded VIDEO rather than as a sequence of pictures.\n *\n * This is what a person driving the desk should watch. `frames()` ships a\n * whole independent image per tick; a video codec ships the DIFFERENCE, and a\n * desktop is mostly still — which is roughly two orders of magnitude fewer\n * bytes on the transport between the guest and here, the one place the live\n * view was actually bounded.\n *\n * The stream anchors the coordinate space exactly as `observe()` and\n * `frames()` do, from the first chunk onwards, because a viewer driving by\n * video is aiming at what the video showed it.\n *\n * Masked like frames: nothing is emitted while a handover is active. And\n * ended like frames when the desk reconnects to its guest agent — a video\n * consumer resumed on a fresh encoder, without its init segment and away\n * from a keyframe, decodes nothing at all and says so nowhere.\n */\n video(options?: {\n fps?: number\n width?: number\n height?: number\n }): AsyncIterable<DeskVideoChunk>\n handover: {\n begin(options: {\n ttlMs: number\n scope?: DeskHandoverScope\n actor?: string\n }): Promise<{ url: string }>\n end(): Promise<void>\n readonly active: boolean\n }\n}\n\nexport interface DeskScreenService {\n start(options: { width: number; height: number }): Promise<DeskScreenHandle>\n stop(): Promise<void>\n readonly running: boolean\n}\n\n/**\n * One leased desk.\n *\n * The handle stays valid across a lost guest connection: the host reconnects\n * underneath it and later calls work, so a guest agent restart or a dropped\n * vsock bridge no longer costs the rest of the lease. Two consequences a\n * caller must actually handle:\n *\n * - A call that was IN FLIGHT when the connection dropped rejects with\n * `DeskRequestFateUnknownError` — it may already have run in the guest.\n * Nothing retries it for you.\n * - A reconnect does not restore guest-side capture state. Live `frames()` and\n * `video()` iterators END, and the coordinate anchor is dropped, so the\n * caller must `observe()` (or take a new frame) before aiming again.\n *\n * When the connection cannot be recovered at all the desk is suspended, so the\n * handle goes dead and `resume()` boots a fresh one — rather than the handle\n * answering \"no longer connected\" for the rest of the lease.\n */\nexport interface DeskHandle {\n readonly deskId: string\n renewLease(ms: number): void\n exec(options: DeskExecOptions & { keepAlive: true }): Promise<DeskJob>\n exec(options: DeskExecOptions): Promise<DeskExecSnapshot>\n /** The keepAlive processes still running on this desk. */\n jobs(): DeskJob[]\n screen: DeskScreenService\n}\n\nexport interface DeskHostStats {\n /** Desks currently resident (booted or booting) against the capacity cap. */\n resident: number\n /** Starts waiting in the FIFO queue for capacity. */\n queued: number\n capacity: number\n suspended: number\n lastStartedAt: string | null\n lastSuspendedAt: string | null\n /**\n * Times a resident desk lost its guest connection mid-lease and got it back.\n * One is a blip; a number that climbs is a desk FLAPPING — a guest agent\n * restarting in a loop, a failing vsock bridge — and that is the difference\n * between \"the desk is slow\" and a diagnosis.\n */\n reconnects: number\n lastReconnectAt: string | null\n /** Which desk reconnected last: enough to go and look at the right one. */\n lastReconnectDeskId: string | null\n lastError: string | null\n}\n\nexport interface DeskHost {\n start(options: DeskStartOptions): Promise<DeskHandle>\n resume(deskId: string): Promise<DeskHandle>\n suspend(deskId: string): Promise<void>\n destroy(deskId: string): Promise<void>\n stats(): DeskHostStats\n /**\n * Enforce every time-based rule now: expire handovers past their TTL and\n * suspend desks past their lease or idle deadline. Returns the number of\n * desks suspended. Timers call this automatically; tests with an injected\n * clock call it directly.\n */\n sweep(): Promise<number>\n}\n\ninterface HandoverState {\n actor: string | null\n scope: DeskHandoverScope\n beganAt: number\n deadline: number\n}\n\ninterface ScreenState {\n running: boolean\n width: number\n height: number\n lastObservation: { width: number; height: number } | null\n lastFocusedId: string | null\n handover: HandoverState | null\n handle: DeskScreenHandle\n}\n\ninterface DeskRecord {\n deskId: string\n startOptions: DeskStartOptions\n status: 'resident' | 'suspending' | 'suspended'\n machine: DeskMachine | null\n epoch: number\n leaseDeadline: number\n lastActivityAt: number\n jobs: Map<string, DeskJob>\n screen: ScreenState | null\n unsubscribe: (() => void) | null\n unwatchConnection: (() => void) | null\n handle: DeskHandle | null\n timer: NodeJS.Timeout | null\n streamStops: Set<() => void>\n}\n\ninterface QueueEntry {\n run: () => Promise<DeskHandle>\n resolve: (handle: DeskHandle) => void\n reject: (error: Error) => void\n}\n\nexport function createDeskHost(options: DeskHostOptions): DeskHost {\n const ports = options.ports\n if (typeof ports?.onEvent !== 'function' || typeof ports?.audit !== 'function') {\n throw new DeskError('createDeskHost requires ports with onEvent and audit functions.')\n }\n const backend = options.backend ?? cloudHypervisorBackend\n const now = options.now ?? Date.now\n const pathExists = options.pathExists ?? existsSync\n const deviceExists = options.deviceExists ?? existsSync\n const removeOverlay = options.removeOverlay ?? ((path: string) => rm(path, { force: true }))\n const freeBytes = options.freeBytes ?? defaultFreeBytes\n const minFreeBytes = nonNegativeInteger(options.minFreeBytes ?? 0, 'minFreeBytes')\n const trimOnSuspend = options.trimOnSuspend ?? true\n const trimCommand = options.trimCommand ?? DEFAULT_TRIM_COMMAND\n const trimArgs = options.trimArgs ?? DEFAULT_TRIM_ARGS\n const trimTimeoutMs = positiveInteger(options.trimTimeoutMs ?? DEFAULT_TRIM_TIMEOUT_MS, 'trimTimeoutMs')\n const capacity = positiveInteger(options.capacity ?? DEFAULT_CAPACITY, 'capacity')\n const idleSuspendMs = positiveInteger(options.idleSuspendMs ?? DEFAULT_IDLE_SUSPEND_MS, 'idleSuspendMs')\n const defaultLeaseMs = positiveInteger(options.defaultLeaseMs ?? DEFAULT_LEASE_MS, 'defaultLeaseMs')\n const kernelPath = options.kernelPath ?? join(options.imageRoot, 'vmlinux')\n // Default the initramfs to <imageRoot>/initrd when present so a modular\n // cloud kernel boots without every caller having to name it; an explicit\n // option always wins.\n const defaultInitramfs = join(options.imageRoot, 'initrd')\n const initramfsPath =\n options.initramfsPath ?? (pathExists(defaultInitramfs) ? defaultInitramfs : undefined)\n const kernelCmdline = options.kernelCmdline\n\n const records = new Map<string, DeskRecord>()\n /**\n * The last lifecycle transition scheduled for each desk. A desk may only\n * have one VMM child touching its overlay, so boot and teardown are ordered\n * on the desk identity rather than allowed to race through independent API\n * calls. The stored tail always resolves; callers still receive their own\n * operation's result or error.\n */\n const lifecycleTransitions = new Map<string, Promise<void>>()\n const queue: QueueEntry[] = []\n let occupied = 0\n let nextCid = positiveInteger(options.cidBase ?? DEFAULT_CID_BASE, 'cidBase')\n let lastStartedAt: string | null = null\n let lastSuspendedAt: string | null = null\n let lastError: string | null = null\n let reconnects = 0\n let lastReconnectAt: string | null = null\n let lastReconnectDeskId: string | null = null\n\n function iso(timestamp: number): string {\n return new Date(timestamp).toISOString()\n }\n\n function serializeLifecycle<T>(deskId: string, transition: () => Promise<T>): Promise<T> {\n const previous = lifecycleTransitions.get(deskId)\n // Preserve the host's existing synchronous admission semantics when this\n // desk has no transition in flight. Only conflicts need the promise tail;\n // unrelated starts must still appear in queue stats before `start` returns.\n const current = previous ? previous.then(transition, transition) : transition()\n const tail = current.then(\n () => undefined,\n () => undefined,\n )\n lifecycleTransitions.set(deskId, tail)\n return current.finally(() => {\n if (lifecycleTransitions.get(deskId) === tail) lifecycleTransitions.delete(deskId)\n })\n }\n\n function emit(record: DeskRecord, detail: DeskEventDetail): void {\n if (record.screen?.handover && HANDOVER_MASKED_KINDS.has(detail.kind)) return\n ports.onEvent({ ...detail, deskId: record.deskId, at: iso(now()) })\n }\n\n function touch(record: DeskRecord): void {\n record.lastActivityAt = now()\n }\n\n function requireMachine(record: DeskRecord, epoch: number): DeskMachine {\n if (record.status !== 'resident' || record.epoch !== epoch || !record.machine) {\n throw new DeskError(`Desk ${record.deskId} is not resident; resume it first.`)\n }\n return record.machine\n }\n\n function requireScreen(record: DeskRecord, epoch: number): ScreenState {\n requireMachine(record, epoch)\n const screen = record.screen\n if (!screen?.running) {\n throw new DeskError(`Desk ${record.deskId} has no screen running; call screen.start first.`)\n }\n return screen\n }\n\n function assertCoordinates(record: DeskRecord, points: readonly DeskPoint[]): void {\n const observation = record.screen?.lastObservation\n if (!observation) {\n throw new DeskError(\n 'Coordinate input needs a frame of reference: call observe(), or start '\n + 'frames() and wait for one. Coordinates are the pixel space of the '\n + 'most recent of those, one to one.',\n )\n }\n for (const point of points) {\n if (\n !Number.isInteger(point.x)\n || !Number.isInteger(point.y)\n || point.x < 0\n || point.y < 0\n || point.x >= observation.width\n || point.y >= observation.height\n ) {\n throw new DeskError(\n `Coordinates (${point.x}, ${point.y}) are outside the most recent view `\n + `(${observation.width}x${observation.height}); observe() again before targeting.`,\n )\n }\n }\n }\n\n function armTimer(record: DeskRecord): void {\n if (record.timer) clearTimeout(record.timer)\n record.timer = null\n if (record.status !== 'resident') return\n const deadlines = [record.leaseDeadline, record.lastActivityAt + idleSuspendMs]\n const handover = record.screen?.handover\n if (handover) deadlines.push(handover.deadline)\n const delayMs = Math.max(Math.min(...deadlines) - now(), MIN_TIMER_DELAY_MS)\n record.timer = setTimeout(() => {\n sweep()\n .then(() => {\n if (record.status === 'resident') armTimer(record)\n })\n .catch((error: unknown) => {\n lastError = errorMessage(error)\n })\n }, delayMs)\n record.timer.unref()\n }\n\n async function endHandover(record: DeskRecord, reason: DeskHandoverEndReason): Promise<void> {\n const screen = record.screen\n const handover = screen?.handover\n if (!screen || !handover) return\n screen.handover = null\n if (record.machine) {\n try {\n await record.machine.request({ op: 'handover-end' })\n } catch (error) {\n lastError = errorMessage(error)\n }\n }\n const durationMs = Math.max(0, now() - handover.beganAt)\n emit(record, { kind: 'handover_end', actor: handover.actor, durationMs })\n ports.audit({\n kind: 'handover_end',\n deskId: record.deskId,\n actor: handover.actor,\n durationMs,\n reason,\n at: iso(now()),\n })\n }\n\n /**\n * Stop the machine and keep the disk. This is the SUSPEND half of the\n * lifecycle and it is shared by three callers — `suspend`, `sweep`, and\n * `destroy` — so it must never delete, truncate, or rewrite the overlay.\n *\n * That is not a stylistic preference. For a suspended desk the overlay IS\n * the desk: its home directory, its installed state, its half-written work.\n * A desk that comes back from suspend with a fresh disk has silently lost\n * everything, and the loss surfaces long after the code that caused it.\n * Reclaiming the disk is the exclusive business of `reclaimOverlay`, which\n * is called from exactly one place — `destroy` — where the caller has said\n * the desk should cease to exist.\n */\n /**\n * Hand the guest's freed blocks back to the host, as the last thing the\n * guest does before it stops.\n *\n * An overlay only ever GROWS otherwise. A block the guest writes is\n * allocated on the host filesystem forever; deleting the file inside the\n * guest frees it in the guest's own filesystem and tells the host nothing,\n * so a long-lived desk ratchets upward until the volume is full even though\n * the guest reports itself half empty. `fstrim` is what closes that loop:\n * it walks the guest filesystem's free space and issues discards, which\n * Cloud Hypervisor's virtio-blk turns into hole-punches on the raw overlay.\n *\n * Suspend is the right moment for it. The image's own `fstrim.timer` fires\n * WEEKLY, and a desk that idle-suspends after minutes is almost never up\n * when that lands — so on a leased-and-parked desk the scheduled trim\n * effectively never runs. Suspend, by contrast, is exactly when the guest\n * has stopped needing its scratch and the host wants the space back.\n *\n * This does not violate the disk contract on `teardown`. `fstrim` discards\n * only blocks the guest's filesystem already considers free; it cannot\n * remove a suspended desk's state, and a desk resumed afterwards sees an\n * identical filesystem. It is also strictly best-effort and bounded: a\n * guest that is wedged, disconnected, or lacks the binary must still\n * suspend promptly, so every failure here is swallowed into `lastError`.\n */\n async function trimGuest(record: DeskRecord, machine: DeskMachine): Promise<void> {\n if (!trimOnSuspend) return\n try {\n await machine.request({\n op: 'exec',\n command: trimCommand,\n args: trimArgs,\n timeoutMs: trimTimeoutMs,\n })\n } catch (error) {\n lastError = `Trim before suspend failed for ${record.deskId}: ${errorMessage(error)}`\n }\n }\n\n async function teardown(record: DeskRecord): Promise<boolean> {\n if (record.status !== 'resident') return false\n await endHandover(record, 'revoked')\n for (const stop of [...record.streamStops]) stop()\n record.streamStops.clear()\n if (record.screen?.running) {\n record.screen.running = false\n emit(record, { kind: 'screen_close' })\n }\n record.screen = null\n for (const job of record.jobs.values()) {\n if (job.status !== 'running') continue\n job.status = 'exited'\n job.signal = 'SIGKILL'\n emit(record, { kind: 'job_exit', jobId: job.jobId, exitCode: null, signal: 'SIGKILL' })\n }\n record.unsubscribe?.()\n record.unsubscribe = null\n record.unwatchConnection?.()\n record.unwatchConnection = null\n if (record.timer) clearTimeout(record.timer)\n record.timer = null\n const machine = record.machine\n record.machine = null\n // Do not advertise this desk as suspended until its VMM child is actually\n // down. `serializeLifecycle` prevents a new boot from entering while this\n // transitional state still owns the overlay.\n record.status = 'suspending'\n record.handle = null\n if (machine) {\n await trimGuest(record, machine)\n try {\n await machine.shutdown()\n } catch (error) {\n lastError = errorMessage(error)\n }\n }\n lastSuspendedAt = iso(now())\n occupied -= 1\n record.status = 'suspended'\n drainQueue()\n return true\n }\n\n function drainQueue(): void {\n while (occupied < capacity && queue.length > 0) {\n const entry = queue.shift()\n if (!entry) break\n occupied += 1\n entry.run().then(entry.resolve, (error: unknown) => {\n occupied -= 1\n entry.reject(error instanceof Error ? error : new Error(String(error)))\n drainQueue()\n })\n }\n }\n\n function admit(run: () => Promise<DeskHandle>): Promise<DeskHandle> {\n if (occupied < capacity) {\n occupied += 1\n return run().catch((error: unknown) => {\n occupied -= 1\n drainQueue()\n throw error\n })\n }\n return new Promise<DeskHandle>((resolvePromise, rejectPromise) => {\n queue.push({ run, resolve: resolvePromise, reject: rejectPromise })\n })\n }\n\n /**\n * Refuse a desk the overlay filesystem cannot afford. A reflink clone costs\n * almost nothing at creation and then grows as the guest writes, so the\n * moment that matters is not the `cp` — it is every write after it. Checking\n * headroom here converts a mid-boot ENOSPC, which the guest reports as a\n * corrupt disk or a hang, into one refusal naming the actual shortage.\n */\n async function admitDisk(overlayPath: string): Promise<void> {\n if (minFreeBytes <= 0) return\n let free: number\n try {\n free = await freeBytes(overlayPath)\n } catch (error) {\n // Fail OPEN on an unreadable filesystem: a desk refused because statfs\n // hiccuped is a worse outcome than one admitted onto a disk that turns\n // out to be full, which at least fails with a real disk error.\n lastError = `Free-space check failed for ${overlayPath}: ${errorMessage(error)}`\n return\n }\n if (free < minFreeBytes) {\n throw new DeskError(\n `Refusing to start a desk: the overlay filesystem holding ${overlayPath} has `\n + `${free} bytes free, below the ${minFreeBytes}-byte floor. Reclaim destroyed `\n + 'desks’ overlays or grow the volume before leasing another desk.',\n )\n }\n }\n\n async function boot(deskId: string, startOptions: DeskStartOptions): Promise<DeskHandle> {\n // Before the plan, so a full disk is reported as a full disk rather than\n // as whatever the overlay copy fails with.\n await admitDisk(startOptions.overlayPath)\n const plan = buildDeskLaunchPlan(\n {\n deskId,\n vmmPath: options.vmmPath,\n kvmPath: options.kvmPath,\n kernelPath,\n ...(initramfsPath === undefined ? {} : { initramfsPath }),\n baseImagePath: startOptions.baseImage,\n overlayPath: startOptions.overlayPath,\n memoryMb: startOptions.memoryMb,\n vcpus: startOptions.vcpus,\n vsockCid: nextCid++,\n runtimeDir: options.runtimeDir,\n tapDevice: startOptions.network?.tapDevice,\n macAddress: startOptions.network?.macAddress,\n // Forward the host's cmdline only when set; otherwise the plan falls\n // back to DEFAULT_KERNEL_CMDLINE.\n ...(kernelCmdline === undefined ? {} : { kernelCmdline }),\n launcherIdentity: options.launcherIdentity,\n },\n { pathExists, deviceExists },\n )\n let machine: DeskMachine\n try {\n machine = await backend.boot(plan)\n } catch (error) {\n lastError = errorMessage(error)\n throw error instanceof DeskError\n ? error\n : new DeskError(`Desk ${deskId} failed to boot: ${errorMessage(error)}`)\n }\n\n let record = records.get(deskId)\n if (!record) {\n record = {\n deskId,\n startOptions,\n status: 'resident',\n machine,\n epoch: 1,\n leaseDeadline: 0,\n lastActivityAt: 0,\n jobs: new Map(),\n screen: null,\n unsubscribe: null,\n unwatchConnection: null,\n handle: null,\n timer: null,\n streamStops: new Set(),\n }\n records.set(deskId, record)\n } else {\n record.startOptions = startOptions\n record.status = 'resident'\n record.machine = machine\n record.epoch += 1\n record.jobs = new Map()\n record.screen = null\n record.streamStops = new Set()\n }\n const current = record\n const epoch = current.epoch\n current.leaseDeadline = now() + positiveInteger(startOptions.leaseMs ?? defaultLeaseMs, 'leaseMs')\n current.lastActivityAt = now()\n current.unsubscribe = machine.subscribe((event) => {\n handleGuestEvent(current, epoch, event)\n })\n current.unwatchConnection =\n machine.onConnectionChange?.((change) => {\n handleConnectionChange(current, epoch, change)\n }) ?? null\n current.handle = makeHandle(current, epoch)\n lastStartedAt = iso(now())\n armTimer(current)\n return current.handle\n }\n\n function handleGuestEvent(record: DeskRecord, epoch: number, event: GuestEventMessage): void {\n if (record.status !== 'resident' || record.epoch !== epoch) return\n if (event.event === 'job-exit') {\n const job = record.jobs.get(event.jobId)\n if (!job || job.status !== 'running') return\n job.status = 'exited'\n job.exitCode = event.exitCode\n job.signal = event.signal\n emit(record, {\n kind: 'job_exit',\n jobId: event.jobId,\n exitCode: event.exitCode,\n signal: event.signal,\n })\n return\n }\n if (event.event === 'window-focus') {\n if (record.screen) record.screen.lastFocusedId = event.window.id\n emit(record, { kind: 'window_focus', window: event.window })\n }\n }\n\n /**\n * What a desk losing (and regaining) its guest channel means up here.\n *\n * The backend can get the CHANNEL back; it cannot get the GUEST's state\n * back, and pretending otherwise is how a consumer ends up waiting forever\n * on a stream that will never produce another byte. So a reconnect is\n * treated as a discontinuity that the caller is able to see, and a\n * permanent loss retires the desk instead of leaving a dead one leased.\n */\n function handleConnectionChange(\n record: DeskRecord,\n epoch: number,\n change: DeskConnectionChange,\n ): void {\n if (record.status !== 'resident' || record.epoch !== epoch) return\n if (change.state === 'reconnected') {\n reconnects += 1\n lastReconnectAt = iso(now())\n lastReconnectDeskId = record.deskId\n // Never silent. A reconnect that hides a guest agent restarting is a\n // debugging trap: the desk misbehaves and nothing anywhere says why.\n lastError = `Desk ${record.deskId} reconnected to its guest agent after ${change.downtimeMs}ms (${change.reason}).`\n // The guest's capture state did not necessarily come back with the\n // channel. An agent that restarted has no screen, no frame encoder and\n // no video encoder; even one that survived starts a fresh encoder whose\n // sequence numbers and init segment do not continue the old stream. A\n // consumer resumed mid-stream decodes nothing, silently — so every live\n // stream is ENDED. `frames()`/`video()` complete normally, which is how\n // the consumer notices, and it can start a new one on a guest that is\n // now definitely capturing.\n for (const stop of [...record.streamStops]) stop()\n record.streamStops.clear()\n // The coordinate anchor goes with them: the screen behind it may be\n // gone, or recreated at another size, and a click aimed at the pixel\n // space of a screen that no longer exists lands somewhere nobody chose.\n // Input then refuses until the caller observes again — the existing\n // contract, not a new one.\n if (record.screen) record.screen.lastObservation = null\n // A handover is deliberately NOT ended here. If a human is still on that\n // screen, dropping the mask would start recording them; letting the TTL\n // expire it fails in the safe direction.\n return\n }\n // Lost for good. Left resident, this desk would answer every call with\n // \"no longer connected\" for the rest of the lease and `resume()` would\n // hand back the same dead handle — the exact product failure this release\n // is about. Suspending it frees the capacity slot and makes the next\n // `resume()` boot a healthy desk.\n lastError = change.reason\n void serializeLifecycle(record.deskId, async () => {\n // The loss belongs to the epoch that registered this watcher. If an\n // earlier queued transition already replaced that machine, this stale\n // signal must not retire the fresh resident.\n if (record.status !== 'resident' || record.epoch !== epoch) return\n await teardown(record)\n }).catch((error: unknown) => {\n lastError = errorMessage(error)\n })\n }\n\n function makeHandle(record: DeskRecord, epoch: number): DeskHandle {\n const execImplementation = async (\n execOptions: DeskExecOptions,\n ): Promise<DeskExecSnapshot | DeskJob> => {\n const machine = requireMachine(record, epoch)\n const command = nonEmptyString(execOptions.command, 'command')\n const args = [...(execOptions.args ?? [])]\n const keepAlive = execOptions.keepAlive === true\n if (ports.policy?.allowExec && !ports.policy.allowExec({\n deskId: record.deskId,\n command,\n args,\n keepAlive,\n })) {\n throw new DeskError(`Policy denied exec of ${command} on desk ${record.deskId}.`)\n }\n touch(record)\n const startedAt = iso(now())\n if (keepAlive) {\n const { jobId } = parseJobStarted(await machine.request({\n op: 'job-start',\n command,\n args,\n cwd: execOptions.cwd,\n env: execOptions.env,\n }))\n const job: DeskJob = {\n jobId,\n deskId: record.deskId,\n command,\n args,\n startedAt,\n status: 'running',\n exitCode: null,\n signal: null,\n }\n record.jobs.set(jobId, job)\n emit(record, { kind: 'job_start', jobId, command, args })\n return { ...job }\n }\n const result = parseExecResult(await machine.request(\n {\n op: 'exec',\n command,\n args,\n cwd: execOptions.cwd,\n env: execOptions.env,\n timeoutMs: execOptions.timeoutMs,\n },\n execOptions.timeoutMs === undefined ? {} : { timeoutMs: execOptions.timeoutMs + 5_000 },\n ))\n emit(record, {\n kind: 'shell_command',\n command,\n args,\n cwd: execOptions.cwd ?? null,\n exitCode: result.exitCode,\n signal: result.signal,\n })\n return {\n deskId: record.deskId,\n command,\n args,\n exitCode: result.exitCode,\n signal: result.signal,\n stdout: result.stdout,\n stderr: result.stderr,\n truncated: result.truncated,\n startedAt,\n finishedAt: iso(now()),\n }\n }\n\n const screenService: DeskScreenService = {\n async start({ width, height }) {\n const machine = requireMachine(record, epoch)\n if (record.screen?.running) return record.screen.handle\n const cleanWidth = positiveInteger(width, 'width')\n const cleanHeight = positiveInteger(height, 'height')\n if (ports.policy?.allowScreen && !ports.policy.allowScreen({\n deskId: record.deskId,\n width: cleanWidth,\n height: cleanHeight,\n })) {\n throw new DeskError(`Policy denied opening a screen on desk ${record.deskId}.`)\n }\n touch(record)\n await machine.request({ op: 'screen-start', width: cleanWidth, height: cleanHeight })\n const handle = makeScreenHandle(record, epoch)\n record.screen = {\n running: true,\n width: cleanWidth,\n height: cleanHeight,\n lastObservation: null,\n lastFocusedId: null,\n handover: null,\n handle,\n }\n emit(record, { kind: 'screen_open', width: cleanWidth, height: cleanHeight })\n return handle\n },\n async stop() {\n const machine = requireMachine(record, epoch)\n const screen = record.screen\n if (!screen?.running) return\n await endHandover(record, 'revoked')\n for (const stop of [...record.streamStops]) stop()\n record.streamStops.clear()\n screen.running = false\n record.screen = null\n touch(record)\n await machine.request({ op: 'screen-stop' })\n emit(record, { kind: 'screen_close' })\n },\n get running() {\n return record.screen?.running === true\n },\n }\n\n return {\n deskId: record.deskId,\n renewLease(ms: number): void {\n requireMachine(record, epoch)\n record.leaseDeadline = now() + positiveInteger(ms, 'ms')\n touch(record)\n armTimer(record)\n },\n exec: execImplementation as DeskHandle['exec'],\n jobs(): DeskJob[] {\n return [...record.jobs.values()]\n .filter((job) => job.status === 'running')\n .map((job) => ({ ...job }))\n },\n screen: screenService,\n }\n }\n\n function makeScreenHandle(record: DeskRecord, epoch: number): DeskScreenHandle {\n async function sendInput(detail: DeskEventDetail | null, input: GuestInput): Promise<void> {\n const machine = requireMachine(record, epoch)\n touch(record)\n await machine.request({ op: 'input', input })\n if (detail) emit(record, detail)\n }\n\n return {\n async observe(): Promise<DeskObservation> {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n touch(record)\n const observation = parseObservation(await machine.request({ op: 'observe' }))\n screen.lastObservation = { width: observation.width, height: observation.height }\n if (observation.focused && observation.focused.id !== screen.lastFocusedId) {\n screen.lastFocusedId = observation.focused.id\n emit(record, { kind: 'window_focus', window: observation.focused })\n }\n return {\n png: Buffer.from(observation.png, 'base64'),\n width: observation.width,\n height: observation.height,\n a11y: observation.a11y,\n windows: observation.windows,\n focused: observation.focused,\n }\n },\n input: {\n async move(x, y) {\n requireScreen(record, epoch)\n assertCoordinates(record, [{ x, y }])\n await sendInput(null, { type: 'move', x, y })\n },\n async click(x, y, button = 'left') {\n requireScreen(record, epoch)\n assertCoordinates(record, [{ x, y }])\n await sendInput({ kind: 'click', x, y, button }, { type: 'click', x, y, button })\n },\n async type(text) {\n requireScreen(record, epoch)\n const cleanText = requireStringValue(text, 'text')\n await sendInput({ kind: 'type', text: cleanText }, { type: 'type', text: cleanText })\n },\n async key(combo) {\n requireScreen(record, epoch)\n const cleanCombo = nonEmptyString(combo, 'combo')\n await sendInput({ kind: 'key', combo: cleanCombo }, { type: 'key', combo: cleanCombo })\n },\n async scroll(x, y, dx, dy) {\n requireScreen(record, epoch)\n assertCoordinates(record, [{ x, y }])\n if (!Number.isInteger(dx) || !Number.isInteger(dy)) {\n throw new DeskError('Scroll deltas must be integers.')\n }\n await sendInput({ kind: 'scroll', x, y, dx, dy }, { type: 'scroll', x, y, dx, dy })\n },\n async drag(from, to) {\n requireScreen(record, epoch)\n assertCoordinates(record, [from, to])\n await sendInput({ kind: 'drag', from, to }, { type: 'drag', from, to })\n },\n },\n a11y: {\n async invoke(nodeId, action) {\n const machine = requireMachine(record, epoch)\n requireScreen(record, epoch)\n touch(record)\n await machine.request({\n op: 'a11y-invoke',\n nodeId: nonEmptyString(nodeId, 'nodeId'),\n action: nonEmptyString(action, 'action'),\n })\n },\n },\n async launch(appId, args = []) {\n const machine = requireMachine(record, epoch)\n requireScreen(record, epoch)\n touch(record)\n const cleanAppId = nonEmptyString(appId, 'appId')\n await machine.request({ op: 'launch', appId: cleanAppId, args: [...args] })\n emit(record, { kind: 'app_launch', appId: cleanAppId, args: [...args] })\n },\n clipboard: {\n async read() {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n if (screen.handover) {\n // The human may have just typed a credential that is now on the\n // clipboard; reading it during a handover would carry it into the\n // agent's context and the consumer's record.\n throw new DeskError('The clipboard is masked while a handover is active.')\n }\n touch(record)\n return parseClipboardText(await machine.request({ op: 'clipboard-read' }))\n },\n async write(text) {\n const machine = requireMachine(record, epoch)\n requireScreen(record, epoch)\n touch(record)\n await machine.request({ op: 'clipboard-write', text: requireStringValue(text, 'text') })\n },\n },\n frames(frameOptions = {}) {\n return {\n [Symbol.asyncIterator]: () => {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n const fps = positiveInteger(frameOptions.fps ?? 10, 'fps')\n const width = positiveInteger(frameOptions.width ?? screen.width, 'width')\n const height = positiveInteger(frameOptions.height ?? screen.height, 'height')\n const format = frameOptions.format\n const buffered: DeskFrame[] = []\n let waiting: ((result: IteratorResult<DeskFrame, undefined>) => void) | null = null\n let finished = false\n const unsubscribe = machine.subscribe((event) => {\n if (finished || event.event !== 'frame') return\n // Masking contract: no frame reaches a recording consumer while\n // a handover is active.\n if (record.screen?.handover) return\n const frame: DeskFrame = {\n seq: event.seq,\n width: event.width,\n height: event.height,\n data: Buffer.from(event.data, 'base64'),\n format: event.format,\n at: iso(now()),\n }\n // A frame anchors coordinates exactly as an observation does.\n // The contract is that a click lands in the pixel space of the\n // most recent thing the caller was SHOWN, and a live view is\n // shown the frame stream, not observe(). Without this a viewer\n // that watches frames and clicks what it sees is refused for\n // never having called observe() — technically true and useless.\n if (record.screen) {\n record.screen.lastObservation = { width: frame.width, height: frame.height }\n }\n if (waiting) {\n const resume = waiting\n waiting = null\n resume({ value: frame, done: false })\n } else {\n buffered.push(frame)\n if (buffered.length > MAX_BUFFERED_FRAMES) buffered.shift()\n }\n })\n const finish = (): void => {\n if (finished) return\n finished = true\n unsubscribe()\n record.streamStops.delete(finish)\n if (record.status === 'resident' && record.machine) {\n record.machine.request({ op: 'frames-stop' }).catch((error: unknown) => {\n lastError = errorMessage(error)\n })\n }\n if (waiting) {\n const resume = waiting\n waiting = null\n resume({ value: undefined, done: true })\n }\n }\n record.streamStops.add(finish)\n const started = machine\n .request({ op: 'frames-start', fps, width, height, format })\n .catch((error: unknown) => {\n finish()\n throw error instanceof Error ? error : new Error(String(error))\n })\n return {\n async next(): Promise<IteratorResult<DeskFrame, undefined>> {\n await started\n const bufferedFrame = buffered.shift()\n if (bufferedFrame) return { value: bufferedFrame, done: false }\n if (finished) return { value: undefined, done: true }\n return new Promise((resolvePromise) => {\n waiting = resolvePromise\n })\n },\n async return(): Promise<IteratorResult<DeskFrame, undefined>> {\n finish()\n return { value: undefined, done: true }\n },\n async throw(error?: unknown): Promise<IteratorResult<DeskFrame, undefined>> {\n finish()\n throw error instanceof Error ? error : new Error(String(error))\n },\n }\n },\n }\n },\n video(videoOptions = {}) {\n return {\n [Symbol.asyncIterator]: () => {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n const fps = positiveInteger(videoOptions.fps ?? 30, 'fps')\n const width = positiveInteger(videoOptions.width ?? screen.width, 'width')\n const height = positiveInteger(videoOptions.height ?? screen.height, 'height')\n const buffered: DeskVideoChunk[] = []\n let waiting: ((result: IteratorResult<DeskVideoChunk, undefined>) => void) | null = null\n let finished = false\n const unsubscribe = machine.subscribe((event) => {\n if (finished || event.event !== 'video-chunk') return\n // The same masking contract frames are held to: while a handover\n // is active a person is on that screen, and nothing derived from\n // watching them may reach a recording consumer.\n if (record.screen?.handover) return\n const chunk: DeskVideoChunk = {\n seq: event.seq,\n kind: event.kind,\n codec: event.codec,\n width: event.width,\n height: event.height,\n keyframe: event.keyframe,\n data: Buffer.from(event.data, 'base64'),\n at: iso(now()),\n }\n // A video chunk anchors coordinates exactly as a frame does, and\n // for the same reason: a viewer driving by video is aiming at the\n // pixel space the video showed it. Anchoring on every chunk, not\n // only the first, is what re-asserts the space when the encoder\n // restarts at a new resolution.\n if (record.screen) {\n record.screen.lastObservation = { width: chunk.width, height: chunk.height }\n }\n if (waiting) {\n const resume = waiting\n waiting = null\n resume({ value: chunk, done: false })\n } else {\n buffered.push(chunk)\n // Dropping the OLDEST would drop the init segment, and a\n // consumer without it decodes nothing at all — so an overrun\n // ends the stream instead. A caller that cannot keep up with a\n // video stream is one that should re-subscribe and be resynced\n // from a keyframe, not one that should be handed a hole.\n if (buffered.length > MAX_BUFFERED_VIDEO_CHUNKS) finish()\n }\n })\n const finish = (): void => {\n if (finished) return\n finished = true\n unsubscribe()\n record.streamStops.delete(finish)\n if (record.status === 'resident' && record.machine) {\n record.machine.request({ op: 'video-stop' }).catch((error: unknown) => {\n lastError = errorMessage(error)\n })\n }\n if (waiting) {\n const resume = waiting\n waiting = null\n resume({ value: undefined, done: true })\n }\n }\n record.streamStops.add(finish)\n const started = machine\n .request({ op: 'video-start', fps, width, height })\n .catch((error: unknown) => {\n finish()\n throw error instanceof Error ? error : new Error(String(error))\n })\n return {\n async next(): Promise<IteratorResult<DeskVideoChunk, undefined>> {\n await started\n const bufferedChunk = buffered.shift()\n if (bufferedChunk) return { value: bufferedChunk, done: false }\n if (finished) return { value: undefined, done: true }\n return new Promise((resolvePromise) => {\n waiting = resolvePromise\n })\n },\n async return(): Promise<IteratorResult<DeskVideoChunk, undefined>> {\n finish()\n return { value: undefined, done: true }\n },\n async throw(error?: unknown): Promise<IteratorResult<DeskVideoChunk, undefined>> {\n finish()\n throw error instanceof Error ? error : new Error(String(error))\n },\n }\n },\n }\n },\n handover: {\n async begin({ ttlMs, scope = 'control', actor }) {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n if (screen.handover) {\n throw new DeskError(`A handover is already active on desk ${record.deskId}.`)\n }\n const cleanTtl = positiveInteger(ttlMs, 'ttlMs')\n if (ports.policy?.allowHandover && !ports.policy.allowHandover({\n deskId: record.deskId,\n scope,\n ttlMs: cleanTtl,\n })) {\n throw new DeskError(`Policy denied a handover on desk ${record.deskId}.`)\n }\n touch(record)\n const begun = parseHandoverBegun(\n await machine.request({ op: 'handover-begin', ttlMs: cleanTtl, scope }),\n )\n const startedAt = now()\n screen.handover = {\n actor: actor ?? null,\n scope,\n beganAt: startedAt,\n deadline: startedAt + cleanTtl,\n }\n // The boundary events are the one thing that crosses the mask.\n emit(record, { kind: 'handover_begin', actor: actor ?? null, scope })\n ports.audit({\n kind: 'handover_begin',\n deskId: record.deskId,\n actor: actor ?? null,\n scope,\n ttlMs: cleanTtl,\n at: iso(startedAt),\n })\n armTimer(record)\n return { url: begun.url }\n },\n async end() {\n requireMachine(record, epoch)\n await endHandover(record, 'ended')\n },\n get active() {\n return record.screen?.handover != null\n },\n },\n }\n }\n\n async function start(startOptions: DeskStartOptions): Promise<DeskHandle> {\n const deskId = cleanDeskId(startOptions.deskId)\n return serializeLifecycle(deskId, async () => {\n const existing = records.get(deskId)\n if (existing?.status === 'resident' && existing.handle) return existing.handle\n return admit(() => boot(deskId, { ...startOptions, deskId }))\n })\n }\n\n async function resume(deskId: string): Promise<DeskHandle> {\n const id = cleanDeskId(deskId)\n return serializeLifecycle(id, async () => {\n const record = records.get(id)\n if (!record) throw new DeskError(`Unknown desk: ${deskId}`)\n if (record.status === 'resident' && record.handle) return record.handle\n return admit(() => boot(record.deskId, record.startOptions))\n })\n }\n\n async function suspend(deskId: string): Promise<void> {\n const id = cleanDeskId(deskId)\n await serializeLifecycle(id, async () => {\n const record = records.get(id)\n if (!record) return\n await teardown(record)\n })\n }\n\n /**\n * Delete a desk's overlay. The ONLY place in this module that removes a\n * desk's disk, and it is reachable from `destroy` alone — see the contract\n * on `teardown` for why suspend must never come near it.\n *\n * The record is dropped whether or not the unlink succeeds: a desk the\n * caller has destroyed must not stay leaseable because its file was busy.\n * A failed unlink is surfaced through `lastError` and leaves the file for\n * the reaper rather than being retried here.\n */\n async function reclaimOverlay(record: DeskRecord): Promise<void> {\n try {\n await removeOverlay(record.startOptions.overlayPath)\n } catch (error) {\n lastError = `Overlay was not reclaimed for ${record.deskId}: ${errorMessage(error)}`\n }\n }\n\n async function destroy(deskId: string): Promise<void> {\n const id = cleanDeskId(deskId)\n await serializeLifecycle(id, async () => {\n const record = records.get(id)\n if (!record) return\n await teardown(record)\n records.delete(id)\n // Strictly after teardown: the VMM still has the file open until its child\n // has exited, and unlinking underneath a live guest would leave the desk\n // writing into an orphaned inode instead of failing loudly.\n await reclaimOverlay(record)\n })\n }\n\n async function sweep(): Promise<number> {\n const timestamp = now()\n let suspendedCount = 0\n for (const record of [...records.values()]) {\n const suspended = await serializeLifecycle(record.deskId, async () => {\n // A destroy and a later start may have replaced a captured record\n // before its turn in the sweep. Never apply the old deadline to the\n // new desk that happens to share its id.\n if (records.get(record.deskId) !== record || record.status !== 'resident') return false\n const handover = record.screen?.handover\n if (handover && handover.deadline <= timestamp) {\n await endHandover(record, 'expired')\n }\n if (\n record.leaseDeadline <= timestamp\n || timestamp - record.lastActivityAt >= idleSuspendMs\n ) {\n return teardown(record)\n }\n return false\n })\n if (suspended) suspendedCount += 1\n }\n return suspendedCount\n }\n\n function stats(): DeskHostStats {\n let suspended = 0\n for (const record of records.values()) {\n if (record.status === 'suspended') suspended += 1\n }\n return {\n resident: occupied,\n queued: queue.length,\n capacity,\n suspended,\n lastStartedAt,\n lastSuspendedAt,\n reconnects,\n lastReconnectAt,\n lastReconnectDeskId,\n lastError,\n }\n }\n\n return { start, resume, suspend, destroy, stats, sweep }\n}\n\nexport interface VerifyDeskHostOptions {\n kernelPath: string\n /** Initramfs for the probe VM; needed for a modular kernel, as at boot. */\n initramfsPath?: string\n /**\n * Kernel command line for the probe VM. It must match what real desks boot\n * with: a probe that panics because its root is on another partition\n * reports a host that cannot run desks, which is indistinguishable from a\n * host that genuinely cannot.\n */\n kernelCmdline?: string\n baseImagePath: string\n vmmPath?: string\n kvmPath?: string\n /** Where the throwaway probe overlay is created; defaults to the OS tmpdir. */\n scratchDir?: string\n runtimeDir?: string\n backend?: DeskBackend\n launcherIdentity?: DeskLauncherIdentity\n platform?: NodeJS.Platform\n pathExists?: (path: string) => boolean\n deviceExists?: (path: string) => boolean\n idFactory?: () => string\n}\n\nexport interface OverlayReflinkCheck {\n /** Whether `cp --reflink` produced a block-sharing clone in this directory. */\n supported: boolean\n overlayDirectory: string\n /** Why the answer is what it is — the `cp` failure when unsupported. */\n detail: string\n}\n\n/**\n * Whether the overlay directory's filesystem can make reflink clones.\n *\n * This exists because `cp --reflink=auto` — what `buildDeskLaunchPlan` uses,\n * deliberately, so a desk still boots on a filesystem without reflink — is\n * SILENT when it falls back. On XFS or Btrfs a 20GB base clones instantly and\n * costs kilobytes; on ext4 the identical command copies all 20GB, slowly, per\n * desk. The failure is invisible until a disk sized for reflink sharing fills\n * after two desks, which looks like a capacity bug rather than the filesystem\n * choice it actually is.\n *\n * So the probe uses `--reflink=always`, which REFUSES to fall back, on a tiny\n * throwaway file. Call it at startup and refuse to serve rather than discover\n * this in production — see `assertOverlayReflink`.\n */\nexport async function verifyOverlayReflink(options: {\n overlayDirectory: string\n idFactory?: () => string\n copy?: (source: string, destination: string) => Promise<void>\n}): Promise<OverlayReflinkCheck> {\n const overlayDirectory = options.overlayDirectory\n const idFactory = options.idFactory ?? randomUUID\n const copy = options.copy ?? reflinkAlways\n const token = idFactory()\n const source = join(overlayDirectory, `.reflink-probe-${token}`)\n const destination = join(overlayDirectory, `.reflink-probe-${token}.clone`)\n try {\n try {\n await writeFile(source, 'reflink probe')\n } catch (error) {\n // A directory that cannot be written to is not a filesystem without\n // reflink — it is a broken deployment, and reporting it as the former\n // would send an operator to reformat a disk over a permissions bug.\n throw new DeskError(\n `The overlay directory ${overlayDirectory} could not be written to, so reflink `\n + `support could not be determined: ${errorMessage(error)}`,\n )\n }\n await copy(source, destination)\n return { supported: true, overlayDirectory, detail: 'cp --reflink=always succeeded.' }\n } catch (error) {\n if (error instanceof DeskError) throw error\n return { supported: false, overlayDirectory, detail: errorMessage(error) }\n } finally {\n await rm(source, { force: true }).catch(() => undefined)\n await rm(destination, { force: true }).catch(() => undefined)\n }\n}\n\n/**\n * Fail loudly at startup on a filesystem without reflink support, naming the\n * cost so the operator can act on it.\n */\nexport async function assertOverlayReflink(options: {\n overlayDirectory: string\n idFactory?: () => string\n copy?: (source: string, destination: string) => Promise<void>\n}): Promise<OverlayReflinkCheck> {\n const check = await verifyOverlayReflink(options)\n if (!check.supported) {\n throw new DeskError(\n `The overlay directory ${check.overlayDirectory} is on a filesystem without reflink `\n + 'support, so every desk would FULL-COPY the base image instead of sharing its '\n + 'blocks — gigabytes and minutes per desk, and a disk sized for sharing fills after '\n + `a handful of them. Put the overlay directory on XFS or Btrfs. Probe said: ${check.detail}`,\n )\n }\n return check\n}\n\nasync function reflinkAlways(source: string, destination: string): Promise<void> {\n await new Promise<void>((resolvePromise, rejectPromise) => {\n execFile('cp', ['--reflink=always', source, destination], (error, _stdout, stderr) => {\n if (error) {\n rejectPromise(new Error(stderr.trim() || errorMessage(error)))\n return\n }\n resolvePromise()\n })\n })\n}\n\nexport interface DeskHostVerification {\n /** Whether this host can serve desks: KVM present and the guest reachable. */\n supported: boolean\n vmmPath: string\n kvm: boolean\n vsock: boolean\n virtioGpu: boolean\n}\n\n/**\n * Boot-time probe. Distinguishes a host that is unusable — wrong platform,\n * missing VMM, missing images — which throws, from capabilities that are\n * merely absent, which are reported as booleans: `kvm` (no boot possible\n * without it), `vsock` (the guest agent answered), and `virtioGpu` (a screen\n * would have hardware-backed rendering). It boots a throwaway microVM through\n * the backend, asks it two questions, and discards it.\n */\nexport async function verifyDeskHost(options: VerifyDeskHostOptions): Promise<DeskHostVerification> {\n const platform = options.platform ?? process.platform\n const pathExists = options.pathExists ?? existsSync\n const deviceExists = options.deviceExists ?? existsSync\n const idFactory = options.idFactory ?? randomUUID\n const backend = options.backend ?? cloudHypervisorBackend\n const vmmPath = options.vmmPath ?? DEFAULT_VMM_PATH\n const kvmPath = options.kvmPath ?? DEFAULT_KVM_PATH\n\n if (platform !== 'linux') {\n throw new DeskError(`The AppKit desk requires Linux; received ${platform}.`)\n }\n if (!pathExists(vmmPath)) {\n throw new DeskError(`Cloud Hypervisor was not found at ${vmmPath}.`)\n }\n if (!pathExists(options.kernelPath)) {\n throw new DeskError(`Guest kernel does not exist: ${options.kernelPath}`)\n }\n if (!pathExists(options.baseImagePath)) {\n throw new DeskError(`Base image does not exist: ${options.baseImagePath}`)\n }\n if (!deviceExists(kvmPath)) {\n return { supported: false, vmmPath, kvm: false, vsock: false, virtioGpu: false }\n }\n\n const scratchDir = options.scratchDir ?? tmpdir()\n const deskId = `verify-${idFactory()}`\n const overlayPath = join(scratchDir, `${deskId}.raw`)\n const plan = buildDeskLaunchPlan(\n {\n deskId,\n vmmPath,\n kvmPath,\n kernelPath: options.kernelPath,\n ...(options.initramfsPath === undefined ? {} : { initramfsPath: options.initramfsPath }),\n ...(options.kernelCmdline === undefined ? {} : { kernelCmdline: options.kernelCmdline }),\n baseImagePath: options.baseImagePath,\n overlayPath,\n vsockCid: 3,\n runtimeDir: options.runtimeDir,\n launcherIdentity: options.launcherIdentity,\n },\n { pathExists, deviceExists },\n )\n\n let machine: DeskMachine\n try {\n machine = await backend.boot(plan)\n } catch (error) {\n throw new DeskError(`Desk verification could not boot a probe VM: ${errorMessage(error)}`)\n }\n let vsock = false\n let virtioGpu = false\n try {\n try {\n await machine.request({ op: 'ping' })\n vsock = true\n } catch {\n vsock = false\n }\n if (vsock) {\n try {\n virtioGpu = parseCapabilities(await machine.request({ op: 'capabilities' })).virtioGpu\n } catch {\n virtioGpu = false\n }\n }\n } finally {\n try {\n await machine.shutdown()\n } catch {\n // The probe VM is discarded regardless of how cleanly it stops.\n }\n await rm(overlayPath, { force: true })\n }\n return { supported: vsock, vmmPath, kvm: true, vsock, virtioGpu }\n}\n\nfunction nonEmptyString(value: string, field: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new DeskError(`${field} must be a non-empty string.`)\n }\n return value\n}\n\nfunction requireStringValue(value: string, field: string): string {\n if (typeof value !== 'string') {\n throw new DeskError(`${field} must be a string.`)\n }\n return value\n}\n\nfunction positiveInteger(value: number, field: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw new DeskError(`${field} must be a positive integer.`)\n }\n return value\n}\n\nfunction nonNegativeInteger(value: number, field: string): number {\n if (!Number.isInteger(value) || value < 0) {\n throw new DeskError(`${field} must be an integer of zero or more.`)\n }\n return value\n}\n\n/**\n * Free bytes on the filesystem holding `path`, measured against the directory\n * so the answer is the same before and after the overlay itself exists.\n */\nasync function defaultFreeBytes(path: string): Promise<number> {\n const stats = await statfs(dirname(path))\n return Number(stats.bsize) * Number(stats.bavail)\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The desk host: lifecycle, leases, and the screen service over a backend.\n *\n * One host manages many desks against one capacity budget. A desk is\n * headless by default; the screen is a service started on demand on the\n * machine the agent is already using. The host owns lease accounting (idle\n * suspend, a hard concurrency cap with a FIFO queue beyond it), event\n * emission to the consumer's ports, and the handover masking contract. It\n * never touches a database and knows nothing about tenants or approvals.\n */\nimport { existsSync } from 'node:fs'\nimport { execFile } from 'node:child_process'\nimport { rm, statfs, writeFile } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport { Buffer } from 'node:buffer'\nimport {\n buildDeskLaunchPlan,\n cleanDeskId,\n DEFAULT_KVM_PATH,\n DEFAULT_VMM_PATH,\n DeskError,\n type DeskLauncherIdentity,\n} from './plan'\nimport {\n cloudHypervisorBackend,\n type DeskBackend,\n type DeskConnectionChange,\n type DeskMachine,\n} from './backend'\nimport {\n parseCapabilities,\n parseClipboardText,\n parseExecResult,\n parseHandoverBegun,\n parseJobStarted,\n parseObservation,\n type GuestEventMessage,\n type GuestInput,\n} from './protocol'\nimport type {\n A11yNode,\n DeskEventDetail,\n DeskEventKind,\n DeskFrameFormat,\n DeskHandoverEndReason,\n DeskHandoverScope,\n DeskPoint,\n DeskPointerButton,\n DeskPorts,\n DeskVideoChunkKind,\n WindowInfo,\n} from './events'\n\nexport const DEFAULT_CAPACITY = 4\nexport const DEFAULT_IDLE_SUSPEND_MS = 5 * 60_000\nexport const DEFAULT_LEASE_MS = 15 * 60_000\n/** The in-guest trim run before a desk suspends — see `trimGuest`. */\nexport const DEFAULT_TRIM_COMMAND = '/usr/sbin/fstrim'\nexport const DEFAULT_TRIM_ARGS: readonly string[] = ['/']\nexport const DEFAULT_TRIM_TIMEOUT_MS = 60_000\nexport const DEFAULT_CID_BASE = 100\nconst MAX_BUFFERED_FRAMES = 60\n/**\n * Video chunks a slow consumer may fall behind by before its stream is ended.\n * Larger than the frame bound because a fragment is a fraction of a frame's\n * bytes, and enforced by ENDING rather than by dropping — see the comment at\n * the overrun.\n */\nconst MAX_BUFFERED_VIDEO_CHUNKS = 600\nconst MIN_TIMER_DELAY_MS = 25\n\n/**\n * Event kinds that must never reach the recording port while a handover is\n * active. Human input and everything derived from watching the human act is\n * masked; only the handover boundaries themselves cross.\n */\nconst HANDOVER_MASKED_KINDS: ReadonlySet<DeskEventKind> = new Set([\n 'click',\n 'type',\n 'key',\n 'scroll',\n 'drag',\n 'window_focus',\n 'app_launch',\n])\n\nexport interface DeskHostOptions {\n /** Root of the golden base image and per-desk assets. */\n imageRoot: string\n vmmPath?: string\n kvmPath?: string\n /** Guest kernel; defaults to `<imageRoot>/vmlinux`. */\n kernelPath?: string\n /**\n * Initramfs the guest kernel boots with. A modular distro cloud kernel needs\n * one to mount root; omit only for a kernel with virtio/ext4 built in. When\n * unset it defaults to `<imageRoot>/initrd` if that file exists, else none.\n */\n initramfsPath?: string\n /**\n * Kernel command line every desk boots with. Defaults to\n * `DEFAULT_KERNEL_CMDLINE`; override it for partitioned cloud images whose\n * root is not `/dev/vda` (e.g. `root=/dev/vda3 rw quiet`).\n */\n kernelCmdline?: string\n /** Directory holding vsock and API control sockets. */\n runtimeDir?: string\n launcherIdentity?: DeskLauncherIdentity\n backend?: DeskBackend\n ports: DeskPorts\n /** Hard cap on concurrently resident desks; starts beyond it queue FIFO. */\n capacity?: number\n idleSuspendMs?: number\n defaultLeaseMs?: number\n /** First guest vsock CID handed out; each boot takes the next one. */\n cidBase?: number\n now?: () => number\n pathExists?: (path: string) => boolean\n deviceExists?: (path: string) => boolean\n /**\n * Delete a destroyed desk's overlay. Injectable so the destroy path is\n * testable without a filesystem; defaults to `rm(path, { force: true })`.\n */\n removeOverlay?: (path: string) => Promise<void>\n /**\n * Bytes that must remain free on the overlay filesystem AFTER admitting a\n * desk. A desk whose overlay cannot be grown fails deep inside the guest —\n * ENOSPC surfaces as a corrupt filesystem or a boot that hangs, which reads\n * as a product bug rather than as a full disk. Refusing the lease up front\n * turns that into one clear error. Zero disables the check.\n */\n minFreeBytes?: number\n /**\n * Free bytes on the filesystem holding `path`. Injectable for tests;\n * defaults to `statfs`.\n */\n freeBytes?: (path: string) => Promise<number>\n /**\n * Run `fstrim` in the guest just before it suspends, returning the blocks it\n * has freed to the host filesystem. On by default: an overlay that is never\n * trimmed only grows. Set false for a guest without the binary, or one whose\n * filesystem should never be discarded.\n */\n trimOnSuspend?: boolean\n /** The in-guest trim binary. */\n trimCommand?: string\n /** Arguments for the trim binary; defaults to trimming the guest root. */\n trimArgs?: readonly string[]\n /** Bound on the trim; a slow trim must not hold up a suspend indefinitely. */\n trimTimeoutMs?: number\n}\n\nexport interface DeskStartOptions {\n deskId: string\n /** Absolute path of the golden base image this desk boots from. */\n baseImage: string\n /** Absolute path of this desk's copy-on-write overlay. */\n overlayPath: string\n memoryMb?: number\n vcpus?: number\n leaseMs?: number\n network?: { tapDevice?: string; macAddress?: string }\n}\n\nexport interface DeskExecOptions {\n command: string\n args?: readonly string[]\n cwd?: string\n env?: Readonly<Record<string, string>>\n timeoutMs?: number\n /** Survive the call as a background job; the job dies with the lease. */\n keepAlive?: boolean\n}\n\nexport interface DeskExecSnapshot {\n deskId: string\n command: string\n args: readonly string[]\n exitCode: number | null\n signal: string | null\n stdout: string\n stderr: string\n truncated: boolean\n startedAt: string\n finishedAt: string\n}\n\nexport interface DeskJob {\n jobId: string\n deskId: string\n command: string\n args: readonly string[]\n startedAt: string\n status: 'running' | 'exited'\n exitCode: number | null\n signal: string | null\n}\n\nexport interface DeskObservation {\n png: Buffer\n width: number\n height: number\n a11y: A11yNode | null\n windows: readonly WindowInfo[]\n focused: WindowInfo | null\n}\n\nexport interface DeskFrame {\n seq: number\n width: number\n height: number\n data: Buffer\n /**\n * How `data` is encoded. A consumer must not assume PNG — it builds the\n * media type it hands on (a `data:` URL, a decoder) from this.\n */\n format: DeskFrameFormat\n at: string\n}\n\n/**\n * One unit of the live video stream: the init segment, or one media fragment.\n *\n * Video is deliberately NOT modelled as a kind of frame. A frame is a picture\n * that stands alone; a video chunk is meaningless without the init segment\n * before it and, for a media chunk, without the keyframe its group of pictures\n * began at. Pretending otherwise produces a consumer that appends bytes in any\n * order and renders black with no error to explain it.\n */\nexport interface DeskVideoChunk {\n seq: number\n kind: DeskVideoChunkKind\n /** RFC 6381, e.g. `avc1.42C020`. What a MediaSource must be told. */\n codec: string\n width: number\n height: number\n /** True when a `media` chunk begins at a sync sample. Always false on `init`. */\n keyframe: boolean\n data: Buffer\n at: string\n}\n\nexport interface DeskScreenInput {\n move(x: number, y: number): Promise<void>\n click(x: number, y: number, button?: DeskPointerButton, clicks?: 1 | 2): Promise<void>\n type(text: string): Promise<void>\n key(combo: string): Promise<void>\n scroll(x: number, y: number, dx: number, dy: number): Promise<void>\n drag(from: DeskPoint, to: DeskPoint): Promise<void>\n}\n\nexport interface DeskScreenHandle {\n observe(): Promise<DeskObservation>\n /**\n * Coordinate contract: all coordinates are in the pixel space of the most\n * recent view of the screen — an `observe()`, a frame from `frames()`, or a\n * chunk from `video()` — one to one. All three anchor it, because the caller\n * aims at whatever it was last shown, and a live viewer is shown a stream\n * rather than an observation. That holds whatever the encoding is: a lossy\n * frame and an H.264 fragment are both true-size views of the screen, so they\n * anchor exactly as a lossless PNG does. Input before any view, or outside\n * its bounds, throws.\n */\n input: DeskScreenInput\n a11y: { invoke(nodeId: string, action: string): Promise<void> }\n launch(appId: string, args?: readonly string[]): Promise<void>\n clipboard: { read(): Promise<string>; write(text: string): Promise<void> }\n /**\n * The live frame stream. `format` picks how the guest encodes each frame and\n * is a bytes-for-fidelity trade: `jpeg` is roughly an order of magnitude\n * smaller per frame, which is what a human driving the screen needs, while\n * `png` stays exact. Omitted leaves the choice to the guest. `observe()` is\n * unaffected and always lossless.\n *\n * The stream also ends when the desk reconnects to its guest agent: the\n * capture behind it did not survive, so the iterator completes rather than\n * waiting on frames that are never coming. Start another one to resume.\n */\n frames(options?: {\n fps?: number\n width?: number\n height?: number\n format?: DeskFrameFormat\n }): AsyncIterable<DeskFrame>\n /**\n * The live screen as encoded VIDEO rather than as a sequence of pictures.\n *\n * This is what a person driving the desk should watch. `frames()` ships a\n * whole independent image per tick; a video codec ships the DIFFERENCE, and a\n * desktop is mostly still — which is roughly two orders of magnitude fewer\n * bytes on the transport between the guest and here, the one place the live\n * view was actually bounded.\n *\n * The stream anchors the coordinate space exactly as `observe()` and\n * `frames()` do, from the first chunk onwards, because a viewer driving by\n * video is aiming at what the video showed it.\n *\n * Masked like frames: nothing is emitted while a handover is active. And\n * ended like frames when the desk reconnects to its guest agent — a video\n * consumer resumed on a fresh encoder, without its init segment and away\n * from a keyframe, decodes nothing at all and says so nowhere.\n */\n video(options?: {\n fps?: number\n width?: number\n height?: number\n }): AsyncIterable<DeskVideoChunk>\n handover: {\n begin(options: {\n ttlMs: number\n scope?: DeskHandoverScope\n actor?: string\n }): Promise<{ url: string }>\n end(): Promise<void>\n readonly active: boolean\n }\n}\n\nexport interface DeskScreenService {\n start(options: { width: number; height: number }): Promise<DeskScreenHandle>\n stop(): Promise<void>\n readonly running: boolean\n}\n\n/**\n * One leased desk.\n *\n * The handle stays valid across a lost guest connection: the host reconnects\n * underneath it and later calls work, so a guest agent restart or a dropped\n * vsock bridge no longer costs the rest of the lease. Two consequences a\n * caller must actually handle:\n *\n * - A call that was IN FLIGHT when the connection dropped rejects with\n * `DeskRequestFateUnknownError` — it may already have run in the guest.\n * Nothing retries it for you.\n * - A reconnect does not restore guest-side capture state. Live `frames()` and\n * `video()` iterators END, and the coordinate anchor is dropped, so the\n * caller must `observe()` (or take a new frame) before aiming again.\n *\n * When the connection cannot be recovered at all the desk is suspended, so the\n * handle goes dead and `resume()` boots a fresh one — rather than the handle\n * answering \"no longer connected\" for the rest of the lease.\n */\nexport interface DeskHandle {\n readonly deskId: string\n renewLease(ms: number): void\n exec(options: DeskExecOptions & { keepAlive: true }): Promise<DeskJob>\n exec(options: DeskExecOptions): Promise<DeskExecSnapshot>\n /** The keepAlive processes still running on this desk. */\n jobs(): DeskJob[]\n screen: DeskScreenService\n}\n\nexport interface DeskHostStats {\n /** Desks currently resident (booted or booting) against the capacity cap. */\n resident: number\n /** Starts waiting in the FIFO queue for capacity. */\n queued: number\n capacity: number\n suspended: number\n lastStartedAt: string | null\n lastSuspendedAt: string | null\n /**\n * Times a resident desk lost its guest connection mid-lease and got it back.\n * One is a blip; a number that climbs is a desk FLAPPING — a guest agent\n * restarting in a loop, a failing vsock bridge — and that is the difference\n * between \"the desk is slow\" and a diagnosis.\n */\n reconnects: number\n lastReconnectAt: string | null\n /** Which desk reconnected last: enough to go and look at the right one. */\n lastReconnectDeskId: string | null\n lastError: string | null\n}\n\nexport interface DeskHost {\n start(options: DeskStartOptions): Promise<DeskHandle>\n resume(deskId: string): Promise<DeskHandle>\n suspend(deskId: string): Promise<void>\n destroy(deskId: string): Promise<void>\n stats(): DeskHostStats\n /**\n * Enforce every time-based rule now: expire handovers past their TTL and\n * suspend desks past their lease or idle deadline. Returns the number of\n * desks suspended. Timers call this automatically; tests with an injected\n * clock call it directly.\n */\n sweep(): Promise<number>\n}\n\ninterface HandoverState {\n actor: string | null\n scope: DeskHandoverScope\n beganAt: number\n deadline: number\n}\n\ninterface ScreenState {\n running: boolean\n width: number\n height: number\n lastObservation: { width: number; height: number } | null\n lastFocusedId: string | null\n handover: HandoverState | null\n handle: DeskScreenHandle\n}\n\ninterface DeskRecord {\n deskId: string\n startOptions: DeskStartOptions\n status: 'resident' | 'suspending' | 'suspended'\n machine: DeskMachine | null\n epoch: number\n leaseDeadline: number\n lastActivityAt: number\n jobs: Map<string, DeskJob>\n screen: ScreenState | null\n unsubscribe: (() => void) | null\n unwatchConnection: (() => void) | null\n handle: DeskHandle | null\n timer: NodeJS.Timeout | null\n streamStops: Set<() => void>\n}\n\ninterface QueueEntry {\n run: () => Promise<DeskHandle>\n resolve: (handle: DeskHandle) => void\n reject: (error: Error) => void\n}\n\nexport function createDeskHost(options: DeskHostOptions): DeskHost {\n const ports = options.ports\n if (typeof ports?.onEvent !== 'function' || typeof ports?.audit !== 'function') {\n throw new DeskError('createDeskHost requires ports with onEvent and audit functions.')\n }\n const backend = options.backend ?? cloudHypervisorBackend\n const now = options.now ?? Date.now\n const pathExists = options.pathExists ?? existsSync\n const deviceExists = options.deviceExists ?? existsSync\n const removeOverlay = options.removeOverlay ?? ((path: string) => rm(path, { force: true }))\n const freeBytes = options.freeBytes ?? defaultFreeBytes\n const minFreeBytes = nonNegativeInteger(options.minFreeBytes ?? 0, 'minFreeBytes')\n const trimOnSuspend = options.trimOnSuspend ?? true\n const trimCommand = options.trimCommand ?? DEFAULT_TRIM_COMMAND\n const trimArgs = options.trimArgs ?? DEFAULT_TRIM_ARGS\n const trimTimeoutMs = positiveInteger(options.trimTimeoutMs ?? DEFAULT_TRIM_TIMEOUT_MS, 'trimTimeoutMs')\n const capacity = positiveInteger(options.capacity ?? DEFAULT_CAPACITY, 'capacity')\n const idleSuspendMs = positiveInteger(options.idleSuspendMs ?? DEFAULT_IDLE_SUSPEND_MS, 'idleSuspendMs')\n const defaultLeaseMs = positiveInteger(options.defaultLeaseMs ?? DEFAULT_LEASE_MS, 'defaultLeaseMs')\n const kernelPath = options.kernelPath ?? join(options.imageRoot, 'vmlinux')\n // Default the initramfs to <imageRoot>/initrd when present so a modular\n // cloud kernel boots without every caller having to name it; an explicit\n // option always wins.\n const defaultInitramfs = join(options.imageRoot, 'initrd')\n const initramfsPath =\n options.initramfsPath ?? (pathExists(defaultInitramfs) ? defaultInitramfs : undefined)\n const kernelCmdline = options.kernelCmdline\n\n const records = new Map<string, DeskRecord>()\n /**\n * The last lifecycle transition scheduled for each desk. A desk may only\n * have one VMM child touching its overlay, so boot and teardown are ordered\n * on the desk identity rather than allowed to race through independent API\n * calls. The stored tail always resolves; callers still receive their own\n * operation's result or error.\n */\n const lifecycleTransitions = new Map<string, Promise<void>>()\n const queue: QueueEntry[] = []\n let occupied = 0\n let nextCid = positiveInteger(options.cidBase ?? DEFAULT_CID_BASE, 'cidBase')\n let lastStartedAt: string | null = null\n let lastSuspendedAt: string | null = null\n let lastError: string | null = null\n let reconnects = 0\n let lastReconnectAt: string | null = null\n let lastReconnectDeskId: string | null = null\n\n function iso(timestamp: number): string {\n return new Date(timestamp).toISOString()\n }\n\n function serializeLifecycle<T>(deskId: string, transition: () => Promise<T>): Promise<T> {\n const previous = lifecycleTransitions.get(deskId)\n // Preserve the host's existing synchronous admission semantics when this\n // desk has no transition in flight. Only conflicts need the promise tail;\n // unrelated starts must still appear in queue stats before `start` returns.\n const current = previous ? previous.then(transition, transition) : transition()\n const tail = current.then(\n () => undefined,\n () => undefined,\n )\n lifecycleTransitions.set(deskId, tail)\n return current.finally(() => {\n if (lifecycleTransitions.get(deskId) === tail) lifecycleTransitions.delete(deskId)\n })\n }\n\n function emit(record: DeskRecord, detail: DeskEventDetail): void {\n if (record.screen?.handover && HANDOVER_MASKED_KINDS.has(detail.kind)) return\n ports.onEvent({ ...detail, deskId: record.deskId, at: iso(now()) })\n }\n\n function touch(record: DeskRecord): void {\n record.lastActivityAt = now()\n }\n\n function requireMachine(record: DeskRecord, epoch: number): DeskMachine {\n if (record.status !== 'resident' || record.epoch !== epoch || !record.machine) {\n throw new DeskError(`Desk ${record.deskId} is not resident; resume it first.`)\n }\n return record.machine\n }\n\n function requireScreen(record: DeskRecord, epoch: number): ScreenState {\n requireMachine(record, epoch)\n const screen = record.screen\n if (!screen?.running) {\n throw new DeskError(`Desk ${record.deskId} has no screen running; call screen.start first.`)\n }\n return screen\n }\n\n function assertCoordinates(record: DeskRecord, points: readonly DeskPoint[]): void {\n const observation = record.screen?.lastObservation\n if (!observation) {\n throw new DeskError(\n 'Coordinate input needs a frame of reference: call observe(), or start '\n + 'frames() and wait for one. Coordinates are the pixel space of the '\n + 'most recent of those, one to one.',\n )\n }\n for (const point of points) {\n if (\n !Number.isInteger(point.x)\n || !Number.isInteger(point.y)\n || point.x < 0\n || point.y < 0\n || point.x >= observation.width\n || point.y >= observation.height\n ) {\n throw new DeskError(\n `Coordinates (${point.x}, ${point.y}) are outside the most recent view `\n + `(${observation.width}x${observation.height}); observe() again before targeting.`,\n )\n }\n }\n }\n\n function armTimer(record: DeskRecord): void {\n if (record.timer) clearTimeout(record.timer)\n record.timer = null\n if (record.status !== 'resident') return\n const deadlines = [record.leaseDeadline, record.lastActivityAt + idleSuspendMs]\n const handover = record.screen?.handover\n if (handover) deadlines.push(handover.deadline)\n const delayMs = Math.max(Math.min(...deadlines) - now(), MIN_TIMER_DELAY_MS)\n record.timer = setTimeout(() => {\n sweep()\n .then(() => {\n if (record.status === 'resident') armTimer(record)\n })\n .catch((error: unknown) => {\n lastError = errorMessage(error)\n })\n }, delayMs)\n record.timer.unref()\n }\n\n async function endHandover(record: DeskRecord, reason: DeskHandoverEndReason): Promise<void> {\n const screen = record.screen\n const handover = screen?.handover\n if (!screen || !handover) return\n screen.handover = null\n if (record.machine) {\n try {\n await record.machine.request({ op: 'handover-end' })\n } catch (error) {\n lastError = errorMessage(error)\n }\n }\n const durationMs = Math.max(0, now() - handover.beganAt)\n emit(record, { kind: 'handover_end', actor: handover.actor, durationMs })\n ports.audit({\n kind: 'handover_end',\n deskId: record.deskId,\n actor: handover.actor,\n durationMs,\n reason,\n at: iso(now()),\n })\n }\n\n /**\n * Stop the machine and keep the disk. This is the SUSPEND half of the\n * lifecycle and it is shared by three callers — `suspend`, `sweep`, and\n * `destroy` — so it must never delete, truncate, or rewrite the overlay.\n *\n * That is not a stylistic preference. For a suspended desk the overlay IS\n * the desk: its home directory, its installed state, its half-written work.\n * A desk that comes back from suspend with a fresh disk has silently lost\n * everything, and the loss surfaces long after the code that caused it.\n * Reclaiming the disk is the exclusive business of `reclaimOverlay`, which\n * is called from exactly one place — `destroy` — where the caller has said\n * the desk should cease to exist.\n */\n /**\n * Hand the guest's freed blocks back to the host, as the last thing the\n * guest does before it stops.\n *\n * An overlay only ever GROWS otherwise. A block the guest writes is\n * allocated on the host filesystem forever; deleting the file inside the\n * guest frees it in the guest's own filesystem and tells the host nothing,\n * so a long-lived desk ratchets upward until the volume is full even though\n * the guest reports itself half empty. `fstrim` is what closes that loop:\n * it walks the guest filesystem's free space and issues discards, which\n * Cloud Hypervisor's virtio-blk turns into hole-punches on the raw overlay.\n *\n * Suspend is the right moment for it. The image's own `fstrim.timer` fires\n * WEEKLY, and a desk that idle-suspends after minutes is almost never up\n * when that lands — so on a leased-and-parked desk the scheduled trim\n * effectively never runs. Suspend, by contrast, is exactly when the guest\n * has stopped needing its scratch and the host wants the space back.\n *\n * This does not violate the disk contract on `teardown`. `fstrim` discards\n * only blocks the guest's filesystem already considers free; it cannot\n * remove a suspended desk's state, and a desk resumed afterwards sees an\n * identical filesystem. It is also strictly best-effort and bounded: a\n * guest that is wedged, disconnected, or lacks the binary must still\n * suspend promptly, so every failure here is swallowed into `lastError`.\n */\n async function trimGuest(record: DeskRecord, machine: DeskMachine): Promise<void> {\n if (!trimOnSuspend) return\n try {\n await machine.request({\n op: 'exec',\n command: trimCommand,\n args: trimArgs,\n timeoutMs: trimTimeoutMs,\n })\n } catch (error) {\n lastError = `Trim before suspend failed for ${record.deskId}: ${errorMessage(error)}`\n }\n }\n\n async function teardown(record: DeskRecord): Promise<boolean> {\n if (record.status !== 'resident') return false\n await endHandover(record, 'revoked')\n for (const stop of [...record.streamStops]) stop()\n record.streamStops.clear()\n if (record.screen?.running) {\n record.screen.running = false\n emit(record, { kind: 'screen_close' })\n }\n record.screen = null\n for (const job of record.jobs.values()) {\n if (job.status !== 'running') continue\n job.status = 'exited'\n job.signal = 'SIGKILL'\n emit(record, { kind: 'job_exit', jobId: job.jobId, exitCode: null, signal: 'SIGKILL' })\n }\n record.unsubscribe?.()\n record.unsubscribe = null\n record.unwatchConnection?.()\n record.unwatchConnection = null\n if (record.timer) clearTimeout(record.timer)\n record.timer = null\n const machine = record.machine\n record.machine = null\n // Do not advertise this desk as suspended until its VMM child is actually\n // down. `serializeLifecycle` prevents a new boot from entering while this\n // transitional state still owns the overlay.\n record.status = 'suspending'\n record.handle = null\n if (machine) {\n await trimGuest(record, machine)\n try {\n await machine.shutdown()\n } catch (error) {\n lastError = errorMessage(error)\n }\n }\n lastSuspendedAt = iso(now())\n occupied -= 1\n record.status = 'suspended'\n drainQueue()\n return true\n }\n\n function drainQueue(): void {\n while (occupied < capacity && queue.length > 0) {\n const entry = queue.shift()\n if (!entry) break\n occupied += 1\n entry.run().then(entry.resolve, (error: unknown) => {\n occupied -= 1\n entry.reject(error instanceof Error ? error : new Error(String(error)))\n drainQueue()\n })\n }\n }\n\n function admit(run: () => Promise<DeskHandle>): Promise<DeskHandle> {\n if (occupied < capacity) {\n occupied += 1\n return run().catch((error: unknown) => {\n occupied -= 1\n drainQueue()\n throw error\n })\n }\n return new Promise<DeskHandle>((resolvePromise, rejectPromise) => {\n queue.push({ run, resolve: resolvePromise, reject: rejectPromise })\n })\n }\n\n /**\n * Refuse a desk the overlay filesystem cannot afford. A reflink clone costs\n * almost nothing at creation and then grows as the guest writes, so the\n * moment that matters is not the `cp` — it is every write after it. Checking\n * headroom here converts a mid-boot ENOSPC, which the guest reports as a\n * corrupt disk or a hang, into one refusal naming the actual shortage.\n */\n async function admitDisk(overlayPath: string): Promise<void> {\n if (minFreeBytes <= 0) return\n let free: number\n try {\n free = await freeBytes(overlayPath)\n } catch (error) {\n // Fail OPEN on an unreadable filesystem: a desk refused because statfs\n // hiccuped is a worse outcome than one admitted onto a disk that turns\n // out to be full, which at least fails with a real disk error.\n lastError = `Free-space check failed for ${overlayPath}: ${errorMessage(error)}`\n return\n }\n if (free < minFreeBytes) {\n throw new DeskError(\n `Refusing to start a desk: the overlay filesystem holding ${overlayPath} has `\n + `${free} bytes free, below the ${minFreeBytes}-byte floor. Reclaim destroyed `\n + 'desks’ overlays or grow the volume before leasing another desk.',\n )\n }\n }\n\n async function boot(deskId: string, startOptions: DeskStartOptions): Promise<DeskHandle> {\n // Before the plan, so a full disk is reported as a full disk rather than\n // as whatever the overlay copy fails with.\n await admitDisk(startOptions.overlayPath)\n const plan = buildDeskLaunchPlan(\n {\n deskId,\n vmmPath: options.vmmPath,\n kvmPath: options.kvmPath,\n kernelPath,\n ...(initramfsPath === undefined ? {} : { initramfsPath }),\n baseImagePath: startOptions.baseImage,\n overlayPath: startOptions.overlayPath,\n memoryMb: startOptions.memoryMb,\n vcpus: startOptions.vcpus,\n vsockCid: nextCid++,\n runtimeDir: options.runtimeDir,\n tapDevice: startOptions.network?.tapDevice,\n macAddress: startOptions.network?.macAddress,\n // Forward the host's cmdline only when set; otherwise the plan falls\n // back to DEFAULT_KERNEL_CMDLINE.\n ...(kernelCmdline === undefined ? {} : { kernelCmdline }),\n launcherIdentity: options.launcherIdentity,\n },\n { pathExists, deviceExists },\n )\n let machine: DeskMachine\n try {\n machine = await backend.boot(plan)\n } catch (error) {\n lastError = errorMessage(error)\n throw error instanceof DeskError\n ? error\n : new DeskError(`Desk ${deskId} failed to boot: ${errorMessage(error)}`)\n }\n\n let record = records.get(deskId)\n if (!record) {\n record = {\n deskId,\n startOptions,\n status: 'resident',\n machine,\n epoch: 1,\n leaseDeadline: 0,\n lastActivityAt: 0,\n jobs: new Map(),\n screen: null,\n unsubscribe: null,\n unwatchConnection: null,\n handle: null,\n timer: null,\n streamStops: new Set(),\n }\n records.set(deskId, record)\n } else {\n record.startOptions = startOptions\n record.status = 'resident'\n record.machine = machine\n record.epoch += 1\n record.jobs = new Map()\n record.screen = null\n record.streamStops = new Set()\n }\n const current = record\n const epoch = current.epoch\n current.leaseDeadline = now() + positiveInteger(startOptions.leaseMs ?? defaultLeaseMs, 'leaseMs')\n current.lastActivityAt = now()\n current.unsubscribe = machine.subscribe((event) => {\n handleGuestEvent(current, epoch, event)\n })\n current.unwatchConnection =\n machine.onConnectionChange?.((change) => {\n handleConnectionChange(current, epoch, change)\n }) ?? null\n current.handle = makeHandle(current, epoch)\n lastStartedAt = iso(now())\n armTimer(current)\n return current.handle\n }\n\n function handleGuestEvent(record: DeskRecord, epoch: number, event: GuestEventMessage): void {\n if (record.status !== 'resident' || record.epoch !== epoch) return\n if (event.event === 'job-exit') {\n const job = record.jobs.get(event.jobId)\n if (!job || job.status !== 'running') return\n job.status = 'exited'\n job.exitCode = event.exitCode\n job.signal = event.signal\n emit(record, {\n kind: 'job_exit',\n jobId: event.jobId,\n exitCode: event.exitCode,\n signal: event.signal,\n })\n return\n }\n if (event.event === 'window-focus') {\n if (record.screen) record.screen.lastFocusedId = event.window.id\n emit(record, { kind: 'window_focus', window: event.window })\n }\n }\n\n /**\n * What a desk losing (and regaining) its guest channel means up here.\n *\n * The backend can get the CHANNEL back; it cannot get the GUEST's state\n * back, and pretending otherwise is how a consumer ends up waiting forever\n * on a stream that will never produce another byte. So a reconnect is\n * treated as a discontinuity that the caller is able to see, and a\n * permanent loss retires the desk instead of leaving a dead one leased.\n */\n function handleConnectionChange(\n record: DeskRecord,\n epoch: number,\n change: DeskConnectionChange,\n ): void {\n if (record.status !== 'resident' || record.epoch !== epoch) return\n if (change.state === 'reconnected') {\n reconnects += 1\n lastReconnectAt = iso(now())\n lastReconnectDeskId = record.deskId\n // Never silent. A reconnect that hides a guest agent restarting is a\n // debugging trap: the desk misbehaves and nothing anywhere says why.\n lastError = `Desk ${record.deskId} reconnected to its guest agent after ${change.downtimeMs}ms (${change.reason}).`\n // The guest's capture state did not necessarily come back with the\n // channel. An agent that restarted has no screen, no frame encoder and\n // no video encoder; even one that survived starts a fresh encoder whose\n // sequence numbers and init segment do not continue the old stream. A\n // consumer resumed mid-stream decodes nothing, silently — so every live\n // stream is ENDED. `frames()`/`video()` complete normally, which is how\n // the consumer notices, and it can start a new one on a guest that is\n // now definitely capturing.\n for (const stop of [...record.streamStops]) stop()\n record.streamStops.clear()\n // The coordinate anchor goes with them: the screen behind it may be\n // gone, or recreated at another size, and a click aimed at the pixel\n // space of a screen that no longer exists lands somewhere nobody chose.\n // Input then refuses until the caller observes again — the existing\n // contract, not a new one.\n if (record.screen) {\n record.screen.lastObservation = null\n // The reconnected channel proves the machine is alive, not that the\n // guest compositor survived. Treat the screen as needing an explicit\n // restart so screen.start() reaches the guest instead of returning the\n // stale handle forever. Keep ScreenState itself so an active handover\n // remains masked in the safe direction until its explicit/TTL end.\n record.screen.running = false\n }\n // A handover is deliberately NOT ended here. If a human is still on that\n // screen, dropping the mask would start recording them; letting the TTL\n // expire it fails in the safe direction.\n return\n }\n // Lost for good. Left resident, this desk would answer every call with\n // \"no longer connected\" for the rest of the lease and `resume()` would\n // hand back the same dead handle — the exact product failure this release\n // is about. Suspending it frees the capacity slot and makes the next\n // `resume()` boot a healthy desk.\n lastError = change.reason\n void serializeLifecycle(record.deskId, async () => {\n // The loss belongs to the epoch that registered this watcher. If an\n // earlier queued transition already replaced that machine, this stale\n // signal must not retire the fresh resident.\n if (record.status !== 'resident' || record.epoch !== epoch) return\n await teardown(record)\n }).catch((error: unknown) => {\n lastError = errorMessage(error)\n })\n }\n\n function makeHandle(record: DeskRecord, epoch: number): DeskHandle {\n const execImplementation = async (\n execOptions: DeskExecOptions,\n ): Promise<DeskExecSnapshot | DeskJob> => {\n const machine = requireMachine(record, epoch)\n const command = nonEmptyString(execOptions.command, 'command')\n const args = [...(execOptions.args ?? [])]\n const keepAlive = execOptions.keepAlive === true\n if (ports.policy?.allowExec && !ports.policy.allowExec({\n deskId: record.deskId,\n command,\n args,\n keepAlive,\n })) {\n throw new DeskError(`Policy denied exec of ${command} on desk ${record.deskId}.`)\n }\n touch(record)\n const startedAt = iso(now())\n if (keepAlive) {\n const { jobId } = parseJobStarted(await machine.request({\n op: 'job-start',\n command,\n args,\n cwd: execOptions.cwd,\n env: execOptions.env,\n }))\n const job: DeskJob = {\n jobId,\n deskId: record.deskId,\n command,\n args,\n startedAt,\n status: 'running',\n exitCode: null,\n signal: null,\n }\n record.jobs.set(jobId, job)\n emit(record, { kind: 'job_start', jobId, command, args })\n return { ...job }\n }\n const result = parseExecResult(await machine.request(\n {\n op: 'exec',\n command,\n args,\n cwd: execOptions.cwd,\n env: execOptions.env,\n timeoutMs: execOptions.timeoutMs,\n },\n execOptions.timeoutMs === undefined ? {} : { timeoutMs: execOptions.timeoutMs + 5_000 },\n ))\n emit(record, {\n kind: 'shell_command',\n command,\n args,\n cwd: execOptions.cwd ?? null,\n exitCode: result.exitCode,\n signal: result.signal,\n })\n return {\n deskId: record.deskId,\n command,\n args,\n exitCode: result.exitCode,\n signal: result.signal,\n stdout: result.stdout,\n stderr: result.stderr,\n truncated: result.truncated,\n startedAt,\n finishedAt: iso(now()),\n }\n }\n\n const screenService: DeskScreenService = {\n async start({ width, height }) {\n const machine = requireMachine(record, epoch)\n if (record.screen?.running) return record.screen.handle\n const cleanWidth = positiveInteger(width, 'width')\n const cleanHeight = positiveInteger(height, 'height')\n if (ports.policy?.allowScreen && !ports.policy.allowScreen({\n deskId: record.deskId,\n width: cleanWidth,\n height: cleanHeight,\n })) {\n throw new DeskError(`Policy denied opening a screen on desk ${record.deskId}.`)\n }\n touch(record)\n await machine.request({ op: 'screen-start', width: cleanWidth, height: cleanHeight })\n const existing = record.screen\n if (existing) {\n // A guest-agent reconnect invalidates what the host knew about the\n // compositor without necessarily ending an active handover. Reuse\n // the same handle so existing consumers can recover, and retain the\n // handover mask until its explicit/TTL end rather than briefly\n // exposing a human's private input while the screen restarts.\n existing.running = true\n existing.width = cleanWidth\n existing.height = cleanHeight\n existing.lastObservation = null\n existing.lastFocusedId = null\n emit(record, { kind: 'screen_open', width: cleanWidth, height: cleanHeight })\n return existing.handle\n }\n const handle = makeScreenHandle(record, epoch)\n record.screen = {\n running: true,\n width: cleanWidth,\n height: cleanHeight,\n lastObservation: null,\n lastFocusedId: null,\n handover: null,\n handle,\n }\n emit(record, { kind: 'screen_open', width: cleanWidth, height: cleanHeight })\n return handle\n },\n async stop() {\n const machine = requireMachine(record, epoch)\n const screen = record.screen\n if (!screen?.running) return\n await endHandover(record, 'revoked')\n for (const stop of [...record.streamStops]) stop()\n record.streamStops.clear()\n screen.running = false\n record.screen = null\n touch(record)\n await machine.request({ op: 'screen-stop' })\n emit(record, { kind: 'screen_close' })\n },\n get running() {\n return record.screen?.running === true\n },\n }\n\n return {\n deskId: record.deskId,\n renewLease(ms: number): void {\n requireMachine(record, epoch)\n record.leaseDeadline = now() + positiveInteger(ms, 'ms')\n touch(record)\n armTimer(record)\n },\n exec: execImplementation as DeskHandle['exec'],\n jobs(): DeskJob[] {\n return [...record.jobs.values()]\n .filter((job) => job.status === 'running')\n .map((job) => ({ ...job }))\n },\n screen: screenService,\n }\n }\n\n function makeScreenHandle(record: DeskRecord, epoch: number): DeskScreenHandle {\n async function sendInput(detail: DeskEventDetail | null, input: GuestInput): Promise<void> {\n const machine = requireMachine(record, epoch)\n touch(record)\n await machine.request({ op: 'input', input })\n if (detail) emit(record, detail)\n }\n\n return {\n async observe(): Promise<DeskObservation> {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n touch(record)\n const observation = parseObservation(await machine.request({ op: 'observe' }))\n screen.lastObservation = { width: observation.width, height: observation.height }\n if (observation.focused && observation.focused.id !== screen.lastFocusedId) {\n screen.lastFocusedId = observation.focused.id\n emit(record, { kind: 'window_focus', window: observation.focused })\n }\n return {\n png: Buffer.from(observation.png, 'base64'),\n width: observation.width,\n height: observation.height,\n a11y: observation.a11y,\n windows: observation.windows,\n focused: observation.focused,\n }\n },\n input: {\n async move(x, y) {\n requireScreen(record, epoch)\n assertCoordinates(record, [{ x, y }])\n await sendInput(null, { type: 'move', x, y })\n },\n async click(x, y, button = 'left', clicks = 1) {\n requireScreen(record, epoch)\n assertCoordinates(record, [{ x, y }])\n if (clicks !== 1 && clicks !== 2) throw new DeskError('clicks must be 1 or 2.')\n await sendInput({ kind: 'click', x, y, button, clicks }, { type: 'click', x, y, button, clicks })\n },\n async type(text) {\n requireScreen(record, epoch)\n const cleanText = requireStringValue(text, 'text')\n await sendInput({ kind: 'type', text: cleanText }, { type: 'type', text: cleanText })\n },\n async key(combo) {\n requireScreen(record, epoch)\n const cleanCombo = nonEmptyString(combo, 'combo')\n await sendInput({ kind: 'key', combo: cleanCombo }, { type: 'key', combo: cleanCombo })\n },\n async scroll(x, y, dx, dy) {\n requireScreen(record, epoch)\n assertCoordinates(record, [{ x, y }])\n if (!Number.isInteger(dx) || !Number.isInteger(dy)) {\n throw new DeskError('Scroll deltas must be integers.')\n }\n await sendInput({ kind: 'scroll', x, y, dx, dy }, { type: 'scroll', x, y, dx, dy })\n },\n async drag(from, to) {\n requireScreen(record, epoch)\n assertCoordinates(record, [from, to])\n await sendInput({ kind: 'drag', from, to }, { type: 'drag', from, to })\n },\n },\n a11y: {\n async invoke(nodeId, action) {\n const machine = requireMachine(record, epoch)\n requireScreen(record, epoch)\n touch(record)\n await machine.request({\n op: 'a11y-invoke',\n nodeId: nonEmptyString(nodeId, 'nodeId'),\n action: nonEmptyString(action, 'action'),\n })\n },\n },\n async launch(appId, args = []) {\n const machine = requireMachine(record, epoch)\n requireScreen(record, epoch)\n touch(record)\n const cleanAppId = nonEmptyString(appId, 'appId')\n await machine.request({ op: 'launch', appId: cleanAppId, args: [...args] })\n emit(record, { kind: 'app_launch', appId: cleanAppId, args: [...args] })\n },\n clipboard: {\n async read() {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n if (screen.handover) {\n // The human may have just typed a credential that is now on the\n // clipboard; reading it during a handover would carry it into the\n // agent's context and the consumer's record.\n throw new DeskError('The clipboard is masked while a handover is active.')\n }\n touch(record)\n return parseClipboardText(await machine.request({ op: 'clipboard-read' }))\n },\n async write(text) {\n const machine = requireMachine(record, epoch)\n requireScreen(record, epoch)\n touch(record)\n await machine.request({ op: 'clipboard-write', text: requireStringValue(text, 'text') })\n },\n },\n frames(frameOptions = {}) {\n return {\n [Symbol.asyncIterator]: () => {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n const fps = positiveInteger(frameOptions.fps ?? 10, 'fps')\n const width = positiveInteger(frameOptions.width ?? screen.width, 'width')\n const height = positiveInteger(frameOptions.height ?? screen.height, 'height')\n const format = frameOptions.format\n const buffered: DeskFrame[] = []\n let waiting: ((result: IteratorResult<DeskFrame, undefined>) => void) | null = null\n let finished = false\n const unsubscribe = machine.subscribe((event) => {\n if (finished || event.event !== 'frame') return\n // Masking contract: no frame reaches a recording consumer while\n // a handover is active.\n if (record.screen?.handover) return\n const frame: DeskFrame = {\n seq: event.seq,\n width: event.width,\n height: event.height,\n data: Buffer.from(event.data, 'base64'),\n format: event.format,\n at: iso(now()),\n }\n // A frame anchors coordinates exactly as an observation does.\n // The contract is that a click lands in the pixel space of the\n // most recent thing the caller was SHOWN, and a live view is\n // shown the frame stream, not observe(). Without this a viewer\n // that watches frames and clicks what it sees is refused for\n // never having called observe() — technically true and useless.\n if (record.screen) {\n record.screen.lastObservation = { width: frame.width, height: frame.height }\n }\n if (waiting) {\n const resume = waiting\n waiting = null\n resume({ value: frame, done: false })\n } else {\n buffered.push(frame)\n if (buffered.length > MAX_BUFFERED_FRAMES) buffered.shift()\n }\n })\n const finish = (): void => {\n if (finished) return\n finished = true\n unsubscribe()\n record.streamStops.delete(finish)\n if (record.status === 'resident' && record.machine) {\n record.machine.request({ op: 'frames-stop' }).catch((error: unknown) => {\n lastError = errorMessage(error)\n })\n }\n if (waiting) {\n const resume = waiting\n waiting = null\n resume({ value: undefined, done: true })\n }\n }\n record.streamStops.add(finish)\n const started = machine\n .request({ op: 'frames-start', fps, width, height, format })\n .catch((error: unknown) => {\n finish()\n throw error instanceof Error ? error : new Error(String(error))\n })\n return {\n async next(): Promise<IteratorResult<DeskFrame, undefined>> {\n await started\n const bufferedFrame = buffered.shift()\n if (bufferedFrame) return { value: bufferedFrame, done: false }\n if (finished) return { value: undefined, done: true }\n return new Promise((resolvePromise) => {\n waiting = resolvePromise\n })\n },\n async return(): Promise<IteratorResult<DeskFrame, undefined>> {\n finish()\n return { value: undefined, done: true }\n },\n async throw(error?: unknown): Promise<IteratorResult<DeskFrame, undefined>> {\n finish()\n throw error instanceof Error ? error : new Error(String(error))\n },\n }\n },\n }\n },\n video(videoOptions = {}) {\n return {\n [Symbol.asyncIterator]: () => {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n const fps = positiveInteger(videoOptions.fps ?? 30, 'fps')\n const width = positiveInteger(videoOptions.width ?? screen.width, 'width')\n const height = positiveInteger(videoOptions.height ?? screen.height, 'height')\n const buffered: DeskVideoChunk[] = []\n let waiting: ((result: IteratorResult<DeskVideoChunk, undefined>) => void) | null = null\n let finished = false\n const unsubscribe = machine.subscribe((event) => {\n if (finished || event.event !== 'video-chunk') return\n // The same masking contract frames are held to: while a handover\n // is active a person is on that screen, and nothing derived from\n // watching them may reach a recording consumer.\n if (record.screen?.handover) return\n const chunk: DeskVideoChunk = {\n seq: event.seq,\n kind: event.kind,\n codec: event.codec,\n width: event.width,\n height: event.height,\n keyframe: event.keyframe,\n data: Buffer.from(event.data, 'base64'),\n at: iso(now()),\n }\n // A video chunk anchors coordinates exactly as a frame does, and\n // for the same reason: a viewer driving by video is aiming at the\n // pixel space the video showed it. Anchoring on every chunk, not\n // only the first, is what re-asserts the space when the encoder\n // restarts at a new resolution.\n if (record.screen) {\n record.screen.lastObservation = { width: chunk.width, height: chunk.height }\n }\n if (waiting) {\n const resume = waiting\n waiting = null\n resume({ value: chunk, done: false })\n } else {\n buffered.push(chunk)\n // Dropping the OLDEST would drop the init segment, and a\n // consumer without it decodes nothing at all — so an overrun\n // ends the stream instead. A caller that cannot keep up with a\n // video stream is one that should re-subscribe and be resynced\n // from a keyframe, not one that should be handed a hole.\n if (buffered.length > MAX_BUFFERED_VIDEO_CHUNKS) finish()\n }\n })\n const finish = (): void => {\n if (finished) return\n finished = true\n unsubscribe()\n record.streamStops.delete(finish)\n if (record.status === 'resident' && record.machine) {\n record.machine.request({ op: 'video-stop' }).catch((error: unknown) => {\n lastError = errorMessage(error)\n })\n }\n if (waiting) {\n const resume = waiting\n waiting = null\n resume({ value: undefined, done: true })\n }\n }\n record.streamStops.add(finish)\n const started = machine\n .request({ op: 'video-start', fps, width, height })\n .catch((error: unknown) => {\n finish()\n throw error instanceof Error ? error : new Error(String(error))\n })\n return {\n async next(): Promise<IteratorResult<DeskVideoChunk, undefined>> {\n await started\n const bufferedChunk = buffered.shift()\n if (bufferedChunk) return { value: bufferedChunk, done: false }\n if (finished) return { value: undefined, done: true }\n return new Promise((resolvePromise) => {\n waiting = resolvePromise\n })\n },\n async return(): Promise<IteratorResult<DeskVideoChunk, undefined>> {\n finish()\n return { value: undefined, done: true }\n },\n async throw(error?: unknown): Promise<IteratorResult<DeskVideoChunk, undefined>> {\n finish()\n throw error instanceof Error ? error : new Error(String(error))\n },\n }\n },\n }\n },\n handover: {\n async begin({ ttlMs, scope = 'control', actor }) {\n const machine = requireMachine(record, epoch)\n const screen = requireScreen(record, epoch)\n if (screen.handover) {\n throw new DeskError(`A handover is already active on desk ${record.deskId}.`)\n }\n const cleanTtl = positiveInteger(ttlMs, 'ttlMs')\n if (ports.policy?.allowHandover && !ports.policy.allowHandover({\n deskId: record.deskId,\n scope,\n ttlMs: cleanTtl,\n })) {\n throw new DeskError(`Policy denied a handover on desk ${record.deskId}.`)\n }\n touch(record)\n const begun = parseHandoverBegun(\n await machine.request({ op: 'handover-begin', ttlMs: cleanTtl, scope }),\n )\n const startedAt = now()\n screen.handover = {\n actor: actor ?? null,\n scope,\n beganAt: startedAt,\n deadline: startedAt + cleanTtl,\n }\n // The boundary events are the one thing that crosses the mask.\n emit(record, { kind: 'handover_begin', actor: actor ?? null, scope })\n ports.audit({\n kind: 'handover_begin',\n deskId: record.deskId,\n actor: actor ?? null,\n scope,\n ttlMs: cleanTtl,\n at: iso(startedAt),\n })\n armTimer(record)\n return { url: begun.url }\n },\n async end() {\n requireMachine(record, epoch)\n await endHandover(record, 'ended')\n },\n get active() {\n return record.screen?.handover != null\n },\n },\n }\n }\n\n async function start(startOptions: DeskStartOptions): Promise<DeskHandle> {\n const deskId = cleanDeskId(startOptions.deskId)\n return serializeLifecycle(deskId, async () => {\n const existing = records.get(deskId)\n if (existing?.status === 'resident' && existing.handle) return existing.handle\n return admit(() => boot(deskId, { ...startOptions, deskId }))\n })\n }\n\n async function resume(deskId: string): Promise<DeskHandle> {\n const id = cleanDeskId(deskId)\n return serializeLifecycle(id, async () => {\n const record = records.get(id)\n if (!record) throw new DeskError(`Unknown desk: ${deskId}`)\n if (record.status === 'resident' && record.handle) return record.handle\n return admit(() => boot(record.deskId, record.startOptions))\n })\n }\n\n async function suspend(deskId: string): Promise<void> {\n const id = cleanDeskId(deskId)\n await serializeLifecycle(id, async () => {\n const record = records.get(id)\n if (!record) return\n await teardown(record)\n })\n }\n\n /**\n * Delete a desk's overlay. The ONLY place in this module that removes a\n * desk's disk, and it is reachable from `destroy` alone — see the contract\n * on `teardown` for why suspend must never come near it.\n *\n * The record is dropped whether or not the unlink succeeds: a desk the\n * caller has destroyed must not stay leaseable because its file was busy.\n * A failed unlink is surfaced through `lastError` and leaves the file for\n * the reaper rather than being retried here.\n */\n async function reclaimOverlay(record: DeskRecord): Promise<void> {\n try {\n await removeOverlay(record.startOptions.overlayPath)\n } catch (error) {\n lastError = `Overlay was not reclaimed for ${record.deskId}: ${errorMessage(error)}`\n }\n }\n\n async function destroy(deskId: string): Promise<void> {\n const id = cleanDeskId(deskId)\n await serializeLifecycle(id, async () => {\n const record = records.get(id)\n if (!record) return\n await teardown(record)\n records.delete(id)\n // Strictly after teardown: the VMM still has the file open until its child\n // has exited, and unlinking underneath a live guest would leave the desk\n // writing into an orphaned inode instead of failing loudly.\n await reclaimOverlay(record)\n })\n }\n\n async function sweep(): Promise<number> {\n const timestamp = now()\n let suspendedCount = 0\n for (const record of [...records.values()]) {\n const suspended = await serializeLifecycle(record.deskId, async () => {\n // A destroy and a later start may have replaced a captured record\n // before its turn in the sweep. Never apply the old deadline to the\n // new desk that happens to share its id.\n if (records.get(record.deskId) !== record || record.status !== 'resident') return false\n const handover = record.screen?.handover\n if (handover && handover.deadline <= timestamp) {\n await endHandover(record, 'expired')\n }\n if (\n record.leaseDeadline <= timestamp\n || timestamp - record.lastActivityAt >= idleSuspendMs\n ) {\n return teardown(record)\n }\n return false\n })\n if (suspended) suspendedCount += 1\n }\n return suspendedCount\n }\n\n function stats(): DeskHostStats {\n let suspended = 0\n for (const record of records.values()) {\n if (record.status === 'suspended') suspended += 1\n }\n return {\n resident: occupied,\n queued: queue.length,\n capacity,\n suspended,\n lastStartedAt,\n lastSuspendedAt,\n reconnects,\n lastReconnectAt,\n lastReconnectDeskId,\n lastError,\n }\n }\n\n return { start, resume, suspend, destroy, stats, sweep }\n}\n\nexport interface VerifyDeskHostOptions {\n kernelPath: string\n /** Initramfs for the probe VM; needed for a modular kernel, as at boot. */\n initramfsPath?: string\n /**\n * Kernel command line for the probe VM. It must match what real desks boot\n * with: a probe that panics because its root is on another partition\n * reports a host that cannot run desks, which is indistinguishable from a\n * host that genuinely cannot.\n */\n kernelCmdline?: string\n baseImagePath: string\n vmmPath?: string\n kvmPath?: string\n /** Where the throwaway probe overlay is created; defaults to the OS tmpdir. */\n scratchDir?: string\n runtimeDir?: string\n backend?: DeskBackend\n launcherIdentity?: DeskLauncherIdentity\n platform?: NodeJS.Platform\n pathExists?: (path: string) => boolean\n deviceExists?: (path: string) => boolean\n idFactory?: () => string\n}\n\nexport interface OverlayReflinkCheck {\n /** Whether `cp --reflink` produced a block-sharing clone in this directory. */\n supported: boolean\n overlayDirectory: string\n /** Why the answer is what it is — the `cp` failure when unsupported. */\n detail: string\n}\n\n/**\n * Whether the overlay directory's filesystem can make reflink clones.\n *\n * This exists because `cp --reflink=auto` — what `buildDeskLaunchPlan` uses,\n * deliberately, so a desk still boots on a filesystem without reflink — is\n * SILENT when it falls back. On XFS or Btrfs a 20GB base clones instantly and\n * costs kilobytes; on ext4 the identical command copies all 20GB, slowly, per\n * desk. The failure is invisible until a disk sized for reflink sharing fills\n * after two desks, which looks like a capacity bug rather than the filesystem\n * choice it actually is.\n *\n * So the probe uses `--reflink=always`, which REFUSES to fall back, on a tiny\n * throwaway file. Call it at startup and refuse to serve rather than discover\n * this in production — see `assertOverlayReflink`.\n */\nexport async function verifyOverlayReflink(options: {\n overlayDirectory: string\n idFactory?: () => string\n copy?: (source: string, destination: string) => Promise<void>\n}): Promise<OverlayReflinkCheck> {\n const overlayDirectory = options.overlayDirectory\n const idFactory = options.idFactory ?? randomUUID\n const copy = options.copy ?? reflinkAlways\n const token = idFactory()\n const source = join(overlayDirectory, `.reflink-probe-${token}`)\n const destination = join(overlayDirectory, `.reflink-probe-${token}.clone`)\n try {\n try {\n await writeFile(source, 'reflink probe')\n } catch (error) {\n // A directory that cannot be written to is not a filesystem without\n // reflink — it is a broken deployment, and reporting it as the former\n // would send an operator to reformat a disk over a permissions bug.\n throw new DeskError(\n `The overlay directory ${overlayDirectory} could not be written to, so reflink `\n + `support could not be determined: ${errorMessage(error)}`,\n )\n }\n await copy(source, destination)\n return { supported: true, overlayDirectory, detail: 'cp --reflink=always succeeded.' }\n } catch (error) {\n if (error instanceof DeskError) throw error\n return { supported: false, overlayDirectory, detail: errorMessage(error) }\n } finally {\n await rm(source, { force: true }).catch(() => undefined)\n await rm(destination, { force: true }).catch(() => undefined)\n }\n}\n\n/**\n * Fail loudly at startup on a filesystem without reflink support, naming the\n * cost so the operator can act on it.\n */\nexport async function assertOverlayReflink(options: {\n overlayDirectory: string\n idFactory?: () => string\n copy?: (source: string, destination: string) => Promise<void>\n}): Promise<OverlayReflinkCheck> {\n const check = await verifyOverlayReflink(options)\n if (!check.supported) {\n throw new DeskError(\n `The overlay directory ${check.overlayDirectory} is on a filesystem without reflink `\n + 'support, so every desk would FULL-COPY the base image instead of sharing its '\n + 'blocks — gigabytes and minutes per desk, and a disk sized for sharing fills after '\n + `a handful of them. Put the overlay directory on XFS or Btrfs. Probe said: ${check.detail}`,\n )\n }\n return check\n}\n\nasync function reflinkAlways(source: string, destination: string): Promise<void> {\n await new Promise<void>((resolvePromise, rejectPromise) => {\n execFile('cp', ['--reflink=always', source, destination], (error, _stdout, stderr) => {\n if (error) {\n rejectPromise(new Error(stderr.trim() || errorMessage(error)))\n return\n }\n resolvePromise()\n })\n })\n}\n\nexport interface DeskHostVerification {\n /** Whether this host can serve desks: KVM present and the guest reachable. */\n supported: boolean\n vmmPath: string\n kvm: boolean\n vsock: boolean\n virtioGpu: boolean\n}\n\n/**\n * Boot-time probe. Distinguishes a host that is unusable — wrong platform,\n * missing VMM, missing images — which throws, from capabilities that are\n * merely absent, which are reported as booleans: `kvm` (no boot possible\n * without it), `vsock` (the guest agent answered), and `virtioGpu` (a screen\n * would have hardware-backed rendering). It boots a throwaway microVM through\n * the backend, asks it two questions, and discards it.\n */\nexport async function verifyDeskHost(options: VerifyDeskHostOptions): Promise<DeskHostVerification> {\n const platform = options.platform ?? process.platform\n const pathExists = options.pathExists ?? existsSync\n const deviceExists = options.deviceExists ?? existsSync\n const idFactory = options.idFactory ?? randomUUID\n const backend = options.backend ?? cloudHypervisorBackend\n const vmmPath = options.vmmPath ?? DEFAULT_VMM_PATH\n const kvmPath = options.kvmPath ?? DEFAULT_KVM_PATH\n\n if (platform !== 'linux') {\n throw new DeskError(`The AppKit desk requires Linux; received ${platform}.`)\n }\n if (!pathExists(vmmPath)) {\n throw new DeskError(`Cloud Hypervisor was not found at ${vmmPath}.`)\n }\n if (!pathExists(options.kernelPath)) {\n throw new DeskError(`Guest kernel does not exist: ${options.kernelPath}`)\n }\n if (!pathExists(options.baseImagePath)) {\n throw new DeskError(`Base image does not exist: ${options.baseImagePath}`)\n }\n if (!deviceExists(kvmPath)) {\n return { supported: false, vmmPath, kvm: false, vsock: false, virtioGpu: false }\n }\n\n const scratchDir = options.scratchDir ?? tmpdir()\n const deskId = `verify-${idFactory()}`\n const overlayPath = join(scratchDir, `${deskId}.raw`)\n const plan = buildDeskLaunchPlan(\n {\n deskId,\n vmmPath,\n kvmPath,\n kernelPath: options.kernelPath,\n ...(options.initramfsPath === undefined ? {} : { initramfsPath: options.initramfsPath }),\n ...(options.kernelCmdline === undefined ? {} : { kernelCmdline: options.kernelCmdline }),\n baseImagePath: options.baseImagePath,\n overlayPath,\n vsockCid: 3,\n runtimeDir: options.runtimeDir,\n launcherIdentity: options.launcherIdentity,\n },\n { pathExists, deviceExists },\n )\n\n let machine: DeskMachine\n try {\n machine = await backend.boot(plan)\n } catch (error) {\n throw new DeskError(`Desk verification could not boot a probe VM: ${errorMessage(error)}`)\n }\n let vsock = false\n let virtioGpu = false\n try {\n try {\n await machine.request({ op: 'ping' })\n vsock = true\n } catch {\n vsock = false\n }\n if (vsock) {\n try {\n virtioGpu = parseCapabilities(await machine.request({ op: 'capabilities' })).virtioGpu\n } catch {\n virtioGpu = false\n }\n }\n } finally {\n try {\n await machine.shutdown()\n } catch {\n // The probe VM is discarded regardless of how cleanly it stops.\n }\n await rm(overlayPath, { force: true })\n }\n return { supported: vsock, vmmPath, kvm: true, vsock, virtioGpu }\n}\n\nfunction nonEmptyString(value: string, field: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new DeskError(`${field} must be a non-empty string.`)\n }\n return value\n}\n\nfunction requireStringValue(value: string, field: string): string {\n if (typeof value !== 'string') {\n throw new DeskError(`${field} must be a string.`)\n }\n return value\n}\n\nfunction positiveInteger(value: number, field: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw new DeskError(`${field} must be a positive integer.`)\n }\n return value\n}\n\nfunction nonNegativeInteger(value: number, field: string): number {\n if (!Number.isInteger(value) || value < 0) {\n throw new DeskError(`${field} must be an integer of zero or more.`)\n }\n return value\n}\n\n/**\n * Free bytes on the filesystem holding `path`, measured against the directory\n * so the answer is the same before and after the overlay itself exists.\n */\nasync function defaultFreeBytes(path: string): Promise<number> {\n const stats = await statfs(dirname(path))\n return Number(stats.bsize) * Number(stats.bavail)\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@braedonsaunders/appkit-desk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Per-agent Debian microVMs under Cloud Hypervisor — headless machines with an on-demand screen, a framed vsock guest-agent protocol, leases with idle suspend and a bounded queue, and load-bearing handover masking behind consumer-supplied policy and recording ports.",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
package/protocol.d.ts
CHANGED
package/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACX,MAAM,UAAU,CAAA;AAEjB,eAAO,MAAM,kBAAkB,IAAI,CAAA;AACnC,eAAO,MAAM,uBAAuB,QAAkB,CAAA;AACtD,oDAAoD;AACpD,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAU1C,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,SAAkB,IAAI,uBAAsB;CAC7C;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/protocol.js
CHANGED
|
@@ -185,6 +185,7 @@ export function parseGuestInput(value) {
|
|
|
185
185
|
x: requireCoordinate(record, 'x'),
|
|
186
186
|
y: requireCoordinate(record, 'y'),
|
|
187
187
|
button: parsePointerButton(record.button),
|
|
188
|
+
clicks: parseClickCount(record.clicks),
|
|
188
189
|
};
|
|
189
190
|
case 'type':
|
|
190
191
|
return { type, text: requireString(record, 'text') };
|
|
@@ -204,6 +205,13 @@ export function parseGuestInput(value) {
|
|
|
204
205
|
throw new DeskProtocolError(`Unknown input type: ${type}`);
|
|
205
206
|
}
|
|
206
207
|
}
|
|
208
|
+
function parseClickCount(value) {
|
|
209
|
+
if (value === undefined || value === 1)
|
|
210
|
+
return 1;
|
|
211
|
+
if (value === 2)
|
|
212
|
+
return 2;
|
|
213
|
+
throw new DeskProtocolError('clicks must be 1 or 2.');
|
|
214
|
+
}
|
|
207
215
|
/** Validate a guest-to-host message: a correlated response or an event. */
|
|
208
216
|
export function parseHostBoundMessage(value) {
|
|
209
217
|
const record = asRecord(value, 'message');
|
package/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The framed JSON protocol spoken between the host and the in-guest agent\n * over vsock. Everything here is pure encode/decode/validate — no sockets, no\n * processes — so the security-critical parsing is unit-testable on any\n * platform, and both the host backend and the guest agent share one message\n * vocabulary.\n *\n * Wire format: a 4-byte big-endian length prefix followed by that many bytes\n * of UTF-8 JSON. Frame sizes are bounded; a peer declaring an oversized frame\n * is a protocol violation and the connection must be dropped, not resynced.\n */\nimport { Buffer } from 'node:buffer'\nimport type {\n A11yNode,\n DeskFrameFormat,\n DeskHandoverScope,\n DeskPoint,\n DeskPointerButton,\n DeskVideoChunkKind,\n WindowInfo,\n} from './events'\n\nexport const FRAME_HEADER_BYTES = 4\nexport const DEFAULT_MAX_FRAME_BYTES = 8 * 1024 * 1024\n/** The vsock port the in-guest agent listens on. */\nexport const GUEST_AGENT_VSOCK_PORT = 5252\n\nconst REQUEST_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/\nconst MAX_STRING_LENGTH = 65_536\nconst MAX_ARGUMENTS = 256\nconst MAX_ENVIRONMENT_ENTRIES = 128\nconst MAX_WINDOWS = 256\nconst MAX_A11Y_NODES = 10_000\nconst MAX_A11Y_DEPTH = 32\n\nexport class DeskProtocolError extends Error {\n override readonly name = 'DeskProtocolError'\n}\n\nexport type GuestInput =\n | { type: 'move'; x: number; y: number }\n | { type: 'click'; x: number; y: number; button: DeskPointerButton }\n | { type: 'type'; text: string }\n | { type: 'key'; combo: string }\n | { type: 'scroll'; x: number; y: number; dx: number; dy: number }\n | { type: 'drag'; from: DeskPoint; to: DeskPoint }\n\n/** A request body, before the transport assigns its correlation id. */\nexport type GuestCommand =\n | { op: 'ping' }\n | { op: 'capabilities' }\n | {\n op: 'exec'\n command: string\n args?: readonly string[]\n cwd?: string\n env?: Readonly<Record<string, string>>\n timeoutMs?: number\n }\n | {\n op: 'job-start'\n command: string\n args?: readonly string[]\n cwd?: string\n env?: Readonly<Record<string, string>>\n }\n | { op: 'job-signal'; jobId: string; signal: 'SIGTERM' | 'SIGKILL' }\n | { op: 'screen-start'; width: number; height: number }\n | { op: 'screen-stop' }\n | { op: 'observe' }\n | { op: 'input'; input: GuestInput }\n | { op: 'a11y-invoke'; nodeId: string; action: string }\n | { op: 'launch'; appId: string; args?: readonly string[] }\n | { op: 'clipboard-read' }\n | { op: 'clipboard-write'; text: string }\n | {\n op: 'frames-start'\n fps: number\n width: number\n height: number\n /** Omitted lets the guest choose; a guest that predates this ignores it. */\n format?: DeskFrameFormat\n }\n | { op: 'frames-stop' }\n | { op: 'video-start'; fps: number; width: number; height: number }\n | { op: 'video-stop' }\n | { op: 'handover-begin'; ttlMs: number; scope: DeskHandoverScope }\n | { op: 'handover-end' }\n\nexport type GuestOp = GuestCommand['op']\n\nexport type GuestRequest = GuestCommand & { id: string }\n\nexport type GuestResponse =\n | { id: string; ok: true; result: unknown }\n | { id: string; ok: false; error: string }\n\n/** Unsolicited guest-to-host messages: job exits, frames, focus changes. */\nexport type GuestEventMessage =\n | { event: 'job-exit'; jobId: string; exitCode: number | null; signal: string | null }\n | {\n event: 'frame'\n seq: number\n width: number\n height: number\n data: string\n /**\n * How `data` is encoded. Absent on the wire means `png`: frames were\n * PNG-only before this field existed, so an older guest paired with a\n * newer host keeps working rather than having its every frame rejected.\n */\n format: DeskFrameFormat\n }\n | {\n event: 'video-chunk'\n seq: number\n kind: DeskVideoChunkKind\n /** RFC 6381, e.g. `avc1.42C020`, read out of the bytes by the guest. */\n codec: string\n width: number\n height: number\n /**\n * Whether a `media` chunk begins at a sync sample. Only a chunk that does\n * can start or resume a decoder; `init` chunks report false because the\n * question does not apply to them.\n */\n keyframe: boolean\n data: string\n }\n | { event: 'window-focus'; window: WindowInfo }\n\nexport type HostBoundMessage = GuestResponse | GuestEventMessage\n\n/** The wire shape of an exec result, before the host turns it into a snapshot. */\nexport interface GuestExecResult {\n exitCode: number | null\n signal: string | null\n stdout: string\n stderr: string\n truncated: boolean\n}\n\n/** The wire shape of an observation; `png` is base64. */\nexport interface GuestObservation {\n png: string\n width: number\n height: number\n a11y: A11yNode | null\n windows: WindowInfo[]\n focused: WindowInfo | null\n}\n\n/** Encode one message as a length-prefixed JSON frame. */\nexport function encodeFrame(message: unknown, maxFrameBytes = DEFAULT_MAX_FRAME_BYTES): Buffer {\n const body = Buffer.from(JSON.stringify(message), 'utf8')\n if (body.byteLength > maxFrameBytes) {\n throw new DeskProtocolError(\n `Refusing to encode a ${body.byteLength}-byte frame; the limit is ${maxFrameBytes}.`,\n )\n }\n const frame = Buffer.allocUnsafe(FRAME_HEADER_BYTES + body.byteLength)\n frame.writeUInt32BE(body.byteLength, 0)\n body.copy(frame, FRAME_HEADER_BYTES)\n return frame\n}\n\n/**\n * Incremental frame decoder. Feed it arbitrary chunk boundaries; it returns\n * every complete parsed JSON value. A declared frame length beyond the bound\n * or a body that is not valid JSON throws — framing violations are fatal to\n * the connection because there is no way to resynchronize a byte stream whose\n * lengths cannot be trusted.\n */\nexport class FrameDecoder {\n readonly #maxFrameBytes: number\n #buffered: Buffer = Buffer.alloc(0)\n\n constructor(options: { maxFrameBytes?: number } = {}) {\n const maxFrameBytes = options.maxFrameBytes ?? DEFAULT_MAX_FRAME_BYTES\n if (!Number.isInteger(maxFrameBytes) || maxFrameBytes < 1) {\n throw new DeskProtocolError('maxFrameBytes must be a positive integer.')\n }\n this.#maxFrameBytes = maxFrameBytes\n }\n\n push(chunk: Buffer): unknown[] {\n this.#buffered = this.#buffered.byteLength === 0\n ? chunk\n : Buffer.concat([this.#buffered, chunk])\n const messages: unknown[] = []\n while (this.#buffered.byteLength >= FRAME_HEADER_BYTES) {\n const declared = this.#buffered.readUInt32BE(0)\n if (declared > this.#maxFrameBytes) {\n throw new DeskProtocolError(\n `Peer declared a ${declared}-byte frame; the limit is ${this.#maxFrameBytes}.`,\n )\n }\n if (this.#buffered.byteLength < FRAME_HEADER_BYTES + declared) break\n const body = this.#buffered.subarray(FRAME_HEADER_BYTES, FRAME_HEADER_BYTES + declared)\n this.#buffered = this.#buffered.subarray(FRAME_HEADER_BYTES + declared)\n try {\n messages.push(JSON.parse(body.toString('utf8')))\n } catch (error) {\n throw new DeskProtocolError(\n `Frame body is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n return messages\n }\n}\n\n/** Validate a host-to-guest request. Unknown ops and malformed fields throw. */\nexport function parseGuestRequest(value: unknown): GuestRequest {\n const record = asRecord(value, 'request')\n const id = requireString(record, 'id')\n if (!REQUEST_ID_PATTERN.test(id)) {\n throw new DeskProtocolError('Request id must be 1–128 URL-safe characters.')\n }\n const op = requireString(record, 'op')\n switch (op) {\n case 'ping':\n case 'capabilities':\n case 'screen-stop':\n case 'observe':\n case 'clipboard-read':\n case 'frames-stop':\n case 'video-stop':\n case 'handover-end':\n return { id, op }\n case 'exec':\n return {\n id,\n op,\n command: requireString(record, 'command'),\n args: optionalStringArray(record, 'args'),\n cwd: optionalString(record, 'cwd'),\n env: optionalEnvironment(record),\n timeoutMs: optionalPositiveInteger(record, 'timeoutMs'),\n }\n case 'job-start':\n return {\n id,\n op,\n command: requireString(record, 'command'),\n args: optionalStringArray(record, 'args'),\n cwd: optionalString(record, 'cwd'),\n env: optionalEnvironment(record),\n }\n case 'job-signal': {\n const signal = requireString(record, 'signal')\n if (signal !== 'SIGTERM' && signal !== 'SIGKILL') {\n throw new DeskProtocolError('job-signal signal must be SIGTERM or SIGKILL.')\n }\n return { id, op, jobId: requireString(record, 'jobId'), signal }\n }\n case 'screen-start':\n return {\n id,\n op,\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n }\n case 'input':\n return { id, op, input: parseGuestInput(record.input) }\n case 'a11y-invoke':\n return {\n id,\n op,\n nodeId: requireString(record, 'nodeId'),\n action: requireString(record, 'action'),\n }\n case 'launch':\n return {\n id,\n op,\n appId: requireString(record, 'appId'),\n args: optionalStringArray(record, 'args'),\n }\n case 'clipboard-write':\n return { id, op, text: requireString(record, 'text') }\n case 'frames-start':\n return {\n id,\n op,\n fps: requirePositiveInteger(record, 'fps'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n format: optionalFrameFormat(record),\n }\n case 'video-start':\n return {\n id,\n op,\n fps: requirePositiveInteger(record, 'fps'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n }\n case 'handover-begin':\n return {\n id,\n op,\n ttlMs: requirePositiveInteger(record, 'ttlMs'),\n scope: parseHandoverScope(record.scope),\n }\n default:\n throw new DeskProtocolError(`Unknown request op: ${op}`)\n }\n}\n\nexport function parseGuestInput(value: unknown): GuestInput {\n const record = asRecord(value, 'input')\n const type = requireString(record, 'type')\n switch (type) {\n case 'move':\n return { type, x: requireCoordinate(record, 'x'), y: requireCoordinate(record, 'y') }\n case 'click':\n return {\n type,\n x: requireCoordinate(record, 'x'),\n y: requireCoordinate(record, 'y'),\n button: parsePointerButton(record.button),\n }\n case 'type':\n return { type, text: requireString(record, 'text') }\n case 'key':\n return { type, combo: requireString(record, 'combo') }\n case 'scroll':\n return {\n type,\n x: requireCoordinate(record, 'x'),\n y: requireCoordinate(record, 'y'),\n dx: requireDelta(record, 'dx'),\n dy: requireDelta(record, 'dy'),\n }\n case 'drag':\n return { type, from: parsePoint(record.from), to: parsePoint(record.to) }\n default:\n throw new DeskProtocolError(`Unknown input type: ${type}`)\n }\n}\n\n/** Validate a guest-to-host message: a correlated response or an event. */\nexport function parseHostBoundMessage(value: unknown): HostBoundMessage {\n const record = asRecord(value, 'message')\n if ('id' in record) {\n const id = requireString(record, 'id')\n if (record.ok === true) return { id, ok: true, result: record.result ?? {} }\n if (record.ok === false) return { id, ok: false, error: requireString(record, 'error') }\n throw new DeskProtocolError('Response ok must be a boolean.')\n }\n const event = requireString(record, 'event')\n switch (event) {\n case 'job-exit':\n return {\n event,\n jobId: requireString(record, 'jobId'),\n exitCode: nullableInteger(record, 'exitCode'),\n signal: nullableString(record, 'signal'),\n }\n case 'frame':\n return {\n event,\n seq: requireNonNegativeInteger(record, 'seq'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n data: requireUnboundedString(record, 'data'),\n // Absent means png — see the field's contract on GuestEventMessage.\n format: optionalFrameFormat(record) ?? 'png',\n }\n case 'video-chunk':\n return {\n event,\n seq: requireNonNegativeInteger(record, 'seq'),\n kind: parseVideoChunkKind(record.kind),\n codec: requireString(record, 'codec'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n keyframe: record.keyframe === true,\n data: requireUnboundedString(record, 'data'),\n }\n case 'window-focus':\n return { event, window: parseWindowInfo(record.window) }\n default:\n throw new DeskProtocolError(`Unknown event: ${event}`)\n }\n}\n\n/** Validate the result payload of an `exec` response. */\nexport function parseExecResult(value: unknown): GuestExecResult {\n const record = asRecord(value, 'exec result')\n return {\n exitCode: nullableInteger(record, 'exitCode'),\n signal: nullableString(record, 'signal'),\n stdout: requireUnboundedString(record, 'stdout'),\n stderr: requireUnboundedString(record, 'stderr'),\n truncated: record.truncated === true,\n }\n}\n\n/** Validate the result payload of a `job-start` response. */\nexport function parseJobStarted(value: unknown): { jobId: string } {\n const record = asRecord(value, 'job-start result')\n return { jobId: requireString(record, 'jobId') }\n}\n\n/** Validate the result payload of an `observe` response. */\nexport function parseObservation(value: unknown): GuestObservation {\n const record = asRecord(value, 'observation')\n const windows = parseWindows(record.windows)\n return {\n png: requireUnboundedString(record, 'png'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n a11y: record.a11y === null || record.a11y === undefined\n ? null\n : parseA11yTree(record.a11y),\n windows,\n focused: record.focused === null || record.focused === undefined\n ? null\n : parseWindowInfo(record.focused),\n }\n}\n\n/** Validate the result payload of a `handover-begin` response. */\nexport function parseHandoverBegun(value: unknown): { url: string } {\n const record = asRecord(value, 'handover-begin result')\n return { url: requireString(record, 'url') }\n}\n\n/** Validate the result payload of a `clipboard-read` response. */\nexport function parseClipboardText(value: unknown): string {\n const record = asRecord(value, 'clipboard-read result')\n return requireUnboundedString(record, 'text')\n}\n\n/** Validate the result payload of a `capabilities` response. */\nexport function parseCapabilities(value: unknown): { virtioGpu: boolean } {\n const record = asRecord(value, 'capabilities result')\n return { virtioGpu: record.virtioGpu === true }\n}\n\nexport function parseWindowInfo(value: unknown): WindowInfo {\n const record = asRecord(value, 'window')\n return {\n id: requireString(record, 'id'),\n title: requireString(record, 'title'),\n appId: nullableString(record, 'appId'),\n }\n}\n\nfunction parseWindows(value: unknown): WindowInfo[] {\n if (value === undefined || value === null) return []\n if (!Array.isArray(value) || value.length > MAX_WINDOWS) {\n throw new DeskProtocolError(`windows must be an array of at most ${MAX_WINDOWS} entries.`)\n }\n return value.map(parseWindowInfo)\n}\n\nfunction parseA11yTree(value: unknown): A11yNode {\n const budget = { remaining: MAX_A11Y_NODES }\n return parseA11yNode(value, budget, 0)\n}\n\nfunction parseA11yNode(value: unknown, budget: { remaining: number }, depth: number): A11yNode {\n if (depth > MAX_A11Y_DEPTH) {\n throw new DeskProtocolError(`Accessibility tree exceeds depth ${MAX_A11Y_DEPTH}.`)\n }\n if (budget.remaining <= 0) {\n throw new DeskProtocolError(`Accessibility tree exceeds ${MAX_A11Y_NODES} nodes.`)\n }\n budget.remaining -= 1\n const record = asRecord(value, 'a11y node')\n const rawChildren = record.children ?? []\n if (!Array.isArray(rawChildren)) {\n throw new DeskProtocolError('a11y node children must be an array.')\n }\n return {\n id: requireString(record, 'id'),\n role: requireString(record, 'role'),\n name: nullableString(record, 'name'),\n actions: optionalStringArray(record, 'actions') ?? [],\n bounds: record.bounds === null || record.bounds === undefined\n ? null\n : parseBounds(record.bounds),\n children: rawChildren.map((child) => parseA11yNode(child, budget, depth + 1)),\n }\n}\n\nfunction parseBounds(value: unknown): { x: number; y: number; width: number; height: number } {\n const record = asRecord(value, 'bounds')\n return {\n x: requireDelta(record, 'x'),\n y: requireDelta(record, 'y'),\n width: requireNonNegativeInteger(record, 'width'),\n height: requireNonNegativeInteger(record, 'height'),\n }\n}\n\nfunction parsePoint(value: unknown): DeskPoint {\n const record = asRecord(value, 'point')\n return { x: requireCoordinate(record, 'x'), y: requireCoordinate(record, 'y') }\n}\n\nfunction parsePointerButton(value: unknown): DeskPointerButton {\n if (value === undefined) return 'left'\n if (value === 'left' || value === 'middle' || value === 'right') return value\n throw new DeskProtocolError('button must be left, middle, or right.')\n}\n\n/**\n * A frame format, when the field is present. Absent is `undefined` here and\n * every caller decides what that means; on a frame event it means `png`,\n * because that is what the field's absence used to imply.\n */\nfunction optionalFrameFormat(record: Record<string, unknown>): DeskFrameFormat | undefined {\n const value = record.format\n if (value === undefined) return undefined\n if (value === 'png' || value === 'jpeg') return value\n throw new DeskProtocolError('format must be png or jpeg.')\n}\n\nfunction parseVideoChunkKind(value: unknown): DeskVideoChunkKind {\n if (value === 'init' || value === 'media') return value\n throw new DeskProtocolError('video chunk kind must be init or media.')\n}\n\nfunction parseHandoverScope(value: unknown): DeskHandoverScope {\n if (value === 'view' || value === 'control') return value\n throw new DeskProtocolError('scope must be view or control.')\n}\n\nfunction asRecord(value: unknown, label: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new DeskProtocolError(`Expected ${label} to be an object.`)\n }\n return value as Record<string, unknown>\n}\n\nfunction requireString(record: Record<string, unknown>, field: string): string {\n const value = record[field]\n if (typeof value !== 'string' || value.length === 0 || value.length > MAX_STRING_LENGTH) {\n throw new DeskProtocolError(\n `${field} must be a string of 1–${MAX_STRING_LENGTH} characters.`,\n )\n }\n return value\n}\n\nfunction requireUnboundedString(record: Record<string, unknown>, field: string): string {\n // Bounded by the frame limit rather than the field limit; used for payloads\n // such as command output, screenshots, and clipboard text.\n const value = record[field]\n if (typeof value !== 'string') {\n throw new DeskProtocolError(`${field} must be a string.`)\n }\n return value\n}\n\nfunction optionalString(record: Record<string, unknown>, field: string): string | undefined {\n return record[field] === undefined ? undefined : requireString(record, field)\n}\n\nfunction nullableString(record: Record<string, unknown>, field: string): string | null {\n const value = record[field]\n if (value === null || value === undefined) return null\n return requireString(record, field)\n}\n\nfunction optionalStringArray(\n record: Record<string, unknown>,\n field: string,\n): string[] | undefined {\n const value = record[field]\n if (value === undefined) return undefined\n if (!Array.isArray(value) || value.length > MAX_ARGUMENTS) {\n throw new DeskProtocolError(`${field} must be an array of at most ${MAX_ARGUMENTS} strings.`)\n }\n return value.map((entry, index) => {\n if (typeof entry !== 'string' || entry.length > MAX_STRING_LENGTH) {\n throw new DeskProtocolError(`${field}[${index}] must be a string of at most ${MAX_STRING_LENGTH} characters.`)\n }\n return entry\n })\n}\n\nfunction optionalEnvironment(\n record: Record<string, unknown>,\n): Record<string, string> | undefined {\n const value = record.env\n if (value === undefined) return undefined\n const env = asRecord(value, 'env')\n const entries = Object.entries(env)\n if (entries.length > MAX_ENVIRONMENT_ENTRIES) {\n throw new DeskProtocolError(`env must have at most ${MAX_ENVIRONMENT_ENTRIES} entries.`)\n }\n const clean: Record<string, string> = {}\n for (const [key, entry] of entries) {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {\n throw new DeskProtocolError(`Invalid environment variable name: ${key}`)\n }\n if (typeof entry !== 'string' || entry.length > MAX_STRING_LENGTH) {\n throw new DeskProtocolError(`env.${key} must be a string of at most ${MAX_STRING_LENGTH} characters.`)\n }\n clean[key] = entry\n }\n return clean\n}\n\nfunction requirePositiveInteger(record: Record<string, unknown>, field: string): number {\n const value = record[field]\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {\n throw new DeskProtocolError(`${field} must be a positive integer.`)\n }\n return value\n}\n\nfunction optionalPositiveInteger(\n record: Record<string, unknown>,\n field: string,\n): number | undefined {\n return record[field] === undefined ? undefined : requirePositiveInteger(record, field)\n}\n\nfunction requireNonNegativeInteger(record: Record<string, unknown>, field: string): number {\n const value = record[field]\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {\n throw new DeskProtocolError(`${field} must be a non-negative integer.`)\n }\n return value\n}\n\nfunction requireDimension(record: Record<string, unknown>, field: string): number {\n const value = requirePositiveInteger(record, field)\n if (value > 16_384) {\n throw new DeskProtocolError(`${field} must be at most 16384 pixels.`)\n }\n return value\n}\n\nfunction requireCoordinate(record: Record<string, unknown>, field: string): number {\n return requireNonNegativeInteger(record, field)\n}\n\nfunction requireDelta(record: Record<string, unknown>, field: string): number {\n const value = record[field]\n if (typeof value !== 'number' || !Number.isInteger(value)) {\n throw new DeskProtocolError(`${field} must be an integer.`)\n }\n return value\n}\n\nfunction nullableInteger(record: Record<string, unknown>, field: string): number | null {\n const value = record[field]\n if (value === null || value === undefined) return null\n if (typeof value !== 'number' || !Number.isInteger(value)) {\n throw new DeskProtocolError(`${field} must be an integer or null.`)\n }\n return value\n}\n"]}
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The framed JSON protocol spoken between the host and the in-guest agent\n * over vsock. Everything here is pure encode/decode/validate — no sockets, no\n * processes — so the security-critical parsing is unit-testable on any\n * platform, and both the host backend and the guest agent share one message\n * vocabulary.\n *\n * Wire format: a 4-byte big-endian length prefix followed by that many bytes\n * of UTF-8 JSON. Frame sizes are bounded; a peer declaring an oversized frame\n * is a protocol violation and the connection must be dropped, not resynced.\n */\nimport { Buffer } from 'node:buffer'\nimport type {\n A11yNode,\n DeskFrameFormat,\n DeskHandoverScope,\n DeskPoint,\n DeskPointerButton,\n DeskVideoChunkKind,\n WindowInfo,\n} from './events'\n\nexport const FRAME_HEADER_BYTES = 4\nexport const DEFAULT_MAX_FRAME_BYTES = 8 * 1024 * 1024\n/** The vsock port the in-guest agent listens on. */\nexport const GUEST_AGENT_VSOCK_PORT = 5252\n\nconst REQUEST_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/\nconst MAX_STRING_LENGTH = 65_536\nconst MAX_ARGUMENTS = 256\nconst MAX_ENVIRONMENT_ENTRIES = 128\nconst MAX_WINDOWS = 256\nconst MAX_A11Y_NODES = 10_000\nconst MAX_A11Y_DEPTH = 32\n\nexport class DeskProtocolError extends Error {\n override readonly name = 'DeskProtocolError'\n}\n\nexport type GuestInput =\n | { type: 'move'; x: number; y: number }\n | { type: 'click'; x: number; y: number; button: DeskPointerButton; clicks: 1 | 2 }\n | { type: 'type'; text: string }\n | { type: 'key'; combo: string }\n | { type: 'scroll'; x: number; y: number; dx: number; dy: number }\n | { type: 'drag'; from: DeskPoint; to: DeskPoint }\n\n/** A request body, before the transport assigns its correlation id. */\nexport type GuestCommand =\n | { op: 'ping' }\n | { op: 'capabilities' }\n | {\n op: 'exec'\n command: string\n args?: readonly string[]\n cwd?: string\n env?: Readonly<Record<string, string>>\n timeoutMs?: number\n }\n | {\n op: 'job-start'\n command: string\n args?: readonly string[]\n cwd?: string\n env?: Readonly<Record<string, string>>\n }\n | { op: 'job-signal'; jobId: string; signal: 'SIGTERM' | 'SIGKILL' }\n | { op: 'screen-start'; width: number; height: number }\n | { op: 'screen-stop' }\n | { op: 'observe' }\n | { op: 'input'; input: GuestInput }\n | { op: 'a11y-invoke'; nodeId: string; action: string }\n | { op: 'launch'; appId: string; args?: readonly string[] }\n | { op: 'clipboard-read' }\n | { op: 'clipboard-write'; text: string }\n | {\n op: 'frames-start'\n fps: number\n width: number\n height: number\n /** Omitted lets the guest choose; a guest that predates this ignores it. */\n format?: DeskFrameFormat\n }\n | { op: 'frames-stop' }\n | { op: 'video-start'; fps: number; width: number; height: number }\n | { op: 'video-stop' }\n | { op: 'handover-begin'; ttlMs: number; scope: DeskHandoverScope }\n | { op: 'handover-end' }\n\nexport type GuestOp = GuestCommand['op']\n\nexport type GuestRequest = GuestCommand & { id: string }\n\nexport type GuestResponse =\n | { id: string; ok: true; result: unknown }\n | { id: string; ok: false; error: string }\n\n/** Unsolicited guest-to-host messages: job exits, frames, focus changes. */\nexport type GuestEventMessage =\n | { event: 'job-exit'; jobId: string; exitCode: number | null; signal: string | null }\n | {\n event: 'frame'\n seq: number\n width: number\n height: number\n data: string\n /**\n * How `data` is encoded. Absent on the wire means `png`: frames were\n * PNG-only before this field existed, so an older guest paired with a\n * newer host keeps working rather than having its every frame rejected.\n */\n format: DeskFrameFormat\n }\n | {\n event: 'video-chunk'\n seq: number\n kind: DeskVideoChunkKind\n /** RFC 6381, e.g. `avc1.42C020`, read out of the bytes by the guest. */\n codec: string\n width: number\n height: number\n /**\n * Whether a `media` chunk begins at a sync sample. Only a chunk that does\n * can start or resume a decoder; `init` chunks report false because the\n * question does not apply to them.\n */\n keyframe: boolean\n data: string\n }\n | { event: 'window-focus'; window: WindowInfo }\n\nexport type HostBoundMessage = GuestResponse | GuestEventMessage\n\n/** The wire shape of an exec result, before the host turns it into a snapshot. */\nexport interface GuestExecResult {\n exitCode: number | null\n signal: string | null\n stdout: string\n stderr: string\n truncated: boolean\n}\n\n/** The wire shape of an observation; `png` is base64. */\nexport interface GuestObservation {\n png: string\n width: number\n height: number\n a11y: A11yNode | null\n windows: WindowInfo[]\n focused: WindowInfo | null\n}\n\n/** Encode one message as a length-prefixed JSON frame. */\nexport function encodeFrame(message: unknown, maxFrameBytes = DEFAULT_MAX_FRAME_BYTES): Buffer {\n const body = Buffer.from(JSON.stringify(message), 'utf8')\n if (body.byteLength > maxFrameBytes) {\n throw new DeskProtocolError(\n `Refusing to encode a ${body.byteLength}-byte frame; the limit is ${maxFrameBytes}.`,\n )\n }\n const frame = Buffer.allocUnsafe(FRAME_HEADER_BYTES + body.byteLength)\n frame.writeUInt32BE(body.byteLength, 0)\n body.copy(frame, FRAME_HEADER_BYTES)\n return frame\n}\n\n/**\n * Incremental frame decoder. Feed it arbitrary chunk boundaries; it returns\n * every complete parsed JSON value. A declared frame length beyond the bound\n * or a body that is not valid JSON throws — framing violations are fatal to\n * the connection because there is no way to resynchronize a byte stream whose\n * lengths cannot be trusted.\n */\nexport class FrameDecoder {\n readonly #maxFrameBytes: number\n #buffered: Buffer = Buffer.alloc(0)\n\n constructor(options: { maxFrameBytes?: number } = {}) {\n const maxFrameBytes = options.maxFrameBytes ?? DEFAULT_MAX_FRAME_BYTES\n if (!Number.isInteger(maxFrameBytes) || maxFrameBytes < 1) {\n throw new DeskProtocolError('maxFrameBytes must be a positive integer.')\n }\n this.#maxFrameBytes = maxFrameBytes\n }\n\n push(chunk: Buffer): unknown[] {\n this.#buffered = this.#buffered.byteLength === 0\n ? chunk\n : Buffer.concat([this.#buffered, chunk])\n const messages: unknown[] = []\n while (this.#buffered.byteLength >= FRAME_HEADER_BYTES) {\n const declared = this.#buffered.readUInt32BE(0)\n if (declared > this.#maxFrameBytes) {\n throw new DeskProtocolError(\n `Peer declared a ${declared}-byte frame; the limit is ${this.#maxFrameBytes}.`,\n )\n }\n if (this.#buffered.byteLength < FRAME_HEADER_BYTES + declared) break\n const body = this.#buffered.subarray(FRAME_HEADER_BYTES, FRAME_HEADER_BYTES + declared)\n this.#buffered = this.#buffered.subarray(FRAME_HEADER_BYTES + declared)\n try {\n messages.push(JSON.parse(body.toString('utf8')))\n } catch (error) {\n throw new DeskProtocolError(\n `Frame body is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n return messages\n }\n}\n\n/** Validate a host-to-guest request. Unknown ops and malformed fields throw. */\nexport function parseGuestRequest(value: unknown): GuestRequest {\n const record = asRecord(value, 'request')\n const id = requireString(record, 'id')\n if (!REQUEST_ID_PATTERN.test(id)) {\n throw new DeskProtocolError('Request id must be 1–128 URL-safe characters.')\n }\n const op = requireString(record, 'op')\n switch (op) {\n case 'ping':\n case 'capabilities':\n case 'screen-stop':\n case 'observe':\n case 'clipboard-read':\n case 'frames-stop':\n case 'video-stop':\n case 'handover-end':\n return { id, op }\n case 'exec':\n return {\n id,\n op,\n command: requireString(record, 'command'),\n args: optionalStringArray(record, 'args'),\n cwd: optionalString(record, 'cwd'),\n env: optionalEnvironment(record),\n timeoutMs: optionalPositiveInteger(record, 'timeoutMs'),\n }\n case 'job-start':\n return {\n id,\n op,\n command: requireString(record, 'command'),\n args: optionalStringArray(record, 'args'),\n cwd: optionalString(record, 'cwd'),\n env: optionalEnvironment(record),\n }\n case 'job-signal': {\n const signal = requireString(record, 'signal')\n if (signal !== 'SIGTERM' && signal !== 'SIGKILL') {\n throw new DeskProtocolError('job-signal signal must be SIGTERM or SIGKILL.')\n }\n return { id, op, jobId: requireString(record, 'jobId'), signal }\n }\n case 'screen-start':\n return {\n id,\n op,\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n }\n case 'input':\n return { id, op, input: parseGuestInput(record.input) }\n case 'a11y-invoke':\n return {\n id,\n op,\n nodeId: requireString(record, 'nodeId'),\n action: requireString(record, 'action'),\n }\n case 'launch':\n return {\n id,\n op,\n appId: requireString(record, 'appId'),\n args: optionalStringArray(record, 'args'),\n }\n case 'clipboard-write':\n return { id, op, text: requireString(record, 'text') }\n case 'frames-start':\n return {\n id,\n op,\n fps: requirePositiveInteger(record, 'fps'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n format: optionalFrameFormat(record),\n }\n case 'video-start':\n return {\n id,\n op,\n fps: requirePositiveInteger(record, 'fps'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n }\n case 'handover-begin':\n return {\n id,\n op,\n ttlMs: requirePositiveInteger(record, 'ttlMs'),\n scope: parseHandoverScope(record.scope),\n }\n default:\n throw new DeskProtocolError(`Unknown request op: ${op}`)\n }\n}\n\nexport function parseGuestInput(value: unknown): GuestInput {\n const record = asRecord(value, 'input')\n const type = requireString(record, 'type')\n switch (type) {\n case 'move':\n return { type, x: requireCoordinate(record, 'x'), y: requireCoordinate(record, 'y') }\n case 'click':\n return {\n type,\n x: requireCoordinate(record, 'x'),\n y: requireCoordinate(record, 'y'),\n button: parsePointerButton(record.button),\n clicks: parseClickCount(record.clicks),\n }\n case 'type':\n return { type, text: requireString(record, 'text') }\n case 'key':\n return { type, combo: requireString(record, 'combo') }\n case 'scroll':\n return {\n type,\n x: requireCoordinate(record, 'x'),\n y: requireCoordinate(record, 'y'),\n dx: requireDelta(record, 'dx'),\n dy: requireDelta(record, 'dy'),\n }\n case 'drag':\n return { type, from: parsePoint(record.from), to: parsePoint(record.to) }\n default:\n throw new DeskProtocolError(`Unknown input type: ${type}`)\n }\n}\n\nfunction parseClickCount(value: unknown): 1 | 2 {\n if (value === undefined || value === 1) return 1\n if (value === 2) return 2\n throw new DeskProtocolError('clicks must be 1 or 2.')\n}\n\n/** Validate a guest-to-host message: a correlated response or an event. */\nexport function parseHostBoundMessage(value: unknown): HostBoundMessage {\n const record = asRecord(value, 'message')\n if ('id' in record) {\n const id = requireString(record, 'id')\n if (record.ok === true) return { id, ok: true, result: record.result ?? {} }\n if (record.ok === false) return { id, ok: false, error: requireString(record, 'error') }\n throw new DeskProtocolError('Response ok must be a boolean.')\n }\n const event = requireString(record, 'event')\n switch (event) {\n case 'job-exit':\n return {\n event,\n jobId: requireString(record, 'jobId'),\n exitCode: nullableInteger(record, 'exitCode'),\n signal: nullableString(record, 'signal'),\n }\n case 'frame':\n return {\n event,\n seq: requireNonNegativeInteger(record, 'seq'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n data: requireUnboundedString(record, 'data'),\n // Absent means png — see the field's contract on GuestEventMessage.\n format: optionalFrameFormat(record) ?? 'png',\n }\n case 'video-chunk':\n return {\n event,\n seq: requireNonNegativeInteger(record, 'seq'),\n kind: parseVideoChunkKind(record.kind),\n codec: requireString(record, 'codec'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n keyframe: record.keyframe === true,\n data: requireUnboundedString(record, 'data'),\n }\n case 'window-focus':\n return { event, window: parseWindowInfo(record.window) }\n default:\n throw new DeskProtocolError(`Unknown event: ${event}`)\n }\n}\n\n/** Validate the result payload of an `exec` response. */\nexport function parseExecResult(value: unknown): GuestExecResult {\n const record = asRecord(value, 'exec result')\n return {\n exitCode: nullableInteger(record, 'exitCode'),\n signal: nullableString(record, 'signal'),\n stdout: requireUnboundedString(record, 'stdout'),\n stderr: requireUnboundedString(record, 'stderr'),\n truncated: record.truncated === true,\n }\n}\n\n/** Validate the result payload of a `job-start` response. */\nexport function parseJobStarted(value: unknown): { jobId: string } {\n const record = asRecord(value, 'job-start result')\n return { jobId: requireString(record, 'jobId') }\n}\n\n/** Validate the result payload of an `observe` response. */\nexport function parseObservation(value: unknown): GuestObservation {\n const record = asRecord(value, 'observation')\n const windows = parseWindows(record.windows)\n return {\n png: requireUnboundedString(record, 'png'),\n width: requireDimension(record, 'width'),\n height: requireDimension(record, 'height'),\n a11y: record.a11y === null || record.a11y === undefined\n ? null\n : parseA11yTree(record.a11y),\n windows,\n focused: record.focused === null || record.focused === undefined\n ? null\n : parseWindowInfo(record.focused),\n }\n}\n\n/** Validate the result payload of a `handover-begin` response. */\nexport function parseHandoverBegun(value: unknown): { url: string } {\n const record = asRecord(value, 'handover-begin result')\n return { url: requireString(record, 'url') }\n}\n\n/** Validate the result payload of a `clipboard-read` response. */\nexport function parseClipboardText(value: unknown): string {\n const record = asRecord(value, 'clipboard-read result')\n return requireUnboundedString(record, 'text')\n}\n\n/** Validate the result payload of a `capabilities` response. */\nexport function parseCapabilities(value: unknown): { virtioGpu: boolean } {\n const record = asRecord(value, 'capabilities result')\n return { virtioGpu: record.virtioGpu === true }\n}\n\nexport function parseWindowInfo(value: unknown): WindowInfo {\n const record = asRecord(value, 'window')\n return {\n id: requireString(record, 'id'),\n title: requireString(record, 'title'),\n appId: nullableString(record, 'appId'),\n }\n}\n\nfunction parseWindows(value: unknown): WindowInfo[] {\n if (value === undefined || value === null) return []\n if (!Array.isArray(value) || value.length > MAX_WINDOWS) {\n throw new DeskProtocolError(`windows must be an array of at most ${MAX_WINDOWS} entries.`)\n }\n return value.map(parseWindowInfo)\n}\n\nfunction parseA11yTree(value: unknown): A11yNode {\n const budget = { remaining: MAX_A11Y_NODES }\n return parseA11yNode(value, budget, 0)\n}\n\nfunction parseA11yNode(value: unknown, budget: { remaining: number }, depth: number): A11yNode {\n if (depth > MAX_A11Y_DEPTH) {\n throw new DeskProtocolError(`Accessibility tree exceeds depth ${MAX_A11Y_DEPTH}.`)\n }\n if (budget.remaining <= 0) {\n throw new DeskProtocolError(`Accessibility tree exceeds ${MAX_A11Y_NODES} nodes.`)\n }\n budget.remaining -= 1\n const record = asRecord(value, 'a11y node')\n const rawChildren = record.children ?? []\n if (!Array.isArray(rawChildren)) {\n throw new DeskProtocolError('a11y node children must be an array.')\n }\n return {\n id: requireString(record, 'id'),\n role: requireString(record, 'role'),\n name: nullableString(record, 'name'),\n actions: optionalStringArray(record, 'actions') ?? [],\n bounds: record.bounds === null || record.bounds === undefined\n ? null\n : parseBounds(record.bounds),\n children: rawChildren.map((child) => parseA11yNode(child, budget, depth + 1)),\n }\n}\n\nfunction parseBounds(value: unknown): { x: number; y: number; width: number; height: number } {\n const record = asRecord(value, 'bounds')\n return {\n x: requireDelta(record, 'x'),\n y: requireDelta(record, 'y'),\n width: requireNonNegativeInteger(record, 'width'),\n height: requireNonNegativeInteger(record, 'height'),\n }\n}\n\nfunction parsePoint(value: unknown): DeskPoint {\n const record = asRecord(value, 'point')\n return { x: requireCoordinate(record, 'x'), y: requireCoordinate(record, 'y') }\n}\n\nfunction parsePointerButton(value: unknown): DeskPointerButton {\n if (value === undefined) return 'left'\n if (value === 'left' || value === 'middle' || value === 'right') return value\n throw new DeskProtocolError('button must be left, middle, or right.')\n}\n\n/**\n * A frame format, when the field is present. Absent is `undefined` here and\n * every caller decides what that means; on a frame event it means `png`,\n * because that is what the field's absence used to imply.\n */\nfunction optionalFrameFormat(record: Record<string, unknown>): DeskFrameFormat | undefined {\n const value = record.format\n if (value === undefined) return undefined\n if (value === 'png' || value === 'jpeg') return value\n throw new DeskProtocolError('format must be png or jpeg.')\n}\n\nfunction parseVideoChunkKind(value: unknown): DeskVideoChunkKind {\n if (value === 'init' || value === 'media') return value\n throw new DeskProtocolError('video chunk kind must be init or media.')\n}\n\nfunction parseHandoverScope(value: unknown): DeskHandoverScope {\n if (value === 'view' || value === 'control') return value\n throw new DeskProtocolError('scope must be view or control.')\n}\n\nfunction asRecord(value: unknown, label: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new DeskProtocolError(`Expected ${label} to be an object.`)\n }\n return value as Record<string, unknown>\n}\n\nfunction requireString(record: Record<string, unknown>, field: string): string {\n const value = record[field]\n if (typeof value !== 'string' || value.length === 0 || value.length > MAX_STRING_LENGTH) {\n throw new DeskProtocolError(\n `${field} must be a string of 1–${MAX_STRING_LENGTH} characters.`,\n )\n }\n return value\n}\n\nfunction requireUnboundedString(record: Record<string, unknown>, field: string): string {\n // Bounded by the frame limit rather than the field limit; used for payloads\n // such as command output, screenshots, and clipboard text.\n const value = record[field]\n if (typeof value !== 'string') {\n throw new DeskProtocolError(`${field} must be a string.`)\n }\n return value\n}\n\nfunction optionalString(record: Record<string, unknown>, field: string): string | undefined {\n return record[field] === undefined ? undefined : requireString(record, field)\n}\n\nfunction nullableString(record: Record<string, unknown>, field: string): string | null {\n const value = record[field]\n if (value === null || value === undefined) return null\n return requireString(record, field)\n}\n\nfunction optionalStringArray(\n record: Record<string, unknown>,\n field: string,\n): string[] | undefined {\n const value = record[field]\n if (value === undefined) return undefined\n if (!Array.isArray(value) || value.length > MAX_ARGUMENTS) {\n throw new DeskProtocolError(`${field} must be an array of at most ${MAX_ARGUMENTS} strings.`)\n }\n return value.map((entry, index) => {\n if (typeof entry !== 'string' || entry.length > MAX_STRING_LENGTH) {\n throw new DeskProtocolError(`${field}[${index}] must be a string of at most ${MAX_STRING_LENGTH} characters.`)\n }\n return entry\n })\n}\n\nfunction optionalEnvironment(\n record: Record<string, unknown>,\n): Record<string, string> | undefined {\n const value = record.env\n if (value === undefined) return undefined\n const env = asRecord(value, 'env')\n const entries = Object.entries(env)\n if (entries.length > MAX_ENVIRONMENT_ENTRIES) {\n throw new DeskProtocolError(`env must have at most ${MAX_ENVIRONMENT_ENTRIES} entries.`)\n }\n const clean: Record<string, string> = {}\n for (const [key, entry] of entries) {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {\n throw new DeskProtocolError(`Invalid environment variable name: ${key}`)\n }\n if (typeof entry !== 'string' || entry.length > MAX_STRING_LENGTH) {\n throw new DeskProtocolError(`env.${key} must be a string of at most ${MAX_STRING_LENGTH} characters.`)\n }\n clean[key] = entry\n }\n return clean\n}\n\nfunction requirePositiveInteger(record: Record<string, unknown>, field: string): number {\n const value = record[field]\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {\n throw new DeskProtocolError(`${field} must be a positive integer.`)\n }\n return value\n}\n\nfunction optionalPositiveInteger(\n record: Record<string, unknown>,\n field: string,\n): number | undefined {\n return record[field] === undefined ? undefined : requirePositiveInteger(record, field)\n}\n\nfunction requireNonNegativeInteger(record: Record<string, unknown>, field: string): number {\n const value = record[field]\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {\n throw new DeskProtocolError(`${field} must be a non-negative integer.`)\n }\n return value\n}\n\nfunction requireDimension(record: Record<string, unknown>, field: string): number {\n const value = requirePositiveInteger(record, field)\n if (value > 16_384) {\n throw new DeskProtocolError(`${field} must be at most 16384 pixels.`)\n }\n return value\n}\n\nfunction requireCoordinate(record: Record<string, unknown>, field: string): number {\n return requireNonNegativeInteger(record, field)\n}\n\nfunction requireDelta(record: Record<string, unknown>, field: string): number {\n const value = record[field]\n if (typeof value !== 'number' || !Number.isInteger(value)) {\n throw new DeskProtocolError(`${field} must be an integer.`)\n }\n return value\n}\n\nfunction nullableInteger(record: Record<string, unknown>, field: string): number | null {\n const value = record[field]\n if (value === null || value === undefined) return null\n if (typeof value !== 'number' || !Number.isInteger(value)) {\n throw new DeskProtocolError(`${field} must be an integer or null.`)\n }\n return value\n}\n"]}
|