@braedonsaunders/appkit-desk 0.8.0 → 0.10.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.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Buffer } from 'node:buffer';
2
2
  import type { Duplex } from 'node:stream';
3
- import { type DeskLauncherIdentity, type DeskGuestNetworkOptions } from './plan.js';
3
+ import { type DeskLauncherIdentity, type DeskGuestNetworkOptions, type DeskShare, type DeskReadOnlyAttachment, type DeskVirtiofsdSandbox } from './plan.js';
4
4
  import { type DeskBackend } from './backend.js';
5
5
  import type { A11yNode, DeskFrameFormat, DeskHandoverScope, DeskPoint, DeskPointerButton, DeskPorts, DeskVideoChunkKind, WindowInfo } from './events.js';
6
6
  export declare const DEFAULT_CAPACITY = 4;
@@ -35,6 +35,13 @@ export interface DeskHostOptions {
35
35
  launcherIdentity?: DeskLauncherIdentity;
36
36
  backend?: DeskBackend;
37
37
  guestNetwork?: DeskGuestNetworkOptions;
38
+ /**
39
+ * Cloud Hypervisor only: the `virtiofsd` (1.13 or later) behind each share.
40
+ * Defaults to the first on `PATH`, then `/usr/libexec/virtiofsd`.
41
+ */
42
+ virtiofsdPath?: string;
43
+ /** Cloud Hypervisor only: how `virtiofsd` confines itself; defaults to `namespace`. */
44
+ virtiofsdSandbox?: DeskVirtiofsdSandbox;
38
45
  ports: DeskPorts;
39
46
  /** Override TCP dialing for tests or a host-specific transport. */
40
47
  connectGuest?: (address: string, port: number) => Promise<Duplex>;
@@ -47,6 +54,8 @@ export interface DeskHostOptions {
47
54
  now?: () => number;
48
55
  pathExists?: (path: string) => boolean;
49
56
  deviceExists?: (path: string) => boolean;
57
+ /** Whether a share's path is an existing directory; injectable for tests. */
58
+ isDirectory?: (path: string) => boolean;
50
59
  /**
51
60
  * Delete a destroyed desk's overlay. Injectable so the destroy path is
52
61
  * testable without a filesystem; defaults to `rm(path, { force: true })`.
@@ -68,17 +77,27 @@ export interface DeskHostOptions {
68
77
  * occurrence is indistinguishable, from inside the guest, from a failing host.
69
78
  */
70
79
  parkWithMemory?: boolean;
80
+ /** Opt in to Cloud Hypervisor copy-on-write snapshot restore. */
81
+ memoryRestoreMode?: 'copyonwrite';
82
+ /** Atomically retire a parked snapshot and sync its parent directory. */
83
+ retireSnapshot?: (from: string, to: string) => Promise<void>;
71
84
  /** Identifies the host CPU for conservative snapshot portability checks. */
72
85
  cpuSignature?: () => Promise<string>;
73
86
  readSnapshotSignature?: (directory: string) => Promise<string | null>;
74
87
  writeSnapshotSignature?: (directory: string, signature: string) => Promise<void>;
88
+ /**
89
+ * The shares a parked desk was snapshotted with, which its restore uses in
90
+ * place of the start options' shares. Defaults to the record the backend
91
+ * writes beside the snapshot; a snapshot without one had no shares.
92
+ */
93
+ readSnapshotShares?: (directory: string) => Promise<readonly DeskShare[]>;
75
94
  /** Create a snapshot directory; defaults to `mkdir(path, { recursive: true })`. */
76
95
  makeSnapshotDir?: (path: string) => Promise<void>;
77
96
  /**
78
97
  * Destroy a snapshot; defaults to `rm(path, { recursive: true, force: true })`.
79
98
  *
80
- * Called at the one moment it is safe to — a restored guest still paused — so
81
- * a failure here is not cosmetic. It is the reason the restore is abandoned.
99
+ * Eager restore removes the snapshot while paused. Copy-on-write restore
100
+ * removes its retired source only after the VMM exits.
82
101
  */
83
102
  removeSnapshot?: (path: string) => Promise<void>;
84
103
  /**
@@ -112,9 +131,14 @@ export interface DeskStartOptions {
112
131
  deskId: string;
113
132
  /** Absolute path of the golden base image this desk boots from. */
114
133
  baseImage: string;
134
+ /** Optional kernel and initramfs for this desk; retain them with its disk. */
135
+ kernelPath?: string;
136
+ initramfsPath?: string;
115
137
  /** Absolute path of this desk's copy-on-write overlay. */
116
138
  overlayPath: string;
117
139
  memoryMb?: number;
140
+ /** Enable Cloud Hypervisor free-page reporting on cold boot. */
141
+ freePageReporting?: boolean;
118
142
  vcpus?: number;
119
143
  leaseMs?: number;
120
144
  network?: {
@@ -122,6 +146,16 @@ export interface DeskStartOptions {
122
146
  macAddress?: string;
123
147
  guestAddress?: string;
124
148
  };
149
+ /**
150
+ * Host directories shared into the guest over virtio-fs. A desk parked with
151
+ * memory is restored with the shares it was parked with, because a snapshot
152
+ * holds its devices; these take effect on its next cold boot (see
153
+ * `shutdown`). A parked share whose directory is gone makes the restore fail,
154
+ * and the desk cold boots with these instead.
155
+ */
156
+ shares?: readonly DeskShare[];
157
+ /** Immutable attachments; retain their path and contents while a snapshot exists. */
158
+ readOnlyAttachments?: readonly DeskReadOnlyAttachment[];
125
159
  }
126
160
  export interface DeskExecOptions {
127
161
  command: string;
@@ -307,7 +341,9 @@ export interface DeskHandle {
307
341
  readonly deskId: string;
308
342
  renewLease(ms: number): void;
309
343
  /** Open a host-to-guest TCP stream; the caller owns and closes it. */
310
- connect(port: number): Promise<Duplex>;
344
+ connect(port: number, options?: {
345
+ transport?: 'tcp' | 'vsock';
346
+ }): Promise<Duplex>;
311
347
  exec(options: DeskExecOptions & {
312
348
  keepAlive: true;
313
349
  }): Promise<DeskJob>;
@@ -345,6 +381,11 @@ export interface DeskHostStats {
345
381
  }
346
382
  export interface DeskHost {
347
383
  start(options: DeskStartOptions): Promise<DeskHandle>;
384
+ /** True when this resident desk supports in-memory pause. */
385
+ canPause(deskId: string): boolean;
386
+ /** Pause a resident desk; its lease and capacity remain in effect. */
387
+ pause(deskId: string): Promise<void>;
388
+ /** Resume a paused resident desk or restore a suspended desk. */
348
389
  resume(deskId: string): Promise<DeskHandle>;
349
390
  suspend(deskId: string): Promise<void>;
350
391
  /**
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
@@ -8,9 +8,9 @@
8
8
  * emission to the consumer's ports, and the handover masking contract. It
9
9
  * never touches a database and knows nothing about tenants or approvals.
10
10
  */
11
- import { existsSync } from 'node:fs';
11
+ import { createReadStream, existsSync } from 'node:fs';
12
12
  import { execFile } from 'node:child_process';
13
- import { mkdir, readFile, rm, statfs, writeFile } from 'node:fs/promises';
13
+ import { mkdir, open, readFile, rename, rm, statfs, writeFile } from 'node:fs/promises';
14
14
  import { arch, cpus, release, tmpdir } from 'node:os';
15
15
  import { dirname, join } from 'node:path';
16
16
  import { createHash, randomUUID } from 'node:crypto';
@@ -18,6 +18,7 @@ import { Buffer } from 'node:buffer';
18
18
  import { connect as tcpConnect, isIP } from 'node:net';
19
19
  import { buildDeskLaunchPlan, cleanDeskId, DEFAULT_KVM_PATH, DEFAULT_VMM_PATH, DeskError, } from './plan.js';
20
20
  import { cloudHypervisorBackend, } from './backend.js';
21
+ import { readShareManifest } from './machine.js';
21
22
  import { parseCapabilities, parseClipboardText, parseExecResult, parseHandoverBegun, parseJobStarted, parseObservation, } from './protocol.js';
22
23
  export const DEFAULT_CAPACITY = 4;
23
24
  export const DEFAULT_IDLE_SUSPEND_MS = 5 * 60_000;
@@ -61,6 +62,19 @@ export function createDeskHost(options) {
61
62
  const deviceExists = options.deviceExists ?? existsSync;
62
63
  const removeOverlay = options.removeOverlay ?? ((path) => rm(path, { force: true }));
63
64
  const parkWithMemory = options.parkWithMemory ?? false;
65
+ if (options.memoryRestoreMode && (!parkWithMemory || backend.hypervisor === 'virtualization')) {
66
+ throw new DeskError('Copy-on-write restore requires Cloud Hypervisor and parkWithMemory.');
67
+ }
68
+ const retireSnapshot = options.retireSnapshot ?? (async (from, to) => {
69
+ await rename(from, to);
70
+ const directory = await open(dirname(from), 'r');
71
+ try {
72
+ await directory.sync();
73
+ }
74
+ finally {
75
+ await directory.close();
76
+ }
77
+ });
64
78
  const makeSnapshotDir = options.makeSnapshotDir ?? ((path) => mkdir(path, { recursive: true }).then(() => undefined));
65
79
  const removeSnapshot = options.removeSnapshot ?? ((path) => rm(path, { recursive: true, force: true }));
66
80
  const freeBytes = options.freeBytes ?? defaultFreeBytes;
@@ -124,7 +138,7 @@ export function createDeskHost(options) {
124
138
  record.lastActivityAt = now();
125
139
  }
126
140
  function requireMachine(record, epoch) {
127
- if (record.status !== 'resident' || record.epoch !== epoch || !record.machine) {
141
+ if (record.status !== 'resident' || record.paused || record.epoch !== epoch || !record.machine) {
128
142
  throw new DeskError(`Desk ${record.deskId} is not resident; resume it first.`);
129
143
  }
130
144
  return record.machine;
@@ -280,8 +294,26 @@ export function createDeskHost(options) {
280
294
  return join(dirname(overlayPath), `${deskId}.snapshot`);
281
295
  }
282
296
  async function teardown(record, keepMemory = true) {
297
+ if (record.status === 'suspending' && record.machine) {
298
+ // A previous stop failed. Keep the overlay fenced until a retry confirms
299
+ // the VMM has exited; never boot another VM or delete it underneath one.
300
+ await record.machine.shutdown();
301
+ await removeSnapshot(snapshotDirFor(record.startOptions.overlayPath, record.deskId));
302
+ record.machine = null;
303
+ record.status = 'suspended';
304
+ occupied -= 1;
305
+ lastSuspendedAt = iso(now());
306
+ drainQueue();
307
+ return true;
308
+ }
283
309
  if (record.status !== 'resident')
284
310
  return false;
311
+ // Resume before issuing trim, sync, or handover commands. On failure leave
312
+ // the resident record intact and fenced so the caller can retry.
313
+ if (record.paused) {
314
+ await record.machine.resume();
315
+ record.paused = false;
316
+ }
285
317
  await endHandover(record, 'revoked');
286
318
  for (const stop of [...record.streamStops])
287
319
  stop();
@@ -333,6 +365,26 @@ export function createDeskHost(options) {
333
365
  if (parking) {
334
366
  const snapshotDir = snapshotDirFor(record.startOptions.overlayPath, record.deskId);
335
367
  await makeSnapshotDir(snapshotDir);
368
+ // Persist attachment identity before the VMM can produce a complete
369
+ // snapshot. A crash must never leave attached VM state with no record.
370
+ if (record.startOptions.readOnlyAttachments?.length) {
371
+ const manifest = join(snapshotDir, 'attachments.json');
372
+ const file = await open(manifest, 'wx', 0o600);
373
+ try {
374
+ await file.writeFile(JSON.stringify(record.startOptions.readOnlyAttachments));
375
+ await file.sync();
376
+ }
377
+ finally {
378
+ await file.close();
379
+ }
380
+ const directory = await open(snapshotDir, 'r');
381
+ try {
382
+ await directory.sync();
383
+ }
384
+ finally {
385
+ await directory.close();
386
+ }
387
+ }
336
388
  await machine.park(snapshotDir);
337
389
  const signature = await (options.cpuSignature ?? hostCpuSignature)();
338
390
  await (options.writeSnapshotSignature ?? writeSnapshotSignature)(snapshotDir, signature);
@@ -342,10 +394,16 @@ export function createDeskHost(options) {
342
394
  }
343
395
  }
344
396
  catch (error) {
345
- // `park` stops the VMM on its own way out, so the desk is down either
346
- // way; what is lost is the memory, not the desk. Leave nothing behind
347
- // that a later boot would try to restore from.
397
+ // Preparation can fail before park is called, so confirm the VMM is
398
+ // down even when park itself normally stops on failure.
348
399
  lastError = errorMessage(error);
400
+ try {
401
+ await machine.shutdown();
402
+ }
403
+ catch (stopError) {
404
+ record.machine = machine;
405
+ throw new DeskError(`Desk ${record.deskId} could not stop after teardown failed: ${errorMessage(stopError)}`);
406
+ }
349
407
  if (parking) {
350
408
  await removeSnapshot(snapshotDirFor(record.startOptions.overlayPath, record.deskId)).catch(() => undefined);
351
409
  }
@@ -419,32 +477,76 @@ export function createDeskHost(options) {
419
477
  // names its vsock and tap, and a cold-boot retry that renumbered them would
420
478
  // come up on a different tap than the one the egress rules were put on.
421
479
  const cid = nextCid++;
422
- const initramfsPath = resolveInitramfsPath();
423
- const planFor = (restore) => buildDeskLaunchPlan({
480
+ const initramfsPath = startOptions.initramfsPath ?? resolveInitramfsPath();
481
+ let restoreDir = snapshotDir;
482
+ const planFor = (restore, shares = startOptions.shares) => buildDeskLaunchPlan({
424
483
  deskId,
425
484
  hypervisor: backend.hypervisor ?? 'cloud-hypervisor',
426
- ...(backend.hypervisor === 'virtualization' ? { guestNetwork: options.guestNetwork } : {}),
485
+ ...(backend.hypervisor === 'virtualization'
486
+ ? { guestNetwork: options.guestNetwork }
487
+ : { virtiofsdPath: options.virtiofsdPath, virtiofsdSandbox: options.virtiofsdSandbox }),
427
488
  vmmPath: options.vmmPath,
428
489
  kvmPath: options.kvmPath,
429
- kernelPath,
490
+ kernelPath: startOptions.kernelPath ?? kernelPath,
430
491
  ...(initramfsPath === undefined ? {} : { initramfsPath }),
431
492
  baseImagePath: startOptions.baseImage,
432
493
  overlayPath: startOptions.overlayPath,
433
494
  memoryMb: startOptions.memoryMb,
495
+ freePageReporting: startOptions.freePageReporting,
434
496
  vcpus: startOptions.vcpus,
435
497
  vsockCid: cid,
436
498
  runtimeDir: options.runtimeDir,
437
499
  tapDevice: startOptions.network?.tapDevice,
438
500
  macAddress: startOptions.network?.macAddress,
501
+ shares,
502
+ readOnlyAttachments: startOptions.readOnlyAttachments,
439
503
  // Forward the host's cmdline only when set; otherwise the plan falls
440
504
  // back to DEFAULT_KERNEL_CMDLINE.
441
505
  ...(kernelCmdline === undefined ? {} : { kernelCmdline }),
442
506
  launcherIdentity: options.launcherIdentity,
443
- snapshotDir,
444
- ...(restore ? { restore: true } : {}),
445
- }, { pathExists, deviceExists });
507
+ snapshotDir: restore ? restoreDir : snapshotDir,
508
+ ...(restore ? { restore: true, ...(options.memoryRestoreMode ? { memoryRestoreMode: options.memoryRestoreMode } : {}) } : {}),
509
+ }, { pathExists, deviceExists, ...(options.isDirectory ? { isDirectory: options.isDirectory } : {}) });
510
+ const restorePlan = async () => {
511
+ const parked = await (options.readSnapshotShares ?? readShareManifest)(restoreDir);
512
+ try {
513
+ return planFor(true, parked);
514
+ }
515
+ catch (error) {
516
+ throw new DeskError(`its restore, with the shares it was parked with, could not be planned: ${errorMessage(error)}`);
517
+ }
518
+ };
519
+ // Verify bytes, not just the caller's label, before the VMM can map them.
520
+ for (const image of startOptions.readOnlyAttachments ?? []) {
521
+ const hash = createHash('sha256');
522
+ for await (const chunk of createReadStream(image.path))
523
+ hash.update(chunk);
524
+ if (hash.digest('hex') !== image.sha256)
525
+ throw new DeskError(`Read-only attachment digest mismatch: ${image.path}`);
526
+ }
446
527
  let resuming = parkWithMemory && pathExists(snapshotDir);
528
+ // Shared guest memory, required by virtio-fs, makes Cloud Hypervisor fall
529
+ // back to eager restore. Reject before retiring the snapshot or cold booting.
530
+ if (options.memoryRestoreMode === 'copyonwrite') {
531
+ if (startOptions.shares?.length)
532
+ throw new DeskError('Copy-on-write restore cannot be combined with virtio-fs shares.');
533
+ if (resuming && (await (options.readSnapshotShares ?? readShareManifest)(snapshotDir)).length) {
534
+ throw new DeskError('The parked snapshot has virtio-fs shares and cannot use copy-on-write restore.');
535
+ }
536
+ }
447
537
  if (resuming) {
538
+ let savedAttachments;
539
+ try {
540
+ savedAttachments = JSON.parse(await readFile(join(snapshotDir, 'attachments.json'), 'utf8'));
541
+ }
542
+ catch (error) {
543
+ if (error.code !== 'ENOENT')
544
+ throw error;
545
+ savedAttachments = [];
546
+ }
547
+ if (JSON.stringify(savedAttachments) !== JSON.stringify(startOptions.readOnlyAttachments ?? [])) {
548
+ throw new DeskError('Snapshot read-only attachment identity does not match; restore requires the original images.');
549
+ }
448
550
  const saved = await (options.readSnapshotSignature ?? readSnapshotSignature)(snapshotDir);
449
551
  if (saved !== null && saved !== await (options.cpuSignature ?? hostCpuSignature)()) {
450
552
  await removeSnapshot(snapshotDir);
@@ -452,15 +554,20 @@ export function createDeskHost(options) {
452
554
  recordCpuFallback(deskId, 'signature_mismatch');
453
555
  }
454
556
  }
557
+ // Retire before starting the VMM: after a crash the old name can never be
558
+ // replayed against a disk the guest may have changed. The retired file is
559
+ // private backing memory, not a restorable snapshot.
560
+ if (resuming && options.memoryRestoreMode === 'copyonwrite') {
561
+ restoreDir = `${snapshotDir}.source-${randomUUID()}`;
562
+ await retireSnapshot(snapshotDir, restoreDir);
563
+ }
455
564
  let machine;
456
565
  try {
457
566
  machine = resuming
458
- ? await backend.boot(planFor(true), {
459
- // The guest is restored and PAUSED here. Destroying the snapshot in
460
- // this window is what stops a memory image ever outliving the disk
461
- // state it belongs to. If it fails the restore is abandoned rather
462
- // than resumed, because resuming would leave both alive at once.
463
- onRestored: () => removeSnapshot(snapshotDir),
567
+ ? await backend.boot(await restorePlan(), {
568
+ // Eager restore removes the parked snapshot before resume. A CoW
569
+ // source was already retired durably before the VMM started.
570
+ onRestored: options.memoryRestoreMode === 'copyonwrite' ? async () => { } : () => removeSnapshot(snapshotDir),
464
571
  })
465
572
  : await backend.boot(planFor(false));
466
573
  }
@@ -471,6 +578,7 @@ export function createDeskHost(options) {
471
578
  // boot. Safe by construction — the guest never ran, so the disk is
472
579
  // exactly as the pre-park sync left it.
473
580
  const why = errorMessage(error);
581
+ resuming = false;
474
582
  await removeSnapshot(snapshotDir);
475
583
  if (isIncompatibleCpuSnapshotError(error))
476
584
  recordCpuFallback(deskId, 'incompatible_cpuid');
@@ -486,12 +594,31 @@ export function createDeskHost(options) {
486
594
  : new DeskError(`Desk ${deskId} failed to boot: ${errorMessage(error)}`);
487
595
  }
488
596
  }
597
+ if (resuming && options.memoryRestoreMode === 'copyonwrite') {
598
+ // The mapping remains file-backed until the VMM has exited. Never remove
599
+ // it after a failed stop; leaking it is safer than invalidating a live VM.
600
+ const restored = machine;
601
+ const stop = restored.shutdown.bind(restored);
602
+ const park = restored.park?.bind(restored);
603
+ const releaseSource = async () => {
604
+ try {
605
+ await removeSnapshot(restoreDir);
606
+ }
607
+ catch (error) {
608
+ lastError = `Snapshot source cleanup failed for ${deskId}: ${errorMessage(error)}`;
609
+ }
610
+ };
611
+ restored.shutdown = async () => { await stop(); await releaseSource(); };
612
+ if (park)
613
+ restored.park = async (dir) => { await park(dir); await releaseSource(); };
614
+ }
489
615
  let record = records.get(deskId);
490
616
  if (!record) {
491
617
  record = {
492
618
  deskId,
493
619
  startOptions,
494
620
  status: 'resident',
621
+ paused: false,
495
622
  machine,
496
623
  epoch: 1,
497
624
  leaseDeadline: 0,
@@ -510,6 +637,7 @@ export function createDeskHost(options) {
510
637
  else {
511
638
  record.startOptions = startOptions;
512
639
  record.status = 'resident';
640
+ record.paused = false;
513
641
  record.machine = machine;
514
642
  record.epoch += 1;
515
643
  record.jobs = new Map();
@@ -756,22 +884,28 @@ export function createDeskHost(options) {
756
884
  return {
757
885
  deskId: record.deskId,
758
886
  renewLease(ms) {
759
- requireMachine(record, epoch);
887
+ // Renewing a lease is host-side and remains valid during resident pause.
888
+ if (record.status !== 'resident' || record.epoch !== epoch || !record.machine) {
889
+ throw new DeskError(`Desk ${record.deskId} is not resident; resume it first.`);
890
+ }
760
891
  record.leaseDeadline = now() + positiveInteger(ms, 'ms');
761
892
  touch(record);
762
893
  armTimer(record);
763
894
  },
764
- async connect(port) {
895
+ async connect(port, choice) {
765
896
  requireMachine(record, epoch);
766
897
  if (!Number.isInteger(port) || port < 1 || port > 65535)
767
898
  throw new DeskError('Guest TCP port must be between 1 and 65535.');
768
899
  const machine = requireMachine(record, epoch);
769
900
  const address = record.startOptions.network?.guestAddress;
770
- if (!machine.connect && (!address || isIP(address) !== 4))
901
+ const useVsock = choice?.transport === 'vsock' || (choice?.transport !== 'tcp' && !!machine.connect);
902
+ if (useVsock && !machine.connect)
903
+ throw new DeskError('This backend has no service vsock connector.');
904
+ if (!useVsock && (!address || isIP(address) !== 4))
771
905
  throw new DeskError('A guest IPv4 address is required to connect to a desk port.');
772
906
  touch(record);
773
907
  try {
774
- const stream = machine.connect ? await machine.connect(port) : await (options.connectGuest ?? connectGuestTcp)(address, port);
908
+ const stream = useVsock ? await machine.connect(port) : await (options.connectGuest ?? connectGuestTcp)(address, port);
775
909
  try {
776
910
  requireMachine(record, epoch);
777
911
  }
@@ -1149,19 +1283,51 @@ export function createDeskHost(options) {
1149
1283
  const deskId = cleanDeskId(startOptions.deskId);
1150
1284
  return serializeLifecycle(deskId, async () => {
1151
1285
  const existing = records.get(deskId);
1152
- if (existing?.status === 'resident' && existing.handle)
1286
+ if (existing?.status === 'suspending')
1287
+ throw new DeskError(`Desk ${deskId} has not stopped; retry suspend first.`);
1288
+ if (existing?.status === 'resident' && existing.handle) {
1289
+ if (existing.paused) {
1290
+ await existing.machine.resume();
1291
+ existing.paused = false;
1292
+ }
1153
1293
  return existing.handle;
1294
+ }
1154
1295
  return admit(() => boot(deskId, { ...startOptions, deskId }));
1155
1296
  });
1156
1297
  }
1298
+ function canPause(deskId) {
1299
+ const record = records.get(cleanDeskId(deskId));
1300
+ return record?.status === 'resident' && typeof record.machine?.pause === 'function' && typeof record.machine?.resume === 'function';
1301
+ }
1302
+ async function pause(deskId) {
1303
+ const id = cleanDeskId(deskId);
1304
+ await serializeLifecycle(id, async () => {
1305
+ const record = records.get(id);
1306
+ if (!record || record.status !== 'resident' || !canPause(id))
1307
+ throw new DeskError(`Desk ${id} cannot be paused.`);
1308
+ if (record.paused)
1309
+ return;
1310
+ if (record.screen?.handover)
1311
+ throw new DeskError(`Desk ${id} has an active handover.`);
1312
+ record.paused = true;
1313
+ await record.machine.pause();
1314
+ });
1315
+ }
1157
1316
  async function resume(deskId) {
1158
1317
  const id = cleanDeskId(deskId);
1159
1318
  return serializeLifecycle(id, async () => {
1160
1319
  const record = records.get(id);
1161
1320
  if (!record)
1162
1321
  throw new DeskError(`Unknown desk: ${deskId}`);
1163
- if (record.status === 'resident' && record.handle)
1322
+ if (record.status === 'suspending')
1323
+ throw new DeskError(`Desk ${id} has not stopped; retry suspend first.`);
1324
+ if (record.status === 'resident' && record.handle) {
1325
+ if (record.paused) {
1326
+ await record.machine.resume();
1327
+ record.paused = false;
1328
+ }
1164
1329
  return record.handle;
1330
+ }
1165
1331
  return admit(() => boot(record.deskId, record.startOptions));
1166
1332
  });
1167
1333
  }
@@ -1283,7 +1449,7 @@ export function createDeskHost(options) {
1283
1449
  lastSnapshotCpuFallback,
1284
1450
  };
1285
1451
  }
1286
- return { start, resume, suspend, shutdown, destroy, stats, sweep };
1452
+ return { start, canPause, pause, resume, suspend, shutdown, destroy, stats, sweep };
1287
1453
  }
1288
1454
  /**
1289
1455
  * Whether the overlay directory's filesystem can make reflink clones.