livedesk 0.1.591 → 0.1.593

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 (69) hide show
  1. package/README.md +8 -8
  2. package/bin/livedesk.js +115 -112
  3. package/bootstrap/client-process-identity.js +1 -1
  4. package/bootstrap/device-role.js +1 -1
  5. package/bootstrap/legacy-client-update.js +15 -15
  6. package/bootstrap/role-bootstrap-server.js +2 -2
  7. package/bootstrap/runtime-lock.js +4 -4
  8. package/bootstrap/runtime-shutdown.js +3 -3
  9. package/bootstrap/update-host-client.mjs +9 -9
  10. package/bootstrap/update-host.mjs +6 -6
  11. package/client/README.md +10 -10
  12. package/client/THIRD_PARTY_NOTICES.md +1 -1
  13. package/client/bin/client-version.js +1 -1
  14. package/client/bin/livedesk-client-node.js +102 -102
  15. package/client/bin/livedesk-client-update-bootstrap.cjs +12 -12
  16. package/client/bin/livedesk-client.js +136 -122
  17. package/client/package.json +7 -7
  18. package/client/src/runtime/agent-process-lifecycle.js +10 -10
  19. package/client/src/runtime/agent-shell.js +66 -66
  20. package/client/src/runtime/client-runtime-server.js +12 -11
  21. package/client/src/runtime/linux-video-acceleration.js +1 -1
  22. package/client/src/runtime/windows-owned-process-manifest.js +9 -9
  23. package/client/tests/client-version.test.mjs +2 -2
  24. package/diagnostics/livedesk-mac-physical-gate-core.mjs +5 -5
  25. package/diagnostics/livedesk-mode3-capture-smoke.mjs +7 -7
  26. package/diagnostics/livedesk-transport-physical.mjs +3 -3
  27. package/electron/auth-session-owner.mjs +24 -24
  28. package/electron/desktop-clipboard-owner.mjs +382 -382
  29. package/electron/electron-builder.e2e.yml +1 -1
  30. package/electron/electron-builder.mac-arm64.yml +1 -1
  31. package/electron/electron-builder.mac-x64.yml +1 -1
  32. package/electron/electron-builder.win-dev.yml +1 -1
  33. package/electron/electron-builder.win.yml +2 -2
  34. package/electron/electron-builder.yml +2 -2
  35. package/electron/main.mjs +175 -174
  36. package/electron/preload.cjs +13 -13
  37. package/electron/runtime-role-transition.mjs +17 -17
  38. package/hub/package.json +4 -4
  39. package/hub/src/agents/agent-manager.js +2 -2
  40. package/hub/src/agents/agent-permissions.js +2 -2
  41. package/hub/src/agents/agent-tool-registry.js +36 -36
  42. package/hub/src/agents/codex-agent-runtime.js +16 -16
  43. package/hub/src/agents/codex-mcp-server.js +5 -5
  44. package/hub/src/filesystem/roots.js +20 -20
  45. package/hub/src/filesystem/shared-folders.js +2 -2
  46. package/hub/src/live-desk-update.js +9 -9
  47. package/hub/src/remote-clipboard-contract.mjs +482 -482
  48. package/hub/src/remote-hub.js +1025 -1025
  49. package/hub/src/server.js +146 -146
  50. package/hub/src/settings/effective-device-policy.js +31 -31
  51. package/hub/src/settings/settings-schema.js +2 -2
  52. package/package.json +7 -7
  53. package/runtime-core/package.json +2 -2
  54. package/runtime-core/src/auth-config.js +1 -1
  55. package/scripts/sync-web-dist.js +9 -9
  56. package/web/dist/app.webmanifest +4 -4
  57. package/web/dist/assets/LiveDeskApp-Djx1CsIp.js +178 -0
  58. package/web/dist/assets/{icons-CebEqIp7.js → icons-DwJmccVC.js} +1 -1
  59. package/web/dist/assets/{index-BPgqiKB-.js → index-DjIbOQxl.js} +6 -6
  60. package/web/dist/assets/{react-BHQWCi9c.js → react-DOZUPHF8.js} +1 -1
  61. package/web/dist/assets/supabase-C7qjtLN3.js +29 -0
  62. package/web/dist/desktop-auth-callback.html +4 -4
  63. package/web/dist/desktop-auth-callback.js +13 -13
  64. package/web/dist/index.html +11 -10
  65. package/web/dist/livedesk-build-evidence.json +30 -30
  66. package/web/dist/offline.html +2 -2
  67. package/web/dist/sw.js +11 -11
  68. package/web/dist/assets/LiveDeskApp-BnYbdi9v.js +0 -178
  69. package/web/dist/assets/supabase-C0Z0FS3K.js +0 -29
package/bin/livedesk.js CHANGED
@@ -101,7 +101,7 @@ function prepareUpdateNeutralCwd(kind, operationId) {
101
101
  if (unexpectedEntry) {
102
102
  const shadowPath = join(neutralCwd, unexpectedEntry);
103
103
  throw new Error(
104
- `LiveDesk update neutral working directory is shadowed by ${shadowPath}: ${neutralCwd}`
104
+ `VuvoDesk update neutral working directory is shadowed by ${shadowPath}: ${neutralCwd}`
105
105
  );
106
106
  }
107
107
  return neutralCwd;
@@ -135,7 +135,7 @@ function restoreUpdateOriginalCwd() {
135
135
  process.chdir(UPDATE_ORIGINAL_CWD);
136
136
  } catch (error) {
137
137
  throw new Error(
138
- `LiveDesk could not restore the pre-update working directory ${UPDATE_ORIGINAL_CWD}: `
138
+ `VuvoDesk could not restore the pre-update working directory ${UPDATE_ORIGINAL_CWD}: `
139
139
  + `${error instanceof Error ? error.message : String(error)}`
140
140
  );
141
141
  }
@@ -190,12 +190,12 @@ async function assertNoActiveMacPhysicalDiagnosticLease() {
190
190
  return;
191
191
  }
192
192
  throw new Error(
193
- `Mac physical diagnostic is running (pid ${lease.pid}); normal LiveDesk startup was not started. `
193
+ `Mac physical diagnostic is running (pid ${lease.pid}); normal VuvoDesk startup was not started. `
194
194
  + 'Wait for its owned cleanup to finish or stop the diagnostic with Ctrl+C.'
195
195
  );
196
196
  }
197
197
  throw new Error(
198
- `Mac physical diagnostic ownership is unreadable at ${lease.path}; normal LiveDesk startup was not started `
198
+ `Mac physical diagnostic ownership is unreadable at ${lease.path}; normal VuvoDesk startup was not started `
199
199
  + 'to avoid overlapping a capture runtime.'
200
200
  );
201
201
  }
@@ -254,11 +254,11 @@ async function waitForHubRestartUpdateHostClaim(updateHost, jobId, expected) {
254
254
  timeoutMs: Math.min(2_000, Math.max(250, claimDeadline - Date.now()))
255
255
  });
256
256
  if (!job) {
257
- throw new Error(`LiveDesk Update Host lost job ${jobId} before handoff.`);
257
+ throw new Error(`VuvoDesk Update Host lost job ${jobId} before handoff.`);
258
258
  }
259
259
  if (['failed', 'cancelled'].includes(String(job.state || ''))) {
260
260
  throw new Error(
261
- `LiveDesk Update Host job ${jobId} failed before handoff: ${job.error || `state=${job.state}`}`
261
+ `VuvoDesk Update Host job ${jobId} failed before handoff: ${job.error || `state=${job.state}`}`
262
262
  );
263
263
  }
264
264
  workerPid = Number(job.workerPid || 0);
@@ -300,7 +300,7 @@ async function waitForHubRestartUpdateHostClaim(updateHost, jobId, expected) {
300
300
  await delay(Math.max(50, HUB_UPDATE_SUPERVISOR_HANDSHAKE_POLL_MS));
301
301
  }
302
302
  throw new Error(
303
- `LiveDesk Update Host job ${jobId} did not publish an atomic handoff for `
303
+ `VuvoDesk Update Host job ${jobId} did not publish an atomic handoff for `
304
304
  + `operation ${expected.operationId} within ${expected.timeoutMs}ms.`
305
305
  );
306
306
  }
@@ -339,7 +339,7 @@ function writeJsonAtomic(filePath, value) {
339
339
 
340
340
  function printHelp() {
341
341
  process.stdout.write(`
342
- LiveDesk
342
+ VuvoDesk
343
343
 
344
344
  Usage:
345
345
  npx -y --prefer-online livedesk@latest
@@ -364,10 +364,10 @@ Hub options:
364
364
  --port <port> Hub HTTP port. Default: 5179
365
365
  --remote-port <port>
366
366
  Client connection port. Default: 5197.
367
- --clean Proactively replace verified stale LiveDesk owners on Hub ports.
367
+ --clean Proactively replace verified stale VuvoDesk owners on Hub ports.
368
368
  --no-clean Do not attempt automatic port-conflict recovery.
369
369
  --no-restart-existing
370
- Keep an existing same-role LiveDesk runtime and open its page.
370
+ Keep an existing same-role VuvoDesk runtime and open its page.
371
371
 
372
372
  Common:
373
373
  --force-role <hub|client>
@@ -382,7 +382,7 @@ Common:
382
382
 
383
383
  function printMacPhysicalDiagnosticHelp() {
384
384
  process.stdout.write(`
385
- LiveDesk macOS physical diagnostic
385
+ VuvoDesk macOS physical diagnostic
386
386
 
387
387
  Usage:
388
388
  npx -y --prefer-online livedesk@latest diagnose mac-physical --confirm-active-motion
@@ -390,16 +390,16 @@ Usage:
390
390
 
391
391
  Requirements:
392
392
  macOS with two connected displays showing visibly different, continuously moving content.
393
- Screen Recording permission for the terminal/LiveDesk capture helper.
394
- Accessibility permission for the terminal/LiveDesk input helper.
395
- Stop every existing LiveDesk Hub, Client, and desktop runtime first.
393
+ Screen Recording permission for the terminal/VuvoDesk capture helper.
394
+ Accessibility permission for the terminal/VuvoDesk input helper.
395
+ Stop every existing VuvoDesk Hub, Client, and desktop runtime first.
396
396
  --confirm-active-motion attests that motion is already running on both displays;
397
397
  measured decoded-pixel change and native cadence must still prove it.
398
398
 
399
399
  Behavior:
400
400
  Starts one production unified Hub root and one production unified Client root
401
401
  with isolated loopback state; the Client starts its normal RemoteFast child.
402
- Refuses to overlap a running LiveDesk runtime or capture helper.
402
+ Refuses to overlap a running VuvoDesk runtime or capture helper.
403
403
  Stops only those exact launcher roots after their descendants drain.
404
404
  Writes the default report under ~/.livedesk/diagnostics.
405
405
 
@@ -425,14 +425,14 @@ async function runDiagnosticCommand(args) {
425
425
  'livedesk-transport-physical.mjs'
426
426
  );
427
427
  if (!existsSync(diagnosticEntry)) {
428
- throw new Error(`LiveDesk transport-physical diagnostic is missing from this package: ${diagnosticEntry}`);
428
+ throw new Error(`VuvoDesk transport-physical diagnostic is missing from this package: ${diagnosticEntry}`);
429
429
  }
430
430
  const diagnostic = await import(pathToFileURL(diagnosticEntry).href);
431
431
  await diagnostic.runTransportPhysicalDiagnosticCli(args.slice(1));
432
432
  return;
433
433
  }
434
434
  if (name !== 'mac-physical') {
435
- throw new Error(`Unknown LiveDesk diagnostic: ${name}. Supported diagnostics: mac-physical, transport-physical.`);
435
+ throw new Error(`Unknown VuvoDesk diagnostic: ${name}. Supported diagnostics: mac-physical, transport-physical.`);
436
436
  }
437
437
  if (args.slice(1).some(argument => ['--help', '-h', 'help'].includes(String(argument).toLowerCase()))) {
438
438
  printMacPhysicalDiagnosticHelp();
@@ -444,21 +444,21 @@ async function runDiagnosticCommand(args) {
444
444
  'livedesk-mode3-capture-smoke.mjs'
445
445
  );
446
446
  if (!existsSync(diagnosticEntry)) {
447
- throw new Error(`LiveDesk mac-physical diagnostic is missing from this package: ${diagnosticEntry}`);
447
+ throw new Error(`VuvoDesk mac-physical diagnostic is missing from this package: ${diagnosticEntry}`);
448
448
  }
449
449
  await import(pathToFileURL(diagnosticEntry).href);
450
450
  }
451
451
 
452
452
  function printClientHelp() {
453
453
  process.stdout.write(`
454
- LiveDesk Client
454
+ VuvoDesk Client
455
455
 
456
456
  Usage:
457
457
  npx -y --prefer-online livedesk@latest client
458
458
  npx -y --prefer-online livedesk@latest client 3
459
459
 
460
460
  Default flow:
461
- Opens a LiveDesk connection page with Google sign-in or a 6-digit PIN.
461
+ Opens a VuvoDesk connection page with Google sign-in or a 6-digit PIN.
462
462
  Omit the number for first-available placement, or pass 1-999 to pin a slot.
463
463
  On Windows, enable auto-start from the connection page checkbox.
464
464
 
@@ -665,7 +665,7 @@ async function waitForRoleTransitionParentExit(pid, timeoutMs = 120_000) {
665
665
  if (!alive) return;
666
666
  await new Promise(resolve => setTimeout(resolve, 250));
667
667
  }
668
- throw new Error(`Previous LiveDesk runtime ${processId} did not exit before the role transition deadline.`);
668
+ throw new Error(`Previous VuvoDesk runtime ${processId} did not exit before the role transition deadline.`);
669
669
  }
670
670
 
671
671
  async function isManagerAlreadyRunning(url = DEFAULT_MANAGER_URL) {
@@ -743,7 +743,7 @@ async function probeExistingRuntimeIdentity(existing) {
743
743
  };
744
744
  }
745
745
  } catch {
746
- // A non-LiveDesk, stopping, or unreachable owner is not runtime proof.
746
+ // A non-VuvoDesk, stopping, or unreachable owner is not runtime proof.
747
747
  } finally {
748
748
  clearTimeout(timer);
749
749
  }
@@ -904,7 +904,7 @@ async function waitForProcessExit(pid, timeoutMs = EXISTING_RUNTIME_STOP_TIMEOUT
904
904
  if (!alive) return;
905
905
  await waitMilliseconds(Math.min(PORT_CLEANUP_POLL_MS, Math.max(1, deadline - Date.now())));
906
906
  }
907
- throw new Error(`Existing LiveDesk runtime ${processId} did not exit before the restart deadline.`);
907
+ throw new Error(`Existing VuvoDesk runtime ${processId} did not exit before the restart deadline.`);
908
908
  }
909
909
 
910
910
  function normalizeExactWindowsProcessRecord(value, depth = 0) {
@@ -958,7 +958,7 @@ async function queryExactWindowsProcessSnapshot() {
958
958
  );
959
959
  if (!result.ok || !result.stdout) {
960
960
  throw new Error(
961
- 'LiveDesk could not establish an immutable Windows process snapshot: '
961
+ 'VuvoDesk could not establish an immutable Windows process snapshot: '
962
962
  + `${result.stderr || result.error?.message || 'CIM query failed'}`
963
963
  );
964
964
  }
@@ -966,7 +966,7 @@ async function queryExactWindowsProcessSnapshot() {
966
966
  try {
967
967
  parsed = JSON.parse(result.stdout);
968
968
  } catch (error) {
969
- throw new Error(`LiveDesk could not parse the immutable Windows process snapshot: ${error.message}`);
969
+ throw new Error(`VuvoDesk could not parse the immutable Windows process snapshot: ${error.message}`);
970
970
  }
971
971
  const records = parsed?.Records == null
972
972
  ? []
@@ -977,7 +977,7 @@ async function queryExactWindowsProcessSnapshot() {
977
977
  async function captureExactWindowsProcessTree(rootDetails, { rootExitedAtMs = null } = {}) {
978
978
  const rootRecord = normalizeExactWindowsProcessRecord(rootDetails, 0);
979
979
  if (!rootRecord) {
980
- throw new Error('LiveDesk could not establish the launcher CreationDate identity; it was preserved.');
980
+ throw new Error('VuvoDesk could not establish the launcher CreationDate identity; it was preserved.');
981
981
  }
982
982
  const snapshot = await queryExactWindowsProcessSnapshot();
983
983
  const currentByPid = new Map(snapshot.map(record => [record.pid, record]));
@@ -1056,7 +1056,7 @@ async function exactReclaimedWindowsRecordsStillRunning(records) {
1056
1056
  );
1057
1057
  if (!result.ok || !result.stdout) {
1058
1058
  throw new Error(
1059
- 'LiveDesk could not revalidate the reclaimed Windows process identities: '
1059
+ 'VuvoDesk could not revalidate the reclaimed Windows process identities: '
1060
1060
  + `${result.stderr || result.error?.message || 'targeted CIM query failed'}`
1061
1061
  );
1062
1062
  }
@@ -1064,7 +1064,7 @@ async function exactReclaimedWindowsRecordsStillRunning(records) {
1064
1064
  try {
1065
1065
  parsed = JSON.parse(result.stdout);
1066
1066
  } catch (error) {
1067
- throw new Error(`LiveDesk could not parse reclaimed Windows process identities: ${error.message}`);
1067
+ throw new Error(`VuvoDesk could not parse reclaimed Windows process identities: ${error.message}`);
1068
1068
  }
1069
1069
  const values = parsed?.Records == null
1070
1070
  ? []
@@ -1094,7 +1094,7 @@ async function terminateExactWindowsProcesses(recordOrRecords) {
1094
1094
  .map(record => normalizeExactWindowsProcessRecord(record, record?.depth))
1095
1095
  .filter(Boolean);
1096
1096
  if (targets.length === 0) {
1097
- throw new Error('LiveDesk refused to terminate Windows processes without immutable CreationDates.');
1097
+ throw new Error('VuvoDesk refused to terminate Windows processes without immutable CreationDates.');
1098
1098
  }
1099
1099
  const targetsJson = JSON.stringify(targets.map(target => ({
1100
1100
  pid: target.pid,
@@ -1175,7 +1175,7 @@ async function drainReclaimedWindowsClientManifest(reclaimedOwner, {
1175
1175
  if (inheritedManifest.missing === true) {
1176
1176
  if (process.env.LIVEDESK_DEBUG === '1') {
1177
1177
  console.log(
1178
- `[LiveDesk] Reclaimed Windows Client generation ${exactOwner.pid} `
1178
+ `[VuvoDesk] Reclaimed Windows Client generation ${exactOwner.pid} `
1179
1179
  + 'has no exact process manifest; continuing legacy cleanup.'
1180
1180
  );
1181
1181
  }
@@ -1219,7 +1219,7 @@ async function drainReclaimedWindowsClientManifest(reclaimedOwner, {
1219
1219
  }
1220
1220
  if (process.env.LIVEDESK_DEBUG === '1') {
1221
1221
  console.log(
1222
- `[LiveDesk] Reclaimed Windows Client generation ${exactOwner.pid} `
1222
+ `[VuvoDesk] Reclaimed Windows Client generation ${exactOwner.pid} `
1223
1223
  + `drained ${tracked.length} exact process record(s) and consumed its manifest.`
1224
1224
  );
1225
1225
  }
@@ -1246,7 +1246,7 @@ async function drainReclaimedWindowsClientManifest(reclaimedOwner, {
1246
1246
  }
1247
1247
 
1248
1248
  async function terminateExactWindowsProcessTree(rootDetails, {
1249
- label = 'LiveDesk process tree',
1249
+ label = 'VuvoDesk process tree',
1250
1250
  maxAttempts = 4,
1251
1251
  additionalRecords = []
1252
1252
  } = {}) {
@@ -1314,7 +1314,7 @@ async function terminateExactWindowsProcessTree(rootDetails, {
1314
1314
  async function stopExistingRuntime(existing) {
1315
1315
  const processId = Number(existing?.pid);
1316
1316
  if (!Number.isInteger(processId) || processId <= 1) {
1317
- throw new Error('Existing LiveDesk runtime has an invalid process id; it was preserved.');
1317
+ throw new Error('Existing VuvoDesk runtime has an invalid process id; it was preserved.');
1318
1318
  }
1319
1319
  const storedOwnerToken = String(existing?.ownerToken || '').trim();
1320
1320
  const storedOwnerInstanceMarker = String(existing?.ownerInstanceMarker || '').trim();
@@ -1334,7 +1334,7 @@ async function stopExistingRuntime(existing) {
1334
1334
  }
1335
1335
  : null;
1336
1336
  if (processId === process.pid) {
1337
- throw new Error('Existing LiveDesk runtime resolves to this launcher without an exact stale-owner proof; it was preserved.');
1337
+ throw new Error('Existing VuvoDesk runtime resolves to this launcher without an exact stale-owner proof; it was preserved.');
1338
1338
  }
1339
1339
 
1340
1340
  // The mailbox is non-destructive and authenticates the current lock token.
@@ -1369,7 +1369,7 @@ async function stopExistingRuntime(existing) {
1369
1369
  const cooperativeStop = await cooperativeStopPromise;
1370
1370
  if (cooperativeStop.exited) {
1371
1371
  console.log(
1372
- `[LiveDesk] Existing ${existing?.role || 'runtime'} launcher pid ${processId} `
1372
+ `[VuvoDesk] Existing ${existing?.role || 'runtime'} launcher pid ${processId} `
1373
1373
  + 'accepted cooperative cleanup and exited before replacement (identity=exact-owner-mailbox).'
1374
1374
  );
1375
1375
  return { runtimeProof: null, staleOwnerProof: null };
@@ -1390,7 +1390,7 @@ async function stopExistingRuntime(existing) {
1390
1390
  && (processInstanceMarker(fallbackDetails) !== processInstanceMarker(details)
1391
1391
  || String(fallbackDetails.startOrder || '') !== String(details.startOrder || ''))) {
1392
1392
  console.warn(
1393
- `[LiveDesk] Launcher pid ${processId} changed identity while cooperative cleanup was pending; `
1393
+ `[VuvoDesk] Launcher pid ${processId} changed identity while cooperative cleanup was pending; `
1394
1394
  + 'the reused process was preserved.'
1395
1395
  );
1396
1396
  if (exactStaleOwnerProof) {
@@ -1404,7 +1404,7 @@ async function stopExistingRuntime(existing) {
1404
1404
  && currentOwnerStartOrder
1405
1405
  && storedOwnerStartOrder !== currentOwnerStartOrder) {
1406
1406
  console.warn(
1407
- `[LiveDesk] Runtime lock pid ${processId} was reused by a different process instance; `
1407
+ `[VuvoDesk] Runtime lock pid ${processId} was reused by a different process instance; `
1408
1408
  + 'the current process was preserved and only the exact stale lock may be reclaimed.'
1409
1409
  );
1410
1410
  return { runtimeProof: null, staleOwnerProof: exactStaleOwnerProof };
@@ -1429,7 +1429,7 @@ async function stopExistingRuntime(existing) {
1429
1429
  && !legacyClientTreeConfirmed
1430
1430
  && !runtimeProof
1431
1431
  && !cooperativeOwnerConfirmed) {
1432
- throw new Error(`Existing runtime pid ${processId} is not a confirmed LiveDesk launcher; it was preserved.`);
1432
+ throw new Error(`Existing runtime pid ${processId} is not a confirmed VuvoDesk launcher; it was preserved.`);
1433
1433
  }
1434
1434
 
1435
1435
  const identityProof = cooperativeOwnerConfirmed
@@ -1459,7 +1459,7 @@ async function stopExistingRuntime(existing) {
1459
1459
  || currentLock.ownerInstanceMarker !== storedOwnerInstanceMarker
1460
1460
  || currentLock.ownerStartOrder !== storedOwnerStartOrder) {
1461
1461
  throw new Error(
1462
- `LiveDesk runtime-lock ownership changed before fallback for pid ${processId}; `
1462
+ `VuvoDesk runtime-lock ownership changed before fallback for pid ${processId}; `
1463
1463
  + 'the current process and newer lock generation were preserved.'
1464
1464
  );
1465
1465
  }
@@ -1488,16 +1488,16 @@ async function stopExistingRuntime(existing) {
1488
1488
  ? `ack=${cooperativeStop.ackStatus || 'accepted'}`
1489
1489
  : 'no-ack';
1490
1490
  console.warn(
1491
- `[LiveDesk] Existing ${existing?.role || 'runtime'} launcher pid ${processId} `
1491
+ `[VuvoDesk] Existing ${existing?.role || 'runtime'} launcher pid ${processId} `
1492
1492
  + `did not finish cooperative cleanup within its ${cooperativeTimeoutMs / 1000}-second `
1493
1493
  + `maximum window (${status}); `
1494
1494
  + 'continuing with exact process-identity fallback.'
1495
1495
  );
1496
1496
  }
1497
- console.log(`[LiveDesk] Stopping existing ${existing?.role || 'runtime'} launcher pid ${processId} before starting a fresh runtime (identity=${identityProof}).`);
1497
+ console.log(`[VuvoDesk] Stopping existing ${existing?.role || 'runtime'} launcher pid ${processId} before starting a fresh runtime (identity=${identityProof}).`);
1498
1498
  if (os.platform() === 'win32') {
1499
1499
  await terminateExactWindowsProcessTree(details, {
1500
- label: `existing LiveDesk ${existing?.role || 'runtime'} launcher pid=${processId}`,
1500
+ label: `existing VuvoDesk ${existing?.role || 'runtime'} launcher pid=${processId}`,
1501
1501
  additionalRecords: inheritedWindowsProcessRecords
1502
1502
  });
1503
1503
  } else {
@@ -1508,7 +1508,7 @@ async function stopExistingRuntime(existing) {
1508
1508
  await waitForProcessExit(processId);
1509
1509
  } catch (error) {
1510
1510
  console.warn(
1511
- `[LiveDesk] Confirmed launcher pid ${processId} did not finish graceful Client cleanup; `
1511
+ `[VuvoDesk] Confirmed launcher pid ${processId} did not finish graceful Client cleanup; `
1512
1512
  + 'force-stopping that launcher only. Verified orphan agents/helpers will be audited before restart.'
1513
1513
  );
1514
1514
  try { process.kill(processId, 'SIGKILL'); } catch (killError) {
@@ -1543,7 +1543,7 @@ function startOwnedRuntimeShutdownWatcher(runtimeOwner, onShutdown) {
1543
1543
  if (!exactOwnerIsComplete) {
1544
1544
  if (runtimeOwner?.ownerToken) {
1545
1545
  console.warn(
1546
- '[LiveDesk] Cooperative shutdown watcher is unavailable because the launcher '
1546
+ '[VuvoDesk] Cooperative shutdown watcher is unavailable because the launcher '
1547
1547
  + 'could not establish a complete process-start identity. Exact fallback remains enabled.'
1548
1548
  );
1549
1549
  }
@@ -1632,7 +1632,7 @@ function assertPortCleanupReady(finalRecords, portStates) {
1632
1632
  .map(formatPortOwner);
1633
1633
  return `TCP ${port.Port}[available=${port.PortAvailable === true},bindable=${port.PortBindable === true},bind-error=${port.BindError || 'none'},owners=${owners.length ? owners.join('; ') : 'owner not visible'}`;
1634
1634
  }).join('], ');
1635
- throw new Error(`LiveDesk Hub startup cleanup could not release the configured port(s): ${summary}]. Unrelated processes are preserved; stop the owning process manually or choose an explicit --port/--remote-port value.`);
1635
+ throw new Error(`VuvoDesk Hub startup cleanup could not release the configured port(s): ${summary}]. Unrelated processes are preserved; stop the owning process manually or choose an explicit --port/--remote-port value.`);
1636
1636
  }
1637
1637
 
1638
1638
  async function collectWindowsPortRecords(ports) {
@@ -1680,7 +1680,7 @@ async function collectWindowsPortRecords(ports) {
1680
1680
  );
1681
1681
  if (!result.ok && !result.stdout) {
1682
1682
  throw new Error(
1683
- `Could not inspect existing LiveDesk Windows ports: `
1683
+ `Could not inspect existing VuvoDesk Windows ports: `
1684
1684
  + `${result.stderr || result.error?.message || 'PowerShell failed'}`
1685
1685
  );
1686
1686
  }
@@ -1689,7 +1689,7 @@ async function collectWindowsPortRecords(ports) {
1689
1689
  try {
1690
1690
  parsed = JSON.parse(result.stdout);
1691
1691
  } catch {
1692
- throw new Error(`Could not parse existing LiveDesk Windows port state: ${result.stdout}`);
1692
+ throw new Error(`Could not parse existing VuvoDesk Windows port state: ${result.stdout}`);
1693
1693
  }
1694
1694
  const records = parsed?.Records == null
1695
1695
  ? []
@@ -1834,7 +1834,7 @@ async function terminateExactWindowsPortOwners(records) {
1834
1834
  );
1835
1835
  if (!result.ok) {
1836
1836
  throw new Error(
1837
- `Could not stop exact LiveDesk Windows port owner tree: `
1837
+ `Could not stop exact VuvoDesk Windows port owner tree: `
1838
1838
  + `${result.stderr || result.error?.message || 'PowerShell failed'}`
1839
1839
  );
1840
1840
  }
@@ -1874,7 +1874,7 @@ async function stopWindowsProcessesOnPorts(ports) {
1874
1874
  const summary = [...stoppedOwners.values()]
1875
1875
  .map(record => `${record.Pid}:${record.ProcessName || 'node'}`)
1876
1876
  .join(', ');
1877
- console.log(`Restarting LiveDesk Hub. Stopped stale LiveDesk owner(s) once: ${summary}`);
1877
+ console.log(`Restarting VuvoDesk Hub. Stopped stale VuvoDesk owner(s) once: ${summary}`);
1878
1878
  }
1879
1879
  assertPortCleanupReady(finalRecords, portStates);
1880
1880
  }
@@ -1950,7 +1950,7 @@ async function stopUnixProcessesOnPorts(ports) {
1950
1950
  if (!stoppedOwners.has(String(record.Pid))) stoppedOwners.set(String(record.Pid), record);
1951
1951
  }
1952
1952
  const summary = [...stoppedOwners.values()].map(record => `${record.Pid}:${record.ProcessName || 'node'}`).join(', ');
1953
- console.log(`Restarting LiveDesk Hub. Stopped stale LiveDesk owner(s) once: ${summary}`);
1953
+ console.log(`Restarting VuvoDesk Hub. Stopped stale VuvoDesk owner(s) once: ${summary}`);
1954
1954
  }
1955
1955
  assertPortCleanupReady(finalRecords, portStates);
1956
1956
  }
@@ -1993,7 +1993,7 @@ async function stopStaleClientAgents() {
1993
1993
  );
1994
1994
  if (!result.ok && !result.stdout) {
1995
1995
  throw new Error(
1996
- `LiveDesk Client lifecycle audit could not enumerate Windows Agent processes: `
1996
+ `VuvoDesk Client lifecycle audit could not enumerate Windows Agent processes: `
1997
1997
  + `${result.stderr || result.error?.message || 'CIM query failed'}`
1998
1998
  );
1999
1999
  }
@@ -2002,7 +2002,7 @@ async function stopStaleClientAgents() {
2002
2002
 
2003
2003
  // One complete ps snapshot avoids treating pgrep execution errors as
2004
2004
  // "nothing is running". The strict identity classifier below decides
2005
- // whether each textual candidate is really a packaged LiveDesk process.
2005
+ // whether each textual candidate is really a packaged VuvoDesk process.
2006
2006
  const result = await runQuiet(
2007
2007
  'ps',
2008
2008
  ['-axo', 'pid=,args='],
@@ -2010,7 +2010,7 @@ async function stopStaleClientAgents() {
2010
2010
  );
2011
2011
  if (!result.ok && !result.stdout) {
2012
2012
  throw new Error(
2013
- `LiveDesk Client lifecycle audit could not enumerate Unix processes: `
2013
+ `VuvoDesk Client lifecycle audit could not enumerate Unix processes: `
2014
2014
  + `${result.stderr || result.error?.message || 'ps failed'}`
2015
2015
  );
2016
2016
  }
@@ -2039,7 +2039,7 @@ async function stopStaleClientAgents() {
2039
2039
  if (!details) {
2040
2040
  if (isPidAlive(pid)) {
2041
2041
  throw new Error(
2042
- `LiveDesk Client lifecycle audit could not establish the identity of candidate pid=${pid}; `
2042
+ `VuvoDesk Client lifecycle audit could not establish the identity of candidate pid=${pid}; `
2043
2043
  + 'startup was preserved instead of signaling an unknown process.'
2044
2044
  );
2045
2045
  }
@@ -2051,7 +2051,7 @@ async function stopStaleClientAgents() {
2051
2051
  const instanceMarker = processInstanceMarker(details);
2052
2052
  if (!instanceMarker) {
2053
2053
  throw new Error(
2054
- `LiveDesk Client lifecycle audit could not establish a start marker for verified ${type} pid=${pid}.`
2054
+ `VuvoDesk Client lifecycle audit could not establish a start marker for verified ${type} pid=${pid}.`
2055
2055
  );
2056
2056
  }
2057
2057
  found.push({
@@ -2189,7 +2189,7 @@ async function stopStaleClientAgents() {
2189
2189
  const remainingProcesses = await findStaleProcesses();
2190
2190
  if (remainingProcesses.length > 0) {
2191
2191
  throw new Error(
2192
- 'LiveDesk Client startup was stopped because new stale capture processes appeared during cleanup: '
2192
+ 'VuvoDesk Client startup was stopped because new stale capture processes appeared during cleanup: '
2193
2193
  + remainingProcesses.map(record => `${record.type} pid=${record.pid}`).join('; ')
2194
2194
  );
2195
2195
  }
@@ -2197,14 +2197,14 @@ async function stopStaleClientAgents() {
2197
2197
  const staleProcesses = [...stoppedProcesses.values()];
2198
2198
  if (staleProcesses.length === 0) {
2199
2199
  if (process.env.LIVEDESK_DEBUG === '1') {
2200
- console.log('[LiveDesk] Client lifecycle audit: verified stale agents=0 capture-helpers=0.');
2200
+ console.log('[VuvoDesk] Client lifecycle audit: verified stale agents=0 capture-helpers=0.');
2201
2201
  }
2202
2202
  return;
2203
2203
  }
2204
2204
  const agentPids = staleProcesses.filter(item => item.type === 'agent').map(item => item.pid);
2205
2205
  const helperPids = staleProcesses.filter(item => item.type === 'capture-helper').map(item => item.pid);
2206
2206
  console.log(
2207
- `[LiveDesk] Client lifecycle audit: verified stale agents=${agentPids.length} `
2207
+ `[VuvoDesk] Client lifecycle audit: verified stale agents=${agentPids.length} `
2208
2208
  + `capture-helpers=${helperPids.length}; confirmed stopped pids=${staleProcesses.map(item => item.pid).join(', ')}.`
2209
2209
  );
2210
2210
  }
@@ -2320,7 +2320,7 @@ function buildHubRestartBootstrapScript() {
2320
2320
  'const captureExactWindowsTrees = (identities, snapshot) => { const currentByPid = new Map(snapshot.map(item => [item.pid, item])); const childrenByParent = new Map(); for (const item of snapshot) { if (!childrenByParent.has(item.parentPid)) childrenByParent.set(item.parentPid, []); childrenByParent.get(item.parentPid).push(item); } const tracked = new Map(); for (const root of identities) { const currentRoot = currentByPid.get(Number(root?.pid || 0)); if (!sameWindowsIdentity(currentRoot, root)) continue; const queue = [{ record: currentRoot, depth: 0 }]; const seen = new Set(); while (queue.length > 0) { const current = queue.shift(); if (seen.has(current.record.pid)) continue; seen.add(current.record.pid); const key = `${current.record.pid}:${current.record.startOrder}`; const previous = tracked.get(key); if (!previous || current.depth > previous.depth) tracked.set(key, { ...current.record, depth: current.depth }); for (const child of childrenByParent.get(current.record.pid) || []) { try { if (BigInt(child.startOrder) < BigInt(current.record.startOrder)) continue; } catch { continue; } queue.push({ record: child, depth: current.depth + 1 }); } } } return [...tracked.values()].sort((left, right) => Number(right.depth || 0) - Number(left.depth || 0)); };',
2321
2321
  'const stopExactWindowsRecords = async records => { if (!Array.isArray(records) || records.length === 0) return; const encoded = Buffer.from(JSON.stringify(records.map(record => ({ pid: record.pid, startOrder: record.startOrder }))), "utf8").toString("base64"); const script = `$ErrorActionPreference = "Stop"; $targetsJson = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("${encoded}")); $targets = ConvertFrom-Json -InputObject $targetsJson; $failures = [System.Collections.Generic.List[string]]::new(); foreach ($item in $targets) { $targetPid = [int]$item.pid; $expectedStartTicks = [string]$item.startOrder; try { $target = Get-CimInstance Win32_Process -Filter "ProcessId = $targetPid" -Property ProcessId,CreationDate -ErrorAction SilentlyContinue | Select-Object -First 1; if (-not $target) { continue }; $targetStartTicks = if ($target.CreationDate) { [string]$target.CreationDate.ToUniversalTime().Ticks } else { "" }; if ($targetStartTicks -ne $expectedStartTicks) { continue }; Stop-Process -Id $targetPid -Force -ErrorAction Stop } catch { $failures.Add("pid=$targetPid $($_.Exception.Message)") } }; if ($failures.Count -gt 0) { [Console]::Error.WriteLine(($failures -join "; ")); exit 1 }`; await runWindowsPowerShell(script); };',
2322
2322
  'const terminateExactWindowsOwnedTrees = async (identities, { skipStop = false } = {}) => { const roots = (Array.isArray(identities) ? identities : []).filter(identity => Number(identity?.pid || 0) > 1 && /^\\d+$/.test(String(identity?.startOrder || ""))); if (roots.length === 0) throw new Error("No immutable Windows replacement identity is available"); const snapshot = await queryWindowsProcessTable(); const targets = captureExactWindowsTrees(roots, snapshot); if (!skipStop) await stopExactWindowsRecords(targets); const finalSnapshot = await queryWindowsProcessTable(); const currentByPid = new Map(finalSnapshot.map(item => [item.pid, item])); const remaining = targets.filter(target => sameWindowsIdentity(currentByPid.get(target.pid), target)); if (remaining.length > 0) throw new Error(`${skipStop ? "simulated exact stop no-op; " : ""}exact pid(s) still alive: ${remaining.map(item => item.pid).join(", ")}`); };',
2323
- 'const waitForExit = async (pid, timeoutMs) => { const deadline = Date.now() + timeoutMs; while (pid > 1 && Date.now() < deadline) { if (!isAlive(pid)) return; await sleep(250); } if (pid > 1 && isAlive(pid)) throw new Error(`Previous LiveDesk Hub launcher pid=${pid} did not exit within ${timeoutMs}ms.`); };',
2323
+ 'const waitForExit = async (pid, timeoutMs) => { const deadline = Date.now() + timeoutMs; while (pid > 1 && Date.now() < deadline) { if (!isAlive(pid)) return; await sleep(250); } if (pid > 1 && isAlive(pid)) throw new Error(`Previous VuvoDesk Hub launcher pid=${pid} did not exit within ${timeoutMs}ms.`); };',
2324
2324
  'const decodeArgs = name => JSON.parse(Buffer.from(process.env[name] || "", "base64").toString("utf8"));',
2325
2325
  'const primary = { command: process.env.LIVEDESK_RESTART_COMMAND || "", args: decodeArgs("LIVEDESK_RESTART_ARGS_BASE64") };',
2326
2326
  'const fallback = { command: process.env.LIVEDESK_RESTART_FALLBACK_COMMAND || "", args: decodeArgs("LIVEDESK_RESTART_FALLBACK_ARGS_BASE64") };',
@@ -2336,7 +2336,7 @@ function buildHubRestartBootstrapScript() {
2336
2336
  'const healthTimeoutMs = terminationFailureOperationId === operationId ? numberFromEnv("LIVEDESK_TEST_HUB_RESTART_TERMINATION_HEALTH_TIMEOUT_MS", 1000, 250) : configuredHealthTimeoutMs;',
2337
2337
  'const pollMs = numberFromEnv("LIVEDESK_RESTART_HEALTH_POLL_MS", 250, 50);',
2338
2338
  'const stabilityMs = numberFromEnv("LIVEDESK_RESTART_STABILITY_MS", 5000, 5000);',
2339
- 'const prepareNeutralCwd = () => { if (!neutralCwd) throw new Error("LiveDesk Hub update neutral working directory is unavailable"); mkdirSync(neutralCwd, { recursive: true }); const unexpectedEntry = readdirSync(neutralCwd)[0]; if (unexpectedEntry) { const shadow = join(neutralCwd, unexpectedEntry); throw new Error(`LiveDesk Hub update neutral working directory is shadowed by ${shadow}: ${neutralCwd}`); } };',
2339
+ 'const prepareNeutralCwd = () => { if (!neutralCwd) throw new Error("VuvoDesk Hub update neutral working directory is unavailable"); mkdirSync(neutralCwd, { recursive: true }); const unexpectedEntry = readdirSync(neutralCwd)[0]; if (unexpectedEntry) { const shadow = join(neutralCwd, unexpectedEntry); throw new Error(`VuvoDesk Hub update neutral working directory is shadowed by ${shadow}: ${neutralCwd}`); } };',
2340
2340
  'const buildLaunchEnv = () => { const env = { ...process.env }; const isolated = new Set(["init_cwd", "npm_config_local_prefix", "npm_config_workspace", "npm_config_workspaces", "npm_config_include_workspace_root", "npm_package_json", "npm_lifecycle_event", "npm_lifecycle_script"]); for (const key of Object.keys(env)) if (isolated.has(key.toLowerCase())) delete env[key]; env.INIT_CWD = neutralCwd; env.npm_config_local_prefix = neutralCwd; env.npm_config_workspaces = "false"; env.npm_config_include_workspace_root = "false"; return env; };',
2341
2341
  'const requestJson = async path => { const response = await fetch(new URL(path, healthBaseUrl), { cache: "no-store", signal: AbortSignal.timeout(Math.min(2000, healthTimeoutMs)) }); if (!response.ok) throw new Error(`HTTP ${response.status} from ${path}`); return response.json(); };',
2342
2342
  'const probeRemotePort = () => new Promise((resolve, reject) => { const socket = net.createConnection({ host: remoteHost, port: remotePort }); const timer = setTimeout(() => socket.destroy(new Error("TCP probe timed out")), Math.min(1500, healthTimeoutMs)); timer.unref?.(); socket.once("connect", () => { clearTimeout(timer); socket.destroy(); resolve(); }); socket.once("error", error => { clearTimeout(timer); reject(error); }); });',
@@ -2447,7 +2447,7 @@ function buildHubRestartBootstrapScript() {
2447
2447
  ' await terminateTree(child, lastRuntimePid);',
2448
2448
  ' throw new Error(`${label} attempt=${attempt} did not remain healthy for ${stabilityMs}ms: ${lastError?.message || (exit ? `command exited code=${exit.code ?? "none"} signal=${exit.signal || "none"}` : "health deadline expired")}`);',
2449
2449
  '};',
2450
- '(async () => { const targetErrors = []; const fallbackErrors = []; if (exitBeforeHandshakeOperationId === operationId) { log("stage=test-exit-before-handshake"); process.exitCode = 86; return; } if (delayHandshakeOperationId === operationId) { const claimDelayMs = numberFromEnv("LIVEDESK_TEST_HUB_RESTART_HANDSHAKE_DELAY_MS", 2000, 1); log(`stage=test-delay-before-handshake delayMs=${claimDelayMs}`); await sleep(claimDelayMs); } writeResult("waiting-for-old-launcher", { outcome: "in-progress" }); log(`stage=waiting-for-old-launcher pid=${waitPid} supervisorPid=${process.pid}`); if (exitAfterHandshakeOperationId === operationId) { log("stage=test-exit-after-handshake"); process.exitCode = 87; return; } await waitForExit(waitPid, 60000); writeResult("old-launcher-exited", { outcome: "in-progress" }); log("stage=old-launcher-exited"); for (let attempt = 1; attempt <= attemptLimit; attempt += 1) { writeResult("target-attempt", { outcome: "in-progress", attempt }); try { const status = await launchAndVerify(primary, "target", expectedVersion, attempt); writeResult("updated", { outcome: "updated", attempt, runtimePid: status.runtimePid, launcherPid: status.launcherPid, appVersion: status.appVersion, completedAt: new Date().toISOString(), error: undefined }); log("stage=completed"); return; } catch (error) { if (["LIVEDESK_HUB_UPDATE_SUPERSEDED", "LIVEDESK_HUB_RESTART_TERMINATION_FAILED"].includes(error?.code)) throw error; targetErrors.push(error.message); writeResult("target-failed", { outcome: "in-progress", attempt, error: error.message }); log(`target attempt=${attempt} stage=failed error=${error.message}`); } } log(`stage=fallback-start target=${fallbackVersion || "current"}`); for (let attempt = 1; attempt <= 2; attempt += 1) { writeResult("fallback-attempt", { outcome: "in-progress", attempt, error: targetErrors.join(" | ") }); try { const status = await launchAndVerify(fallback, "fallback", fallbackVersion, attempt); writeResult("restored", { outcome: "restored", attempt, runtimePid: status.runtimePid, launcherPid: status.launcherPid, appVersion: status.appVersion, completedAt: new Date().toISOString(), error: `Target Hub ${expectedVersion} failed verification: ${targetErrors.join(" | ")}` }); log("stage=completed-with-fallback"); return; } catch (error) { if (["LIVEDESK_HUB_UPDATE_SUPERSEDED", "LIVEDESK_HUB_RESTART_TERMINATION_FAILED"].includes(error?.code)) throw error; fallbackErrors.push(error.message); writeResult("fallback-failed", { outcome: "in-progress", attempt, error: [...targetErrors, ...fallbackErrors].join(" | ") }); log(`fallback attempt=${attempt} stage=failed error=${error.message}`); } } throw new Error(`No verified LiveDesk Hub replacement could be started. Target failures: ${targetErrors.join(" | ") || "none"}. Fallback failures: ${fallbackErrors.join(" | ") || "none"}. Inspect ${logPath || "the Hub restart log"} and start the frozen local LiveDesk Hub manually.`); })().catch(error => { if (error?.code === "LIVEDESK_HUB_UPDATE_SUPERSEDED") { log("stage=bootstrap-superseded error=" + error.message); return; } try { writeResult("failed", { outcome: "failed", completedAt: new Date().toISOString(), error: error.message }); } catch (writeError) { log("stage=result-write-failed resultStage=failed error=" + writeError.message); } log("stage=bootstrap-failed error=" + error.message); process.exitCode = 1; });',
2450
+ '(async () => { const targetErrors = []; const fallbackErrors = []; if (exitBeforeHandshakeOperationId === operationId) { log("stage=test-exit-before-handshake"); process.exitCode = 86; return; } if (delayHandshakeOperationId === operationId) { const claimDelayMs = numberFromEnv("LIVEDESK_TEST_HUB_RESTART_HANDSHAKE_DELAY_MS", 2000, 1); log(`stage=test-delay-before-handshake delayMs=${claimDelayMs}`); await sleep(claimDelayMs); } writeResult("waiting-for-old-launcher", { outcome: "in-progress" }); log(`stage=waiting-for-old-launcher pid=${waitPid} supervisorPid=${process.pid}`); if (exitAfterHandshakeOperationId === operationId) { log("stage=test-exit-after-handshake"); process.exitCode = 87; return; } await waitForExit(waitPid, 60000); writeResult("old-launcher-exited", { outcome: "in-progress" }); log("stage=old-launcher-exited"); for (let attempt = 1; attempt <= attemptLimit; attempt += 1) { writeResult("target-attempt", { outcome: "in-progress", attempt }); try { const status = await launchAndVerify(primary, "target", expectedVersion, attempt); writeResult("updated", { outcome: "updated", attempt, runtimePid: status.runtimePid, launcherPid: status.launcherPid, appVersion: status.appVersion, completedAt: new Date().toISOString(), error: undefined }); log("stage=completed"); return; } catch (error) { if (["LIVEDESK_HUB_UPDATE_SUPERSEDED", "LIVEDESK_HUB_RESTART_TERMINATION_FAILED"].includes(error?.code)) throw error; targetErrors.push(error.message); writeResult("target-failed", { outcome: "in-progress", attempt, error: error.message }); log(`target attempt=${attempt} stage=failed error=${error.message}`); } } log(`stage=fallback-start target=${fallbackVersion || "current"}`); for (let attempt = 1; attempt <= 2; attempt += 1) { writeResult("fallback-attempt", { outcome: "in-progress", attempt, error: targetErrors.join(" | ") }); try { const status = await launchAndVerify(fallback, "fallback", fallbackVersion, attempt); writeResult("restored", { outcome: "restored", attempt, runtimePid: status.runtimePid, launcherPid: status.launcherPid, appVersion: status.appVersion, completedAt: new Date().toISOString(), error: `Target Hub ${expectedVersion} failed verification: ${targetErrors.join(" | ")}` }); log("stage=completed-with-fallback"); return; } catch (error) { if (["LIVEDESK_HUB_UPDATE_SUPERSEDED", "LIVEDESK_HUB_RESTART_TERMINATION_FAILED"].includes(error?.code)) throw error; fallbackErrors.push(error.message); writeResult("fallback-failed", { outcome: "in-progress", attempt, error: [...targetErrors, ...fallbackErrors].join(" | ") }); log(`fallback attempt=${attempt} stage=failed error=${error.message}`); } } throw new Error(`No verified VuvoDesk Hub replacement could be started. Target failures: ${targetErrors.join(" | ") || "none"}. Fallback failures: ${fallbackErrors.join(" | ") || "none"}. Inspect ${logPath || "the Hub restart log"} and start the frozen local VuvoDesk Hub manually.`); })().catch(error => { if (error?.code === "LIVEDESK_HUB_UPDATE_SUPERSEDED") { log("stage=bootstrap-superseded error=" + error.message); return; } try { writeResult("failed", { outcome: "failed", completedAt: new Date().toISOString(), error: error.message }); } catch (writeError) { log("stage=result-write-failed resultStage=failed error=" + writeError.message); } log("stage=bootstrap-failed error=" + error.message); process.exitCode = 1; });',
2451
2451
  ''
2452
2452
  ].join('\n');
2453
2453
  }
@@ -2524,7 +2524,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2524
2524
  hubLogStream.on('error', () => {
2525
2525
  hubLogStream = null;
2526
2526
  });
2527
- hubLogStream.write(`\n--- LiveDesk Hub ${readVersion()} pid=${process.pid} started ${new Date().toISOString()} debug=${debugConsole} ---\n`);
2527
+ hubLogStream.write(`\n--- VuvoDesk Hub ${readVersion()} pid=${process.pid} started ${new Date().toISOString()} debug=${debugConsole} ---\n`);
2528
2528
  } catch {
2529
2529
  // Console output remains available when the optional diagnostic log cannot be written.
2530
2530
  }
@@ -2570,7 +2570,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2570
2570
  });
2571
2571
  } catch (error) {
2572
2572
  reportLauncherUpdate(
2573
- `[LiveDesk Hub] Self Agent is unavailable: ${error?.message || error}. Remote Clients remain available.`,
2573
+ `[VuvoDesk Hub] Self Agent is unavailable: ${error?.message || error}. Remote Clients remain available.`,
2574
2574
  true
2575
2575
  );
2576
2576
  }
@@ -2618,7 +2618,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2618
2618
  return;
2619
2619
  }
2620
2620
  reportLauncherUpdate(
2621
- `[LiveDesk Hub] Launcher received ${signal}; requesting graceful Hub shutdown for pid=${child.pid || 'unknown'}.`
2621
+ `[VuvoDesk Hub] Launcher received ${signal}; requesting graceful Hub shutdown for pid=${child.pid || 'unknown'}.`
2622
2622
  );
2623
2623
  void (async () => {
2624
2624
  const gracefulDeadline = Date.now() + 2_000;
@@ -2633,7 +2633,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2633
2633
  });
2634
2634
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
2635
2635
  reportLauncherUpdate(
2636
- `[LiveDesk Hub] Owned Hub pid=${child.pid || 'unknown'} acknowledged graceful shutdown.`
2636
+ `[VuvoDesk Hub] Owned Hub pid=${child.pid || 'unknown'} acknowledged graceful shutdown.`
2637
2637
  );
2638
2638
  return;
2639
2639
  } catch (error) {
@@ -2643,7 +2643,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2643
2643
  }
2644
2644
  if (child.exitCode !== null || child.signalCode) return;
2645
2645
  reportLauncherUpdate(
2646
- `[LiveDesk Hub] Graceful shutdown API remained unavailable for pid=${child.pid || 'unknown'}`
2646
+ `[VuvoDesk Hub] Graceful shutdown API remained unavailable for pid=${child.pid || 'unknown'}`
2647
2647
  + `${lastError?.message ? ` (${lastError.message})` : ''}; exact child fallback remains armed.`,
2648
2648
  true
2649
2649
  );
@@ -2654,7 +2654,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2654
2654
  launcherShutdownHardStopTimer = setTimeout(() => {
2655
2655
  if (child.exitCode !== null || child.signalCode) return;
2656
2656
  reportLauncherUpdate(
2657
- `[LiveDesk Hub] Owned Hub pid=${child.pid || 'unknown'} exceeded graceful shutdown; `
2657
+ `[VuvoDesk Hub] Owned Hub pid=${child.pid || 'unknown'} exceeded graceful shutdown; `
2658
2658
  + 'force-stopping that exact child root.',
2659
2659
  true
2660
2660
  );
@@ -2671,7 +2671,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2671
2671
 
2672
2672
  const restartWithLatest = async request => {
2673
2673
  if (!updateHost?.available) {
2674
- throw new Error('The independent LiveDesk Update Host is unavailable. The unchanged Hub remains running.');
2674
+ throw new Error('The independent VuvoDesk Update Host is unavailable. The unchanged Hub remains running.');
2675
2675
  }
2676
2676
  const requestedVersion = normalizeExactUpdateVersion(request?.latestVersion);
2677
2677
  if (!requestedVersion) {
@@ -2726,7 +2726,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2726
2726
  updatedAt: restartStartedAt
2727
2727
  });
2728
2728
  } catch (error) {
2729
- reportLauncherUpdate(`[LiveDesk Hub] Could not persist the restart supervisor state: ${error instanceof Error ? error.message : String(error)}.`, true);
2729
+ reportLauncherUpdate(`[VuvoDesk Hub] Could not persist the restart supervisor state: ${error instanceof Error ? error.message : String(error)}.`, true);
2730
2730
  throw error;
2731
2731
  }
2732
2732
  const workerEnvironment = buildUpdateHostWorkerEnvironment(process.env, {
@@ -2767,10 +2767,10 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2767
2767
  }, { timeoutMs: handshakeTimeoutMs });
2768
2768
  hostJob = submitted?.job || null;
2769
2769
  if (!hostJob || Number(hostJob.workerPid || 0) <= 1) {
2770
- throw new Error('LiveDesk Update Host accepted the request without a worker identity.');
2770
+ throw new Error('VuvoDesk Update Host accepted the request without a worker identity.');
2771
2771
  }
2772
2772
  } catch (error) {
2773
- throw new Error(`LiveDesk Update Host rejected the Hub replacement: ${error instanceof Error ? error.message : String(error)}`);
2773
+ throw new Error(`VuvoDesk Update Host rejected the Hub replacement: ${error instanceof Error ? error.message : String(error)}`);
2774
2774
  }
2775
2775
  try {
2776
2776
  await waitForHubRestartUpdateHostClaim(updateHost, hostJobId, {
@@ -2801,7 +2801,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2801
2801
  throw error;
2802
2802
  }
2803
2803
  reportLauncherUpdate(
2804
- `[LiveDesk Hub] Update handoff claimed target=${requestedVersion} `
2804
+ `[VuvoDesk Hub] Update handoff claimed target=${requestedVersion} `
2805
2805
  + `updateHostPid=${updateHost.host?.pid || 0} workerPid=${hostJob.workerPid || 0} operation=${operationId}. `
2806
2806
  + `The current launcher will now exit. Restart diagnostics: ${hubLogPath}`
2807
2807
  );
@@ -2823,14 +2823,14 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2823
2823
  const requestPid = Number(request?.pid || 0);
2824
2824
  const activeChildPid = Number(activeChild?.pid || 0);
2825
2825
  if (!Number.isInteger(requestPid) || requestPid <= 1) {
2826
- reportLauncherUpdate('[LiveDesk Hub] Ignored an invalid update restart request without a Hub PID.', true);
2826
+ reportLauncherUpdate('[VuvoDesk Hub] Ignored an invalid update restart request without a Hub PID.', true);
2827
2827
  } else if (requestPid !== activeChildPid) {
2828
- reportLauncherUpdate(`[LiveDesk Hub] Ignored stale update restart request for pid ${requestPid}; active Hub pid is ${activeChildPid || 'unavailable'}.`, true);
2828
+ reportLauncherUpdate(`[VuvoDesk Hub] Ignored stale update restart request for pid ${requestPid}; active Hub pid is ${activeChildPid || 'unavailable'}.`, true);
2829
2829
  } else {
2830
2830
  const operationId = String(request?.operationId || `hub-update-${Date.now()}`).trim();
2831
2831
  const requestedVersion = normalizeExactUpdateVersion(request?.latestVersion);
2832
2832
  const failPreflight = message => {
2833
- reportLauncherUpdate(`[LiveDesk Hub] ${message}. The current Hub remains running.`, true);
2833
+ reportLauncherUpdate(`[VuvoDesk Hub] ${message}. The current Hub remains running.`, true);
2834
2834
  try {
2835
2835
  const now = new Date().toISOString();
2836
2836
  writeJsonAtomic(hubUpdateResultPath, {
@@ -2847,7 +2847,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2847
2847
  error: message
2848
2848
  });
2849
2849
  } catch (persistError) {
2850
- reportLauncherUpdate(`[LiveDesk Hub] Could not persist the update preflight failure: ${persistError instanceof Error ? persistError.message : String(persistError)}.`, true);
2850
+ reportLauncherUpdate(`[VuvoDesk Hub] Could not persist the update preflight failure: ${persistError instanceof Error ? persistError.message : String(persistError)}.`, true);
2851
2851
  }
2852
2852
  };
2853
2853
  if (!requestedVersion) {
@@ -2870,7 +2870,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2870
2870
  _neutralCwd: neutralCwd,
2871
2871
  _originalCwd: UPDATE_ORIGINAL_CWD
2872
2872
  };
2873
- reportLauncherUpdate(`[LiveDesk Hub] Restart requested for update ${request.operationId || 'unknown'} target=${requestedVersion}.`);
2873
+ reportLauncherUpdate(`[VuvoDesk Hub] Restart requested for update ${request.operationId || 'unknown'} target=${requestedVersion}.`);
2874
2874
  void stopHubSelfAgent('hub-update');
2875
2875
  const updateChild = activeChild;
2876
2876
  let shutdownFallbackStarted = false;
@@ -2878,18 +2878,18 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2878
2878
  if (!updateChild || updateChild.exitCode !== null || updateChild.signalCode) return;
2879
2879
  if (shutdownFallbackStarted) return;
2880
2880
  shutdownFallbackStarted = true;
2881
- reportLauncherUpdate(`[LiveDesk Hub] Update shutdown fallback: ${reason}; terminating Hub pid=${requestPid}.`, true);
2881
+ reportLauncherUpdate(`[VuvoDesk Hub] Update shutdown fallback: ${reason}; terminating Hub pid=${requestPid}.`, true);
2882
2882
  try { updateChild.kill('SIGTERM'); } catch { /* child already exited */ }
2883
2883
  updateHardStopTimer = setTimeout(() => {
2884
2884
  if (!updateChild || updateChild.exitCode !== null || updateChild.signalCode) return;
2885
- reportLauncherUpdate(`[LiveDesk Hub] Update shutdown hard fallback: Hub pid=${requestPid} ignored graceful termination; force-stopping the owned Hub process.`, true);
2885
+ reportLauncherUpdate(`[VuvoDesk Hub] Update shutdown hard fallback: Hub pid=${requestPid} ignored graceful termination; force-stopping the owned Hub process.`, true);
2886
2886
  if (process.platform === 'win32') {
2887
2887
  // updateChild is the exact ChildProcess instance spawned by this
2888
2888
  // launcher. Stop only that owned Hub root; never let taskkill /T
2889
2889
  // follow unverified PPID descendants.
2890
2890
  try { updateChild.kill('SIGKILL'); } catch (error) {
2891
2891
  if (updateChild.exitCode === null && !updateChild.signalCode) {
2892
- reportLauncherUpdate(`[LiveDesk Hub] hard-stop fallback failed for pid=${requestPid}: ${error.message}`, true);
2892
+ reportLauncherUpdate(`[VuvoDesk Hub] hard-stop fallback failed for pid=${requestPid}: ${error.message}`, true);
2893
2893
  }
2894
2894
  }
2895
2895
  } else {
@@ -2905,7 +2905,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2905
2905
  signal: AbortSignal.timeout(2_500)
2906
2906
  }).then(response => {
2907
2907
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
2908
- reportLauncherUpdate(`[LiveDesk Hub] Update shutdown acknowledged by Hub pid=${requestPid}.`);
2908
+ reportLauncherUpdate(`[VuvoDesk Hub] Update shutdown acknowledged by Hub pid=${requestPid}.`);
2909
2909
  }).catch(error => forceStop(`shutdown API failed (${error?.message || error})`));
2910
2910
  }
2911
2911
  } catch {
@@ -2933,7 +2933,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2933
2933
  hubSelfAgent?.start();
2934
2934
  }).catch(error => {
2935
2935
  reportLauncherUpdate(
2936
- `[LiveDesk Hub] Self Agent startup wait failed: ${error?.message || error}.`,
2936
+ `[VuvoDesk Hub] Self Agent startup wait failed: ${error?.message || error}.`,
2937
2937
  true
2938
2938
  );
2939
2939
  });
@@ -2955,7 +2955,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2955
2955
  });
2956
2956
 
2957
2957
  child.once('error', error => {
2958
- console.error(`Failed to start LiveDesk Hub: ${error.message}`);
2958
+ console.error(`Failed to start VuvoDesk Hub: ${error.message}`);
2959
2959
  process.exitCode = 1;
2960
2960
  });
2961
2961
  child.once('exit', (code, signal) => {
@@ -2990,7 +2990,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2990
2990
  }
2991
2991
  void stopHubSelfAgent('hub-update').then(() => restartWithLatest(request)).catch(error => {
2992
2992
  const message = `The Hub restart handoff failed after shutdown: ${error instanceof Error ? error.message : String(error)}`;
2993
- reportLauncherUpdate(`[LiveDesk Hub] ${message}. Restarting the unchanged Hub.`, true);
2993
+ reportLauncherUpdate(`[VuvoDesk Hub] ${message}. Restarting the unchanged Hub.`, true);
2994
2994
  try {
2995
2995
  const now = new Date().toISOString();
2996
2996
  const previous = readJsonFile(hubUpdateResultPath);
@@ -3033,7 +3033,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
3033
3033
  runtimeLock?.updateRole?.('client');
3034
3034
  } catch (error) {
3035
3035
  console.error(
3036
- `[LiveDesk Hub] The shared runtime lock could not transition to Client: ${error?.message || error}. `
3036
+ `[VuvoDesk Hub] The shared runtime lock could not transition to Client: ${error?.message || error}. `
3037
3037
  + 'The launcher will exit so a clean invocation can recover.'
3038
3038
  );
3039
3039
  runtimeShutdownWatcher?.stop();
@@ -3049,15 +3049,15 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
3049
3049
  source: 'supabase',
3050
3050
  isOfflineFallback: false
3051
3051
  }, { stateDir: MANAGER_STATE_DIR });
3052
- console.log('[LiveDesk Hub] Role transition accepted. Starting the Client runtime.');
3052
+ console.log('[VuvoDesk Hub] Role transition accepted. Starting the Client runtime.');
3053
3053
  runtimeShutdownWatcher?.stop();
3054
3054
  removeLauncherSignalHandlers();
3055
3055
  void runClient([], { ...resolvedRole, role: 'client', source: 'supabase', roleTransition: true }, runtimeLock).catch(error => {
3056
- console.error(`Failed to start LiveDesk Client runtime: ${error?.message || error}`);
3056
+ console.error(`Failed to start VuvoDesk Client runtime: ${error?.message || error}`);
3057
3057
  process.exitCode = 1;
3058
3058
  });
3059
3059
  }).catch(error => {
3060
- console.error(`[LiveDesk Hub] Self Agent did not stop for role transition: ${error?.message || error}`);
3060
+ console.error(`[VuvoDesk Hub] Self Agent did not stop for role transition: ${error?.message || error}`);
3061
3061
  process.exit(1);
3062
3062
  });
3063
3063
  return;
@@ -3068,7 +3068,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
3068
3068
  && startupRetryCount < HUB_STARTUP_RETRY_LIMIT
3069
3069
  && isPortConflictOutput(startupOutput)) {
3070
3070
  startupRetryCount += 1;
3071
- console.warn('[LiveDesk Hub] Startup port conflict detected. Cleaning Hub ports and retrying once.');
3071
+ console.warn('[VuvoDesk Hub] Startup port conflict detected. Cleaning Hub ports and retrying once.');
3072
3072
  void stopProcessesOnPorts([httpPort, remotePort])
3073
3073
  .then(() => startHubProcess())
3074
3074
  .catch(error => {
@@ -3092,7 +3092,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
3092
3092
 
3093
3093
  runtimeShutdownWatcher = startOwnedRuntimeShutdownWatcher(runtimeOwner, async request => {
3094
3094
  reportLauncherUpdate(
3095
- `[LiveDesk Hub] Cooperative replacement request accepted `
3095
+ `[VuvoDesk Hub] Cooperative replacement request accepted `
3096
3096
  + `request=${request.requestId} reason=${request.reason}.`
3097
3097
  );
3098
3098
  requestLauncherShutdown('COOPERATIVE_REPLACEMENT');
@@ -3111,15 +3111,15 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
3111
3111
  }
3112
3112
  void transferSavedClientSessionToHub(hubProbeBaseUrl, MANAGER_STATE_DIR).then(handoff => {
3113
3113
  if (handoff.ok) {
3114
- reportLauncherUpdate('[LiveDesk Hub] Saved Client sign-in adopted by the Hub.');
3114
+ reportLauncherUpdate('[VuvoDesk Hub] Saved Client sign-in adopted by the Hub.');
3115
3115
  if (!handoff.hostTargetOk) {
3116
- reportLauncherUpdate('[LiveDesk Hub] Sign-in was adopted; host publication will continue through lease renewal.', true);
3116
+ reportLauncherUpdate('[VuvoDesk Hub] Sign-in was adopted; host publication will continue through lease renewal.', true);
3117
3117
  }
3118
3118
  } else if (!handoff.skipped) {
3119
- reportLauncherUpdate(`[LiveDesk Hub] Saved Client sign-in could not be adopted: ${handoff.reason}. Continue sign-in in the Hub page.`, true);
3119
+ reportLauncherUpdate(`[VuvoDesk Hub] Saved Client sign-in could not be adopted: ${handoff.reason}. Continue sign-in in the Hub page.`, true);
3120
3120
  }
3121
3121
  }).catch(error => {
3122
- reportLauncherUpdate(`[LiveDesk Hub] Saved Client sign-in could not be adopted: ${error instanceof Error ? error.message : String(error)}. Continue sign-in in the Hub page.`, true);
3122
+ reportLauncherUpdate(`[VuvoDesk Hub] Saved Client sign-in could not be adopted: ${error instanceof Error ? error.message : String(error)}. Continue sign-in in the Hub page.`, true);
3123
3123
  });
3124
3124
  return true;
3125
3125
  });
@@ -3129,15 +3129,16 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
3129
3129
  if (ok) {
3130
3130
  openBrowser(openUrl);
3131
3131
  } else {
3132
- console.warn(`LiveDesk Hub did not answer at ${openUrl} yet. Open it manually when it is ready.`);
3132
+ console.warn(`VuvoDesk Hub did not answer at ${openUrl} yet. Open it manually when it is ready.`);
3133
3133
  }
3134
3134
  });
3135
3135
  }
3136
3136
  }
3137
3137
 
3138
- async function runClient(args, resolvedRole = null, runtimeLock = null) {
3139
- const runtimeOwner = runtimeLock?.payload || null;
3140
- const internalClientEntry = resolve(packageRoot, 'client', 'bin', 'livedesk-client.js');
3138
+ async function runClient(args, resolvedRole = null, runtimeLock = null) {
3139
+ const runtimeOwner = runtimeLock?.payload || null;
3140
+ const internalClientEntry = resolve(packageRoot, 'client', 'bin', 'livedesk-client.js');
3141
+ const packagedWebDist = resolve(packageRoot, 'web', 'dist');
3141
3142
  if (!existsSync(internalClientEntry)) {
3142
3143
  throw new Error('The published livedesk package is missing its internal Client runtime. Rebuild the package with npm run build.');
3143
3144
  }
@@ -3151,7 +3152,9 @@ async function runClient(args, resolvedRole = null, runtimeLock = null) {
3151
3152
  LIVEDESK_NPM_LAUNCHER_VERSION: readVersion(),
3152
3153
  LIVEDESK_RUNTIME_ROLE: 'client',
3153
3154
  LIVEDESK_UNIFIED_RUNTIME: '1',
3154
- LIVEDESK_WEB_DIST: resolve(packageRoot, 'web', 'dist'),
3155
+ LIVEDESK_WEB_DIST: existsSync(resolve(packagedWebDist, 'index.html'))
3156
+ ? packagedWebDist
3157
+ : String(process.env.LIVEDESK_WEB_DIST || ''),
3155
3158
  LIVEDESK_CLIENT_RUNTIME_PORT: String(process.env.LIVEDESK_CLIENT_RUNTIME_PORT || process.env.LIVEDESK_LOCAL_RUNTIME_PORT || DEFAULT_MANAGER_HTTP_PORT),
3156
3159
  LIVEDESK_UNIFIED_LAUNCHER_ENTRY: String(process.argv[1] || ''),
3157
3160
  LIVEDESK_ROLE_TRANSITION: resolvedRole?.roleTransition === true || process.env.LIVEDESK_ROLE_TRANSITION === '1'
@@ -3177,7 +3180,7 @@ async function runClient(args, resolvedRole = null, runtimeLock = null) {
3177
3180
  }
3178
3181
  const runtimeShutdownWatcher = startOwnedRuntimeShutdownWatcher(runtimeOwner, async request => {
3179
3182
  console.log(
3180
- `[LiveDesk Client] Cooperative replacement request accepted `
3183
+ `[VuvoDesk Client] Cooperative replacement request accepted `
3181
3184
  + `request=${request.requestId} reason=${request.reason}. Draining the owned capture tree.`
3182
3185
  );
3183
3186
  if (typeof clientModule.requestClientRuntimeShutdown !== 'function') {
@@ -3193,7 +3196,7 @@ async function runClient(args, resolvedRole = null, runtimeLock = null) {
3193
3196
  recoverHubClientPort: async port => {
3194
3197
  const normalizedPort = normalizePort(port, 0);
3195
3198
  if (!normalizedPort) {
3196
- throw new Error(`LiveDesk cannot recover an invalid Hub client port: ${port}.`);
3199
+ throw new Error(`VuvoDesk cannot recover an invalid Hub client port: ${port}.`);
3197
3200
  }
3198
3201
  await stopProcessesOnPorts([normalizedPort]);
3199
3202
  }
@@ -3217,7 +3220,7 @@ async function runDesktopRoleBootstrap() {
3217
3220
  onShutdown: () => process.exit(0)
3218
3221
  });
3219
3222
  await bootstrap.start();
3220
- console.log(`[LiveDesk] Role bootstrap is ready at ${bootstrap.url}. Sign in and choose Hub or Client.`);
3223
+ console.log(`[VuvoDesk] Role bootstrap is ready at ${bootstrap.url}. Sign in and choose Hub or Client.`);
3221
3224
  await new Promise(() => undefined);
3222
3225
  }
3223
3226
 
@@ -3253,7 +3256,7 @@ async function main() {
3253
3256
  const commandArgs = args.slice(1).map(value => String(value || '').trim().toLowerCase());
3254
3257
  if (commandArgs.some(value => value === '--help' || value === '-h' || value === 'help')) {
3255
3258
  if (command === 'client') {
3256
- console.warn('[LiveDesk] Legacy client command detected. Use `npx -y --prefer-online livedesk@latest` for automatic role selection.');
3259
+ console.warn('[VuvoDesk] Legacy client command detected. Use `npx -y --prefer-online livedesk@latest` for automatic role selection.');
3257
3260
  printClientHelp();
3258
3261
  } else {
3259
3262
  printHelp();
@@ -3262,7 +3265,7 @@ async function main() {
3262
3265
  }
3263
3266
  if (commandArgs.some(value => value === '--version' || value === '-v' || value === 'version')) {
3264
3267
  if (command === 'client') {
3265
- console.warn('[LiveDesk] Legacy client command detected. Use `npx -y --prefer-online livedesk@latest` for automatic role selection.');
3268
+ console.warn('[VuvoDesk] Legacy client command detected. Use `npx -y --prefer-online livedesk@latest` for automatic role selection.');
3266
3269
  }
3267
3270
  console.log(readVersion());
3268
3271
  return;
@@ -3285,7 +3288,7 @@ async function main() {
3285
3288
  writeRoleCache({ ...resolvedRole, source: 'local-cache', isOfflineFallback: false }, roleStateOptions);
3286
3289
  runtimeArgs = args.slice(1);
3287
3290
  if (command === 'client') {
3288
- console.warn('[LiveDesk] Legacy client command detected. Use `npx -y --prefer-online livedesk@latest` for automatic role selection.');
3291
+ console.warn('[VuvoDesk] Legacy client command detected. Use `npx -y --prefer-online livedesk@latest` for automatic role selection.');
3289
3292
  }
3290
3293
  } else {
3291
3294
  const forceDesktopBootstrap = process.env.LIVEDESK_DESKTOP_HOST === '1'
@@ -3298,7 +3301,7 @@ async function main() {
3298
3301
  });
3299
3302
  if (!resolvedRole.role) {
3300
3303
  if (resolvedRole.disabled) {
3301
- throw new Error(`LiveDesk device ${resolvedRole.deviceId} is disabled for this account.`);
3304
+ throw new Error(`VuvoDesk device ${resolvedRole.deviceId} is disabled for this account.`);
3302
3305
  }
3303
3306
  if (forceDesktopBootstrap) {
3304
3307
  await runDesktopRoleBootstrap();
@@ -3319,7 +3322,7 @@ async function main() {
3319
3322
  }
3320
3323
 
3321
3324
  if (topLevel.noSingleInstance || process.env.LIVEDESK_DISABLE_SINGLE_INSTANCE === '1') {
3322
- console.warn('[LiveDesk] Single-instance lock disabled for this run.');
3325
+ console.warn('[VuvoDesk] Single-instance lock disabled for this run.');
3323
3326
  }
3324
3327
  const launcherProcessDetails = await getProcessDetails(process.pid);
3325
3328
  const launcherInstanceMarker = processInstanceMarker(launcherProcessDetails);
@@ -3327,7 +3330,7 @@ async function main() {
3327
3330
  const reportExistingRuntime = existing => {
3328
3331
  const port = DEFAULT_MANAGER_HTTP_PORT;
3329
3332
  openBrowser(`http://127.0.0.1:${port}`);
3330
- console.log(`[LiveDesk] An existing ${existing.role || 'runtime'} is already running (pid ${existing.pid}). Opened its local page. Hub diagnostics: ${join(MANAGER_STATE_DIR, 'hub.log')}`);
3333
+ console.log(`[VuvoDesk] An existing ${existing.role || 'runtime'} is already running (pid ${existing.pid}). Opened its local page. Hub diagnostics: ${join(MANAGER_STATE_DIR, 'hub.log')}`);
3331
3334
  };
3332
3335
  let lock = topLevel.noSingleInstance || process.env.LIVEDESK_DISABLE_SINGLE_INSTANCE === '1'
3333
3336
  ? { acquired: true, release: () => undefined }
@@ -3382,12 +3385,12 @@ async function main() {
3382
3385
  Object.assign(process.env, updateHostEnvironment(updateHost));
3383
3386
  if (updateHost.available) {
3384
3387
  console.log(
3385
- `[LiveDesk] Independent Update Host ready pid=${updateHost.host?.pid || 'unknown'} `
3388
+ `[VuvoDesk] Independent Update Host ready pid=${updateHost.host?.pid || 'unknown'} `
3386
3389
  + `source=${updateHost.host?.sourceVersion || readVersion()}.`
3387
3390
  );
3388
3391
  } else if (!updateHost.disabled) {
3389
3392
  console.warn(
3390
- `[LiveDesk] Independent Update Host is unavailable; updates are disabled for this run: `
3393
+ `[VuvoDesk] Independent Update Host is unavailable; updates are disabled for this run: `
3391
3394
  + `${updateHost.error || 'unknown error'}`
3392
3395
  );
3393
3396
  }
@@ -3413,7 +3416,7 @@ async function main() {
3413
3416
  && process.env.LIVEDESK_DEBUG === '1'
3414
3417
  && Number.isFinite(testHoldAfterDrainMs)
3415
3418
  && testHoldAfterDrainMs > 0) {
3416
- console.log('[LiveDesk test] Holding after reclaimed manifest drain before Agent startup.');
3419
+ console.log('[VuvoDesk test] Holding after reclaimed manifest drain before Agent startup.');
3417
3420
  await waitMilliseconds(Math.min(60_000, Math.round(testHoldAfterDrainMs)));
3418
3421
  }
3419
3422
  }
@@ -3429,7 +3432,7 @@ async function main() {
3429
3432
  if (!explicitMultiInstance) {
3430
3433
  await stopStaleClientAgents();
3431
3434
  } else if (process.env.LIVEDESK_DEBUG === '1') {
3432
- console.log('[LiveDesk] Client lifecycle audit skipped for explicit multi-instance mode.');
3435
+ console.log('[VuvoDesk] Client lifecycle audit skipped for explicit multi-instance mode.');
3433
3436
  }
3434
3437
  }
3435
3438