livedesk 0.1.501 → 0.1.503
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/bin/livedesk.js +199 -196
- package/bootstrap/client-process-identity.js +74 -74
- package/bootstrap/device-role.js +224 -224
- package/bootstrap/hub-auth-handoff.js +3 -3
- package/bootstrap/legacy-client-update.js +1806 -1806
- package/bootstrap/npm-update-cache.mjs +158 -158
- package/bootstrap/port-inspection.js +10 -10
- package/bootstrap/role-bootstrap-server.js +102 -102
- package/bootstrap/runtime-lock.js +368 -368
- package/bootstrap/runtime-shutdown.js +414 -414
- package/bootstrap/update-host-client.mjs +442 -431
- package/bootstrap/update-host.mjs +607 -520
- package/client/README.md +20 -20
- package/client/THIRD_PARTY_NOTICES.md +26 -26
- package/client/bin/client-version.js +23 -23
- package/client/bin/livedesk-client-fast.js +23 -23
- package/client/bin/livedesk-client-node.js +65 -65
- package/client/bin/livedesk-client-update-bootstrap.cjs +319 -319
- package/client/package.json +6 -6
- package/client/src/runtime/agent-process-lifecycle.js +860 -860
- package/client/src/runtime/client-runtime-server.js +10 -10
- package/client/src/runtime/hub-wake-listener.js +159 -159
- package/client/src/runtime/linux-video-acceleration.js +390 -390
- package/client/src/runtime/windows-owned-process-manifest.js +402 -402
- package/client/tests/client-version.test.mjs +27 -27
- package/diagnostics/livedesk-mac-physical-gate-core.mjs +1844 -1844
- package/diagnostics/livedesk-mac-physical-isolation.mjs +354 -354
- package/diagnostics/livedesk-transport-physical-core.mjs +702 -702
- package/diagnostics/livedesk-transport-physical.mjs +567 -567
- package/electron/auth-config.mjs +10 -10
- package/electron/bounded-desktop-log.mjs +609 -609
- package/electron/electron-builder.e2e.yml +8 -8
- package/electron/electron-builder.win.yml +38 -38
- package/electron/electron-builder.yml +4 -4
- package/electron/icon.svg +11 -11
- package/electron/oauth-pkce.mjs +143 -143
- package/electron/preload.cjs +13 -13
- package/electron/runtime-process-owner.mjs +287 -287
- package/electron/update-feed.json +4 -4
- package/hub/package.json +2 -2
- package/hub/src/agents/agent-device-scope.js +29 -29
- package/hub/src/agents/agent-manager.js +103 -103
- package/hub/src/agents/agent-permission-store.js +78 -78
- package/hub/src/agents/agent-runtime-error.js +9 -9
- package/hub/src/agents/agent-settings.js +71 -71
- package/hub/src/agents/codex-agent-runtime.js +594 -594
- package/hub/src/agents/codex-mcp-server.js +100 -100
- package/hub/src/filesystem/directory-reader.js +187 -187
- package/hub/src/filesystem/hub-filesystem.js +78 -78
- package/hub/src/filesystem/path-registry.js +78 -78
- package/hub/src/filesystem/roots.js +115 -115
- package/hub/src/frame-packet-contract.mjs +427 -427
- package/hub/src/http/hub-ui-session.js +119 -119
- package/hub/src/live-capture-transition-retry.mjs +297 -297
- package/hub/src/live-desk-update.js +88 -88
- package/hub/src/live-stream-monitor-contract.js +38 -38
- package/hub/src/lzo1x.js +109 -109
- package/hub/src/mode4-atlas-pool.js +137 -137
- package/hub/src/mode4-atlas-sizing.js +32 -32
- package/hub/src/mode4-atlas-worker.js +599 -599
- package/hub/src/mode4-atlas.js +306 -306
- package/hub/src/remote-audio-subscription-contract.mjs +109 -109
- package/hub/src/remote-audio-subscription-contract.test.mjs +72 -72
- package/hub/src/remote-hub.js +140 -111
- package/hub/src/server.js +190 -175
- package/hub/src/settings/effective-device-policy.js +16 -16
- package/hub/src/transport/udp-protocol.js +453 -453
- package/package.json +7 -7
- package/runtime-core/package.json +1 -1
- package/runtime-core/src/auth-config.js +48 -48
- package/runtime-core/src/auth-http.js +29 -29
- package/runtime-core/src/auth-session.js +36 -36
- package/runtime-core/src/role-transition-supervisor.js +384 -384
- package/runtime-core/src/windows-owned-process-tree.js +580 -580
- package/scripts/sync-web-dist.js +115 -115
- package/web/dist/_headers +2 -2
- package/web/dist/assets/{index-PHlwNiVH.js → index-DqXhTKiG.js} +1 -1
- package/web/dist/favicon.svg +11 -11
- package/web/dist/index.html +16 -16
- package/web/dist/livedesk-build-evidence.json +14 -14
package/bin/livedesk.js
CHANGED
|
@@ -31,16 +31,16 @@ import {
|
|
|
31
31
|
isKnownLiveDeskCaptureHelperProcess,
|
|
32
32
|
isKnownLiveDeskClientAgentProcess
|
|
33
33
|
} from '../bootstrap/client-process-identity.js';
|
|
34
|
-
import { runLegacyClientUpdateSupervisorCli } from '../bootstrap/legacy-client-update.js';
|
|
35
|
-
import { transferSavedClientSessionToHub } from '../bootstrap/hub-auth-handoff.js';
|
|
36
|
-
import {
|
|
37
|
-
buildUpdateHostWorkerEnvironment,
|
|
38
|
-
cancelUpdateHostJob,
|
|
39
|
-
ensureUpdateHost,
|
|
40
|
-
getUpdateHostJob,
|
|
41
|
-
submitUpdateHostJob,
|
|
42
|
-
updateHostEnvironment
|
|
43
|
-
} from '../bootstrap/update-host-client.mjs';
|
|
34
|
+
import { runLegacyClientUpdateSupervisorCli } from '../bootstrap/legacy-client-update.js';
|
|
35
|
+
import { transferSavedClientSessionToHub } from '../bootstrap/hub-auth-handoff.js';
|
|
36
|
+
import {
|
|
37
|
+
buildUpdateHostWorkerEnvironment,
|
|
38
|
+
cancelUpdateHostJob,
|
|
39
|
+
ensureUpdateHost,
|
|
40
|
+
getUpdateHostJob,
|
|
41
|
+
submitUpdateHostJob,
|
|
42
|
+
updateHostEnvironment
|
|
43
|
+
} from '../bootstrap/update-host-client.mjs';
|
|
44
44
|
import {
|
|
45
45
|
consumeDeadWindowsOwnedProcessManifest,
|
|
46
46
|
readDeadWindowsOwnedProcessManifest,
|
|
@@ -228,80 +228,80 @@ function readBoundedMilliseconds(value, fallback, minimum = 1) {
|
|
|
228
228
|
return Number.isFinite(parsed) && parsed >= minimum ? Math.round(parsed) : fallback;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
async function cancelUnclaimedHubUpdateHostJob(updateHost, jobId, reason) {
|
|
232
|
-
try {
|
|
233
|
-
await cancelUpdateHostJob(updateHost, jobId, reason);
|
|
234
|
-
} catch (error) {
|
|
235
|
-
const job = await getUpdateHostJob(updateHost, jobId).catch(() => null);
|
|
236
|
-
if (job && ['accepted', 'running', 'cancelling'].includes(String(job.state || ''))) {
|
|
237
|
-
throw new Error(
|
|
238
|
-
`Update Host job ${jobId} could not be cancelled: ${error instanceof Error ? error.message : String(error)}`
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
async function waitForHubRestartUpdateHostClaim(updateHost, jobId, expected) {
|
|
245
|
-
const claimDeadline = Date.now() + expected.timeoutMs;
|
|
246
|
-
let matchingClaimSince = 0;
|
|
247
|
-
let workerPid = 0;
|
|
248
|
-
while (Date.now() < claimDeadline) {
|
|
249
|
-
const job = await getUpdateHostJob(updateHost, jobId, {
|
|
250
|
-
timeoutMs: Math.min(2_000, Math.max(250, claimDeadline - Date.now()))
|
|
251
|
-
});
|
|
252
|
-
if (!job) {
|
|
253
|
-
throw new Error(`LiveDesk Update Host lost job ${jobId} before handoff.`);
|
|
254
|
-
}
|
|
255
|
-
if (['failed', 'cancelled'].includes(String(job.state || ''))) {
|
|
256
|
-
throw new Error(
|
|
257
|
-
`LiveDesk Update Host job ${jobId} failed before handoff: ${job.error || `state=${job.state}`}`
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
workerPid = Number(job.workerPid || 0);
|
|
261
|
-
const claim = readJsonFile(expected.resultPath);
|
|
262
|
-
if (
|
|
263
|
-
job.state === 'running'
|
|
264
|
-
&& workerPid > 1
|
|
265
|
-
&& claim?.operationId === expected.operationId
|
|
266
|
-
&& claim?.stage === 'waiting-for-old-launcher'
|
|
267
|
-
&& claim?.outcome === 'in-progress'
|
|
268
|
-
&& Number(claim?.supervisorPid || 0) === workerPid
|
|
269
|
-
&& Number(claim?.launcherPid || 0) === expected.launcherPid
|
|
270
|
-
&& claim?.targetVersion === expected.targetVersion
|
|
271
|
-
&& claim?.handoffToken === expected.handoffToken
|
|
272
|
-
) {
|
|
273
|
-
if (!matchingClaimSince) matchingClaimSince = Date.now();
|
|
274
|
-
if (Date.now() - matchingClaimSince >= expected.stabilityMs) {
|
|
275
|
-
await delay(HUB_UPDATE_SUPERVISOR_HANDSHAKE_POLL_MS);
|
|
276
|
-
const stableJob = await getUpdateHostJob(updateHost, jobId, { timeoutMs: 2_000 });
|
|
277
|
-
const stableClaim = readJsonFile(expected.resultPath);
|
|
278
|
-
if (
|
|
279
|
-
stableJob?.state === 'running'
|
|
280
|
-
&& Number(stableJob?.workerPid || 0) === workerPid
|
|
281
|
-
&& stableClaim?.operationId === expected.operationId
|
|
282
|
-
&& stableClaim?.stage === 'waiting-for-old-launcher'
|
|
283
|
-
&& stableClaim?.outcome === 'in-progress'
|
|
284
|
-
&& Number(stableClaim?.supervisorPid || 0) === workerPid
|
|
285
|
-
&& Number(stableClaim?.launcherPid || 0) === expected.launcherPid
|
|
286
|
-
&& stableClaim?.targetVersion === expected.targetVersion
|
|
287
|
-
&& stableClaim?.handoffToken === expected.handoffToken
|
|
288
|
-
) {
|
|
289
|
-
return stableClaim;
|
|
290
|
-
}
|
|
291
|
-
matchingClaimSince = 0;
|
|
292
|
-
}
|
|
293
|
-
} else {
|
|
294
|
-
matchingClaimSince = 0;
|
|
295
|
-
}
|
|
296
|
-
await delay(Math.max(50, HUB_UPDATE_SUPERVISOR_HANDSHAKE_POLL_MS));
|
|
297
|
-
}
|
|
298
|
-
throw new Error(
|
|
299
|
-
`LiveDesk Update Host job ${jobId} did not publish an atomic handoff for `
|
|
300
|
-
+ `operation ${expected.operationId} within ${expected.timeoutMs}ms.`
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function writeJsonAtomic(filePath, value) {
|
|
231
|
+
async function cancelUnclaimedHubUpdateHostJob(updateHost, jobId, reason) {
|
|
232
|
+
try {
|
|
233
|
+
await cancelUpdateHostJob(updateHost, jobId, reason);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
const job = await getUpdateHostJob(updateHost, jobId).catch(() => null);
|
|
236
|
+
if (job && ['accepted', 'running', 'cancelling'].includes(String(job.state || ''))) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
`Update Host job ${jobId} could not be cancelled: ${error instanceof Error ? error.message : String(error)}`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function waitForHubRestartUpdateHostClaim(updateHost, jobId, expected) {
|
|
245
|
+
const claimDeadline = Date.now() + expected.timeoutMs;
|
|
246
|
+
let matchingClaimSince = 0;
|
|
247
|
+
let workerPid = 0;
|
|
248
|
+
while (Date.now() < claimDeadline) {
|
|
249
|
+
const job = await getUpdateHostJob(updateHost, jobId, {
|
|
250
|
+
timeoutMs: Math.min(2_000, Math.max(250, claimDeadline - Date.now()))
|
|
251
|
+
});
|
|
252
|
+
if (!job) {
|
|
253
|
+
throw new Error(`LiveDesk Update Host lost job ${jobId} before handoff.`);
|
|
254
|
+
}
|
|
255
|
+
if (['failed', 'cancelled'].includes(String(job.state || ''))) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
`LiveDesk Update Host job ${jobId} failed before handoff: ${job.error || `state=${job.state}`}`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
workerPid = Number(job.workerPid || 0);
|
|
261
|
+
const claim = readJsonFile(expected.resultPath);
|
|
262
|
+
if (
|
|
263
|
+
job.state === 'running'
|
|
264
|
+
&& workerPid > 1
|
|
265
|
+
&& claim?.operationId === expected.operationId
|
|
266
|
+
&& claim?.stage === 'waiting-for-old-launcher'
|
|
267
|
+
&& claim?.outcome === 'in-progress'
|
|
268
|
+
&& Number(claim?.supervisorPid || 0) === workerPid
|
|
269
|
+
&& Number(claim?.launcherPid || 0) === expected.launcherPid
|
|
270
|
+
&& claim?.targetVersion === expected.targetVersion
|
|
271
|
+
&& claim?.handoffToken === expected.handoffToken
|
|
272
|
+
) {
|
|
273
|
+
if (!matchingClaimSince) matchingClaimSince = Date.now();
|
|
274
|
+
if (Date.now() - matchingClaimSince >= expected.stabilityMs) {
|
|
275
|
+
await delay(HUB_UPDATE_SUPERVISOR_HANDSHAKE_POLL_MS);
|
|
276
|
+
const stableJob = await getUpdateHostJob(updateHost, jobId, { timeoutMs: 2_000 });
|
|
277
|
+
const stableClaim = readJsonFile(expected.resultPath);
|
|
278
|
+
if (
|
|
279
|
+
stableJob?.state === 'running'
|
|
280
|
+
&& Number(stableJob?.workerPid || 0) === workerPid
|
|
281
|
+
&& stableClaim?.operationId === expected.operationId
|
|
282
|
+
&& stableClaim?.stage === 'waiting-for-old-launcher'
|
|
283
|
+
&& stableClaim?.outcome === 'in-progress'
|
|
284
|
+
&& Number(stableClaim?.supervisorPid || 0) === workerPid
|
|
285
|
+
&& Number(stableClaim?.launcherPid || 0) === expected.launcherPid
|
|
286
|
+
&& stableClaim?.targetVersion === expected.targetVersion
|
|
287
|
+
&& stableClaim?.handoffToken === expected.handoffToken
|
|
288
|
+
) {
|
|
289
|
+
return stableClaim;
|
|
290
|
+
}
|
|
291
|
+
matchingClaimSince = 0;
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
matchingClaimSince = 0;
|
|
295
|
+
}
|
|
296
|
+
await delay(Math.max(50, HUB_UPDATE_SUPERVISOR_HANDSHAKE_POLL_MS));
|
|
297
|
+
}
|
|
298
|
+
throw new Error(
|
|
299
|
+
`LiveDesk Update Host job ${jobId} did not publish an atomic handoff for `
|
|
300
|
+
+ `operation ${expected.operationId} within ${expected.timeoutMs}ms.`
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function writeJsonAtomic(filePath, value) {
|
|
305
305
|
if (!filePath) return;
|
|
306
306
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
307
307
|
const previous = readJsonFile(filePath);
|
|
@@ -2445,7 +2445,7 @@ function buildHubRestartBootstrapScript() {
|
|
|
2445
2445
|
].join('\n');
|
|
2446
2446
|
}
|
|
2447
2447
|
|
|
2448
|
-
async function runManager(args, resolvedRole = null, runtimeLock = null, updateHost = null) {
|
|
2448
|
+
async function runManager(args, resolvedRole = null, runtimeLock = null, updateHost = null) {
|
|
2449
2449
|
const runtimeOwner = runtimeLock?.payload || null;
|
|
2450
2450
|
const options = parseManagerArgs(args);
|
|
2451
2451
|
const httpPort = normalizePort(
|
|
@@ -2493,7 +2493,7 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
|
|
|
2493
2493
|
LIVEDESK_HUB_HTTP_PORT: String(httpPort),
|
|
2494
2494
|
LIVEDESK_MANAGER_VERSION: readVersion(),
|
|
2495
2495
|
LIVEDESK_CLIENT_PACKAGE_VERSION: readClientVersion(),
|
|
2496
|
-
LIVEDESK_HUB_UPDATE_REQUEST_PATH: updateHost?.available ? updateRequestPath : '',
|
|
2496
|
+
LIVEDESK_HUB_UPDATE_REQUEST_PATH: updateHost?.available ? updateRequestPath : '',
|
|
2497
2497
|
LIVEDESK_HUB_UPDATE_RESULT_PATH: hubUpdateResultPath,
|
|
2498
2498
|
LIVEDESK_UDP_ENABLED: String(process.env.LIVEDESK_UDP_ENABLED || '1'),
|
|
2499
2499
|
LIVEDESK_UDP_PREFER_P2P: String(process.env.LIVEDESK_UDP_PREFER_P2P || '0'),
|
|
@@ -2621,10 +2621,10 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
|
|
|
2621
2621
|
process.on(signal, handler);
|
|
2622
2622
|
}
|
|
2623
2623
|
|
|
2624
|
-
const restartWithLatest = async request => {
|
|
2625
|
-
if (!updateHost?.available) {
|
|
2626
|
-
throw new Error('The independent LiveDesk Update Host is unavailable. The unchanged Hub remains running.');
|
|
2627
|
-
}
|
|
2624
|
+
const restartWithLatest = async request => {
|
|
2625
|
+
if (!updateHost?.available) {
|
|
2626
|
+
throw new Error('The independent LiveDesk Update Host is unavailable. The unchanged Hub remains running.');
|
|
2627
|
+
}
|
|
2628
2628
|
const requestedVersion = normalizeExactUpdateVersion(request?.latestVersion);
|
|
2629
2629
|
if (!requestedVersion) {
|
|
2630
2630
|
throw new Error('The Hub update target version must be one exact semantic version.');
|
|
@@ -2641,9 +2641,9 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
|
|
|
2641
2641
|
);
|
|
2642
2642
|
const packageTarget = `livedesk@${requestedVersion}`;
|
|
2643
2643
|
const nextArgs = [
|
|
2644
|
-
'-y',
|
|
2645
|
-
'--prefer-offline',
|
|
2646
|
-
'--prefix',
|
|
2644
|
+
'-y',
|
|
2645
|
+
'--prefer-offline',
|
|
2646
|
+
'--prefix',
|
|
2647
2647
|
neutralCwd,
|
|
2648
2648
|
'--workspaces=false',
|
|
2649
2649
|
packageTarget,
|
|
@@ -2681,82 +2681,82 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
|
|
|
2681
2681
|
reportLauncherUpdate(`[LiveDesk Hub] Could not persist the restart supervisor state: ${error instanceof Error ? error.message : String(error)}.`, true);
|
|
2682
2682
|
throw error;
|
|
2683
2683
|
}
|
|
2684
|
-
const workerEnvironment = buildUpdateHostWorkerEnvironment(process.env, {
|
|
2685
|
-
LIVEDESK_RESTART_WAIT_PID: String(process.pid),
|
|
2686
|
-
LIVEDESK_RESTART_PREVIOUS_RUNTIME_PID: String(request?.pid || 0),
|
|
2687
|
-
LIVEDESK_RESTART_OPERATION_ID: operationId,
|
|
2688
|
-
LIVEDESK_RESTART_STARTED_AT: restartStartedAt,
|
|
2689
|
-
LIVEDESK_RESTART_HANDOFF_TOKEN: handoffToken,
|
|
2690
|
-
LIVEDESK_RESTART_RESULT_PATH: hubUpdateResultPath,
|
|
2691
|
-
LIVEDESK_RESTART_COMMAND: restartInvocation.command,
|
|
2692
|
-
LIVEDESK_RESTART_ARGS_BASE64: Buffer.from(JSON.stringify(restartInvocation.args), 'utf8').toString('base64'),
|
|
2693
|
-
LIVEDESK_RESTART_FALLBACK_COMMAND: fallbackInvocation.command,
|
|
2694
|
-
LIVEDESK_RESTART_FALLBACK_ARGS_BASE64: Buffer.from(JSON.stringify(fallbackInvocation.args), 'utf8').toString('base64'),
|
|
2695
|
-
LIVEDESK_RESTART_EXPECTED_VERSION: requestedVersion,
|
|
2696
|
-
LIVEDESK_RESTART_FALLBACK_VERSION: readVersion(),
|
|
2697
|
-
LIVEDESK_RESTART_HEALTH_URL: hubProbeBaseUrl,
|
|
2698
|
-
LIVEDESK_RESTART_REMOTE_HOST: '127.0.0.1',
|
|
2699
|
-
LIVEDESK_RESTART_REMOTE_PORT: String(remotePort),
|
|
2700
|
-
LIVEDESK_RESTART_NEUTRAL_CWD: neutralCwd,
|
|
2701
|
-
LIVEDESK_RESTART_FALLBACK_CWD: originalCwd,
|
|
2702
|
-
LIVEDESK_UPDATE_ORIGINAL_CWD: originalCwd,
|
|
2703
|
-
LIVEDESK_RESTART_LOG_PATH: hubLogPath
|
|
2704
|
-
});
|
|
2705
|
-
const hostJobId = `hub-${safeUpdatePathSegment(operationId)}`;
|
|
2706
|
-
let hostJob;
|
|
2707
|
-
try {
|
|
2708
|
-
const submitted = await submitUpdateHostJob(updateHost, {
|
|
2709
|
-
jobId: hostJobId,
|
|
2710
|
-
kind: 'hub-update',
|
|
2711
|
-
operationId,
|
|
2712
|
-
command: process.execPath,
|
|
2713
|
-
args: ['-e', buildHubRestartBootstrapScript()],
|
|
2714
|
-
cwd: neutralCwd,
|
|
2715
|
-
env: workerEnvironment,
|
|
2716
|
-
resultPath: hubUpdateResultPath,
|
|
2717
|
-
requestedAt: restartStartedAt,
|
|
2718
|
-
expiresAt: new Date(Date.parse(restartStartedAt) + 90 * 60_000).toISOString()
|
|
2719
|
-
}, { timeoutMs: handshakeTimeoutMs });
|
|
2720
|
-
hostJob = submitted?.job || null;
|
|
2721
|
-
if (!hostJob || Number(hostJob.workerPid || 0) <= 1) {
|
|
2722
|
-
throw new Error('LiveDesk Update Host accepted the request without a worker identity.');
|
|
2723
|
-
}
|
|
2724
|
-
} catch (error) {
|
|
2725
|
-
throw new Error(`LiveDesk Update Host rejected the Hub replacement: ${error instanceof Error ? error.message : String(error)}`);
|
|
2726
|
-
}
|
|
2727
|
-
try {
|
|
2728
|
-
await waitForHubRestartUpdateHostClaim(updateHost, hostJobId, {
|
|
2729
|
-
operationId,
|
|
2730
|
-
targetVersion: requestedVersion,
|
|
2731
|
-
resultPath: hubUpdateResultPath,
|
|
2684
|
+
const workerEnvironment = buildUpdateHostWorkerEnvironment(process.env, {
|
|
2685
|
+
LIVEDESK_RESTART_WAIT_PID: String(process.pid),
|
|
2686
|
+
LIVEDESK_RESTART_PREVIOUS_RUNTIME_PID: String(request?.pid || 0),
|
|
2687
|
+
LIVEDESK_RESTART_OPERATION_ID: operationId,
|
|
2688
|
+
LIVEDESK_RESTART_STARTED_AT: restartStartedAt,
|
|
2689
|
+
LIVEDESK_RESTART_HANDOFF_TOKEN: handoffToken,
|
|
2690
|
+
LIVEDESK_RESTART_RESULT_PATH: hubUpdateResultPath,
|
|
2691
|
+
LIVEDESK_RESTART_COMMAND: restartInvocation.command,
|
|
2692
|
+
LIVEDESK_RESTART_ARGS_BASE64: Buffer.from(JSON.stringify(restartInvocation.args), 'utf8').toString('base64'),
|
|
2693
|
+
LIVEDESK_RESTART_FALLBACK_COMMAND: fallbackInvocation.command,
|
|
2694
|
+
LIVEDESK_RESTART_FALLBACK_ARGS_BASE64: Buffer.from(JSON.stringify(fallbackInvocation.args), 'utf8').toString('base64'),
|
|
2695
|
+
LIVEDESK_RESTART_EXPECTED_VERSION: requestedVersion,
|
|
2696
|
+
LIVEDESK_RESTART_FALLBACK_VERSION: readVersion(),
|
|
2697
|
+
LIVEDESK_RESTART_HEALTH_URL: hubProbeBaseUrl,
|
|
2698
|
+
LIVEDESK_RESTART_REMOTE_HOST: '127.0.0.1',
|
|
2699
|
+
LIVEDESK_RESTART_REMOTE_PORT: String(remotePort),
|
|
2700
|
+
LIVEDESK_RESTART_NEUTRAL_CWD: neutralCwd,
|
|
2701
|
+
LIVEDESK_RESTART_FALLBACK_CWD: originalCwd,
|
|
2702
|
+
LIVEDESK_UPDATE_ORIGINAL_CWD: originalCwd,
|
|
2703
|
+
LIVEDESK_RESTART_LOG_PATH: hubLogPath
|
|
2704
|
+
});
|
|
2705
|
+
const hostJobId = `hub-${safeUpdatePathSegment(operationId)}`;
|
|
2706
|
+
let hostJob;
|
|
2707
|
+
try {
|
|
2708
|
+
const submitted = await submitUpdateHostJob(updateHost, {
|
|
2709
|
+
jobId: hostJobId,
|
|
2710
|
+
kind: 'hub-update',
|
|
2711
|
+
operationId,
|
|
2712
|
+
command: process.execPath,
|
|
2713
|
+
args: ['-e', buildHubRestartBootstrapScript()],
|
|
2714
|
+
cwd: neutralCwd,
|
|
2715
|
+
env: workerEnvironment,
|
|
2716
|
+
resultPath: hubUpdateResultPath,
|
|
2717
|
+
requestedAt: restartStartedAt,
|
|
2718
|
+
expiresAt: new Date(Date.parse(restartStartedAt) + 90 * 60_000).toISOString()
|
|
2719
|
+
}, { timeoutMs: handshakeTimeoutMs });
|
|
2720
|
+
hostJob = submitted?.job || null;
|
|
2721
|
+
if (!hostJob || Number(hostJob.workerPid || 0) <= 1) {
|
|
2722
|
+
throw new Error('LiveDesk Update Host accepted the request without a worker identity.');
|
|
2723
|
+
}
|
|
2724
|
+
} catch (error) {
|
|
2725
|
+
throw new Error(`LiveDesk Update Host rejected the Hub replacement: ${error instanceof Error ? error.message : String(error)}`);
|
|
2726
|
+
}
|
|
2727
|
+
try {
|
|
2728
|
+
await waitForHubRestartUpdateHostClaim(updateHost, hostJobId, {
|
|
2729
|
+
operationId,
|
|
2730
|
+
targetVersion: requestedVersion,
|
|
2731
|
+
resultPath: hubUpdateResultPath,
|
|
2732
2732
|
launcherPid: process.pid,
|
|
2733
2733
|
handoffToken,
|
|
2734
2734
|
timeoutMs: handshakeTimeoutMs,
|
|
2735
2735
|
stabilityMs: HUB_UPDATE_SUPERVISOR_CLAIM_STABILITY_MS
|
|
2736
2736
|
});
|
|
2737
|
-
} catch (handshakeError) {
|
|
2738
|
-
let stopError = null;
|
|
2739
|
-
try {
|
|
2740
|
-
await cancelUnclaimedHubUpdateHostJob(updateHost, hostJobId, 'Hub handoff was not proven.');
|
|
2741
|
-
} catch (error) {
|
|
2742
|
-
stopError = error;
|
|
2743
|
-
}
|
|
2737
|
+
} catch (handshakeError) {
|
|
2738
|
+
let stopError = null;
|
|
2739
|
+
try {
|
|
2740
|
+
await cancelUnclaimedHubUpdateHostJob(updateHost, hostJobId, 'Hub handoff was not proven.');
|
|
2741
|
+
} catch (error) {
|
|
2742
|
+
stopError = error;
|
|
2743
|
+
}
|
|
2744
2744
|
const error = new Error(
|
|
2745
2745
|
`Hub restart supervisor handoff failed: `
|
|
2746
2746
|
+ `${handshakeError instanceof Error ? handshakeError.message : String(handshakeError)}`
|
|
2747
2747
|
+ `${stopError ? ` ${stopError.message}` : ''}`
|
|
2748
2748
|
);
|
|
2749
|
-
error.supervisorPid = Number(hostJob?.workerPid || 0);
|
|
2750
|
-
error.updateHostPid = Number(updateHost?.host?.pid || 0);
|
|
2751
|
-
error.handoffToken = handoffToken;
|
|
2752
|
-
error.handoffCancelled = true;
|
|
2753
|
-
throw error;
|
|
2754
|
-
}
|
|
2755
|
-
reportLauncherUpdate(
|
|
2756
|
-
`[LiveDesk Hub] Update handoff claimed target=${requestedVersion} `
|
|
2757
|
-
+ `updateHostPid=${updateHost.host?.pid || 0} workerPid=${hostJob.workerPid || 0} operation=${operationId}. `
|
|
2758
|
-
+ `The current launcher will now exit. Restart diagnostics: ${hubLogPath}`
|
|
2759
|
-
);
|
|
2749
|
+
error.supervisorPid = Number(hostJob?.workerPid || 0);
|
|
2750
|
+
error.updateHostPid = Number(updateHost?.host?.pid || 0);
|
|
2751
|
+
error.handoffToken = handoffToken;
|
|
2752
|
+
error.handoffCancelled = true;
|
|
2753
|
+
throw error;
|
|
2754
|
+
}
|
|
2755
|
+
reportLauncherUpdate(
|
|
2756
|
+
`[LiveDesk Hub] Update handoff claimed target=${requestedVersion} `
|
|
2757
|
+
+ `updateHostPid=${updateHost.host?.pid || 0} workerPid=${hostJob.workerPid || 0} operation=${operationId}. `
|
|
2758
|
+
+ `The current launcher will now exit. Restart diagnostics: ${hubLogPath}`
|
|
2759
|
+
);
|
|
2760
2760
|
process.exit(0);
|
|
2761
2761
|
};
|
|
2762
2762
|
|
|
@@ -3034,19 +3034,22 @@ async function runManager(args, resolvedRole = null, runtimeLock = null, updateH
|
|
|
3034
3034
|
updatePollId = setInterval(pollUpdateRequest, HUB_UPDATE_POLL_MS);
|
|
3035
3035
|
|
|
3036
3036
|
const hubReady = waitForManager(hubProbeBaseUrl);
|
|
3037
|
-
const hubStartup = hubReady.then(
|
|
3037
|
+
const hubStartup = hubReady.then(ok => {
|
|
3038
3038
|
if (!ok) {
|
|
3039
3039
|
return false;
|
|
3040
3040
|
}
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3041
|
+
void transferSavedClientSessionToHub(hubProbeBaseUrl, MANAGER_STATE_DIR).then(handoff => {
|
|
3042
|
+
if (handoff.ok) {
|
|
3043
|
+
reportLauncherUpdate('[LiveDesk Hub] Saved Client sign-in adopted by the Hub.');
|
|
3044
|
+
if (!handoff.hostTargetOk) {
|
|
3045
|
+
reportLauncherUpdate('[LiveDesk Hub] Sign-in was adopted; host publication will continue through lease renewal.', true);
|
|
3046
|
+
}
|
|
3047
|
+
} else if (!handoff.skipped) {
|
|
3048
|
+
reportLauncherUpdate(`[LiveDesk Hub] Saved Client sign-in could not be adopted: ${handoff.reason}. Continue sign-in in the Hub page.`, true);
|
|
3046
3049
|
}
|
|
3047
|
-
}
|
|
3048
|
-
reportLauncherUpdate(`[LiveDesk Hub] Saved Client sign-in could not be adopted: ${
|
|
3049
|
-
}
|
|
3050
|
+
}).catch(error => {
|
|
3051
|
+
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);
|
|
3052
|
+
});
|
|
3050
3053
|
return true;
|
|
3051
3054
|
});
|
|
3052
3055
|
|
|
@@ -3285,30 +3288,30 @@ async function main() {
|
|
|
3285
3288
|
});
|
|
3286
3289
|
}
|
|
3287
3290
|
}
|
|
3288
|
-
if (!lock.acquired) {
|
|
3289
|
-
reportExistingRuntime(lock.existing || { role: resolvedRole.role, pid: 'unknown' });
|
|
3290
|
-
return;
|
|
3291
|
-
}
|
|
3292
|
-
process.once('exit', lock.release);
|
|
3293
|
-
|
|
3294
|
-
const updateHost = await ensureUpdateHost({
|
|
3295
|
-
stateDir: MANAGER_STATE_DIR,
|
|
3296
|
-
entryPath: resolve(packageRoot, 'bootstrap', 'update-host.mjs'),
|
|
3297
|
-
sourceVersion: readVersion(),
|
|
3298
|
-
env: process.env
|
|
3299
|
-
});
|
|
3300
|
-
Object.assign(process.env, updateHostEnvironment(updateHost));
|
|
3301
|
-
if (updateHost.available) {
|
|
3302
|
-
console.log(
|
|
3303
|
-
`[LiveDesk] Independent Update Host ready pid=${updateHost.host?.pid || 'unknown'} `
|
|
3304
|
-
+ `source=${updateHost.host?.sourceVersion || readVersion()}.`
|
|
3305
|
-
);
|
|
3306
|
-
} else if (!updateHost.disabled) {
|
|
3307
|
-
console.warn(
|
|
3308
|
-
`[LiveDesk] Independent Update Host is unavailable; updates are disabled for this run: `
|
|
3309
|
-
+ `${updateHost.error || 'unknown error'}`
|
|
3310
|
-
);
|
|
3311
|
-
}
|
|
3291
|
+
if (!lock.acquired) {
|
|
3292
|
+
reportExistingRuntime(lock.existing || { role: resolvedRole.role, pid: 'unknown' });
|
|
3293
|
+
return;
|
|
3294
|
+
}
|
|
3295
|
+
process.once('exit', lock.release);
|
|
3296
|
+
|
|
3297
|
+
const updateHost = await ensureUpdateHost({
|
|
3298
|
+
stateDir: MANAGER_STATE_DIR,
|
|
3299
|
+
entryPath: resolve(packageRoot, 'bootstrap', 'update-host.mjs'),
|
|
3300
|
+
sourceVersion: readVersion(),
|
|
3301
|
+
env: process.env
|
|
3302
|
+
});
|
|
3303
|
+
Object.assign(process.env, updateHostEnvironment(updateHost));
|
|
3304
|
+
if (updateHost.available) {
|
|
3305
|
+
console.log(
|
|
3306
|
+
`[LiveDesk] Independent Update Host ready pid=${updateHost.host?.pid || 'unknown'} `
|
|
3307
|
+
+ `source=${updateHost.host?.sourceVersion || readVersion()}.`
|
|
3308
|
+
);
|
|
3309
|
+
} else if (!updateHost.disabled) {
|
|
3310
|
+
console.warn(
|
|
3311
|
+
`[LiveDesk] Independent Update Host is unavailable; updates are disabled for this run: `
|
|
3312
|
+
+ `${updateHost.error || 'unknown error'}`
|
|
3313
|
+
);
|
|
3314
|
+
}
|
|
3312
3315
|
|
|
3313
3316
|
// Only the contender that won the replacement lock may clean residual
|
|
3314
3317
|
// listener ports. A simultaneous losing launcher must never kill the newly
|
|
@@ -3352,16 +3355,16 @@ async function main() {
|
|
|
3352
3355
|
await runClient(runtimeArgs, resolvedRole, lock);
|
|
3353
3356
|
return;
|
|
3354
3357
|
}
|
|
3355
|
-
if (command === 'hub' || command === 'manager') {
|
|
3356
|
-
await runManager(runtimeArgs, resolvedRole, lock, updateHost);
|
|
3358
|
+
if (command === 'hub' || command === 'manager') {
|
|
3359
|
+
await runManager(runtimeArgs, resolvedRole, lock, updateHost);
|
|
3357
3360
|
return;
|
|
3358
3361
|
}
|
|
3359
3362
|
if (resolvedRole.role === 'client') {
|
|
3360
3363
|
await runClient(runtimeArgs, resolvedRole, lock);
|
|
3361
3364
|
return;
|
|
3362
3365
|
}
|
|
3363
|
-
await runManager(runtimeArgs, resolvedRole, lock, updateHost);
|
|
3364
|
-
}
|
|
3366
|
+
await runManager(runtimeArgs, resolvedRole, lock, updateHost);
|
|
3367
|
+
}
|
|
3365
3368
|
|
|
3366
3369
|
main().catch(error => {
|
|
3367
3370
|
console.error(error?.message || error);
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
function firstCommandArgument(commandLine) {
|
|
2
|
-
const value = String(commandLine || '').trim();
|
|
3
|
-
if (!value) return '';
|
|
4
|
-
const quote = value[0] === '"' || value[0] === "'" ? value[0] : '';
|
|
5
|
-
if (!quote) return value.split(/\s+/, 1)[0] || '';
|
|
6
|
-
const end = value.indexOf(quote, 1);
|
|
7
|
-
return end > 0 ? value.slice(1, end) : '';
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function normalizeExecutablePath(value) {
|
|
11
|
-
return String(value || '').trim().replaceAll('\\', '/').replace(/\s+\(deleted\)$/i, '');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const BUNDLED_FAST_ROOT = '(?:node_modules/(?:livedesk/client|@livedesk/client)|packages/(?:livedesk/client|client))/fast/[^/\\s]+';
|
|
15
|
-
const OPTIONAL_FAST_ROOT = 'node_modules/@livedesk/fast-(?:linux-x64|osx-arm64|osx-x64|win-x64)/fast';
|
|
16
|
-
const FAST_ROOT = `(?:${BUNDLED_FAST_ROOT}|${OPTIONAL_FAST_ROOT})`;
|
|
17
|
-
const KNOWN_FAST_EXECUTABLE_PATH = new RegExp(`${FAST_ROOT}/livedesk-client-fast(?:\\.exe)?$`, 'i');
|
|
18
|
-
|
|
19
|
-
export function isKnownLiveDeskClientAgentProcess(processName, commandLine, executablePath = '') {
|
|
20
|
-
const normalizedName = String(processName || '').trim().replaceAll('\\', '/').split('/').pop() || '';
|
|
21
|
-
const normalizedCommandLine = String(commandLine || '').replaceAll('\\', '/');
|
|
22
|
-
const isNode = /^(?:node|node\.exe)$/i.test(normalizedName);
|
|
23
|
-
const isDotnet = /^(?:dotnet|dotnet\.exe)$/i.test(normalizedName);
|
|
24
|
-
const isFast = /^livedesk-client-fast(?:\.exe)?$/i.test(normalizedName);
|
|
25
|
-
// Linux TASK_COMM_LEN exposes a 15-character `comm`, so the native apphost
|
|
26
|
-
// appears as `livedesk-client`. Accept that truncated name only when an
|
|
27
|
-
// independently resolved executable path, or argv[0], proves the canonical
|
|
28
|
-
// packaged LiveDesk Fast binary. A matching path elsewhere in argv is not
|
|
29
|
-
// sufficient.
|
|
30
|
-
const isTruncatedLinuxFast = /^livedesk-client$/i.test(normalizedName);
|
|
31
|
-
const isKnownNodeAgent = /(?:node_modules\/(?:livedesk\/client|@livedesk\/client)|packages\/(?:livedesk\/client|client))\/bin\/livedesk-client-node\.js(?:\s|["']|$)/i.test(normalizedCommandLine);
|
|
32
|
-
const isKnownFastExecutable = new RegExp(
|
|
33
|
-
`${FAST_ROOT}/livedesk-client-fast(?:\\.exe)?(?:\\s|["']|$)`,
|
|
34
|
-
'i'
|
|
35
|
-
).test(normalizedCommandLine);
|
|
36
|
-
const isKnownFastDll = new RegExp(
|
|
37
|
-
`${FAST_ROOT}/livedesk-client-fast\\.dll(?:\\s|["']|$)`,
|
|
38
|
-
'i'
|
|
39
|
-
).test(normalizedCommandLine);
|
|
40
|
-
const resolvedExecutable = normalizeExecutablePath(executablePath);
|
|
41
|
-
const argvExecutable = normalizeExecutablePath(firstCommandArgument(normalizedCommandLine));
|
|
42
|
-
const hasStrictFastExecutableProof = KNOWN_FAST_EXECUTABLE_PATH.test(resolvedExecutable)
|
|
43
|
-
|| KNOWN_FAST_EXECUTABLE_PATH.test(argvExecutable);
|
|
44
|
-
return (isNode && isKnownNodeAgent)
|
|
45
|
-
|| (isFast && isKnownFastExecutable)
|
|
46
|
-
|| (isTruncatedLinuxFast && hasStrictFastExecutableProof)
|
|
47
|
-
|| (isDotnet && isKnownFastDll);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function isKnownLiveDeskCaptureHelperProcess(processName, commandLine, executablePath = '') {
|
|
51
|
-
const normalizedName = String(processName || '').trim().replaceAll('\\', '/').split('/').pop() || '';
|
|
52
|
-
const normalizedCommandLine = String(commandLine || '').replaceAll('\\', '/');
|
|
53
|
-
const normalizedExecutablePath = normalizeExecutablePath(executablePath);
|
|
54
|
-
const argvExecutable = normalizeExecutablePath(firstCommandArgument(normalizedCommandLine));
|
|
55
|
-
const videoHelperPath = /(?:^|\/)\.livedesk\/helpers\/macos-sck-h264\/livedesk-sck-h264$/i;
|
|
56
|
-
const audioHelperPath = /(?:^|\/)\.livedesk\/helpers\/macos-sck-audio\/livedesk-sck-audio$/i;
|
|
57
|
-
const knownVideoCommand = /(?:^|\/)\.livedesk\/helpers\/macos-sck-h264\/livedesk-sck-h264(?:\s|["']|$)/i
|
|
58
|
-
.test(normalizedCommandLine);
|
|
59
|
-
const knownAudioCommand = /(?:^|\/)\.livedesk\/helpers\/macos-sck-audio\/livedesk-sck-audio(?:\s|["']|$)/i
|
|
60
|
-
.test(normalizedCommandLine);
|
|
61
|
-
const strictVideoExecutableProof = videoHelperPath.test(normalizedExecutablePath)
|
|
62
|
-
|| videoHelperPath.test(argvExecutable);
|
|
63
|
-
const strictAudioExecutableProof = audioHelperPath.test(normalizedExecutablePath)
|
|
64
|
-
|| audioHelperPath.test(argvExecutable);
|
|
65
|
-
const knownRawCaptureCommand = new RegExp(
|
|
66
|
-
`^(?:"[^"]*"|'[^']*'|\\S+)\\s+["']?\\S*${FAST_ROOT}/livedesk-raw-capture-helper\\.mjs(?:["']|\\s|$)`,
|
|
67
|
-
'i'
|
|
68
|
-
).test(normalizedCommandLine);
|
|
69
|
-
return (/^livedesk-sck-h264$/i.test(normalizedName) && knownVideoCommand)
|
|
70
|
-
|| (/^livedesk-sck-h2$/i.test(normalizedName) && strictVideoExecutableProof)
|
|
71
|
-
|| (/^livedesk-sck-audio$/i.test(normalizedName) && knownAudioCommand)
|
|
72
|
-
|| (/^livedesk-sck-aud$/i.test(normalizedName) && strictAudioExecutableProof)
|
|
73
|
-
|| (/^(?:node|node\.exe)$/i.test(normalizedName) && knownRawCaptureCommand);
|
|
74
|
-
}
|
|
1
|
+
function firstCommandArgument(commandLine) {
|
|
2
|
+
const value = String(commandLine || '').trim();
|
|
3
|
+
if (!value) return '';
|
|
4
|
+
const quote = value[0] === '"' || value[0] === "'" ? value[0] : '';
|
|
5
|
+
if (!quote) return value.split(/\s+/, 1)[0] || '';
|
|
6
|
+
const end = value.indexOf(quote, 1);
|
|
7
|
+
return end > 0 ? value.slice(1, end) : '';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function normalizeExecutablePath(value) {
|
|
11
|
+
return String(value || '').trim().replaceAll('\\', '/').replace(/\s+\(deleted\)$/i, '');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const BUNDLED_FAST_ROOT = '(?:node_modules/(?:livedesk/client|@livedesk/client)|packages/(?:livedesk/client|client))/fast/[^/\\s]+';
|
|
15
|
+
const OPTIONAL_FAST_ROOT = 'node_modules/@livedesk/fast-(?:linux-x64|osx-arm64|osx-x64|win-x64)/fast';
|
|
16
|
+
const FAST_ROOT = `(?:${BUNDLED_FAST_ROOT}|${OPTIONAL_FAST_ROOT})`;
|
|
17
|
+
const KNOWN_FAST_EXECUTABLE_PATH = new RegExp(`${FAST_ROOT}/livedesk-client-fast(?:\\.exe)?$`, 'i');
|
|
18
|
+
|
|
19
|
+
export function isKnownLiveDeskClientAgentProcess(processName, commandLine, executablePath = '') {
|
|
20
|
+
const normalizedName = String(processName || '').trim().replaceAll('\\', '/').split('/').pop() || '';
|
|
21
|
+
const normalizedCommandLine = String(commandLine || '').replaceAll('\\', '/');
|
|
22
|
+
const isNode = /^(?:node|node\.exe)$/i.test(normalizedName);
|
|
23
|
+
const isDotnet = /^(?:dotnet|dotnet\.exe)$/i.test(normalizedName);
|
|
24
|
+
const isFast = /^livedesk-client-fast(?:\.exe)?$/i.test(normalizedName);
|
|
25
|
+
// Linux TASK_COMM_LEN exposes a 15-character `comm`, so the native apphost
|
|
26
|
+
// appears as `livedesk-client`. Accept that truncated name only when an
|
|
27
|
+
// independently resolved executable path, or argv[0], proves the canonical
|
|
28
|
+
// packaged LiveDesk Fast binary. A matching path elsewhere in argv is not
|
|
29
|
+
// sufficient.
|
|
30
|
+
const isTruncatedLinuxFast = /^livedesk-client$/i.test(normalizedName);
|
|
31
|
+
const isKnownNodeAgent = /(?:node_modules\/(?:livedesk\/client|@livedesk\/client)|packages\/(?:livedesk\/client|client))\/bin\/livedesk-client-node\.js(?:\s|["']|$)/i.test(normalizedCommandLine);
|
|
32
|
+
const isKnownFastExecutable = new RegExp(
|
|
33
|
+
`${FAST_ROOT}/livedesk-client-fast(?:\\.exe)?(?:\\s|["']|$)`,
|
|
34
|
+
'i'
|
|
35
|
+
).test(normalizedCommandLine);
|
|
36
|
+
const isKnownFastDll = new RegExp(
|
|
37
|
+
`${FAST_ROOT}/livedesk-client-fast\\.dll(?:\\s|["']|$)`,
|
|
38
|
+
'i'
|
|
39
|
+
).test(normalizedCommandLine);
|
|
40
|
+
const resolvedExecutable = normalizeExecutablePath(executablePath);
|
|
41
|
+
const argvExecutable = normalizeExecutablePath(firstCommandArgument(normalizedCommandLine));
|
|
42
|
+
const hasStrictFastExecutableProof = KNOWN_FAST_EXECUTABLE_PATH.test(resolvedExecutable)
|
|
43
|
+
|| KNOWN_FAST_EXECUTABLE_PATH.test(argvExecutable);
|
|
44
|
+
return (isNode && isKnownNodeAgent)
|
|
45
|
+
|| (isFast && isKnownFastExecutable)
|
|
46
|
+
|| (isTruncatedLinuxFast && hasStrictFastExecutableProof)
|
|
47
|
+
|| (isDotnet && isKnownFastDll);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function isKnownLiveDeskCaptureHelperProcess(processName, commandLine, executablePath = '') {
|
|
51
|
+
const normalizedName = String(processName || '').trim().replaceAll('\\', '/').split('/').pop() || '';
|
|
52
|
+
const normalizedCommandLine = String(commandLine || '').replaceAll('\\', '/');
|
|
53
|
+
const normalizedExecutablePath = normalizeExecutablePath(executablePath);
|
|
54
|
+
const argvExecutable = normalizeExecutablePath(firstCommandArgument(normalizedCommandLine));
|
|
55
|
+
const videoHelperPath = /(?:^|\/)\.livedesk\/helpers\/macos-sck-h264\/livedesk-sck-h264$/i;
|
|
56
|
+
const audioHelperPath = /(?:^|\/)\.livedesk\/helpers\/macos-sck-audio\/livedesk-sck-audio$/i;
|
|
57
|
+
const knownVideoCommand = /(?:^|\/)\.livedesk\/helpers\/macos-sck-h264\/livedesk-sck-h264(?:\s|["']|$)/i
|
|
58
|
+
.test(normalizedCommandLine);
|
|
59
|
+
const knownAudioCommand = /(?:^|\/)\.livedesk\/helpers\/macos-sck-audio\/livedesk-sck-audio(?:\s|["']|$)/i
|
|
60
|
+
.test(normalizedCommandLine);
|
|
61
|
+
const strictVideoExecutableProof = videoHelperPath.test(normalizedExecutablePath)
|
|
62
|
+
|| videoHelperPath.test(argvExecutable);
|
|
63
|
+
const strictAudioExecutableProof = audioHelperPath.test(normalizedExecutablePath)
|
|
64
|
+
|| audioHelperPath.test(argvExecutable);
|
|
65
|
+
const knownRawCaptureCommand = new RegExp(
|
|
66
|
+
`^(?:"[^"]*"|'[^']*'|\\S+)\\s+["']?\\S*${FAST_ROOT}/livedesk-raw-capture-helper\\.mjs(?:["']|\\s|$)`,
|
|
67
|
+
'i'
|
|
68
|
+
).test(normalizedCommandLine);
|
|
69
|
+
return (/^livedesk-sck-h264$/i.test(normalizedName) && knownVideoCommand)
|
|
70
|
+
|| (/^livedesk-sck-h2$/i.test(normalizedName) && strictVideoExecutableProof)
|
|
71
|
+
|| (/^livedesk-sck-audio$/i.test(normalizedName) && knownAudioCommand)
|
|
72
|
+
|| (/^livedesk-sck-aud$/i.test(normalizedName) && strictAudioExecutableProof)
|
|
73
|
+
|| (/^(?:node|node\.exe)$/i.test(normalizedName) && knownRawCaptureCommand);
|
|
74
|
+
}
|