livedesk 0.1.549 → 0.1.551

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/README.md CHANGED
@@ -4,10 +4,10 @@
4
4
  RemoteFast package for the current operating system and CPU, so Windows, macOS,
5
5
  and Linux native binaries are no longer downloaded together.
6
6
 
7
- One-command LiveDesk application. The same launcher resolves this computer's
8
- Hub or Client role. A Client starts one managed Agent. A Hub starts the Hub
9
- server plus one headless Self Agent, so the Hub computer also appears on the
10
- wall and can be controlled like the other computers.
7
+ One-command LiveDesk application. The same launcher resolves this computer's
8
+ Hub or Client role. A Client starts one managed Agent. A Hub starts the Hub
9
+ server plus one headless Self Agent, so the Hub computer also appears on the
10
+ wall and can be controlled like the other computers.
11
11
 
12
12
  The `hub/`, `client/`, `runtime-core/`, and `web/` folders in this package are
13
13
  generated copies. Edit the source packages and run
@@ -45,11 +45,11 @@ npx -y --prefer-online livedesk@latest --force-role client
45
45
  npx -y --prefer-online livedesk@latest hub
46
46
  ```
47
47
 
48
- This starts the LiveDesk Hub, opens the local screen wall, accepts clients, and
49
- connects one local Self Agent through loopback TCP. The Self Agent reuses the
50
- Hub computer's stable device identity and does not open another login or status
51
- page. Hub shutdown, update, and role change drain that exact Agent tree before
52
- the launcher exits or hands off.
48
+ This starts the LiveDesk Hub, opens the local screen wall, accepts clients, and
49
+ connects one local Self Agent through loopback TCP. The Self Agent reuses the
50
+ Hub computer's stable device identity and does not open another login or status
51
+ page. Hub shutdown, update, and role change drain that exact Agent tree before
52
+ the launcher exits or hands off.
53
53
  The Hub UI/API listens on `127.0.0.1` by default while the client endpoint
54
54
  continues to listen on the LAN.
55
55
 
package/bin/livedesk.js CHANGED
@@ -46,11 +46,11 @@ import {
46
46
  readDeadWindowsOwnedProcessManifest,
47
47
  readWindowsOwnedProcessManifest
48
48
  } from '../client/src/runtime/windows-owned-process-manifest.js';
49
- import { inspectMacDiagnosticLease } from '../diagnostics/livedesk-mac-physical-isolation.mjs';
50
- import {
51
- buildHubSelfAgentLaunchSpec,
52
- createHubSelfAgentSupervisor
53
- } from '../bootstrap/hub-self-agent.js';
49
+ import { inspectMacDiagnosticLease } from '../diagnostics/livedesk-mac-physical-isolation.mjs';
50
+ import {
51
+ buildHubSelfAgentLaunchSpec,
52
+ createHubSelfAgentSupervisor
53
+ } from '../bootstrap/hub-self-agent.js';
54
54
 
55
55
  const require = createRequire(import.meta.url);
56
56
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -2540,47 +2540,47 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2540
2540
  let updateStopTimer = null;
2541
2541
  let updateHardStopTimer = null;
2542
2542
  let launcherShutdownSignal = '';
2543
- let launcherShutdownHardStopTimer = null;
2544
- let runtimeShutdownWatcher = null;
2545
- let selfAgentStopPromise = null;
2546
- const launcherSignalHandlers = new Map();
2547
-
2548
- let hubSelfAgent = null;
2549
- try {
2550
- const clientEntry = resolve(packageRoot, 'client', 'bin', 'livedesk-client.js');
2551
- if (!existsSync(clientEntry)) {
2552
- throw new Error('the packaged Client runtime is missing');
2553
- }
2554
- hubSelfAgent = createHubSelfAgentSupervisor({
2555
- launch: buildHubSelfAgentLaunchSpec({
2556
- nodePath: process.execPath,
2557
- clientEntry,
2558
- remotePort,
2559
- pairToken,
2560
- deviceId: env.LIVEDESK_DEVICE_ID,
2561
- deviceName: env.LIVEDESK_DEVICE_NAME,
2562
- stateDir: MANAGER_STATE_DIR,
2563
- runtimeOwner,
2564
- baseEnv: env
2565
- }),
2566
- report: reportLauncherUpdate
2567
- });
2568
- } catch (error) {
2569
- reportLauncherUpdate(
2570
- `[LiveDesk Hub] Self Agent is unavailable: ${error?.message || error}. Remote Clients remain available.`,
2571
- true
2572
- );
2573
- }
2574
-
2575
- const stopHubSelfAgent = reason => {
2576
- if (!hubSelfAgent) return Promise.resolve({ ok: true, skipped: true });
2577
- if (!selfAgentStopPromise) {
2578
- selfAgentStopPromise = hubSelfAgent.stop(reason).finally(() => {
2579
- selfAgentStopPromise = null;
2580
- });
2581
- }
2582
- return selfAgentStopPromise;
2583
- };
2543
+ let launcherShutdownHardStopTimer = null;
2544
+ let runtimeShutdownWatcher = null;
2545
+ let selfAgentStopPromise = null;
2546
+ const launcherSignalHandlers = new Map();
2547
+
2548
+ let hubSelfAgent = null;
2549
+ try {
2550
+ const clientEntry = resolve(packageRoot, 'client', 'bin', 'livedesk-client.js');
2551
+ if (!existsSync(clientEntry)) {
2552
+ throw new Error('the packaged Client runtime is missing');
2553
+ }
2554
+ hubSelfAgent = createHubSelfAgentSupervisor({
2555
+ launch: buildHubSelfAgentLaunchSpec({
2556
+ nodePath: process.execPath,
2557
+ clientEntry,
2558
+ remotePort,
2559
+ pairToken,
2560
+ deviceId: env.LIVEDESK_DEVICE_ID,
2561
+ deviceName: env.LIVEDESK_DEVICE_NAME,
2562
+ stateDir: MANAGER_STATE_DIR,
2563
+ runtimeOwner,
2564
+ baseEnv: env
2565
+ }),
2566
+ report: reportLauncherUpdate
2567
+ });
2568
+ } catch (error) {
2569
+ reportLauncherUpdate(
2570
+ `[LiveDesk Hub] Self Agent is unavailable: ${error?.message || error}. Remote Clients remain available.`,
2571
+ true
2572
+ );
2573
+ }
2574
+
2575
+ const stopHubSelfAgent = reason => {
2576
+ if (!hubSelfAgent) return Promise.resolve({ ok: true, skipped: true });
2577
+ if (!selfAgentStopPromise) {
2578
+ selfAgentStopPromise = hubSelfAgent.stop(reason).finally(() => {
2579
+ selfAgentStopPromise = null;
2580
+ });
2581
+ }
2582
+ return selfAgentStopPromise;
2583
+ };
2584
2584
 
2585
2585
  const removeLauncherSignalHandlers = () => {
2586
2586
  for (const [signal, handler] of launcherSignalHandlers) {
@@ -2589,7 +2589,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2589
2589
  launcherSignalHandlers.clear();
2590
2590
  };
2591
2591
 
2592
- const requestLauncherShutdown = signal => {
2592
+ const requestLauncherShutdown = signal => {
2593
2593
  if (launcherShutdownSignal) return;
2594
2594
  launcherShutdownSignal = signal;
2595
2595
  restartRequest = null;
@@ -2601,18 +2601,18 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2601
2601
  clearTimeout(updateStopTimer);
2602
2602
  updateStopTimer = null;
2603
2603
  }
2604
- if (updateHardStopTimer) {
2604
+ if (updateHardStopTimer) {
2605
2605
  clearTimeout(updateHardStopTimer);
2606
- updateHardStopTimer = null;
2607
- }
2608
- void stopHubSelfAgent(`launcher-${signal}`);
2609
- const child = activeChild;
2610
- if (!child || child.exitCode !== null || child.signalCode) {
2611
- void stopHubSelfAgent(`launcher-${signal}`).finally(() => {
2612
- try { hubLogStream?.end(); } catch {}
2613
- process.exit(0);
2614
- });
2615
- return;
2606
+ updateHardStopTimer = null;
2607
+ }
2608
+ void stopHubSelfAgent(`launcher-${signal}`);
2609
+ const child = activeChild;
2610
+ if (!child || child.exitCode !== null || child.signalCode) {
2611
+ void stopHubSelfAgent(`launcher-${signal}`).finally(() => {
2612
+ try { hubLogStream?.end(); } catch {}
2613
+ process.exit(0);
2614
+ });
2615
+ return;
2616
2616
  }
2617
2617
  reportLauncherUpdate(
2618
2618
  `[LiveDesk Hub] Launcher received ${signal}; requesting graceful Hub shutdown for pid=${child.pid || 'unknown'}.`
@@ -2859,17 +2859,17 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2859
2859
  failPreflight(message);
2860
2860
  return;
2861
2861
  }
2862
- restartRequest = {
2862
+ restartRequest = {
2863
2863
  ...request,
2864
2864
  latestVersion: requestedVersion,
2865
2865
  pid: requestPid,
2866
2866
  operationId,
2867
2867
  _neutralCwd: neutralCwd,
2868
2868
  _originalCwd: UPDATE_ORIGINAL_CWD
2869
- };
2870
- reportLauncherUpdate(`[LiveDesk Hub] Restart requested for update ${request.operationId || 'unknown'} target=${requestedVersion}.`);
2871
- void stopHubSelfAgent('hub-update');
2872
- const updateChild = activeChild;
2869
+ };
2870
+ reportLauncherUpdate(`[LiveDesk Hub] Restart requested for update ${request.operationId || 'unknown'} target=${requestedVersion}.`);
2871
+ void stopHubSelfAgent('hub-update');
2872
+ const updateChild = activeChild;
2873
2873
  let shutdownFallbackStarted = false;
2874
2874
  const forceStop = reason => {
2875
2875
  if (!updateChild || updateChild.exitCode !== null || updateChild.signalCode) return;
@@ -2910,7 +2910,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2910
2910
  }
2911
2911
  };
2912
2912
 
2913
- const startHubProcess = () => {
2913
+ const startHubProcess = () => {
2914
2914
  const stderrChunks = [];
2915
2915
  let stderrLength = 0;
2916
2916
  const child = spawn(process.execPath, [hubEntry, ...options.forwarded], {
@@ -2918,22 +2918,22 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2918
2918
  stdio: ['inherit', 'pipe', 'pipe'],
2919
2919
  windowsHide: !debugConsole
2920
2920
  });
2921
- activeChild = child;
2922
-
2923
- void waitForManager(hubProbeBaseUrl).then(ok => {
2924
- if (!ok
2925
- || activeChild !== child
2926
- || child.exitCode !== null
2927
- || child.signalCode
2928
- || launcherShutdownSignal
2929
- || restartRequest) return;
2930
- hubSelfAgent?.start();
2931
- }).catch(error => {
2932
- reportLauncherUpdate(
2933
- `[LiveDesk Hub] Self Agent startup wait failed: ${error?.message || error}.`,
2934
- true
2935
- );
2936
- });
2921
+ activeChild = child;
2922
+
2923
+ void waitForManager(hubProbeBaseUrl).then(ok => {
2924
+ if (!ok
2925
+ || activeChild !== child
2926
+ || child.exitCode !== null
2927
+ || child.signalCode
2928
+ || launcherShutdownSignal
2929
+ || restartRequest) return;
2930
+ hubSelfAgent?.start();
2931
+ }).catch(error => {
2932
+ reportLauncherUpdate(
2933
+ `[LiveDesk Hub] Self Agent startup wait failed: ${error?.message || error}.`,
2934
+ true
2935
+ );
2936
+ });
2937
2937
 
2938
2938
  child.stdout.on('data', chunk => {
2939
2939
  appendHubLog(chunk.toString());
@@ -2957,19 +2957,19 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2957
2957
  });
2958
2958
  child.once('exit', (code, signal) => {
2959
2959
  const startupOutput = stderrChunks.join('');
2960
- if (launcherShutdownSignal) {
2960
+ if (launcherShutdownSignal) {
2961
2961
  if (launcherShutdownHardStopTimer) {
2962
2962
  clearTimeout(launcherShutdownHardStopTimer);
2963
2963
  launcherShutdownHardStopTimer = null;
2964
2964
  }
2965
- runtimeShutdownWatcher?.stop();
2966
- removeLauncherSignalHandlers();
2967
- void stopHubSelfAgent(`launcher-${launcherShutdownSignal}`).finally(() => {
2968
- try { hubLogStream?.end(); } catch {}
2969
- process.exit(0);
2970
- });
2971
- return;
2972
- }
2965
+ runtimeShutdownWatcher?.stop();
2966
+ removeLauncherSignalHandlers();
2967
+ void stopHubSelfAgent(`launcher-${launcherShutdownSignal}`).finally(() => {
2968
+ try { hubLogStream?.end(); } catch {}
2969
+ process.exit(0);
2970
+ });
2971
+ return;
2972
+ }
2973
2973
  if (restartRequest) {
2974
2974
  const request = restartRequest;
2975
2975
  restartRequest = null;
@@ -2985,7 +2985,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
2985
2985
  clearInterval(updatePollId);
2986
2986
  updatePollId = null;
2987
2987
  }
2988
- void stopHubSelfAgent('hub-update').then(() => restartWithLatest(request)).catch(error => {
2988
+ void stopHubSelfAgent('hub-update').then(() => restartWithLatest(request)).catch(error => {
2989
2989
  const message = `The Hub restart handoff failed after shutdown: ${error instanceof Error ? error.message : String(error)}`;
2990
2990
  reportLauncherUpdate(`[LiveDesk Hub] ${message}. Restarting the unchanged Hub.`, true);
2991
2991
  try {
@@ -3012,7 +3012,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
3012
3012
  } catch {
3013
3013
  // The unchanged Hub still restarts even if diagnostics are read-only.
3014
3014
  }
3015
- startHubProcess();
3015
+ startHubProcess();
3016
3016
  if (!updatePollId) {
3017
3017
  updatePollId = setInterval(pollUpdateRequest, HUB_UPDATE_POLL_MS);
3018
3018
  updatePollId.unref?.();
@@ -3020,44 +3020,44 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
3020
3020
  });
3021
3021
  return;
3022
3022
  }
3023
- if (!signal && code === ROLE_TRANSITION_EXIT_CODE) {
3024
- if (updatePollId) {
3025
- clearInterval(updatePollId);
3026
- updatePollId = null;
3027
- }
3028
- void stopHubSelfAgent('role-transition').then(() => {
3029
- try {
3030
- runtimeLock?.updateRole?.('client');
3031
- } catch (error) {
3032
- console.error(
3033
- `[LiveDesk Hub] The shared runtime lock could not transition to Client: ${error?.message || error}. `
3034
- + 'The launcher will exit so a clean invocation can recover.'
3035
- );
3036
- runtimeShutdownWatcher?.stop();
3037
- removeLauncherSignalHandlers();
3038
- try { hubLogStream?.end(); } catch {}
3039
- process.exit(1);
3040
- return;
3041
- }
3042
- writeRoleCache({
3043
- role: 'client',
3044
- deviceId: resolvedRole?.deviceId || process.env.LIVEDESK_DEVICE_ID || '',
3045
- deviceName: resolvedRole?.deviceName || os.hostname(),
3046
- source: 'supabase',
3047
- isOfflineFallback: false
3048
- }, { stateDir: MANAGER_STATE_DIR });
3049
- console.log('[LiveDesk Hub] Role transition accepted. Starting the Client runtime.');
3050
- runtimeShutdownWatcher?.stop();
3051
- removeLauncherSignalHandlers();
3052
- void runClient([], { ...resolvedRole, role: 'client', source: 'supabase', roleTransition: true }, runtimeLock).catch(error => {
3053
- console.error(`Failed to start LiveDesk Client runtime: ${error?.message || error}`);
3054
- process.exitCode = 1;
3055
- });
3056
- }).catch(error => {
3057
- console.error(`[LiveDesk Hub] Self Agent did not stop for role transition: ${error?.message || error}`);
3058
- process.exit(1);
3059
- });
3060
- return;
3023
+ if (!signal && code === ROLE_TRANSITION_EXIT_CODE) {
3024
+ if (updatePollId) {
3025
+ clearInterval(updatePollId);
3026
+ updatePollId = null;
3027
+ }
3028
+ void stopHubSelfAgent('role-transition').then(() => {
3029
+ try {
3030
+ runtimeLock?.updateRole?.('client');
3031
+ } catch (error) {
3032
+ console.error(
3033
+ `[LiveDesk Hub] The shared runtime lock could not transition to Client: ${error?.message || error}. `
3034
+ + 'The launcher will exit so a clean invocation can recover.'
3035
+ );
3036
+ runtimeShutdownWatcher?.stop();
3037
+ removeLauncherSignalHandlers();
3038
+ try { hubLogStream?.end(); } catch {}
3039
+ process.exit(1);
3040
+ return;
3041
+ }
3042
+ writeRoleCache({
3043
+ role: 'client',
3044
+ deviceId: resolvedRole?.deviceId || process.env.LIVEDESK_DEVICE_ID || '',
3045
+ deviceName: resolvedRole?.deviceName || os.hostname(),
3046
+ source: 'supabase',
3047
+ isOfflineFallback: false
3048
+ }, { stateDir: MANAGER_STATE_DIR });
3049
+ console.log('[LiveDesk Hub] Role transition accepted. Starting the Client runtime.');
3050
+ runtimeShutdownWatcher?.stop();
3051
+ removeLauncherSignalHandlers();
3052
+ void runClient([], { ...resolvedRole, role: 'client', source: 'supabase', roleTransition: true }, runtimeLock).catch(error => {
3053
+ console.error(`Failed to start LiveDesk Client runtime: ${error?.message || error}`);
3054
+ process.exitCode = 1;
3055
+ });
3056
+ }).catch(error => {
3057
+ console.error(`[LiveDesk Hub] Self Agent did not stop for role transition: ${error?.message || error}`);
3058
+ process.exit(1);
3059
+ });
3060
+ return;
3061
3061
  }
3062
3062
  if (!signal
3063
3063
  && code !== 0
@@ -3079,11 +3079,11 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
3079
3079
  });
3080
3080
  return;
3081
3081
  }
3082
- if (signal) {
3083
- void stopHubSelfAgent(`hub-signal-${signal}`).finally(() => process.kill(process.pid, signal));
3084
- return;
3085
- }
3086
- void stopHubSelfAgent('hub-exited').finally(() => process.exit(code ?? 0));
3082
+ if (signal) {
3083
+ void stopHubSelfAgent(`hub-signal-${signal}`).finally(() => process.kill(process.pid, signal));
3084
+ return;
3085
+ }
3086
+ void stopHubSelfAgent('hub-exited').finally(() => process.exit(code ?? 0));
3087
3087
  });
3088
3088
  };
3089
3089
 
@@ -3389,12 +3389,12 @@ async function main() {
3389
3389
  await stopProcessesOnPorts([replacementCleanup.runtimePort, remotePort]);
3390
3390
  }
3391
3391
 
3392
- if (resolvedRole.role === 'client' || resolvedRole.role === 'hub') {
3393
- // A launcher and Agent can both die while an independently spawned capture
3394
- // helper survives. This applies to a normal Client and to the Hub-owned
3395
- // Self Agent. Consume only the exact manifest generation returned by the
3396
- // stale-lock compare-and-swap; no process-name scan participates here.
3397
- const reclaimedManifestDrain = await drainReclaimedWindowsClientManifest(lock.reclaimedOwner);
3392
+ if (resolvedRole.role === 'client' || resolvedRole.role === 'hub') {
3393
+ // A launcher and Agent can both die while an independently spawned capture
3394
+ // helper survives. This applies to a normal Client and to the Hub-owned
3395
+ // Self Agent. Consume only the exact manifest generation returned by the
3396
+ // stale-lock compare-and-swap; no process-name scan participates here.
3397
+ const reclaimedManifestDrain = await drainReclaimedWindowsClientManifest(lock.reclaimedOwner);
3398
3398
  const testHoldAfterDrainMs = Number(
3399
3399
  process.env.LIVEDESK_TEST_HOLD_AFTER_RECLAIMED_WINDOWS_DRAIN_MS || 0
3400
3400
  );
@@ -3402,12 +3402,12 @@ async function main() {
3402
3402
  && process.env.LIVEDESK_DEBUG === '1'
3403
3403
  && Number.isFinite(testHoldAfterDrainMs)
3404
3404
  && testHoldAfterDrainMs > 0) {
3405
- console.log('[LiveDesk test] Holding after reclaimed manifest drain before Agent startup.');
3406
- await waitMilliseconds(Math.min(60_000, Math.round(testHoldAfterDrainMs)));
3407
- }
3408
- }
3409
-
3410
- if (resolvedRole.role === 'client') {
3405
+ console.log('[LiveDesk test] Holding after reclaimed manifest drain before Agent startup.');
3406
+ await waitMilliseconds(Math.min(60_000, Math.round(testHoldAfterDrainMs)));
3407
+ }
3408
+ }
3409
+
3410
+ if (resolvedRole.role === 'client') {
3411
3411
  const clientRuntimePort = normalizePort(
3412
3412
  process.env.LIVEDESK_CLIENT_RUNTIME_PORT || process.env.LIVEDESK_LOCAL_RUNTIME_PORT,
3413
3413
  DEFAULT_MANAGER_HTTP_PORT