@livedesk/client 0.1.240 → 0.1.242
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 +20 -20
- package/THIRD_PARTY_NOTICES.md +26 -26
- package/bin/client-version.js +23 -23
- package/bin/livedesk-client-fast.js +23 -23
- package/bin/livedesk-client-node.js +65 -65
- package/bin/livedesk-client-update-bootstrap.cjs +319 -319
- package/bin/livedesk-client.js +83 -19
- package/package.json +6 -6
- package/src/runtime/agent-process-lifecycle.js +860 -860
- package/src/runtime/client-runtime-server.js +10 -10
- package/src/runtime/hub-wake-listener.js +159 -159
- package/src/runtime/linux-video-acceleration.js +390 -390
- package/src/runtime/windows-owned-process-manifest.js +402 -402
- package/tests/client-version.test.mjs +27 -27
package/README.md
CHANGED
|
@@ -17,14 +17,14 @@ npx -y --prefer-online livedesk@latest client 3
|
|
|
17
17
|
advanced diagnostics. The public command above keeps Hub and client versions
|
|
18
18
|
aligned.
|
|
19
19
|
|
|
20
|
-
The default flow lets the local Client runtime own Google authorization,
|
|
21
|
-
callback exchange, and saved authentication as one path. The browser only
|
|
22
|
-
shows progress; it does not maintain a second session that must be transferred
|
|
23
|
-
back to the Client. LiveDesk then waits for the active Hub published by the
|
|
24
|
-
same account and connects locally. If the Hub is not
|
|
25
|
-
ready yet, the client waits for a Hub-online event and polls the registry at
|
|
26
|
-
most every six seconds as a fallback. Missing a wake event can never leave a
|
|
27
|
-
Client asleep for minutes. If a
|
|
20
|
+
The default flow lets the local Client runtime own Google authorization,
|
|
21
|
+
callback exchange, and saved authentication as one path. The browser only
|
|
22
|
+
shows progress; it does not maintain a second session that must be transferred
|
|
23
|
+
back to the Client. LiveDesk then waits for the active Hub published by the
|
|
24
|
+
same account and connects locally. If the Hub is not
|
|
25
|
+
ready yet, the client waits for a Hub-online event and polls the registry at
|
|
26
|
+
most every six seconds as a fallback. Missing a wake event can never leave a
|
|
27
|
+
Client asleep for minutes. If a
|
|
28
28
|
connected Hub is replaced, the launcher also leaves the stale endpoint and
|
|
29
29
|
discovers the newly published Hub without another Google login. Omit the number
|
|
30
30
|
for first-available placement, or pass `1` to `999` to pin this machine to a
|
|
@@ -34,11 +34,11 @@ On Windows, check **Start with Windows** on the connection page to reconnect thi
|
|
|
34
34
|
client automatically after reboot. The startup entry reuses the saved Google
|
|
35
35
|
session and only opens the connection page again if sign-in is needed.
|
|
36
36
|
|
|
37
|
-
On the Hub computer, open the LiveDesk dashboard, sign in, and run **Sync
|
|
38
|
-
Server** once. The dashboard transfers the signed-in session to the local Hub;
|
|
39
|
-
the Hub process then keeps its own local address and private pair token
|
|
40
|
-
refreshed in the LiveDesk Supabase registry. The dashboard can be closed after
|
|
41
|
-
that while the Hub remains running.
|
|
37
|
+
On the Hub computer, open the LiveDesk dashboard, sign in, and run **Sync
|
|
38
|
+
Server** once. The dashboard transfers the signed-in session to the local Hub;
|
|
39
|
+
the Hub process then keeps its own local address and private pair token
|
|
40
|
+
refreshed in the LiveDesk Supabase registry. The dashboard can be closed after
|
|
41
|
+
that while the Hub remains running.
|
|
42
42
|
|
|
43
43
|
Supabase Auth must allow the CLI callback URL:
|
|
44
44
|
|
|
@@ -52,9 +52,9 @@ the matching callback URL to Supabase Auth redirect URLs.
|
|
|
52
52
|
The client registers the device, sends status heartbeats, can return
|
|
53
53
|
Hub-requested thumbnails, can stream a focused view-only live screen, and
|
|
54
54
|
can receive safe task-only instructions. The C# RemoteFast engine also supports
|
|
55
|
-
keyboard/mouse control on Windows, macOS, and Linux/X11, file transfer, and
|
|
56
|
-
system-audio playback from Windows, macOS, and Linux. Linux captures the default
|
|
57
|
-
output through PipeWire `pw-record` or PulseAudio `parec`. macOS control requires Accessibility
|
|
55
|
+
keyboard/mouse control on Windows, macOS, and Linux/X11, file transfer, and
|
|
56
|
+
system-audio playback from Windows, macOS, and Linux. Linux captures the default
|
|
57
|
+
output through PipeWire `pw-record` or PulseAudio `parec`. macOS control requires Accessibility
|
|
58
58
|
permission for the terminal app that started LiveDesk; screen streaming and
|
|
59
59
|
system-audio capture require Screen Recording permission. LiveDesk checks these
|
|
60
60
|
permissions without opening repeated system dialogs and prints the matching
|
|
@@ -62,9 +62,9 @@ System Settings path when access is missing; after granting access, restart the
|
|
|
62
62
|
client. When file transfer is enabled by the Hub, received files are saved
|
|
63
63
|
to `Desktop/LiveDeskFiles` unless the Hub sets another destination folder.
|
|
64
64
|
|
|
65
|
-
By default, the launcher uses the packaged C# RemoteFast engine when supported.
|
|
66
|
-
It falls back to the Node engine only when a compatible RemoteFast runtime is
|
|
67
|
-
unavailable. Windows, macOS, and Linux all try RemoteFast first so
|
|
65
|
+
By default, the launcher uses the packaged C# RemoteFast engine when supported.
|
|
66
|
+
It falls back to the Node engine only when a compatible RemoteFast runtime is
|
|
67
|
+
unavailable. Windows, macOS, and Linux all try RemoteFast first so
|
|
68
68
|
the Hub can request the Mode 3 hardware video path when it is available.
|
|
69
69
|
RemoteFast is shipped as a platform-specific self-contained .NET executable,
|
|
70
70
|
so client computers do not need a separate .NET installation.
|
|
@@ -91,7 +91,7 @@ Frame pipeline roadmap:
|
|
|
91
91
|
|
|
92
92
|
- Mode 1: `mode1-jpeg` - current test path using screen capture, resize, and JPEG binary frames.
|
|
93
93
|
- Mode 2: `mode2-lzo` - cross-platform wall path using independent RGB565LE frames capped at 320x180 and compressed as LZO1X blocks. The wall defaults to 8 fps. macOS and Linux keep one persistent local capture helper per client process. Legacy `mode2-lz4` settings migrate to this mode.
|
|
94
|
-
- Mode 3: `mode3-h264-hw` - OS-specific H.264 path. Windows tries Media Foundation/NVENC/QSV/AMF, macOS prefers ScreenCaptureKit plus VideoToolbox, and Linux tries NVENC/VAAPI/QSV before falling back to the bundled ffmpeg `libx264` encoder. Linux users do not need to install ffmpeg separately when starting LiveDesk through the published npm package. macOS emits one startup key frame and then an approximately half-second recovery GOP. The launcher uses bundled ffmpeg for fallback paths unless `LIVEDESK_FFMPEG` points to a custom binary. On macOS, set `LIVEDESK_FFMPEG_AVFOUNDATION_INPUT` only when the ScreenCaptureKit helper is unavailable and the AVFoundation fallback input is not `1:none`.
|
|
94
|
+
- Mode 3: `mode3-h264-hw` - OS-specific H.264 path. Windows tries Media Foundation/NVENC/QSV/AMF, macOS prefers ScreenCaptureKit plus VideoToolbox, and Linux tries NVENC/VAAPI/QSV before falling back to the bundled ffmpeg `libx264` encoder. Linux users do not need to install ffmpeg separately when starting LiveDesk through the published npm package. macOS emits one startup key frame and then an approximately half-second recovery GOP. The launcher uses bundled ffmpeg for fallback paths unless `LIVEDESK_FFMPEG` points to a custom binary. On macOS, set `LIVEDESK_FFMPEG_AVFOUNDATION_INPUT` only when the ScreenCaptureKit helper is unavailable and the AVFoundation fallback input is not `1:none`.
|
|
95
95
|
|
|
96
96
|
Legacy mode names such as `remote-fast` and `remote-quality` are treated as
|
|
97
97
|
Mode 1 aliases.
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
# Third-Party Notices
|
|
2
|
-
|
|
3
|
-
## lzokay
|
|
4
|
-
|
|
5
|
-
LiveDesk's LZO1X block encoder and decoder follow the instruction layout of
|
|
6
|
-
[lzokay](https://github.com/AxioDL/lzokay), Copyright (c) 2018 Jack Andersen.
|
|
7
|
-
|
|
8
|
-
The MIT License
|
|
9
|
-
|
|
10
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
11
|
-
this software and associated documentation files (the "Software"), to deal in
|
|
12
|
-
the Software without restriction, including without limitation the rights to
|
|
13
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
14
|
-
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
15
|
-
subject to the following conditions:
|
|
16
|
-
|
|
17
|
-
The above copyright notice and this permission notice shall be included in all
|
|
18
|
-
copies or substantial portions of the Software.
|
|
19
|
-
|
|
20
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
-
SOFTWARE.
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
## lzokay
|
|
4
|
+
|
|
5
|
+
LiveDesk's LZO1X block encoder and decoder follow the instruction layout of
|
|
6
|
+
[lzokay](https://github.com/AxioDL/lzokay), Copyright (c) 2018 Jack Andersen.
|
|
7
|
+
|
|
8
|
+
The MIT License
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
11
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
12
|
+
the Software without restriction, including without limitation the rights to
|
|
13
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
14
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
15
|
+
subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
package/bin/client-version.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, join, resolve } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
|
|
5
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
const packageRoot = resolve(__dirname, '..');
|
|
7
|
-
|
|
8
|
-
export function readClientPackageVersion() {
|
|
9
|
-
try {
|
|
10
|
-
const packageInfo = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
|
|
11
|
-
return String(packageInfo.version || '0.0.0');
|
|
12
|
-
} catch {
|
|
13
|
-
return '0.0.0';
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function formatClientVersionBanner(env = process.env) {
|
|
18
|
-
const launcherName = String(env.LIVEDESK_NPM_LAUNCHER_NAME || '').trim();
|
|
19
|
-
const launcherVersion = String(env.LIVEDESK_NPM_LAUNCHER_VERSION || '').trim();
|
|
20
|
-
const productName = launcherName || 'livedesk';
|
|
21
|
-
const productVersion = launcherVersion || readClientPackageVersion();
|
|
22
|
-
return `[LiveDesk Client] ${productName}@${productVersion}`;
|
|
23
|
-
}
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const packageRoot = resolve(__dirname, '..');
|
|
7
|
+
|
|
8
|
+
export function readClientPackageVersion() {
|
|
9
|
+
try {
|
|
10
|
+
const packageInfo = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
|
|
11
|
+
return String(packageInfo.version || '0.0.0');
|
|
12
|
+
} catch {
|
|
13
|
+
return '0.0.0';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function formatClientVersionBanner(env = process.env) {
|
|
18
|
+
const launcherName = String(env.LIVEDESK_NPM_LAUNCHER_NAME || '').trim();
|
|
19
|
+
const launcherVersion = String(env.LIVEDESK_NPM_LAUNCHER_VERSION || '').trim();
|
|
20
|
+
const productName = launcherName || 'livedesk';
|
|
21
|
+
const productVersion = launcherVersion || readClientPackageVersion();
|
|
22
|
+
return `[LiveDesk Client] ${productName}@${productVersion}`;
|
|
23
|
+
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { dirname, join } from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { spawn } from 'node:child_process';
|
|
6
|
-
|
|
7
|
-
const launcherPath = join(dirname(fileURLToPath(import.meta.url)), 'livedesk-client.js');
|
|
8
|
-
const child = spawn(process.execPath, [launcherPath, '--fast', ...process.argv.slice(2)], {
|
|
9
|
-
stdio: 'inherit',
|
|
10
|
-
windowsHide: true
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
child.once('error', error => {
|
|
14
|
-
console.error(`Failed to launch C# RemoteFast: ${error.message}`);
|
|
15
|
-
process.exitCode = 1;
|
|
16
|
-
});
|
|
17
|
-
child.once('exit', (code, signal) => {
|
|
18
|
-
if (signal) {
|
|
19
|
-
process.kill(process.pid, signal);
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
process.exit(code ?? 0);
|
|
23
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
6
|
+
|
|
7
|
+
const launcherPath = join(dirname(fileURLToPath(import.meta.url)), 'livedesk-client.js');
|
|
8
|
+
const child = spawn(process.execPath, [launcherPath, '--fast', ...process.argv.slice(2)], {
|
|
9
|
+
stdio: 'inherit',
|
|
10
|
+
windowsHide: true
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
child.once('error', error => {
|
|
14
|
+
console.error(`Failed to launch C# RemoteFast: ${error.message}`);
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
});
|
|
17
|
+
child.once('exit', (code, signal) => {
|
|
18
|
+
if (signal) {
|
|
19
|
+
process.kill(process.pid, signal);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
process.exit(code ?? 0);
|
|
23
|
+
});
|
|
@@ -251,7 +251,7 @@ async function waitForClientUpdateShutdownSignal(
|
|
|
251
251
|
return { ready: false, error };
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
function markClientUpdateConnected() {
|
|
254
|
+
function markClientUpdateConnected() {
|
|
255
255
|
const operationId = String(process.env.LIVEDESK_CLIENT_UPDATE_OPERATION_ID || '').trim();
|
|
256
256
|
if (!operationId) return;
|
|
257
257
|
void writeClientUpdateState('connected', {
|
|
@@ -262,59 +262,59 @@ function markClientUpdateConnected() {
|
|
|
262
262
|
error: ''
|
|
263
263
|
}).catch(error => {
|
|
264
264
|
console.error(`LiveDesk client update diagnostics could not be persisted: ${error?.message || error}`);
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
async function publishClientUpdateSupervisorProof(socket) {
|
|
269
|
-
const operationId = String(process.env.LIVEDESK_CLIENT_UPDATE_OPERATION_ID || '').trim();
|
|
270
|
-
const attemptId = String(process.env.LIVEDESK_CLIENT_UPDATE_ATTEMPT_ID || '').trim();
|
|
271
|
-
const expectedLauncherPid = Number(process.env.LIVEDESK_CLIENT_PARENT_PID || 0);
|
|
272
|
-
if (!operationId || !attemptId || !Number.isInteger(expectedLauncherPid) || expectedLauncherPid <= 1) return;
|
|
273
|
-
const deadline = Date.now() + 60_000;
|
|
274
|
-
while (Date.now() < deadline && !socket.destroyed) {
|
|
275
|
-
try {
|
|
276
|
-
const state = JSON.parse(await fs.readFile(getClientUpdateStatePath(), 'utf8'));
|
|
277
|
-
if (String(state?.operationId || '') !== operationId
|
|
278
|
-
|| String(state?.attemptId || '') !== attemptId) {
|
|
279
|
-
await wait(100);
|
|
280
|
-
continue;
|
|
281
|
-
}
|
|
282
|
-
if (['failed', 'restored', 'cancelled'].includes(String(state.stage || ''))) return;
|
|
283
|
-
const launcherPid = Number(state.launcherPid || 0);
|
|
284
|
-
const agentPid = Number(state.agentPid || 0);
|
|
285
|
-
const supervisorPid = Number(state.supervisorPid || 0);
|
|
286
|
-
const completedAt = String(state.completedAt || '').trim();
|
|
287
|
-
const exactSupervisorCompletion = state.stage === 'connected'
|
|
288
|
-
&& state.restartVerified === true
|
|
289
|
-
&& Number.isFinite(Date.parse(completedAt))
|
|
290
|
-
&& launcherPid === expectedLauncherPid
|
|
291
|
-
&& agentPid === process.pid
|
|
292
|
-
&& Number.isInteger(supervisorPid)
|
|
293
|
-
&& supervisorPid > 1
|
|
294
|
-
&& String(state.productVersion || '') === PRODUCT_VERSION
|
|
295
|
-
&& String(state.agentVersion || '') === AGENT_VERSION
|
|
296
|
-
&& String(state.targetProductVersion || '') === PRODUCT_VERSION
|
|
297
|
-
&& String(state.targetAgentVersion || state.targetVersion || '') === AGENT_VERSION;
|
|
298
|
-
if (exactSupervisorCompletion) {
|
|
299
|
-
writeJsonLine(socket, {
|
|
300
|
-
type: 'client.update.verified',
|
|
301
|
-
operationId,
|
|
302
|
-
attemptId,
|
|
303
|
-
launcherPid,
|
|
304
|
-
agentPid,
|
|
305
|
-
supervisorPid,
|
|
306
|
-
productVersion: PRODUCT_VERSION,
|
|
307
|
-
agentVersion: AGENT_VERSION,
|
|
308
|
-
completedAt
|
|
309
|
-
});
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
} catch {
|
|
313
|
-
// The exact package supervisor may be replacing the atomic state file.
|
|
314
|
-
}
|
|
315
|
-
await wait(100);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function publishClientUpdateSupervisorProof(socket) {
|
|
269
|
+
const operationId = String(process.env.LIVEDESK_CLIENT_UPDATE_OPERATION_ID || '').trim();
|
|
270
|
+
const attemptId = String(process.env.LIVEDESK_CLIENT_UPDATE_ATTEMPT_ID || '').trim();
|
|
271
|
+
const expectedLauncherPid = Number(process.env.LIVEDESK_CLIENT_PARENT_PID || 0);
|
|
272
|
+
if (!operationId || !attemptId || !Number.isInteger(expectedLauncherPid) || expectedLauncherPid <= 1) return;
|
|
273
|
+
const deadline = Date.now() + 60_000;
|
|
274
|
+
while (Date.now() < deadline && !socket.destroyed) {
|
|
275
|
+
try {
|
|
276
|
+
const state = JSON.parse(await fs.readFile(getClientUpdateStatePath(), 'utf8'));
|
|
277
|
+
if (String(state?.operationId || '') !== operationId
|
|
278
|
+
|| String(state?.attemptId || '') !== attemptId) {
|
|
279
|
+
await wait(100);
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (['failed', 'restored', 'cancelled'].includes(String(state.stage || ''))) return;
|
|
283
|
+
const launcherPid = Number(state.launcherPid || 0);
|
|
284
|
+
const agentPid = Number(state.agentPid || 0);
|
|
285
|
+
const supervisorPid = Number(state.supervisorPid || 0);
|
|
286
|
+
const completedAt = String(state.completedAt || '').trim();
|
|
287
|
+
const exactSupervisorCompletion = state.stage === 'connected'
|
|
288
|
+
&& state.restartVerified === true
|
|
289
|
+
&& Number.isFinite(Date.parse(completedAt))
|
|
290
|
+
&& launcherPid === expectedLauncherPid
|
|
291
|
+
&& agentPid === process.pid
|
|
292
|
+
&& Number.isInteger(supervisorPid)
|
|
293
|
+
&& supervisorPid > 1
|
|
294
|
+
&& String(state.productVersion || '') === PRODUCT_VERSION
|
|
295
|
+
&& String(state.agentVersion || '') === AGENT_VERSION
|
|
296
|
+
&& String(state.targetProductVersion || '') === PRODUCT_VERSION
|
|
297
|
+
&& String(state.targetAgentVersion || state.targetVersion || '') === AGENT_VERSION;
|
|
298
|
+
if (exactSupervisorCompletion) {
|
|
299
|
+
writeJsonLine(socket, {
|
|
300
|
+
type: 'client.update.verified',
|
|
301
|
+
operationId,
|
|
302
|
+
attemptId,
|
|
303
|
+
launcherPid,
|
|
304
|
+
agentPid,
|
|
305
|
+
supervisorPid,
|
|
306
|
+
productVersion: PRODUCT_VERSION,
|
|
307
|
+
agentVersion: AGENT_VERSION,
|
|
308
|
+
completedAt
|
|
309
|
+
});
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
} catch {
|
|
313
|
+
// The exact package supervisor may be replacing the atomic state file.
|
|
314
|
+
}
|
|
315
|
+
await wait(100);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
318
|
|
|
319
319
|
function printHelp() {
|
|
320
320
|
console.log(`
|
|
@@ -2023,10 +2023,10 @@ function connectOnce(options, deviceId) {
|
|
|
2023
2023
|
remoteFiles: true,
|
|
2024
2024
|
fileTransferMaxBytes: MAX_FILE_TRANSFER_BYTES,
|
|
2025
2025
|
computerAgent: options.taskEnabled,
|
|
2026
|
-
taskDispatch: options.taskEnabled,
|
|
2027
|
-
clientUpdate: true,
|
|
2028
|
-
clientUpdateVerifiedProof: true,
|
|
2029
|
-
productVersion: PRODUCT_VERSION,
|
|
2026
|
+
taskDispatch: options.taskEnabled,
|
|
2027
|
+
clientUpdate: true,
|
|
2028
|
+
clientUpdateVerifiedProof: true,
|
|
2029
|
+
productVersion: PRODUCT_VERSION,
|
|
2030
2030
|
agentApproval: options.taskEnabled,
|
|
2031
2031
|
agentAudit: options.taskEnabled,
|
|
2032
2032
|
agentTools: [...NODE_AGENT_OPERATIONS],
|
|
@@ -2052,13 +2052,13 @@ function connectOnce(options, deviceId) {
|
|
|
2052
2052
|
options.effectivePolicy = message.effectivePolicy && typeof message.effectivePolicy === 'object'
|
|
2053
2053
|
? message.effectivePolicy
|
|
2054
2054
|
: null;
|
|
2055
|
-
console.log(`Connected to LiveDesk Hub as ${options.name} (${deviceId})`);
|
|
2056
|
-
markClientUpdateConnected();
|
|
2057
|
-
void publishClientUpdateSupervisorProof(socket).catch(error => {
|
|
2058
|
-
if (!socket.destroyed) {
|
|
2059
|
-
console.error(`LiveDesk client update verification proof failed: ${error?.message || error}`);
|
|
2060
|
-
}
|
|
2061
|
-
});
|
|
2055
|
+
console.log(`Connected to LiveDesk Hub as ${options.name} (${deviceId})`);
|
|
2056
|
+
markClientUpdateConnected();
|
|
2057
|
+
void publishClientUpdateSupervisorProof(socket).catch(error => {
|
|
2058
|
+
if (!socket.destroyed) {
|
|
2059
|
+
console.error(`LiveDesk client update verification proof failed: ${error?.message || error}`);
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2062
2062
|
writeJsonLine(socket, {
|
|
2063
2063
|
type: 'status',
|
|
2064
2064
|
status: getStatus(options)
|