@braedonsaunders/appkit-desk 0.6.0 → 0.8.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.
Files changed (53) hide show
  1. package/README.md +83 -1
  2. package/backend.d.ts +28 -7
  3. package/backend.d.ts.map +1 -1
  4. package/backend.js +18 -521
  5. package/backend.js.map +1 -1
  6. package/events.d.ts +3 -0
  7. package/events.d.ts.map +1 -1
  8. package/events.js.map +1 -1
  9. package/host.d.ts +32 -1
  10. package/host.d.ts.map +1 -1
  11. package/host.js +141 -23
  12. package/host.js.map +1 -1
  13. package/index.d.ts +3 -0
  14. package/index.d.ts.map +1 -1
  15. package/index.js +3 -0
  16. package/index.js.map +1 -1
  17. package/machine.d.ts +145 -0
  18. package/machine.d.ts.map +1 -0
  19. package/machine.js +518 -0
  20. package/machine.js.map +1 -0
  21. package/network.d.ts +37 -0
  22. package/network.d.ts.map +1 -0
  23. package/network.js +173 -0
  24. package/network.js.map +1 -0
  25. package/package.json +2 -2
  26. package/plan.d.ts +129 -31
  27. package/plan.d.ts.map +1 -1
  28. package/plan.js +165 -9
  29. package/plan.js.map +1 -1
  30. package/port-relay.d.ts +13 -0
  31. package/port-relay.d.ts.map +1 -0
  32. package/port-relay.js +56 -0
  33. package/port-relay.js.map +1 -0
  34. package/virtualization.d.ts +16 -0
  35. package/virtualization.d.ts.map +1 -0
  36. package/virtualization.js +148 -0
  37. package/virtualization.js.map +1 -0
  38. package/vz/Package.swift +23 -0
  39. package/vz/Sources/DeskNet/Addresses.swift +106 -0
  40. package/vz/Sources/DeskNet/DHCP.swift +111 -0
  41. package/vz/Sources/DeskNet/Fence.swift +57 -0
  42. package/vz/Sources/DeskNet/NetworkStack.swift +547 -0
  43. package/vz/Sources/DeskNet/Packets.swift +355 -0
  44. package/vz/Sources/DeskNet/Plumbing.swift +312 -0
  45. package/vz/Sources/DeskNet/Sockets.swift +221 -0
  46. package/vz/Sources/DeskNet/TCPFlow.swift +448 -0
  47. package/vz/Sources/appkit-desk-vz/Control.swift +152 -0
  48. package/vz/Sources/appkit-desk-vz/Helper.swift +505 -0
  49. package/vz/Sources/appkit-desk-vz/main.swift +38 -0
  50. package/vz/Tests/DeskNetTests/DeskNetTests.swift +426 -0
  51. package/vz/appkit-desk-vz.entitlements +8 -0
  52. package/vz/build.sh +23 -0
  53. package/vz/check/extract-boot.py +221 -0
package/README.md CHANGED
@@ -112,6 +112,12 @@ stops, the disk persists, applications cold-start on `resume`. Keep-alive jobs
112
112
  die with the lease, and their termination is recorded as `job_exit` so no
113
113
  process ever runs where an operator cannot see it.
114
114
 
115
+ `host.shutdown(deskId)` is a restart, not a destroy: a resident desk is synced
116
+ and shut down instead of parked, a parked desk's memory snapshot is discarded,
117
+ and the overlay stays, so the next `start` or `resume` cold boots from disk.
118
+ Use it when a desk must come back fresh — new memory or vCPU settings, or a
119
+ guest wedged in a way a resume would bring straight back.
120
+
115
121
  Residency is bounded by a hard capacity cap. Starts beyond the cap queue FIFO
116
122
  rather than overcommitting host memory. `host.stats()` reports
117
123
  `{ resident, queued, capacity, suspended, lastStartedAt, lastSuspendedAt,
@@ -179,7 +185,8 @@ append-only record that cannot be edited afterward.
179
185
 
180
186
  `onEvent` receives a closed union — `shell_command`, `app_launch`, `click`,
181
187
  `type`, `key`, `scroll`, `drag`, `window_focus`, `screen_open`,
182
- `screen_close`, `handover_begin`, `handover_end`, `job_start`, `job_exit` —
188
+ `screen_close`, `handover_begin`, `handover_end`, `job_start`, `job_exit`,
189
+ `snapshot_cpu_fallback` —
183
190
  each stamped with `deskId` and an ISO timestamp. The union is defined here so
184
191
  the consumer's ledger and this package agree on the taxonomy; persistence is
185
192
  entirely the consumer's concern.
@@ -231,3 +238,78 @@ masking boundary changes.
231
238
  Do not fall back to unconfined execution when this package reports an
232
239
  unsupported host. A deployment without KVM loses the desk ability entirely —
233
240
  the same fail-closed posture as the rest of AppKit.
241
+
242
+ ## Routed guest networking and TCP services
243
+
244
+ `deskNetworkIdentity(index)` returns a deterministic TAP name and MAC address. `createDeskNetwork({ gateway, dns, egress, chainPrefix?, allowHostPorts?, prefixLength?, runner?, enableForwarding? })` provides routed point-to-point TAP setup. Set `egress: { mode: 'open' }` to masquerade guest-originated IPv4 traffic for arbitrary TCP and UDP; IPv6 traffic on the TAP is blocked with `ip6tables` so it cannot bypass host isolation; new inbound forwarded connections are dropped. Set `egress: { mode: 'proxied', httpProxyPort, httpsProxyPort }` to transparently redirect HTTP and HTTPS to proxy listeners, pin DNS to the supplied resolver, and drop other guest egress. The proxy supplies destination policy. Both modes drop new connections to host services, except TCP and UDP ports explicitly listed in `allowHostPorts` on the gateway address; proxied mode also permits its proxy listeners. Established replies to host-initiated guest connections are accepted.
245
+
246
+ The default iptables chain prefix is `desk`. Existing deployments using the `bh` chains must supply `chainPrefix: 'bh'` to retain those names during a rolling upgrade and avoid orphaning the old rules. `ensure({ tap, guest })` must finish before boot; `teardown({ tap, guest })` removes its rules and TAP after the VM stops. Configure Linux IPv4 forwarding, NET_ADMIN, `ip`, and `iptables` in the host namespace; open mode also requires `ip6tables`. When changing egress modes, tear down the old mode before installing the new one. `configureGuest(desk, { tap, guest })` configures the guest interface, route, and resolver through exec. `syncDeskGuestClock(desk, now?)` sets the guest clock after wake. Failures are reported to the caller. Operations on one TAP are serialized within the network instance; use one instance per namespace. Rule replacement uses multiple iptables commands and is not atomic: call `ensure` before the VM starts, and do not refresh rules on a live TAP.
247
+
248
+ Supply `network: { tapDevice, macAddress, guestAddress }` to `host.start`, then `await desk.connect(port)` returns a Node `Duplex` TCP stream to the guest. The caller owns the stream; suspension closes it. A service must listen on the guest interface, and its protocol and authentication remain the application's responsibility. `connectGuest` on host options injects a dialer for testing.
249
+
250
+ With `parkWithMemory`, new snapshots carry a host CPU signature. A changed signature skips restore and cold boots; Cloud Hypervisor's specific incompatible-CPUID restore error also triggers a cold boot. These outcomes increment `stats().snapshotCpuFallbacks`, set `lastSnapshotCpuFallback`, and emit `snapshot_cpu_fallback`, rather than setting `lastError`. Existing snapshots without a signature are attempted normally. Signatures are conservative CPU identity and feature fingerprints, not a guarantee of CPUID compatibility; a cold boot loses the parked process state. Keep snapshots and their overlays together.
251
+
252
+ For a disposable real-host check, provide a guest image with the desk agent and Python 3, Cloud Hypervisor, KVM, and a free TAP name and IP pair. Run from the repository root in the target network namespace with privileges to manage TAP and iptables:
253
+
254
+ ```sh
255
+ DESK_CHECK_TAP=dsk9001 DESK_CHECK_GUEST=172.30.0.2 DESK_CHECK_GATEWAY=172.30.0.1 \
256
+ DESK_CHECK_IMAGE_ROOT=/data/desk-image DESK_CHECK_BASE_IMAGE=/data/desk-image/base.img \
257
+ DESK_CHECK_TMPDIR=/data/tmp pnpm --filter @braedonsaunders/appkit-desk exec tsx scripts/check-kvm.mts
258
+ ```
259
+
260
+ Set `DESK_CHECK_KERNEL_CMDLINE` for images that require a custom root device. The check creates and removes a disposable VM, overlay, snapshot, TAP and firewall rules. It verifies a guest HTTP stream before and after memory restore; it does not verify the proxy or cross-CPU migration. Choose addresses that do not overlap existing routes.
261
+
262
+ ## macOS Virtualization.framework backend
263
+
264
+ On Apple silicon with macOS 14 or later, a host can supply a signed
265
+ `appkit-desk-vz` helper to `createVirtualizationBackend` and pass that backend
266
+ into `createDeskHost`:
267
+
268
+ ```ts
269
+ import { createDeskHost, createVirtualizationBackend, isDeskSupported } from '@braedonsaunders/appkit-desk'
270
+
271
+ const helperPath = '/opt/appkit/bin/appkit-desk-vz'
272
+ if (!isDeskSupported({ helperPath })) throw new Error('This host cannot run desks.')
273
+ const backend = createVirtualizationBackend({ helperPath })
274
+ const host = createDeskHost({
275
+ imageRoot: '/var/lib/appkit/desk',
276
+ backend,
277
+ guestNetwork: { allowLan: false },
278
+ ports,
279
+ })
280
+ ```
281
+
282
+ The guest needs an arm64 Linux kernel, raw base image and the same desk guest
283
+ agent as the Linux backend. Use the kernel command line appropriate to the
284
+ image. Per-desk disks use macOS `cp -c`; provision the overlay directory on a
285
+ filesystem that supports cloning. The helper creates a userspace IPv4 network
286
+ with DHCP, defaults to `10.0.2.15/24` and gateway `10.0.2.2`, and blocks
287
+ private, link-local, shared and host addresses by default. RFC 5737 documentation
288
+ subnets (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`) are always blocked,
289
+ including when LAN access is allowed. Set `allowLan` only
290
+ when the host policy explicitly permits local network access. `DeskHandle.connect`
291
+ uses the helper's TCP relay; no routable guest IP on the Mac is required.
292
+
293
+ The npm package includes the Swift source under `vz/`. Build it on macOS with
294
+ Xcode and `vz/build.sh`; the script signs with the required virtualization
295
+ entitlement. Its default ad hoc signature is for local use. Distributors must
296
+ sign with their own Developer ID (`APPKIT_CODESIGN_IDENTITY`) and handle
297
+ notarization and distribution. The caller supplies the absolute installed
298
+ helper path; installation does not download or execute a binary. Save and
299
+ restore use a stable desk MAC and machine identifier; the host removes the
300
+ snapshot while the restored VM is paused before resuming it. The userspace
301
+ network is recreated on restore, so existing TCP and UDP flows must reconnect.
302
+
303
+ For a disposable macOS integration check, supply a prepared guest image with
304
+ its desk agent and Python 3, its matching `vmlinux` and `initrd`, and the signed
305
+ helper. In a source checkout, run `packages/desk/scripts/check-vz.mts` with `DESK_CHECK_IMAGE_ROOT`,
306
+ `DESK_CHECK_BASE_IMAGE`, and `DESK_CHECK_VZ_HELPER`; set
307
+ `DESK_CHECK_KERNEL_CMDLINE` if the image uses a different root device. The
308
+ check creates a temporary guest and tests guest execution, a private-host
309
+ network fence, guest TCP access, and memory save/restore. It removes the guest
310
+ and its temporary files on exit.
311
+
312
+ For clients that require a local TCP URL, `await listenDeskPort(desk, port)`
313
+ returns a loopback-only `{ host, port, close }` listener. Each incoming
314
+ connection opens a guest stream through `desk.connect`; call `close()` when the
315
+ lease ends to close the listener and its connections.
package/backend.d.ts CHANGED
@@ -1,18 +1,19 @@
1
1
  /**
2
- * The backend port and its default Cloud Hypervisor implementation.
2
+ * The backend port.
3
3
  *
4
4
  * `DeskBackend` is the seam that keeps the package testable without a
5
5
  * hypervisor: the host asks a backend to boot a `DeskLaunchPlan` and gets a
6
6
  * `DeskMachine` — a request/response channel to the in-guest agent plus an
7
7
  * event subscription. CI and non-KVM developer machines inject an in-memory
8
- * fake; production uses `cloudHypervisorBackend`, whose process-spawning glue
9
- * is deliberately thin because everything that can be pure lives in the plan
10
- * builder and the protocol module.
8
+ * fake; production uses `cloudHypervisorBackend` on Linux or
9
+ * `createVirtualizationBackend` on an Apple silicon Mac, whose process glue is
10
+ * deliberately thin because everything that can be pure lives in the plan
11
+ * builder, the protocol module, and the shared guest channel.
11
12
  */
12
- import { type ChildProcess } from 'node:child_process';
13
+ import type { ChildProcess } from 'node:child_process';
13
14
  import type { Duplex } from 'node:stream';
14
- import { DeskError, type DeskLaunchPlan, type DeskLauncherIdentity } from './plan.js';
15
- import { type GuestCommand, type GuestEventMessage } from './protocol.js';
15
+ import { DeskError, type DeskHypervisor, type DeskLaunchPlan, type DeskLauncherIdentity } from './plan.js';
16
+ import type { GuestCommand, GuestEventMessage } from './protocol.js';
16
17
  /**
17
18
  * A request that was in flight when the guest connection dropped.
18
19
  *
@@ -88,6 +89,16 @@ export interface DeskMachine {
88
89
  * misbehaves for reasons nobody can find.
89
90
  */
90
91
  onConnectionChange?(listener: (change: DeskConnectionChange) => void): () => void;
92
+ /**
93
+ * Open a TCP stream from the host to `port` on the guest.
94
+ *
95
+ * Optional: a backend whose guest has a routable address (Cloud Hypervisor's
96
+ * TAP) leaves this out and the host dials the guest address directly. A
97
+ * backend whose guest sits behind a userspace NAT (Virtualization.framework)
98
+ * provides it, because there is no address on the Mac to dial. Rejects with
99
+ * `DeskError` when the guest refuses or does not answer.
100
+ */
101
+ connect?(port: number): Promise<Duplex>;
91
102
  /** Stop the VM. Idempotent; resolves once the VMM process has exited. */
92
103
  shutdown(): Promise<void>;
93
104
  /**
@@ -123,6 +134,16 @@ export interface DeskBootHooks {
123
134
  onRestored?: () => Promise<void>;
124
135
  }
125
136
  export interface DeskBackend {
137
+ /**
138
+ * Which hypervisor this backend boots, and so which plan the host builds
139
+ * for it. Absent means Cloud Hypervisor.
140
+ */
141
+ readonly hypervisor?: DeskHypervisor;
142
+ /**
143
+ * The binary the backend launches — the VMM or the helper — for readiness
144
+ * reporting. Optional; `verifyDeskHost` falls back to its own option.
145
+ */
146
+ readonly vmmPath?: string;
126
147
  boot(plan: DeskLaunchPlan, hooks?: DeskBootHooks): Promise<DeskMachine>;
127
148
  }
128
149
  export type DeskProcessLauncher = (command: string, args: readonly string[], options: {
package/backend.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"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"}