livedesk 0.1.494 → 0.1.496

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 (46) hide show
  1. package/README.md +87 -118
  2. package/bin/livedesk.js +14 -33
  3. package/bootstrap/hub-auth-handoff.js +189 -242
  4. package/client/bin/livedesk-client-node.js +82 -190
  5. package/client/bin/livedesk-client.js +111 -482
  6. package/client/package.json +6 -6
  7. package/client/src/runtime/client-runtime-server.js +20 -114
  8. package/diagnostics/livedesk-mode3-capture-smoke.mjs +2 -102
  9. package/electron/electron-builder.mac-arm64.yml +35 -35
  10. package/electron/electron-builder.mac-x64.yml +35 -35
  11. package/electron/main.mjs +856 -905
  12. package/electron/update-manager.mjs +101 -146
  13. package/hub/package.json +32 -32
  14. package/hub/src/agents/agent-audit-store.js +6 -16
  15. package/hub/src/agents/agent-permissions.js +27 -33
  16. package/hub/src/agents/agent-tool-registry.js +322 -340
  17. package/hub/src/captures/capture-store.js +252 -299
  18. package/hub/src/filesystem/shared-folders.js +181 -189
  19. package/hub/src/filesystem/transfer-jobs.js +314 -345
  20. package/hub/src/live-desk-update.js +615 -683
  21. package/hub/src/remote-hub.js +85 -654
  22. package/hub/src/server.js +154 -965
  23. package/hub/src/settings/settings-schema.js +40 -32
  24. package/hub/src/settings/settings-store.js +2 -7
  25. package/hub/src/transport/relay-hub-control.js +1376 -1703
  26. package/hub/src/transport/udp-hub-transport.js +520 -543
  27. package/hub/src/transport/udp-rendezvous.js +408 -574
  28. package/package.json +63 -64
  29. package/runtime-core/package.json +20 -25
  30. package/runtime-core/src/index.js +4 -6
  31. package/web/dist/assets/{icons-BtzQBJR4.js → icons-CpeZfjFK.js} +1 -1
  32. package/web/dist/assets/index-B994Eyui.js +186 -0
  33. package/web/dist/assets/{index-B6LQSCl2.css → index-C-ZITB9q.css} +1 -1
  34. package/web/dist/assets/{react-BDGiddLC.js → react-CSxCfTKV.js} +1 -1
  35. package/web/dist/index.html +4 -4
  36. package/web/dist/livedesk-build-evidence.json +17 -17
  37. package/client/src/runtime/fast-runtime-repair.js +0 -300
  38. package/client/src/security/device-credential-store.js +0 -219
  39. package/client/src/security/secure-direct-client.js +0 -224
  40. package/hub/src/security/device-credential-authority.js +0 -406
  41. package/hub/src/security/security-audit-store.js +0 -260
  42. package/hub/src/transport/secure-direct-acceptor.js +0 -543
  43. package/runtime-core/src/os-secret-store.js +0 -142
  44. package/runtime-core/src/secure-session-protocol.js +0 -347
  45. package/runtime-core/src/signed-update-manifest.js +0 -220
  46. package/web/dist/assets/index-BRPz6Wux.js +0 -186
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # LiveDesk
2
-
3
- `livedesk` is a thin cross-platform launcher. npm installs only the matching
4
- RemoteFast package for the current operating system and CPU, so Windows, macOS,
5
- and Linux native binaries are no longer downloaded together.
1
+ # LiveDesk
2
+
3
+ `livedesk` is a thin cross-platform launcher. npm installs only the matching
4
+ RemoteFast package for the current operating system and CPU, so Windows, macOS,
5
+ and Linux native binaries are no longer downloaded together.
6
6
 
7
7
  One-command LiveDesk application. The same launcher resolves this computer's
8
8
  Hub or Client role, then starts only the runtime required by that role.
@@ -11,15 +11,15 @@ The `hub/`, `client/`, `runtime-core/`, and `web/` folders in this package are
11
11
  generated copies. Edit the source packages and run
12
12
  `node packages/livedesk/scripts/sync-web-dist.js` before building or packing
13
13
  the product. The published `livedesk` package owns both runtime roles; the
14
- source-only `@livedesk/client` workspace is not a runtime dependency.
15
-
16
- LiveDesk's top runtime contract is transmission performance together with
17
- long-running stability. A faster path is not accepted if it permits duplicate
18
- capture helpers, stale monitor generations, unbounded frame queues, or an
19
- unproven Direct/P2P/relay transition. Release builds run the same lifecycle,
20
- transport recovery, and browser H.264 population gates used by CI.
21
-
22
- ## Unified launch
14
+ source-only `@livedesk/client` workspace is not a runtime dependency.
15
+
16
+ LiveDesk's top runtime contract is transmission performance together with
17
+ long-running stability. A faster path is not accepted if it permits duplicate
18
+ capture helpers, stale monitor generations, unbounded frame queues, or an
19
+ unproven Direct/P2P/relay transition. Release builds run the same lifecycle,
20
+ transport recovery, and browser H.264 population gates used by CI.
21
+
22
+ ## Unified launch
23
23
 
24
24
  ```powershell
25
25
  npx -y --prefer-online livedesk@latest
@@ -57,7 +57,7 @@ Pass `--no-clean` to disable the startup cleanup explicitly. If a child Hub
57
57
  still loses a startup race with `EADDRINUSE`, the launcher performs one cleanup
58
58
  and startup retry, then exits without looping.
59
59
 
60
- ## Client compatibility
60
+ ## Client compatibility
61
61
 
62
62
  ```powershell
63
63
  npx -y --prefer-online livedesk@latest client 3
@@ -67,75 +67,75 @@ The `client` form remains as a legacy compatibility alias. It records the
67
67
  Client role and uses the same unified runtime lock. The client signs in with
68
68
  Google, discovers the active Hub, and connects to the wall. On Windows, enable
69
69
  **Start with Windows** on the connection page to reconnect automatically after
70
- reboot; the generated startup command uses the unified launcher.
71
-
72
- ## macOS physical diagnostic
73
-
74
- On a Mac with two connected displays, stop every running LiveDesk runtime,
75
- start visibly different continuously moving content on both displays, grant
76
- Screen Recording and Accessibility permissions, then explicitly confirm that
77
- the motion is already running:
78
-
79
- ```bash
80
- npx -y --prefer-online livedesk@latest diagnose mac-physical --confirm-active-motion
81
- ```
82
-
83
- This command branches before role resolution, state migration, and the normal
84
- runtime lock. It refuses to overlap an existing LiveDesk runtime or capture
85
- helper, and normal macOS startup reciprocally refuses an active diagnostic
86
- lease. The lease owner authorizes exactly one direct-child production unified
87
- Hub launcher and one direct-child production unified Client launcher using the
88
- lease PID, parent PID, and token, then each launcher consumes and removes that
89
- capability before starting descendants. The Client therefore runs
90
- the normal Client bootstrap and starts its normal RemoteFast child instead of
91
- testing RemoteFast in isolation. All state and network discovery remain
92
- isolated. Cleanup joins those exact launcher roots after their Hub, RemoteFast,
93
- and ScreenCaptureKit descendants drain. Ctrl+C and termination signals join the
94
- same owned cleanup before exit. The default JSON report is written to
95
- one final path after cleanup, and run/cleanup errors always produce a failed
96
- result. It is written under `~/.livedesk/diagnostics`. To select a path relative
97
- to the directory where the command was invoked:
98
-
99
- ```bash
100
- npx -y --prefer-online livedesk@latest diagnose mac-physical --confirm-active-motion --report ./mac-result.json
101
- ```
102
-
103
- Use `diagnose mac-physical --help` to inspect requirements without starting a
104
- runtime or changing cached role/account state. The confirmation flag is not
105
- treated as proof by itself: each display must also show two different decoded
106
- pixel hashes while native capture/compression/stdout counters advance at the
107
- active cadence. Diagnostic ffmpeg observers run sequentially after product
108
- CPU/RSS/process sampling, are labeled as diagnostic observers, and are excluded
109
- from those product budgets. Product resource evidence covers both unified
110
- launcher roots plus the Hub, RemoteFast, and ScreenCaptureKit descendants.
111
- VideoToolbox ownership comes from native active and terminal telemetry. The
112
- terminal v4 record must match the exact final restored-Wall helper observation,
113
- PID, profile, start time, capture generation, purpose, and stream, and must be
114
- newer than that stream's stop request. Its PID must equal the single OS helper
115
- sampled at that exact restored-Wall ready point; an earlier aggregate PID sighting
116
- is insufficient. A stale/ownerless/internal-only terminal record or a retired
117
- helper process alone is not accepted as encoder-session cleanup proof.
118
-
119
- ## Physical transport diagnostic
120
-
121
- While the local Hub is running and at least one Client is sending a current
122
- Mode 3 H.264 stream, run:
123
-
124
- ```bash
125
- npx -y --prefer-online livedesk@latest diagnose transport-physical
126
- ```
127
-
128
- The diagnostic proves one unchanged stream identity through Direct TCP,
129
- encrypted UDP P2P, encrypted relay, and Direct recovery. Every phase requires
130
- an independently decodable SPS/PPS/IDR frame observed by the Hub within a
131
- bounded deadline. It uses an exact-owner temporary lease, changes no firewall
132
- or router settings, and writes a redacted report under
133
- `~/.livedesk/diagnostics`. Use `diagnose transport-physical --help` for
134
- device, Hub URL, timeout, and report-path options.
135
-
136
- ## Frame modes
137
-
138
- - Mode 2: independent 320x180 RGB565+LZO tiles for large, stable walls.
70
+ reboot; the generated startup command uses the unified launcher.
71
+
72
+ ## macOS physical diagnostic
73
+
74
+ On a Mac with two connected displays, stop every running LiveDesk runtime,
75
+ start visibly different continuously moving content on both displays, grant
76
+ Screen Recording and Accessibility permissions, then explicitly confirm that
77
+ the motion is already running:
78
+
79
+ ```bash
80
+ npx -y --prefer-online livedesk@latest diagnose mac-physical --confirm-active-motion
81
+ ```
82
+
83
+ This command branches before role resolution, state migration, and the normal
84
+ runtime lock. It refuses to overlap an existing LiveDesk runtime or capture
85
+ helper, and normal macOS startup reciprocally refuses an active diagnostic
86
+ lease. The lease owner authorizes exactly one direct-child production unified
87
+ Hub launcher and one direct-child production unified Client launcher using the
88
+ lease PID, parent PID, and token, then each launcher consumes and removes that
89
+ capability before starting descendants. The Client therefore runs
90
+ the normal Client bootstrap and starts its normal RemoteFast child instead of
91
+ testing RemoteFast in isolation. All state and network discovery remain
92
+ isolated. Cleanup joins those exact launcher roots after their Hub, RemoteFast,
93
+ and ScreenCaptureKit descendants drain. Ctrl+C and termination signals join the
94
+ same owned cleanup before exit. The default JSON report is written to
95
+ one final path after cleanup, and run/cleanup errors always produce a failed
96
+ result. It is written under `~/.livedesk/diagnostics`. To select a path relative
97
+ to the directory where the command was invoked:
98
+
99
+ ```bash
100
+ npx -y --prefer-online livedesk@latest diagnose mac-physical --confirm-active-motion --report ./mac-result.json
101
+ ```
102
+
103
+ Use `diagnose mac-physical --help` to inspect requirements without starting a
104
+ runtime or changing cached role/account state. The confirmation flag is not
105
+ treated as proof by itself: each display must also show two different decoded
106
+ pixel hashes while native capture/compression/stdout counters advance at the
107
+ active cadence. Diagnostic ffmpeg observers run sequentially after product
108
+ CPU/RSS/process sampling, are labeled as diagnostic observers, and are excluded
109
+ from those product budgets. Product resource evidence covers both unified
110
+ launcher roots plus the Hub, RemoteFast, and ScreenCaptureKit descendants.
111
+ VideoToolbox ownership comes from native active and terminal telemetry. The
112
+ terminal v4 record must match the exact final restored-Wall helper observation,
113
+ PID, profile, start time, capture generation, purpose, and stream, and must be
114
+ newer than that stream's stop request. Its PID must equal the single OS helper
115
+ sampled at that exact restored-Wall ready point; an earlier aggregate PID sighting
116
+ is insufficient. A stale/ownerless/internal-only terminal record or a retired
117
+ helper process alone is not accepted as encoder-session cleanup proof.
118
+
119
+ ## Physical transport diagnostic
120
+
121
+ While the local Hub is running and at least one Client is sending a current
122
+ Mode 3 H.264 stream, run:
123
+
124
+ ```bash
125
+ npx -y --prefer-online livedesk@latest diagnose transport-physical
126
+ ```
127
+
128
+ The diagnostic proves one unchanged stream identity through Direct TCP,
129
+ encrypted UDP P2P, encrypted relay, and Direct recovery. Every phase requires
130
+ an independently decodable SPS/PPS/IDR frame observed by the Hub within a
131
+ bounded deadline. It uses an exact-owner temporary lease, changes no firewall
132
+ or router settings, and writes a redacted report under
133
+ `~/.livedesk/diagnostics`. Use `diagnose transport-physical --help` for
134
+ device, Hub URL, timeout, and report-path options.
135
+
136
+ ## Frame modes
137
+
138
+ - Mode 2: independent 320x180 RGB565+LZO tiles for large, stable walls.
139
139
  - Mode 3: direct hardware H.264 for focused remote control up to 4K.
140
140
  - Mode 4: client Mode 2 inputs composited by an isolated Hub worker into one
141
141
  bounded H.264 Atlas stream, then split by UV into the normal browser slots.
@@ -148,7 +148,7 @@ device, Hub URL, timeout, and report-path options.
148
148
 
149
149
  Monthly and yearly subscriptions are planned after the LTD launch.
150
150
 
151
- ## Free ad slot
151
+ ## Free ad slot
152
152
 
153
153
  Free accounts show a standard bottom ad slot. Set these Vite build variables
154
154
  for a real AdSense placement:
@@ -158,36 +158,5 @@ VITE_LIVEDESK_ADSENSE_CLIENT=ca-pub-...
158
158
  VITE_LIVEDESK_ADSENSE_SLOT=...
159
159
  ```
160
160
 
161
- Without those values, LiveDesk renders a neutral sponsored-placement placeholder
162
- so the free-plan layout can still be tested.
163
-
164
- ## Signed update configuration
165
-
166
- Production update checks fail closed until all applicable values are set:
167
-
168
- ```text
169
- LIVEDESK_UPDATE_MANIFEST_URL=https://updates.example.com/stable.json
170
- LIVEDESK_UPDATE_PUBLIC_KEY=<Ed25519 SPKI PEM or base64 DER public key>
171
- LIVEDESK_UPDATE_URL=https://updates.example.com/desktop
172
- ```
173
-
174
- The public key may instead be bundled at
175
- `electron/update-public-key.pem` for desktop builds. Keep the Ed25519 private
176
- key offline and outside this repository. Release automation supplies it only to
177
- the signing command as `LIVEDESK_UPDATE_PRIVATE_KEY` or `--private-key`:
178
-
179
- ```powershell
180
- npm run sign:update-manifest -- --input release-payload.json --output stable.json --private-key E:\secure\livedesk-update-ed25519.pem
181
- ```
182
-
183
- The payload must include exact npm `dist.integrity` values for `livedesk` and
184
- `@livedesk/client`, desktop version/platform/architecture SHA-512 values, a
185
- maximum 31-day validity window, and emergency blocked-version lists.
186
-
187
- Desktop publisher signing is independent of the LiveDesk manifest signature.
188
- Configure electron-builder secrets only in the release environment: `CSC_LINK`
189
- and `CSC_KEY_PASSWORD` for the Windows/macOS certificate; for Apple
190
- notarization also configure `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, and
191
- `APPLE_TEAM_ID`. Do not put any private key, certificate password, OAuth secret,
192
- Supabase service key, Dodo webhook secret, or API token in source, Vite public
193
- variables, logs, or the signed manifest.
161
+ Without those values, LiveDesk renders a neutral sponsored-placement placeholder
162
+ so the free-plan layout can still be tested.
package/bin/livedesk.js CHANGED
@@ -65,20 +65,6 @@ const MANAGER_STATE_DIR = resolve(
65
65
  const MANAGER_STATE_PATH = join(MANAGER_STATE_DIR, 'manager.json');
66
66
  const TERMINAL_HUB_UPDATE_OUTCOMES = new Set(['updated', 'restored', 'failed']);
67
67
 
68
- async function preflightPackagedRuntimeDependencies() {
69
- try {
70
- await Promise.all([
71
- import('@livedesk/runtime-core'),
72
- import('@livedesk/runtime-core/os-secret-store')
73
- ]);
74
- } catch (error) {
75
- throw new Error(
76
- 'LiveDesk runtime dependency preflight failed before replacing the existing runtime: '
77
- + `${error instanceof Error ? error.message : String(error)}`
78
- );
79
- }
80
- }
81
-
82
68
  function safeUpdatePathSegment(value, fallback = 'unknown') {
83
69
  return String(value || '')
84
70
  .replace(/[^A-Za-z0-9._-]/g, '_')
@@ -2521,7 +2507,6 @@ async function runManager(args, resolvedRole = null, runtimeLock = null) {
2521
2507
  ? internalHubEntry
2522
2508
  : resolvePackageEntry('@livedesk/hub', '@livedesk/hub/src/server.js'));
2523
2509
  const packagedWebDist = resolve(packageRoot, 'web', 'dist');
2524
- const launcherShutdownToken = randomBytes(32).toString('base64url');
2525
2510
  const env = {
2526
2511
  ...process.env,
2527
2512
  LIVEDESK_HUB_HTTP_HOST: configuredHttpHost,
@@ -2542,7 +2527,6 @@ async function runManager(args, resolvedRole = null, runtimeLock = null) {
2542
2527
  LIVEDESK_DEVICE_NAME: String(resolvedRole?.deviceName || process.env.LIVEDESK_DEVICE_NAME || os.hostname()),
2543
2528
  LIVEDESK_ROLE_CACHE_PATH: join(MANAGER_STATE_DIR, 'device-role.json'),
2544
2529
  LIVEDESK_AUTH_STATE_PATH: join(MANAGER_STATE_DIR, 'auth.json'),
2545
- LIVEDESK_LAUNCHER_SHUTDOWN_TOKEN: launcherShutdownToken,
2546
2530
  LIVEDESK_ROLE_SOURCE: String(resolvedRole?.source || process.env.LIVEDESK_ROLE_SOURCE || '')
2547
2531
  };
2548
2532
  const debugConsole = process.env.LIVEDESK_DEBUG === '1';
@@ -2617,7 +2601,6 @@ async function runManager(args, resolvedRole = null, runtimeLock = null) {
2617
2601
  try {
2618
2602
  const response = await fetch(`${hubProbeBaseUrl}/api/runtime/shutdown`, {
2619
2603
  method: 'POST',
2620
- headers: { 'X-LiveDesk-Launcher-Shutdown': launcherShutdownToken },
2621
2604
  signal: AbortSignal.timeout(750)
2622
2605
  });
2623
2606
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
@@ -2872,7 +2855,6 @@ async function runManager(args, resolvedRole = null, runtimeLock = null) {
2872
2855
  updateStopTimer.unref?.();
2873
2856
  void fetch(`${hubProbeBaseUrl}/api/runtime/shutdown`, {
2874
2857
  method: 'POST',
2875
- headers: { 'X-LiveDesk-Launcher-Shutdown': launcherShutdownToken },
2876
2858
  signal: AbortSignal.timeout(2_500)
2877
2859
  }).then(response => {
2878
2860
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
@@ -3054,24 +3036,24 @@ async function runManager(args, resolvedRole = null, runtimeLock = null) {
3054
3036
  updatePollId = setInterval(pollUpdateRequest, HUB_UPDATE_POLL_MS);
3055
3037
 
3056
3038
  const hubReady = waitForManager(hubProbeBaseUrl);
3057
- void hubReady.then(ok => {
3058
- if (!ok) return;
3059
- void transferSavedClientSessionToHub(hubProbeBaseUrl, MANAGER_STATE_DIR).then(handoff => {
3060
- if (handoff.ok) {
3061
- reportLauncherUpdate('[LiveDesk Hub] Saved Client sign-in adopted by the Hub.');
3062
- if (!handoff.hostTargetOk) {
3063
- reportLauncherUpdate('[LiveDesk Hub] Sign-in was adopted; host publication will continue through lease renewal.', true);
3064
- }
3065
- } else if (!handoff.skipped) {
3066
- reportLauncherUpdate(`[LiveDesk Hub] Saved Client sign-in could not be adopted: ${handoff.reason}. Continue sign-in in the Hub page.`, true);
3039
+ const hubStartup = hubReady.then(async ok => {
3040
+ if (!ok) {
3041
+ return false;
3042
+ }
3043
+ const handoff = await transferSavedClientSessionToHub(hubProbeBaseUrl, MANAGER_STATE_DIR);
3044
+ if (handoff.ok) {
3045
+ reportLauncherUpdate('[LiveDesk Hub] Saved Client sign-in adopted by the Hub.');
3046
+ if (!handoff.hostTargetOk) {
3047
+ reportLauncherUpdate('[LiveDesk Hub] Sign-in was adopted; host publication will continue through lease renewal.', true);
3067
3048
  }
3068
- }).catch(error => {
3069
- reportLauncherUpdate(`[LiveDesk Hub] Saved Client sign-in handoff failed: ${error?.message || error}. Continue sign-in in the Hub page.`, true);
3070
- });
3049
+ } else if (!handoff.skipped) {
3050
+ reportLauncherUpdate(`[LiveDesk Hub] Saved Client sign-in could not be adopted: ${handoff.reason}. Continue sign-in in the Hub page.`, true);
3051
+ }
3052
+ return true;
3071
3053
  });
3072
3054
 
3073
3055
  if (options.openBrowserOnStart) {
3074
- void hubReady.then(ok => {
3056
+ void hubStartup.then(ok => {
3075
3057
  if (ok) {
3076
3058
  openBrowser(openUrl);
3077
3059
  } else {
@@ -3207,7 +3189,6 @@ async function main() {
3207
3189
  }
3208
3190
  }
3209
3191
  await assertNoActiveMacPhysicalDiagnosticLease();
3210
- await preflightPackagedRuntimeDependencies();
3211
3192
  const roleStateOptions = {
3212
3193
  stateDir: MANAGER_STATE_DIR,
3213
3194
  legacyClientStateDir: process.env.LIVEDESK_LEGACY_CLIENT_STATE_DIR