livedesk 0.1.447 → 0.1.449
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 +150 -17
- package/bootstrap/legacy-client-update.js +1 -7
- package/client/README.md +3 -3
- package/client/bin/livedesk-client-node.js +70 -190
- package/client/bin/livedesk-client.js +71 -31
- package/client/package.json +5 -6
- package/hub/package.json +1 -1
- package/hub/src/agents/agent-manager.js +123 -175
- package/hub/src/agents/agent-settings.js +9 -100
- package/hub/src/agents/agent-tool-registry.js +1 -1
- package/hub/src/agents/codex-agent-runtime.js +14 -16
- package/hub/src/remote-hub.js +92 -124
- package/hub/src/server.js +58 -46
- package/package.json +8 -9
- package/web/dist/assets/icons-CCS0Avce.js +1 -0
- package/web/dist/assets/index-CDA-kp_V.js +25 -0
- package/web/dist/assets/{react-C7a9r614.js → react-Cg5haagh.js} +1 -1
- package/web/dist/index.html +3 -3
- package/hub/src/agents/opencode-go-provider.js +0 -260
- package/hub/src/agents/secret-store.js +0 -165
- package/web/dist/assets/icons-BIyRF-ou.js +0 -1
- package/web/dist/assets/index-5opXQY8X.js +0 -25
|
@@ -67,6 +67,11 @@ const FAST_PREFLIGHT_CACHE_PATH = join(UNIFIED_CLIENT_STATE_DIR, 'fast-preflight
|
|
|
67
67
|
const CLIENT_SLOT_PATH = join(UNIFIED_CLIENT_STATE_DIR, 'device-slot.json');
|
|
68
68
|
const CLIENT_UPDATE_STATE_PATH = process.env.LIVEDESK_CLIENT_UPDATE_STATE_PATH
|
|
69
69
|
|| join(UNIFIED_CLIENT_STATE_DIR, 'client-update.json');
|
|
70
|
+
// Migration-only compatibility: releases before 0.1.204 could persist these
|
|
71
|
+
// Client-side model options in startup/update commands. Consume them without
|
|
72
|
+
// forwarding so an upgrade starts normally, but never restores that feature.
|
|
73
|
+
const RETIRED_CLIENT_MODEL_SINGLE_OPTIONS = new Set(['--ai', '--no-ai', '--fake-ai']);
|
|
74
|
+
const RETIRED_CLIENT_MODEL_VALUE_OPTION = '--ai-model';
|
|
70
75
|
let activeAgentProcess = null;
|
|
71
76
|
let roleRestartRequest = null;
|
|
72
77
|
let agentRestartRequest = null;
|
|
@@ -301,8 +306,8 @@ Options:
|
|
|
301
306
|
--version Show the agent version.
|
|
302
307
|
--help Show this help.
|
|
303
308
|
|
|
304
|
-
Auto uses C# RemoteFast when supported and falls back to Node
|
|
305
|
-
|
|
309
|
+
Auto uses C# RemoteFast when supported and falls back to Node only when a
|
|
310
|
+
packaged RemoteFast runtime is unavailable.
|
|
306
311
|
Enable Windows auto-start from the connection page when this client signs in.
|
|
307
312
|
`.trimStart());
|
|
308
313
|
}
|
|
@@ -394,15 +399,30 @@ export function parseLauncherArgs(argv) {
|
|
|
394
399
|
let slot = process.env.LIVEDESK_CLIENT_SLOT || process.env.MINDEXEC_REMOTE_SLOT || '';
|
|
395
400
|
let authPort = normalizePort(process.env.LIVEDESK_CLIENT_RUNTIME_PORT || process.env.LIVEDESK_CLIENT_AUTH_PORT) || DEFAULT_AUTH_CALLBACK_PORT;
|
|
396
401
|
let command = 'connect';
|
|
397
|
-
let
|
|
398
|
-
let fakeThumbnail = false;
|
|
402
|
+
let fakeThumbnail = false;
|
|
399
403
|
let startupRun = isTruthy(process.env.LIVEDESK_ROLE_TRANSITION);
|
|
400
|
-
let openBrowserOnStart = !isTruthy(process.env.LIVEDESK_SKIP_BROWSER_OPEN);
|
|
401
|
-
let updateWaitPid = 0;
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
404
|
+
let openBrowserOnStart = !isTruthy(process.env.LIVEDESK_SKIP_BROWSER_OPEN);
|
|
405
|
+
let updateWaitPid = 0;
|
|
406
|
+
let retiredModelOptionsDiscarded = 0;
|
|
407
|
+
|
|
408
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
409
|
+
const arg = argv[index];
|
|
410
|
+
if (RETIRED_CLIENT_MODEL_SINGLE_OPTIONS.has(arg)) {
|
|
411
|
+
retiredModelOptionsDiscarded += 1;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (arg === RETIRED_CLIENT_MODEL_VALUE_OPTION) {
|
|
415
|
+
retiredModelOptionsDiscarded += 1;
|
|
416
|
+
if (index + 1 < argv.length && !String(argv[index + 1] || '').startsWith('-')) {
|
|
417
|
+
index += 1;
|
|
418
|
+
}
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (String(arg || '').startsWith(`${RETIRED_CLIENT_MODEL_VALUE_OPTION}=`)) {
|
|
422
|
+
retiredModelOptionsDiscarded += 1;
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (arg && !arg.startsWith('-')) {
|
|
406
426
|
const lowerArg = arg.toLowerCase();
|
|
407
427
|
const shortcutSlot = normalizeSlotNumber(arg);
|
|
408
428
|
if (lowerArg === 'connect') {
|
|
@@ -512,11 +532,8 @@ export function parseLauncherArgs(argv) {
|
|
|
512
532
|
if (arg === '--version') {
|
|
513
533
|
version = true;
|
|
514
534
|
}
|
|
515
|
-
if (arg === '--
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
if (arg === '--fake-thumbnail') {
|
|
519
|
-
fakeThumbnail = true;
|
|
535
|
+
if (arg === '--fake-thumbnail') {
|
|
536
|
+
fakeThumbnail = true;
|
|
520
537
|
}
|
|
521
538
|
forwarded.push(arg);
|
|
522
539
|
}
|
|
@@ -539,13 +556,13 @@ export function parseLauncherArgs(argv) {
|
|
|
539
556
|
deviceId,
|
|
540
557
|
slot,
|
|
541
558
|
authPort,
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
};
|
|
548
|
-
}
|
|
559
|
+
fakeThumbnail,
|
|
560
|
+
startupRun,
|
|
561
|
+
openBrowserOnStart,
|
|
562
|
+
updateWaitPid,
|
|
563
|
+
retiredModelOptionsDiscarded
|
|
564
|
+
};
|
|
565
|
+
}
|
|
549
566
|
|
|
550
567
|
function normalizePort(value) {
|
|
551
568
|
const port = Number(String(value || '').trim());
|
|
@@ -854,13 +871,15 @@ const CLIENT_UPDATE_SINGLE_FLAGS = new Set([
|
|
|
854
871
|
'--no-open',
|
|
855
872
|
'--exit-on-disconnect',
|
|
856
873
|
'--exit-on-invalid-pair',
|
|
857
|
-
'--once'
|
|
874
|
+
'--once',
|
|
875
|
+
...RETIRED_CLIENT_MODEL_SINGLE_OPTIONS
|
|
858
876
|
]);
|
|
859
877
|
const CLIENT_UPDATE_VALUE_FLAGS = new Set([
|
|
860
878
|
'--update-wait-pid',
|
|
861
879
|
// Pairing credentials stay in the inherited private environment and must
|
|
862
880
|
// never be copied onto a replacement process command line.
|
|
863
|
-
'--pair'
|
|
881
|
+
'--pair',
|
|
882
|
+
RETIRED_CLIENT_MODEL_VALUE_OPTION
|
|
864
883
|
]);
|
|
865
884
|
|
|
866
885
|
export function buildClientUpdateRestartArgs(prepared = {}) {
|
|
@@ -874,6 +893,9 @@ export function buildClientUpdateRestartArgs(prepared = {}) {
|
|
|
874
893
|
if (arg.startsWith('--pair=')) {
|
|
875
894
|
continue;
|
|
876
895
|
}
|
|
896
|
+
if (arg.startsWith(`${RETIRED_CLIENT_MODEL_VALUE_OPTION}=`)) {
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
877
899
|
if (CLIENT_UPDATE_VALUE_FLAGS.has(arg)) {
|
|
878
900
|
index += 1;
|
|
879
901
|
continue;
|
|
@@ -4233,6 +4255,18 @@ export function buildFastArgs(args, fakeThumbnail, transport = 'auto', relay = '
|
|
|
4233
4255
|
const forwarded = [];
|
|
4234
4256
|
for (let index = 0; index < args.length; index += 1) {
|
|
4235
4257
|
const arg = args[index];
|
|
4258
|
+
if (RETIRED_CLIENT_MODEL_SINGLE_OPTIONS.has(arg)) {
|
|
4259
|
+
continue;
|
|
4260
|
+
}
|
|
4261
|
+
if (arg === RETIRED_CLIENT_MODEL_VALUE_OPTION) {
|
|
4262
|
+
if (index + 1 < args.length && !String(args[index + 1] || '').startsWith('-')) {
|
|
4263
|
+
index += 1;
|
|
4264
|
+
}
|
|
4265
|
+
continue;
|
|
4266
|
+
}
|
|
4267
|
+
if (String(arg || '').startsWith(`${RETIRED_CLIENT_MODEL_VALUE_OPTION}=`)) {
|
|
4268
|
+
continue;
|
|
4269
|
+
}
|
|
4236
4270
|
if (arg === '--transport' || arg === '--relay') {
|
|
4237
4271
|
index += 1;
|
|
4238
4272
|
continue;
|
|
@@ -4241,8 +4275,8 @@ export function buildFastArgs(args, fakeThumbnail, transport = 'auto', relay = '
|
|
|
4241
4275
|
forwarded.push('--fake-frame');
|
|
4242
4276
|
continue;
|
|
4243
4277
|
}
|
|
4244
|
-
if (arg === '--tasks' || arg === '--no-tasks'
|
|
4245
|
-
continue;
|
|
4278
|
+
if (arg === '--tasks' || arg === '--no-tasks') {
|
|
4279
|
+
continue;
|
|
4246
4280
|
}
|
|
4247
4281
|
forwarded.push(arg);
|
|
4248
4282
|
}
|
|
@@ -4446,15 +4480,15 @@ function spawnAgent(command, args, env = process.env, onStart = null) {
|
|
|
4446
4480
|
});
|
|
4447
4481
|
}
|
|
4448
4482
|
|
|
4449
|
-
function shouldUseFast(parsed) {
|
|
4450
|
-
if (parsed.engine === 'node') {
|
|
4451
|
-
return false;
|
|
4483
|
+
function shouldUseFast(parsed) {
|
|
4484
|
+
if (parsed.engine === 'node') {
|
|
4485
|
+
return false;
|
|
4452
4486
|
}
|
|
4453
4487
|
if (parsed.engine === 'fast') {
|
|
4454
4488
|
return true;
|
|
4455
4489
|
}
|
|
4456
|
-
return
|
|
4457
|
-
}
|
|
4490
|
+
return true;
|
|
4491
|
+
}
|
|
4458
4492
|
|
|
4459
4493
|
function shouldTryFast(parsed, runtime) {
|
|
4460
4494
|
if (parsed.engine === 'fast') {
|
|
@@ -4480,6 +4514,12 @@ export async function runClientRuntime(argv = process.argv.slice(2)) {
|
|
|
4480
4514
|
console.warn('[LiveDesk] @livedesk/client is deprecated. Use the unified livedesk package or LiveDesk Desktop.');
|
|
4481
4515
|
}
|
|
4482
4516
|
const parsed = parseLauncherArgs(argv);
|
|
4517
|
+
if (parsed.retiredModelOptionsDiscarded > 0) {
|
|
4518
|
+
console.warn(
|
|
4519
|
+
'[LiveDesk Client] Ignored retired Client model-runtime options. '
|
|
4520
|
+
+ 'Approved AI computer commands are handled by the Hub Codex Agent.'
|
|
4521
|
+
);
|
|
4522
|
+
}
|
|
4483
4523
|
if (parsed.updateWaitPid) {
|
|
4484
4524
|
await waitForProcessExit(parsed.updateWaitPid);
|
|
4485
4525
|
}
|
package/client/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livedesk/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.204",
|
|
4
4
|
"description": "LiveDesk local remote client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,14 +37,13 @@
|
|
|
37
37
|
"@livedesk/runtime-core": "0.1.0",
|
|
38
38
|
"@supabase/supabase-js": "^2.110.0",
|
|
39
39
|
"node-screenshots": "^0.2.8",
|
|
40
|
-
"openai": "^6.42.0",
|
|
41
40
|
"ws": "^8.18.3"
|
|
42
41
|
},
|
|
43
42
|
"optionalDependencies": {
|
|
44
|
-
"@livedesk/fast-linux-x64": "0.1.
|
|
45
|
-
"@livedesk/fast-osx-arm64": "0.1.
|
|
46
|
-
"@livedesk/fast-osx-x64": "0.1.
|
|
47
|
-
"@livedesk/fast-win-x64": "0.1.
|
|
43
|
+
"@livedesk/fast-linux-x64": "0.1.411",
|
|
44
|
+
"@livedesk/fast-osx-arm64": "0.1.411",
|
|
45
|
+
"@livedesk/fast-osx-x64": "0.1.411",
|
|
46
|
+
"@livedesk/fast-win-x64": "0.1.411"
|
|
48
47
|
},
|
|
49
48
|
"publishConfig": {
|
|
50
49
|
"access": "public"
|
package/hub/package.json
CHANGED
|
@@ -1,175 +1,123 @@
|
|
|
1
|
-
import os from 'node:os';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { AgentSettingsStore, AGENT_PROVIDER_CODEX
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
async
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
await secrets.deleteApiKey(AGENT_PROVIDER_OPENCODE_GO);
|
|
125
|
-
return publicSettings();
|
|
126
|
-
},
|
|
127
|
-
async getModels() {
|
|
128
|
-
const { current, active } = await currentProvider();
|
|
129
|
-
if (current.provider === AGENT_PROVIDER_CODEX) {
|
|
130
|
-
return [{ id: '', name: 'Codex default', protocol: 'codex-sdk', available: true, capabilities: { supportsReasoningLevel: true, supportsStreaming: true, supportsTools: true } }];
|
|
131
|
-
}
|
|
132
|
-
return active.getModels(current, await legacyApiKey());
|
|
133
|
-
},
|
|
134
|
-
async testConnection() {
|
|
135
|
-
const { current, active } = await currentProvider();
|
|
136
|
-
if (current.provider === AGENT_PROVIDER_CODEX) {
|
|
137
|
-
if (!active) throw new AgentProviderError('codex-sdk-not-installed', 'Codex SDK is not installed.', { status: 503 });
|
|
138
|
-
statusCache = { expiresAt: 0, value: null };
|
|
139
|
-
return active.testConnection();
|
|
140
|
-
}
|
|
141
|
-
return active.testConnection(current, await legacyApiKey());
|
|
142
|
-
},
|
|
143
|
-
async createPlan(input) {
|
|
144
|
-
const { current, active } = await currentProvider();
|
|
145
|
-
if (!current.enabled) throw new AgentProviderError('agent-ai-disabled', 'Agent AI is disabled in Settings.', { status: 409 });
|
|
146
|
-
if (current.provider === AGENT_PROVIDER_CODEX) {
|
|
147
|
-
throw new AgentProviderError('agent-codex-run-required', 'Codex runs use the LiveDesk tool loop.', { status: 409 });
|
|
148
|
-
}
|
|
149
|
-
return active.createPlan(input, current, await legacyApiKey());
|
|
150
|
-
},
|
|
151
|
-
async createSummary(input) {
|
|
152
|
-
const { current, active } = await currentProvider();
|
|
153
|
-
if (!current.enabled || !current.generateSummary) throw new AgentProviderError('agent-summary-disabled', 'Agent summaries are disabled in Settings.', { status: 409 });
|
|
154
|
-
if (current.provider === AGENT_PROVIDER_CODEX) {
|
|
155
|
-
const source = input && typeof input === 'object' ? input : {};
|
|
156
|
-
const results = Array.isArray(source.results) ? source.results : [];
|
|
157
|
-
return { summary: String(results.length ? `${source.completed || 0} completed, ${source.failed || 0} failed.` : 'LiveDesk Agent run completed.').slice(0, 1200), modelId: current.codexModelId || 'Codex default' };
|
|
158
|
-
}
|
|
159
|
-
const source = input && typeof input === 'object' ? input : {};
|
|
160
|
-
const results = Array.isArray(source.results) ? source.results : [];
|
|
161
|
-
const safeResults = current.includeRawDeviceDetails
|
|
162
|
-
? results.map(result => ({ deviceName: String(result?.deviceName || '').slice(0, 120), status: String(result?.status || '').slice(0, 40), result: String(result?.result || '').slice(0, 1200), error: String(result?.error || '').slice(0, 500) }))
|
|
163
|
-
: results.map(result => ({ deviceName: String(result?.deviceName || '').slice(0, 120), status: String(result?.status || '').slice(0, 40), hasResult: Boolean(result?.result), hasError: Boolean(result?.error) }));
|
|
164
|
-
return active.createSummary({ instruction: String(source.instruction || '').slice(0, 500), operation: String(source.operation || '').slice(0, 80), summary: { total: Number(source.total || results.length), completed: Number(source.completed || 0), failed: Number(source.failed || 0), results: safeResults } }, current, await legacyApiKey());
|
|
165
|
-
},
|
|
166
|
-
async startRun(input) {
|
|
167
|
-
const current = await settings.get();
|
|
168
|
-
if (current.provider !== AGENT_PROVIDER_CODEX || !runtime) throw new AgentProviderError('agent-codex-not-active', 'Codex SDK is not the active Agent provider.', { status: 409 });
|
|
169
|
-
return runtime.start(input);
|
|
170
|
-
},
|
|
171
|
-
getRun(runId) { return runtime?.get(runId) || null; },
|
|
172
|
-
cancelRun(runId) { return runtime?.cancel(runId) || null; },
|
|
173
|
-
cancelAllRuns() { return runtime?.cancelAll?.() || 0; }
|
|
174
|
-
};
|
|
175
|
-
}
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { AgentSettingsStore, AGENT_PROVIDER_CODEX } from './agent-settings.js';
|
|
4
|
+
import { AgentProviderError } from './provider-errors.js';
|
|
5
|
+
|
|
6
|
+
function publicCodexStatus(status = {}) {
|
|
7
|
+
return {
|
|
8
|
+
installed: status.installed === true,
|
|
9
|
+
authenticated: ['signed-in', 'not-signed-in'].includes(status.authenticated) ? status.authenticated : 'unknown',
|
|
10
|
+
status: String(status.status || 'unknown').slice(0, 40),
|
|
11
|
+
codexPath: String(status.codexPath || '').slice(0, 500),
|
|
12
|
+
detail: String(status.detail || '').slice(0, 300)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createAgentManager({
|
|
17
|
+
dataDir = path.join(os.homedir(), '.livedesk'),
|
|
18
|
+
settingsStore,
|
|
19
|
+
codexRuntime
|
|
20
|
+
} = {}) {
|
|
21
|
+
const settings = settingsStore || new AgentSettingsStore({ dataDir });
|
|
22
|
+
const runtime = codexRuntime;
|
|
23
|
+
let statusCache = { expiresAt: 0, value: null };
|
|
24
|
+
|
|
25
|
+
async function getCodexStatus() {
|
|
26
|
+
if (!runtime) return { installed: false, authenticated: 'unknown', status: 'unavailable', codexPath: '' };
|
|
27
|
+
if (statusCache.value && statusCache.expiresAt > Date.now()) return statusCache.value;
|
|
28
|
+
let value;
|
|
29
|
+
try {
|
|
30
|
+
value = publicCodexStatus(await runtime.getStatus());
|
|
31
|
+
} catch (error) {
|
|
32
|
+
value = publicCodexStatus({
|
|
33
|
+
installed: true,
|
|
34
|
+
authenticated: 'unknown',
|
|
35
|
+
status: error?.code || 'security-unavailable',
|
|
36
|
+
detail: error?.message || 'Codex security isolation is unavailable.'
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
statusCache = { value, expiresAt: Date.now() + 10000 };
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function publicSettings() {
|
|
44
|
+
const current = await settings.get();
|
|
45
|
+
const { codexMaxTurns: _codexMaxTurns, ...exposedSettings } = current;
|
|
46
|
+
const codex = await getCodexStatus();
|
|
47
|
+
const securityStatus = runtime?.getSecurityStatus?.() || {
|
|
48
|
+
isolatedCodexHome: false,
|
|
49
|
+
restrictedEnvironment: false,
|
|
50
|
+
livedeskMcpOnly: false,
|
|
51
|
+
selectedDeviceScopeEnforced: false,
|
|
52
|
+
failClosed: true,
|
|
53
|
+
verified: false,
|
|
54
|
+
state: 'unavailable'
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
...exposedSettings,
|
|
58
|
+
provider: AGENT_PROVIDER_CODEX,
|
|
59
|
+
codexInstallation: codex.installed ? 'installed' : 'not-installed',
|
|
60
|
+
codexAuth: codex.authenticated,
|
|
61
|
+
codexStatus: codex.status,
|
|
62
|
+
codexPath: codex.codexPath,
|
|
63
|
+
agentWorkspacePath: current.codexWorkingDirectory,
|
|
64
|
+
securityStatus
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
getSettings: publicSettings,
|
|
70
|
+
async updateSettings(patch = {}) {
|
|
71
|
+
const nextPatch = { ...patch };
|
|
72
|
+
const requestedProvider = String(nextPatch.provider || AGENT_PROVIDER_CODEX).trim().toLowerCase();
|
|
73
|
+
const suppliedLegacyKey = typeof nextPatch.apiKey === 'string' && nextPatch.apiKey.trim().length > 0;
|
|
74
|
+
delete nextPatch.provider;
|
|
75
|
+
delete nextPatch.apiKey;
|
|
76
|
+
if (requestedProvider !== AGENT_PROVIDER_CODEX || suppliedLegacyKey) {
|
|
77
|
+
throw new AgentProviderError(
|
|
78
|
+
'agent-provider-retired',
|
|
79
|
+
'LiveDesk uses the Hub-hosted Codex Agent and does not configure alternate model providers.',
|
|
80
|
+
{ status: 400 }
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
await settings.update({ ...nextPatch, provider: AGENT_PROVIDER_CODEX });
|
|
84
|
+
statusCache = { expiresAt: 0, value: null };
|
|
85
|
+
return publicSettings();
|
|
86
|
+
},
|
|
87
|
+
async resetSettings() {
|
|
88
|
+
await settings.reset();
|
|
89
|
+
statusCache = { expiresAt: 0, value: null };
|
|
90
|
+
return publicSettings();
|
|
91
|
+
},
|
|
92
|
+
// Kept as a harmless compatibility endpoint for an older cached web UI.
|
|
93
|
+
// No credential is read, written, or returned by the current Hub.
|
|
94
|
+
async deleteApiKey() {
|
|
95
|
+
return publicSettings();
|
|
96
|
+
},
|
|
97
|
+
async testConnection() {
|
|
98
|
+
if (!runtime) throw new AgentProviderError('codex-sdk-not-installed', 'Codex SDK is not installed.', { status: 503 });
|
|
99
|
+
statusCache = { expiresAt: 0, value: null };
|
|
100
|
+
return runtime.testConnection();
|
|
101
|
+
},
|
|
102
|
+
async createPlan() {
|
|
103
|
+
throw new AgentProviderError('agent-codex-run-required', 'Codex Agent requests use the LiveDesk tool loop.', { status: 409 });
|
|
104
|
+
},
|
|
105
|
+
async createSummary(input) {
|
|
106
|
+
const source = input && typeof input === 'object' ? input : {};
|
|
107
|
+
const results = Array.isArray(source.results) ? source.results : [];
|
|
108
|
+
return {
|
|
109
|
+
summary: String(results.length ? `${source.completed || 0} completed, ${source.failed || 0} failed.` : 'LiveDesk Agent run completed.').slice(0, 1200)
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
async startRun(input) {
|
|
113
|
+
const current = await settings.get();
|
|
114
|
+
if (current.provider !== AGENT_PROVIDER_CODEX || !runtime) {
|
|
115
|
+
throw new AgentProviderError('agent-codex-not-active', 'Codex SDK is not the active Agent runtime.', { status: 409 });
|
|
116
|
+
}
|
|
117
|
+
return runtime.start(input);
|
|
118
|
+
},
|
|
119
|
+
getRun(runId) { return runtime?.get(runId) || null; },
|
|
120
|
+
cancelRun(runId) { return runtime?.cancel(runId) || null; },
|
|
121
|
+
cancelAllRuns() { return runtime?.cancelAll?.() || 0; }
|
|
122
|
+
};
|
|
123
|
+
}
|