@braedonsaunders/appkit-desk 0.4.0

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/host.js.map ADDED
@@ -0,0 +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 { rm } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { 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\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\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' | '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 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 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 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 async function teardown(record: DeskRecord): Promise<void> {\n if (record.status !== 'resident') return\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 record.status = 'suspended'\n record.handle = null\n if (machine) {\n try {\n await machine.shutdown()\n } catch (error) {\n lastError = errorMessage(error)\n }\n }\n lastSuspendedAt = iso(now())\n occupied -= 1\n drainQueue()\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 async function boot(deskId: string, startOptions: DeskStartOptions): Promise<DeskHandle> {\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 teardown(record).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 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 async function resume(deskId: string): Promise<DeskHandle> {\n const record = records.get(cleanDeskId(deskId))\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 async function suspend(deskId: string): Promise<void> {\n const record = records.get(cleanDeskId(deskId))\n if (!record) return\n await teardown(record)\n }\n\n async function destroy(deskId: string): Promise<void> {\n const id = cleanDeskId(deskId)\n const record = records.get(id)\n if (!record) return\n await teardown(record)\n records.delete(id)\n }\n\n async function sweep(): Promise<number> {\n const timestamp = now()\n let suspendedCount = 0\n for (const record of [...records.values()]) {\n if (record.status !== 'resident') continue\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 await teardown(record)\n suspendedCount += 1\n }\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 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 errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n"]}
package/index.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from './events.js';
2
+ export * from './protocol.js';
3
+ export * from './plan.js';
4
+ export * from './guest-agent.js';
5
+ export * from './backend.js';
6
+ export * from './host.js';
7
+ export * from './frames.js';
8
+ export * from './portable-home.js';
9
+ export * from './conformance.js';
10
+ //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,QAAQ,CAAA;AACtB,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA"}
package/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export * from './events.js';
2
+ export * from './protocol.js';
3
+ export * from './plan.js';
4
+ export * from './guest-agent.js';
5
+ export * from './backend.js';
6
+ export * from './host.js';
7
+ export * from './frames.js';
8
+ export * from './portable-home.js';
9
+ export * from './conformance.js';
10
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,QAAQ,CAAA;AACtB,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA","sourcesContent":["export * from './events'\nexport * from './protocol'\nexport * from './plan'\nexport * from './guest-agent'\nexport * from './backend'\nexport * from './host'\nexport * from './frames'\nexport * from './portable-home'\nexport * from './conformance'\n"]}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@braedonsaunders/appkit-desk",
3
+ "version": "0.4.0",
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
+ "license": "AGPL-3.0-or-later",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./index.d.ts",
10
+ "import": "./index.js",
11
+ "default": "./index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "main": "./index.js",
16
+ "types": "./index.d.ts",
17
+ "author": "Braedon Saunders",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/braedonsaunders/appkit.git",
21
+ "directory": "packages/desk"
22
+ },
23
+ "homepage": "https://github.com/braedonsaunders/appkit/tree/main/packages/desk#readme",
24
+ "bugs": {
25
+ "url": "https://github.com/braedonsaunders/appkit/issues"
26
+ },
27
+ "engines": {
28
+ "node": ">=22"
29
+ },
30
+ "keywords": [
31
+ "agents",
32
+ "appkit",
33
+ "application-framework",
34
+ "cloud-hypervisor",
35
+ "desktop",
36
+ "microvm",
37
+ "sandbox",
38
+ "typescript",
39
+ "virtualization"
40
+ ]
41
+ }
package/plan.d.ts ADDED
@@ -0,0 +1,117 @@
1
+ export declare const DEFAULT_VMM_PATH = "/usr/bin/cloud-hypervisor";
2
+ export declare const DEFAULT_KVM_PATH = "/dev/kvm";
3
+ export declare const DEFAULT_QEMU_IMG_PATH = "/usr/bin/qemu-img";
4
+ export declare const DEFAULT_RUNTIME_DIR = "/run/appkit-desk";
5
+ export declare const DEFAULT_MEMORY_MB = 384;
6
+ export declare const DEFAULT_VCPUS = 2;
7
+ export declare const DEFAULT_KERNEL_CMDLINE = "root=/dev/vda rw quiet";
8
+ /**
9
+ * Every failure this package raises. The `name` is annotated as `string`
10
+ * rather than left to infer its literal so a subclass can narrow the meaning
11
+ * of a failure — see `DeskRequestFateUnknownError` — without callers losing
12
+ * the one `instanceof DeskError` they already check.
13
+ */
14
+ export declare class DeskError extends Error {
15
+ readonly name: string;
16
+ }
17
+ export interface DeskLauncherIdentity {
18
+ /** Host/container UID used to invoke the VMM and image tooling. */
19
+ uid: number;
20
+ /** Host/container GID used to invoke the VMM and image tooling. */
21
+ gid: number;
22
+ }
23
+ export interface DeskLaunchPlanOptions {
24
+ deskId: string;
25
+ vmmPath?: string;
26
+ kvmPath?: string;
27
+ qemuImgPath?: string;
28
+ /** Absolute path of the kernel image the microVM boots. */
29
+ kernelPath: string;
30
+ /**
31
+ * Absolute path of an initramfs. Required whenever the kernel loads its
32
+ * root-filesystem or virtio drivers as modules — a stock distro cloud kernel
33
+ * panics with "VFS: Unable to mount root fs" if it boots without one. Omit
34
+ * only for a kernel with virtio_blk/ext4 built in.
35
+ */
36
+ initramfsPath?: string;
37
+ /** Absolute path of the golden raw base image every desk clones. */
38
+ baseImagePath: string;
39
+ /** Absolute path of this desk's copy-on-write overlay (a raw reflink clone). */
40
+ overlayPath: string;
41
+ memoryMb?: number;
42
+ vcpus?: number;
43
+ /** Guest vsock context ID; must be unique among resident desks. */
44
+ vsockCid: number;
45
+ /** Directory holding the vsock and API control sockets. */
46
+ runtimeDir?: string;
47
+ /** Host TAP device name; derived from the CID when omitted. */
48
+ tapDevice?: string;
49
+ /** Guest MAC address; derived from the CID when omitted. */
50
+ macAddress?: string;
51
+ kernelCmdline?: string;
52
+ launcherIdentity?: DeskLauncherIdentity;
53
+ }
54
+ /**
55
+ * The complete Cloud Hypervisor invocation as inspectable data. Nothing here
56
+ * has been spawned: tests, audit logs, and readiness screens can assert on the
57
+ * exact argv a desk would boot with.
58
+ */
59
+ export interface DeskLaunchPlan {
60
+ deskId: string;
61
+ vmm: {
62
+ command: string;
63
+ args: string[];
64
+ };
65
+ overlay: {
66
+ path: string;
67
+ basePath: string;
68
+ /** The overlay-creation step, or `null` when the overlay already exists. */
69
+ create: {
70
+ command: string;
71
+ args: string[];
72
+ } | null;
73
+ };
74
+ vsock: {
75
+ cid: number;
76
+ socketPath: string;
77
+ };
78
+ api: {
79
+ socketPath: string;
80
+ };
81
+ tap: {
82
+ device: string;
83
+ mac: string;
84
+ };
85
+ memoryMb: number;
86
+ vcpus: number;
87
+ kernelPath: string;
88
+ /** Resolved initramfs path, or `null` when the kernel needs none. */
89
+ initramfsPath: string | null;
90
+ kernelCmdline: string;
91
+ launcherIdentity?: DeskLauncherIdentity;
92
+ }
93
+ /**
94
+ * Whether this host can run desks at all: Linux, a usable `/dev/kvm`, and the
95
+ * Cloud Hypervisor binary. All three checks are injectable and the answer is
96
+ * fail-closed — a host missing any of them gets no desk capability rather
97
+ * than a degraded one.
98
+ */
99
+ export declare function isDeskSupported(options?: {
100
+ platform?: NodeJS.Platform;
101
+ kvmPath?: string;
102
+ vmmPath?: string;
103
+ pathExists?: (path: string) => boolean;
104
+ }): boolean;
105
+ /** Validate a desk identifier, which is used in socket paths and device names. */
106
+ export declare function cleanDeskId(value: string): string;
107
+ /**
108
+ * Build the deterministic Cloud Hypervisor launch plan without spawning
109
+ * anything. Fail closed: a missing `/dev/kvm`, VMM binary, kernel, base image,
110
+ * or overlay directory throws instead of producing a plan that cannot boot.
111
+ */
112
+ export declare function buildDeskLaunchPlan(options: DeskLaunchPlanOptions, dependencies?: {
113
+ pathExists?: (path: string) => boolean;
114
+ deviceExists?: (path: string) => boolean;
115
+ }): DeskLaunchPlan;
116
+ export declare function cleanLauncherIdentity(identity: DeskLauncherIdentity | undefined): DeskLauncherIdentity | undefined;
117
+ //# sourceMappingURL=plan.d.ts.map
package/plan.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"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"}
package/plan.js ADDED
@@ -0,0 +1,187 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { dirname, isAbsolute, join, resolve } from 'node:path';
3
+ export const DEFAULT_VMM_PATH = '/usr/bin/cloud-hypervisor';
4
+ export const DEFAULT_KVM_PATH = '/dev/kvm';
5
+ export const DEFAULT_QEMU_IMG_PATH = '/usr/bin/qemu-img';
6
+ export const DEFAULT_RUNTIME_DIR = '/run/appkit-desk';
7
+ export const DEFAULT_MEMORY_MB = 384;
8
+ export const DEFAULT_VCPUS = 2;
9
+ export const DEFAULT_KERNEL_CMDLINE = 'root=/dev/vda rw quiet';
10
+ const DESK_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
11
+ const TAP_DEVICE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,14}$/;
12
+ const MAC_ADDRESS_PATTERN = /^[0-9a-f]{2}(?::[0-9a-f]{2}){5}$/i;
13
+ /** vsock CIDs 0–2 are reserved (hypervisor, loopback, host). */
14
+ const MIN_GUEST_CID = 3;
15
+ const MAX_GUEST_CID = 0xffff_fffe;
16
+ /**
17
+ * Every failure this package raises. The `name` is annotated as `string`
18
+ * rather than left to infer its literal so a subclass can narrow the meaning
19
+ * of a failure — see `DeskRequestFateUnknownError` — without callers losing
20
+ * the one `instanceof DeskError` they already check.
21
+ */
22
+ export class DeskError extends Error {
23
+ name = 'DeskError';
24
+ }
25
+ /**
26
+ * Whether this host can run desks at all: Linux, a usable `/dev/kvm`, and the
27
+ * Cloud Hypervisor binary. All three checks are injectable and the answer is
28
+ * fail-closed — a host missing any of them gets no desk capability rather
29
+ * than a degraded one.
30
+ */
31
+ export function isDeskSupported(options = {}) {
32
+ const platform = options.platform ?? process.platform;
33
+ const pathExists = options.pathExists ?? existsSync;
34
+ return (platform === 'linux'
35
+ && pathExists(options.kvmPath ?? DEFAULT_KVM_PATH)
36
+ && pathExists(options.vmmPath ?? DEFAULT_VMM_PATH));
37
+ }
38
+ /** Validate a desk identifier, which is used in socket paths and device names. */
39
+ export function cleanDeskId(value) {
40
+ if (!DESK_ID_PATTERN.test(value)) {
41
+ throw new DeskError('deskId must be 1–64 letters, numbers, dots, underscores, or hyphens.');
42
+ }
43
+ return value;
44
+ }
45
+ /**
46
+ * Build the deterministic Cloud Hypervisor launch plan without spawning
47
+ * anything. Fail closed: a missing `/dev/kvm`, VMM binary, kernel, base image,
48
+ * or overlay directory throws instead of producing a plan that cannot boot.
49
+ */
50
+ export function buildDeskLaunchPlan(options, dependencies = {}) {
51
+ const pathExists = dependencies.pathExists ?? existsSync;
52
+ const deviceExists = dependencies.deviceExists ?? existsSync;
53
+ const deskId = cleanDeskId(options.deskId);
54
+ const kvmPath = absolutePath(options.kvmPath ?? DEFAULT_KVM_PATH, 'kvmPath');
55
+ if (!deviceExists(kvmPath)) {
56
+ throw new DeskError(`KVM is not available at ${kvmPath}. Desks require hardware virtualization; `
57
+ + 'there is no software-emulation fallback.');
58
+ }
59
+ const vmmPath = absolutePath(options.vmmPath ?? DEFAULT_VMM_PATH, 'vmmPath');
60
+ if (!pathExists(vmmPath)) {
61
+ throw new DeskError(`Cloud Hypervisor was not found at ${vmmPath}. Install cloud-hypervisor or configure vmmPath.`);
62
+ }
63
+ const kernelPath = absolutePath(options.kernelPath, 'kernelPath');
64
+ if (!pathExists(kernelPath)) {
65
+ throw new DeskError(`Guest kernel does not exist: ${kernelPath}`);
66
+ }
67
+ const initramfsPath = options.initramfsPath === undefined
68
+ ? null
69
+ : absolutePath(options.initramfsPath, 'initramfsPath');
70
+ if (initramfsPath !== null && !pathExists(initramfsPath)) {
71
+ throw new DeskError(`Initramfs does not exist: ${initramfsPath}`);
72
+ }
73
+ const baseImagePath = absolutePath(options.baseImagePath, 'baseImagePath');
74
+ if (!pathExists(baseImagePath)) {
75
+ throw new DeskError(`Base image does not exist: ${baseImagePath}`);
76
+ }
77
+ const overlayPath = absolutePath(options.overlayPath, 'overlayPath');
78
+ const overlayDirectory = dirname(overlayPath);
79
+ if (!pathExists(overlayDirectory)) {
80
+ throw new DeskError(`Overlay directory does not exist: ${overlayDirectory}`);
81
+ }
82
+ const memoryMb = positiveInteger(options.memoryMb ?? DEFAULT_MEMORY_MB, 'memoryMb');
83
+ const vcpus = positiveInteger(options.vcpus ?? DEFAULT_VCPUS, 'vcpus');
84
+ const vsockCid = cleanCid(options.vsockCid);
85
+ const runtimeDir = absolutePath(options.runtimeDir ?? DEFAULT_RUNTIME_DIR, 'runtimeDir');
86
+ const tapDevice = cleanTapDevice(options.tapDevice ?? defaultTapDevice(vsockCid));
87
+ const macAddress = cleanMacAddress(options.macAddress ?? defaultMacAddress(vsockCid));
88
+ const kernelCmdline = options.kernelCmdline ?? DEFAULT_KERNEL_CMDLINE;
89
+ const launcherIdentity = cleanLauncherIdentity(options.launcherIdentity);
90
+ const vsockSocketPath = join(runtimeDir, `desk-${deskId}.vsock`);
91
+ const apiSocketPath = join(runtimeDir, `desk-${deskId}.api.sock`);
92
+ const create = pathExists(overlayPath)
93
+ ? null
94
+ : {
95
+ // Cloud Hypervisor cannot follow disk backing chains: a qcow2 overlay
96
+ // over a qcow2/raw base is rejected with UnsupportedFeature /
97
+ // MaxNestingDepthExceeded. So the overlay is a plain raw file, cloned
98
+ // from the raw base with `cp --reflink=auto` — an instant, block-sharing
99
+ // copy-on-write clone on XFS/Btrfs and a graceful full-copy fallback on
100
+ // ext4. Either way CH boots the resulting raw file with no backing chain.
101
+ command: 'cp',
102
+ args: ['--reflink=auto', baseImagePath, overlayPath],
103
+ };
104
+ const args = [
105
+ '--api-socket', apiSocketPath,
106
+ '--kernel', kernelPath,
107
+ // A modular distro kernel needs its initramfs to bring up virtio_blk and
108
+ // mount root; omitted only for a kernel with those drivers built in.
109
+ ...(initramfsPath === null ? [] : ['--initramfs', initramfsPath]),
110
+ '--cmdline', kernelCmdline,
111
+ // Be explicit that the disk is raw: CH deprecated image-format auto-detection
112
+ // and warns without image_type; there is never a qcow2 overlay here.
113
+ '--disk', `path=${overlayPath},image_type=raw`,
114
+ '--memory', `size=${memoryMb}M`,
115
+ '--cpus', `boot=${vcpus}`,
116
+ '--vsock', `cid=${vsockCid},socket=${vsockSocketPath}`,
117
+ '--net', `tap=${tapDevice},mac=${macAddress}`,
118
+ '--serial', 'off',
119
+ '--console', 'off',
120
+ ];
121
+ return {
122
+ deskId,
123
+ vmm: { command: vmmPath, args },
124
+ overlay: { path: overlayPath, basePath: baseImagePath, create },
125
+ vsock: { cid: vsockCid, socketPath: vsockSocketPath },
126
+ api: { socketPath: apiSocketPath },
127
+ tap: { device: tapDevice, mac: macAddress },
128
+ memoryMb,
129
+ vcpus,
130
+ kernelPath,
131
+ initramfsPath,
132
+ kernelCmdline,
133
+ launcherIdentity,
134
+ };
135
+ }
136
+ function defaultTapDevice(cid) {
137
+ return `dsk${cid}`;
138
+ }
139
+ function defaultMacAddress(cid) {
140
+ // Locally administered, unicast prefix; the low four octets carry the CID so
141
+ // the address is stable per desk and never collides across resident desks.
142
+ const octets = [0x06, 0x00, (cid >>> 24) & 0xff, (cid >>> 16) & 0xff, (cid >>> 8) & 0xff, cid & 0xff];
143
+ return octets.map((octet) => octet.toString(16).padStart(2, '0')).join(':');
144
+ }
145
+ function cleanCid(value) {
146
+ if (!Number.isInteger(value) || value < MIN_GUEST_CID || value > MAX_GUEST_CID) {
147
+ throw new DeskError(`vsockCid must be an integer between ${MIN_GUEST_CID} and ${MAX_GUEST_CID}.`);
148
+ }
149
+ return value;
150
+ }
151
+ function cleanTapDevice(value) {
152
+ if (!TAP_DEVICE_PATTERN.test(value)) {
153
+ throw new DeskError('tapDevice must be 1–15 characters of letters, numbers, underscores, or hyphens.');
154
+ }
155
+ return value;
156
+ }
157
+ function cleanMacAddress(value) {
158
+ if (!MAC_ADDRESS_PATTERN.test(value)) {
159
+ throw new DeskError(`macAddress is not a valid MAC address: ${value}`);
160
+ }
161
+ return value.toLowerCase();
162
+ }
163
+ export function cleanLauncherIdentity(identity) {
164
+ if (!identity)
165
+ return undefined;
166
+ const max = 2_147_483_647;
167
+ if (!Number.isInteger(identity.uid) || identity.uid < 1 || identity.uid > max) {
168
+ throw new DeskError(`launcherIdentity.uid must be an integer between 1 and ${max}.`);
169
+ }
170
+ if (!Number.isInteger(identity.gid) || identity.gid < 0 || identity.gid > max) {
171
+ throw new DeskError(`launcherIdentity.gid must be an integer between 0 and ${max}.`);
172
+ }
173
+ return { uid: identity.uid, gid: identity.gid };
174
+ }
175
+ function absolutePath(value, field) {
176
+ if (!value || !isAbsolute(value)) {
177
+ throw new DeskError(`${field} must be an absolute path.`);
178
+ }
179
+ return resolve(value);
180
+ }
181
+ function positiveInteger(value, field) {
182
+ if (!Number.isInteger(value) || value < 1) {
183
+ throw new DeskError(`${field} must be a positive integer.`);
184
+ }
185
+ return value;
186
+ }
187
+ //# sourceMappingURL=plan.js.map