@livedesk/hub 0.1.46 → 0.1.47

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.
@@ -241,11 +241,11 @@ function resetReconnectCandidate(target) {
241
241
  target.stabilityDeadlineAt = '';
242
242
  }
243
243
 
244
- export function createLiveDeskUpdateManager({
245
- remoteHub,
246
- currentManagerVersion,
247
- currentClientVersion,
248
- excludedDeviceIds = [],
244
+ export function createLiveDeskUpdateManager({
245
+ remoteHub,
246
+ currentManagerVersion,
247
+ currentClientVersion,
248
+ excludedDeviceIds = [],
249
249
  restartSupported = false,
250
250
  requestHubRestart,
251
251
  fetchImpl = globalThis.fetch,
@@ -261,16 +261,16 @@ export function createLiveDeskUpdateManager({
261
261
  let checkPromise = null;
262
262
  let run = null;
263
263
  let checkTimer = null;
264
- let runTimer = null;
265
- const excludedDeviceIdSet = new Set(
266
- (Array.isArray(excludedDeviceIds) ? excludedDeviceIds : [excludedDeviceIds])
267
- .map(value => String(value || '').trim())
268
- .filter(Boolean)
269
- );
270
- const connectedClientDevices = () => connectedDevices(remoteHub)
271
- .filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')));
272
- const knownOfflineClientDevices = () => knownOfflineDevices(remoteHub)
273
- .filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')));
264
+ let runTimer = null;
265
+ const excludedDeviceIdSet = new Set(
266
+ (Array.isArray(excludedDeviceIds) ? excludedDeviceIds : [excludedDeviceIds])
267
+ .map(value => String(value || '').trim())
268
+ .filter(Boolean)
269
+ );
270
+ const connectedClientDevices = () => connectedDevices(remoteHub)
271
+ .filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')));
272
+ const knownOfflineClientDevices = () => knownOfflineDevices(remoteHub)
273
+ .filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')));
274
274
  const effectiveClientBatchSize = Math.max(
275
275
  1,
276
276
  Math.min(50, Math.floor(Number(clientBatchSize) || LIVE_DESK_UPDATE_CLIENT_BATCH_SIZE))
@@ -321,7 +321,7 @@ export function createLiveDeskUpdateManager({
321
321
  const getStatus = () => {
322
322
  const managerUpdateAvailable = !!latestRelease
323
323
  && compareVersions(latestRelease.latestManagerVersion, currentManagerVersion) > 0;
324
- const clientDevices = connectedClientDevices();
324
+ const clientDevices = connectedClientDevices();
325
325
  const outdatedClientDevices = latestRelease
326
326
  ? clientDevices.filter(device => deviceNeedsUpdate(
327
327
  device,
@@ -330,7 +330,7 @@ export function createLiveDeskUpdateManager({
330
330
  ))
331
331
  : [];
332
332
  const pendingOfflineClientCount = latestRelease
333
- ? knownOfflineClientDevices().filter(device => deviceNeedsUpdate(
333
+ ? knownOfflineClientDevices().filter(device => deviceNeedsUpdate(
334
334
  device,
335
335
  latestRelease.latestManagerVersion,
336
336
  latestRelease.latestClientVersion
@@ -414,9 +414,9 @@ export function createLiveDeskUpdateManager({
414
414
  if (!run || run.state !== 'failed') return [];
415
415
  const currentTime = now();
416
416
  const devices = new Map(
417
- remoteHub.listDevices({ includeDataUrl: false })
418
- .filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')))
419
- .map(device => [String(device.deviceId), device])
417
+ remoteHub.listDevices({ includeDataUrl: false })
418
+ .filter(device => !excludedDeviceIdSet.has(String(device?.deviceId || '')))
419
+ .map(device => [String(device.deviceId), device])
420
420
  );
421
421
  return run.targets.filter(target => {
422
422
  if (target.state !== 'failed' || !target.dispatchedAt) return false;
@@ -523,7 +523,7 @@ export function createLiveDeskUpdateManager({
523
523
  const activeCount = run.targets.filter(target => target.state === 'waiting').length;
524
524
  let availableSlots = Math.max(0, run.batchSize - activeCount);
525
525
  if (availableSlots <= 0) return true;
526
- const devices = new Map(connectedClientDevices().map(device => [String(device.deviceId), device]));
526
+ const devices = new Map(connectedClientDevices().map(device => [String(device.deviceId), device]));
527
527
  for (const target of run.targets) {
528
528
  if (availableSlots <= 0) break;
529
529
  if (!['queued', 'pending-offline'].includes(target.state)) continue;
@@ -562,7 +562,7 @@ export function createLiveDeskUpdateManager({
562
562
  failRun(`Timed out waiting for ${unfinishedCount} client(s) to finish the rollout.`);
563
563
  return;
564
564
  }
565
- const devices = new Map(connectedClientDevices().map(device => [String(device.deviceId), device]));
565
+ const devices = new Map(connectedClientDevices().map(device => [String(device.deviceId), device]));
566
566
  for (const target of run.targets) {
567
567
  if (target.state === 'failed' || target.state === 'completed') continue;
568
568
  const device = devices.get(target.deviceId);
@@ -689,7 +689,7 @@ export function createLiveDeskUpdateManager({
689
689
  if (!release) return { ok: false, error: checkError || 'LiveDesk update check failed.', ...getStatus() };
690
690
  const managerNeedsUpdate = compareVersions(release.latestManagerVersion, currentManagerVersion) > 0;
691
691
  const clientPackageNeedsUpdate = compareVersions(release.latestClientVersion, currentClientVersion) > 0;
692
- const connected = connectedClientDevices();
692
+ const connected = connectedClientDevices();
693
693
  const outdatedClients = connected.filter(device => deviceNeedsUpdate(
694
694
  device,
695
695
  release.latestManagerVersion,
@@ -790,7 +790,7 @@ export function createLiveDeskUpdateManager({
790
790
  if (target.method === 'dedicated'
791
791
  && target.bootstrapRetryCount === 0
792
792
  && isDedicatedBootstrapFailure(failure)) {
793
- const retryDevice = connectedClientDevices()
793
+ const retryDevice = connectedClientDevices()
794
794
  .find(device => String(device.deviceId || '') === target.deviceId);
795
795
  const remainingMs = Date.parse(target.deadlineAt || '') - now();
796
796
  if (retryDevice?.connected === true && remainingMs >= 10_000) {
package/src/remote-hub.js CHANGED
@@ -1164,10 +1164,12 @@ function normalizeRemoteKeyboardKey(value) {
1164
1164
  return raw === ' ' ? ' ' : safeString(raw, 80);
1165
1165
  }
1166
1166
 
1167
- function normalizeRemoteKeyboardText(value) {
1168
- const raw = String(value ?? '').replace(/\0/g, '');
1169
- return raw === ' ' ? ' ' : safeText(raw, 256);
1170
- }
1167
+ function normalizeRemoteKeyboardText(value) {
1168
+ const raw = String(value ?? '').replace(/\0/g, '');
1169
+ // Remote text is input data, not a label. Preserve leading/trailing spaces
1170
+ // and IME whitespace while keeping every ordered message bounded.
1171
+ return raw.slice(0, 256);
1172
+ }
1171
1173
 
1172
1174
  function safeTaskData(value) {
1173
1175
  if (value === undefined || value === null) return undefined;
package/src/server.js CHANGED
@@ -7,9 +7,9 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, wri
7
7
  import { dirname, resolve } from 'node:path';
8
8
  import { fileURLToPath } from 'node:url';
9
9
  import os from 'node:os';
10
- import { WebSocketServer } from 'ws';
11
- import { createRemoteHub } from './remote-hub.js';
12
- import { createHubConsoleRelay } from './console-relay.js';
10
+ import { WebSocketServer } from 'ws';
11
+ import { createRemoteHub } from './remote-hub.js';
12
+ import { createHubConsoleRelay } from './console-relay.js';
13
13
  import {
14
14
  buildImmutableRemoteFramePacket,
15
15
  createRemoteFramePacketMetrics,
@@ -40,9 +40,9 @@ import { createAgentDeviceScope, resolveAgentTargetIds } from './agents/agent-de
40
40
  import { AgentRuntimeError } from './agents/agent-runtime-error.js';
41
41
  import { AGENT_PERMISSION_MODES, createAgentPermissionPolicy, evaluateAgentToolPermission, hashAgentPermissionPolicy } from './agents/agent-permissions.js';
42
42
  import { createAgentPermissionStore } from './agents/agent-permission-store.js';
43
- import { createAgentAuditStore } from './agents/agent-audit-store.js';
44
- import { getAgentToolDefinition } from './agents/agent-tool-registry.js';
45
- import { enrichAgentTaskResults } from './agents/agent-result-enrichment.js';
43
+ import { createAgentAuditStore } from './agents/agent-audit-store.js';
44
+ import { getAgentToolDefinition } from './agents/agent-tool-registry.js';
45
+ import { enrichAgentTaskResults } from './agents/agent-result-enrichment.js';
46
46
  import { LiveDeskSettingsStore, SettingsConflictError } from './settings/settings-store.js';
47
47
  import { effectiveDevicePolicy } from './settings/settings-schema.js';
48
48
  import { buildEffectiveDevicePolicy } from './settings/effective-device-policy.js';
@@ -204,22 +204,22 @@ let verifiedLicense = {
204
204
  let frameClientSeq = 0;
205
205
  let inputClientSeq = 0;
206
206
  let audioClientSeq = 0;
207
- let liveDeskUpdateManager = null;
208
- let hubTransferJobs = null;
209
- let hubConsoleRelay = null;
207
+ let liveDeskUpdateManager = null;
208
+ let hubTransferJobs = null;
209
+ let hubConsoleRelay = null;
210
210
  const HUB_HOST_TARGET_LEASE_MS = Math.max(5000, readPositiveIntegerEnv('LIVEDESK_HOST_TARGET_LEASE_MS', 60_000));
211
211
  const HUB_HOST_TARGET_RENEW_MS = Math.max(1000, Math.min(
212
212
  readPositiveIntegerEnv('LIVEDESK_HOST_TARGET_RENEW_MS', 20_000),
213
213
  Math.max(1000, HUB_HOST_TARGET_LEASE_MS - 1000)
214
214
  ));
215
- const HUB_ACCESS_TOKEN_REFRESH_SKEW_MS = 90_000;
216
- const hubWakeBaseUrl = String(process.env.LIVEDESK_WAKE_URL || 'https://livedesk-wake.lovecrdm.workers.dev').trim();
217
- const hubConsoleRelayBaseUrl = String(
218
- process.env.LIVEDESK_CONSOLE_RELAY_URL
219
- || (process.env.LIVEDESK_TEST_MODE === '1' || process.env.LIVEDESK_AUTH_TEST_MODE === '1'
220
- ? 'off'
221
- : 'https://livedesk-wake.lovecrdm.workers.dev')
222
- ).trim();
215
+ const HUB_ACCESS_TOKEN_REFRESH_SKEW_MS = 90_000;
216
+ const hubWakeBaseUrl = String(process.env.LIVEDESK_WAKE_URL || 'https://livedesk-wake.lovecrdm.workers.dev').trim();
217
+ const hubConsoleRelayBaseUrl = String(
218
+ process.env.LIVEDESK_CONSOLE_RELAY_URL
219
+ || (process.env.LIVEDESK_TEST_MODE === '1' || process.env.LIVEDESK_AUTH_TEST_MODE === '1'
220
+ ? 'off'
221
+ : 'https://livedesk-wake.lovecrdm.workers.dev')
222
+ ).trim();
223
223
  const HUB_WAKE_NOTIFY_RETRY_MS = 60_000;
224
224
  let hubHostTargetRenewTimer = null;
225
225
  let hubHostTargetRenewInFlight = false;
@@ -513,19 +513,19 @@ async function getRuntimeAccessToken() {
513
513
  const accessToken = String(runtimeAccessToken || '').trim();
514
514
  const expiresSoon = runtimeAccessTokenExpiresAt > 0
515
515
  && runtimeAccessTokenExpiresAt <= Date.now() + HUB_ACCESS_TOKEN_REFRESH_SKEW_MS;
516
- if (accessToken && !expiresSoon) {
517
- return accessToken;
518
- }
519
-
520
- // The packaged Electron main process owns the encrypted refresh token and
521
- // proactively sends each rotation to this child runtime. A second refresh
522
- // owner here could consume the one-time token first and make the desktop
523
- // shell appear signed out after sleep.
524
- if (desktopMainAuthConfig) {
525
- return accessToken;
526
- }
527
-
528
- const refreshToken = String(runtimeRefreshToken || '').trim();
516
+ if (accessToken && !expiresSoon) {
517
+ return accessToken;
518
+ }
519
+
520
+ // The packaged Electron main process owns the encrypted refresh token and
521
+ // proactively sends each rotation to this child runtime. A second refresh
522
+ // owner here could consume the one-time token first and make the desktop
523
+ // shell appear signed out after sleep.
524
+ if (desktopMainAuthConfig) {
525
+ return accessToken;
526
+ }
527
+
528
+ const refreshToken = String(runtimeRefreshToken || '').trim();
529
529
  if (!refreshToken) {
530
530
  return accessToken;
531
531
  }
@@ -629,9 +629,9 @@ async function queryAuthoritativeRuntimeRole() {
629
629
  },
630
630
  SUPABASE_AUTH_TIMEOUT_MS
631
631
  );
632
- if (response.status === 401 || response.status === 403) {
633
- if (!desktopMainAuthConfig) clearRuntimeSession();
634
- throw new Error(`hub-role-query-not-authenticated:${response.status}`);
632
+ if (response.status === 401 || response.status === 403) {
633
+ if (!desktopMainAuthConfig) clearRuntimeSession();
634
+ throw new Error(`hub-role-query-not-authenticated:${response.status}`);
635
635
  }
636
636
  if (!response.ok) {
637
637
  throw new Error(`hub-role-query-failed:${response.status}`);
@@ -813,12 +813,12 @@ function getLiveDeskUpdateStatus() {
813
813
  }
814
814
 
815
815
  if (process.env.LIVEDESK_DESKTOP_HOST !== '1') {
816
- liveDeskUpdateManager = createLiveDeskUpdateManager({
817
- remoteHub,
818
- currentManagerVersion: process.env.LIVEDESK_MANAGER_VERSION || packageInfo.version,
819
- currentClientVersion: process.env.LIVEDESK_CLIENT_PACKAGE_VERSION || '',
820
- excludedDeviceIds: [runtimeDeviceId],
821
- restartSupported: !!String(process.env.LIVEDESK_HUB_UPDATE_REQUEST_PATH || '').trim(),
816
+ liveDeskUpdateManager = createLiveDeskUpdateManager({
817
+ remoteHub,
818
+ currentManagerVersion: process.env.LIVEDESK_MANAGER_VERSION || packageInfo.version,
819
+ currentClientVersion: process.env.LIVEDESK_CLIENT_PACKAGE_VERSION || '',
820
+ excludedDeviceIds: [runtimeDeviceId],
821
+ restartSupported: !!String(process.env.LIVEDESK_HUB_UPDATE_REQUEST_PATH || '').trim(),
822
822
  requestHubRestart
823
823
  });
824
824
  }
@@ -1278,16 +1278,16 @@ async function dispatchAgentMcpTool(session, name, args = {}) {
1278
1278
  remoteHub.cancelTaskBatch(result.batchId);
1279
1279
  return { ok: false, error: 'cancelled-by-user', batchId: result.batchId };
1280
1280
  }
1281
- const batch = remoteHub.getTaskBatch(result.batchId);
1282
- if (!batch) return { ok: false, error: 'task-not-found', batchId: result.batchId };
1283
- if (!['queued', 'running'].includes(batch.status)) {
1284
- const taskResults = enrichAgentTaskResults({
1285
- operation,
1286
- results: batch.results,
1287
- devices: remoteHub.listDevices({ includeDataUrl: false })
1288
- .filter(device => targetIds.includes(device.deviceId))
1289
- });
1290
- return {
1281
+ const batch = remoteHub.getTaskBatch(result.batchId);
1282
+ if (!batch) return { ok: false, error: 'task-not-found', batchId: result.batchId };
1283
+ if (!['queued', 'running'].includes(batch.status)) {
1284
+ const taskResults = enrichAgentTaskResults({
1285
+ operation,
1286
+ results: batch.results,
1287
+ devices: remoteHub.listDevices({ includeDataUrl: false })
1288
+ .filter(device => targetIds.includes(device.deviceId))
1289
+ });
1290
+ return {
1291
1291
  ok: true,
1292
1292
  batchId: result.batchId,
1293
1293
  operation,
@@ -1295,8 +1295,8 @@ async function dispatchAgentMcpTool(session, name, args = {}) {
1295
1295
  total: batch.total,
1296
1296
  completed: batch.completed,
1297
1297
  failed: batch.failed,
1298
- results: taskResults.map(item => ({ deviceId: item.deviceId, deviceName: item.deviceName, status: item.status, stage: item.stage, result: String(item.result || '').slice(0, 3000), data: item.data, error: String(item.error || '').slice(0, 500) }))
1299
- };
1298
+ results: taskResults.map(item => ({ deviceId: item.deviceId, deviceName: item.deviceName, status: item.status, stage: item.stage, result: String(item.result || '').slice(0, 3000), data: item.data, error: String(item.error || '').slice(0, 500) }))
1299
+ };
1300
1300
  }
1301
1301
  await delayAgentMcp(200);
1302
1302
  }
@@ -1356,16 +1356,16 @@ const hubSharedFolders = createHubSharedFolders({
1356
1356
  dataDir: agentDataDir
1357
1357
  });
1358
1358
 
1359
- const app = express();
1360
- const httpServer = createServer(app);
1361
- hubConsoleRelay = createHubConsoleRelay({
1362
- url: runtimeRole === 'hub' ? hubConsoleRelayBaseUrl : 'off',
1363
- deviceId: runtimeDeviceId,
1364
- httpBaseUrl: `http://127.0.0.1:${httpPort}`,
1365
- getAccessToken: () => getRuntimeAccessToken(),
1366
- logger: console
1367
- });
1368
- const httpConnections = new Set();
1359
+ const app = express();
1360
+ const httpServer = createServer(app);
1361
+ hubConsoleRelay = createHubConsoleRelay({
1362
+ url: runtimeRole === 'hub' ? hubConsoleRelayBaseUrl : 'off',
1363
+ deviceId: runtimeDeviceId,
1364
+ httpBaseUrl: `http://127.0.0.1:${httpPort}`,
1365
+ getAccessToken: () => getRuntimeAccessToken(),
1366
+ logger: console
1367
+ });
1368
+ const httpConnections = new Set();
1369
1369
  const frameWss = new WebSocketServer({ noServer: true, perMessageDeflate: false });
1370
1370
  const atlasWss = new WebSocketServer({ noServer: true, perMessageDeflate: false });
1371
1371
  const inputWss = new WebSocketServer({ noServer: true, perMessageDeflate: false });
@@ -4249,10 +4249,10 @@ app.get('/api/remote/status', (_req, res) => {
4249
4249
  runtimeRole,
4250
4250
  deviceId: runtimeDeviceId,
4251
4251
  deviceName: runtimeDeviceName,
4252
- roleSource: runtimeRoleSource,
4253
- agentPackage: '@livedesk/client',
4254
- consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' },
4255
- frameLanes: snapshotFrameLaneResourceHealth(),
4252
+ roleSource: runtimeRoleSource,
4253
+ agentPackage: '@livedesk/client',
4254
+ consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' },
4255
+ frameLanes: snapshotFrameLaneResourceHealth(),
4256
4256
  update: getLiveDeskUpdateStatus()
4257
4257
  });
4258
4258
  });
@@ -4484,11 +4484,11 @@ app.post('/api/auth/session', async (req, res) => {
4484
4484
  csrfToken: uiSession.csrfToken,
4485
4485
  expiresAt: uiSession.expiresAt
4486
4486
  }
4487
- });
4488
- if (runtimeRole === 'hub') {
4489
- hubConsoleRelay?.refresh();
4490
- scheduleAuthenticatedHubHostTargetPublication('session-received');
4491
- }
4487
+ });
4488
+ if (runtimeRole === 'hub') {
4489
+ hubConsoleRelay?.refresh();
4490
+ scheduleAuthenticatedHubHostTargetPublication('session-received');
4491
+ }
4492
4492
  } catch (error) {
4493
4493
  const message = error instanceof Error ? error.message : String(error);
4494
4494
  const status = authVerificationHttpStatus(message);
@@ -4508,11 +4508,11 @@ function getHubHostTargetLeaseStatus() {
4508
4508
  ...hubHostTargetLeaseState,
4509
4509
  renewing: hubHostTargetRenewInFlight,
4510
4510
  renewalIntervalMs: HUB_HOST_TARGET_RENEW_MS,
4511
- leaseDurationMs: HUB_HOST_TARGET_LEASE_MS,
4512
- authenticated: Boolean(runtimeAccessToken),
4513
- timerActive: Boolean(hubHostTargetRenewTimer),
4514
- wake: { ...hubWakeNotificationState },
4515
- consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' }
4511
+ leaseDurationMs: HUB_HOST_TARGET_LEASE_MS,
4512
+ authenticated: Boolean(runtimeAccessToken),
4513
+ timerActive: Boolean(hubHostTargetRenewTimer),
4514
+ wake: { ...hubWakeNotificationState },
4515
+ consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' }
4516
4516
  };
4517
4517
  }
4518
4518
 
@@ -4609,9 +4609,9 @@ async function callHubSupabaseRpc(name, payload, accessToken) {
4609
4609
  );
4610
4610
  const data = await response.json().catch(() => null);
4611
4611
  const result = Array.isArray(data) ? data[0] : data;
4612
- if (response.status === 401 || response.status === 403) {
4613
- if (!desktopMainAuthConfig) clearRuntimeSession();
4614
- throw new Error(`${name}-not-authenticated:${response.status}`);
4612
+ if (response.status === 401 || response.status === 403) {
4613
+ if (!desktopMainAuthConfig) clearRuntimeSession();
4614
+ throw new Error(`${name}-not-authenticated:${response.status}`);
4615
4615
  }
4616
4616
  if (!response.ok) {
4617
4617
  throw new Error(`${name}-failed:${response.status}`);
@@ -4816,11 +4816,11 @@ app.get('/api/hub/status', (_req, res) => {
4816
4816
  ...remoteHub.getStatus({ includeSecrets: false }),
4817
4817
  role: 'hub',
4818
4818
  deviceId: runtimeDeviceId,
4819
- deviceName: runtimeDeviceName,
4820
- roleSource: runtimeRoleSource,
4821
- runtimeStarted: true,
4822
- consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' },
4823
- hostTargetLease: getHubHostTargetLeaseStatus(),
4819
+ deviceName: runtimeDeviceName,
4820
+ roleSource: runtimeRoleSource,
4821
+ runtimeStarted: true,
4822
+ consoleRelay: hubConsoleRelay?.inspect() || { enabled: false, state: 'starting' },
4823
+ hostTargetLease: getHubHostTargetLeaseStatus(),
4824
4824
  update: getLiveDeskUpdateStatus()
4825
4825
  });
4826
4826
  });
@@ -5827,14 +5827,14 @@ hubSharedFolders.startAutoSync(
5827
5827
  () => remoteHub.listDevices({ includeDataUrl: false }).filter(device => device.connected).map(device => device.deviceId),
5828
5828
  () => process.env.LIVEDESK_REMOTE_DIRECTORY || 'Desktop/LiveDeskFiles'
5829
5829
  );
5830
- httpServer.listen(httpPort, httpHost, () => {
5830
+ httpServer.listen(httpPort, httpHost, () => {
5831
5831
  const status = remoteHub.getStatus({ includeSecrets: true });
5832
5832
  const managerVersion = String(process.env.LIVEDESK_MANAGER_VERSION || packageInfo.version || 'dev');
5833
5833
  console.log(`[LiveDesk Hub] Version ${managerVersion}`);
5834
- console.log(`[LiveDesk Hub] HTTP API http://${httpHost}:${httpPort}`);
5835
- console.log(`[LiveDesk Hub] Client endpoint ${status.agentEndpoint} pair=${status.pairTokenPreview}`);
5836
- hubConsoleRelay?.start();
5837
- });
5834
+ console.log(`[LiveDesk Hub] HTTP API http://${httpHost}:${httpPort}`);
5835
+ console.log(`[LiveDesk Hub] Client endpoint ${status.agentEndpoint} pair=${status.pairTokenPreview}`);
5836
+ hubConsoleRelay?.start();
5837
+ });
5838
5838
 
5839
5839
  const roleWatchTimer = runtimeRole === 'hub'
5840
5840
  ? setInterval(() => { void watchAuthoritativeRuntimeRole(); }, 5000)
@@ -5915,10 +5915,10 @@ function shutdownHub(signal) {
5915
5915
  const startedAt = Date.now();
5916
5916
  console.log(`[LiveDesk Hub] Shutdown started signal=${signal} grace=${hubShutdownGraceMs}ms timeout=${hubShutdownTimeoutMs}ms.`);
5917
5917
  if (roleWatchTimer) clearInterval(roleWatchTimer);
5918
- clearInterval(browserWebSocketHeartbeatTimer);
5919
- runSynchronousShutdownStep('update manager close', () => liveDeskUpdateManager?.close());
5920
- runSynchronousShutdownStep('mobile console relay close', () => hubConsoleRelay?.close());
5921
- atlasClients.clear();
5918
+ clearInterval(browserWebSocketHeartbeatTimer);
5919
+ runSynchronousShutdownStep('update manager close', () => liveDeskUpdateManager?.close());
5920
+ runSynchronousShutdownStep('mobile console relay close', () => hubConsoleRelay?.close());
5921
+ atlasClients.clear();
5922
5922
  runSynchronousShutdownStep('shared folder close', () => hubSharedFolders.close());
5923
5923
 
5924
5924
  const httpClosed = new Promise(resolveClose => {
@@ -13,7 +13,8 @@ export const DEFAULT_LIVEDESK_SETTINGS = Object.freeze({
13
13
  approveNewDevices: true,
14
14
  startWithComputer: true,
15
15
  keepRunningInTray: true,
16
- showConnectionNotifications: true
16
+ showConnectionNotifications: true,
17
+ showThisComputer: false
17
18
  },
18
19
  security: {
19
20
  accessMode: 'trusted-only',
@@ -157,7 +158,7 @@ const numbers = (entries) => Object.fromEntries(entries.map(([key, min, max]) =>
157
158
 
158
159
  const RULES = {
159
160
  connection: {
160
- ...bools(['usePinToAddDevices', 'rotatePinAfterPairing', 'allowNewDevices', 'approveNewDevices', 'startWithComputer', 'keepRunningInTray', 'showConnectionNotifications']),
161
+ ...bools(['usePinToAddDevices', 'rotatePinAfterPairing', 'allowNewDevices', 'approveNewDevices', 'startWithComputer', 'keepRunningInTray', 'showConnectionNotifications', 'showThisComputer']),
161
162
  ...numbers([['pinValidityMinutes', 10, 1440]])
162
163
  },
163
164
  security: {