@agent-webui/ai-desk-daemon 1.0.61-beta5 → 1.0.61-beta7
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/cli.js +60 -1
- package/lib/daemon-registry.js +133 -13
- package/package.json +11 -11
package/bin/cli.js
CHANGED
|
@@ -12,7 +12,12 @@ const { start, stop, restart, status } = require('../lib/daemon-manager');
|
|
|
12
12
|
const { getLogPath } = require('../lib/platform');
|
|
13
13
|
const { VERSION } = require('../lib/platform');
|
|
14
14
|
const { getPort } = require('../lib/config');
|
|
15
|
-
const {
|
|
15
|
+
const {
|
|
16
|
+
configureRegistryUrl,
|
|
17
|
+
getRegistryConfig,
|
|
18
|
+
reportLifecycle,
|
|
19
|
+
syncRegistryConfigToDaemonConfig,
|
|
20
|
+
} = require('../lib/daemon-registry');
|
|
16
21
|
const { upgradePackage } = require('../lib/self-upgrade');
|
|
17
22
|
|
|
18
23
|
function wait(ms) {
|
|
@@ -141,11 +146,63 @@ async function reportRegistryLifecycle(event) {
|
|
|
141
146
|
}
|
|
142
147
|
}
|
|
143
148
|
|
|
149
|
+
function syncRegistryConfigForDaemonStart() {
|
|
150
|
+
try {
|
|
151
|
+
syncRegistryConfigToDaemonConfig();
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.warn(chalk.yellow(`[registry] Failed to sync daemon registry config: ${error.message || error}`));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
144
157
|
program
|
|
145
158
|
.name('aidesk')
|
|
146
159
|
.description('AI Desk Daemon - CLI tool for managing the AI Desk daemon service')
|
|
147
160
|
.version(VERSION);
|
|
148
161
|
|
|
162
|
+
const registryCommand = program
|
|
163
|
+
.command('registry')
|
|
164
|
+
.description('Manage shared runtime registry backend settings');
|
|
165
|
+
|
|
166
|
+
registryCommand
|
|
167
|
+
.command('set-url <url>')
|
|
168
|
+
.description('Persist the AI Desk backend URL used for daemon registry reporting')
|
|
169
|
+
.option('--insecure-skip-tls-verify', 'Skip TLS certificate verification for this registry URL')
|
|
170
|
+
.option('--strict-tls', 'Require strict TLS certificate verification for this registry URL')
|
|
171
|
+
.action((url, options) => {
|
|
172
|
+
try {
|
|
173
|
+
if (options.insecureSkipTlsVerify && options.strictTls) {
|
|
174
|
+
throw new Error('Use either --insecure-skip-tls-verify or --strict-tls, not both');
|
|
175
|
+
}
|
|
176
|
+
const tlsInsecureSkipVerify = options.insecureSkipTlsVerify
|
|
177
|
+
? true
|
|
178
|
+
: (options.strictTls ? false : undefined);
|
|
179
|
+
const config = configureRegistryUrl(url, { tlsInsecureSkipVerify });
|
|
180
|
+
console.log(chalk.green('✓ Registry URL updated'));
|
|
181
|
+
console.log(`API base URL: ${config.apiBaseUrl}`);
|
|
182
|
+
console.log(`TLS verification: ${config.tlsInsecureSkipVerify ? 'skip for this URL' : 'strict'}`);
|
|
183
|
+
console.log(chalk.cyan('Restart the daemon for the new registry URL to be used by background heartbeats.'));
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error(chalk.red('Failed to update registry URL:'), error.message);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
registryCommand
|
|
191
|
+
.command('status')
|
|
192
|
+
.description('Show the effective daemon registry backend settings')
|
|
193
|
+
.action(() => {
|
|
194
|
+
const config = getRegistryConfig();
|
|
195
|
+
if (!config) {
|
|
196
|
+
console.log(chalk.yellow('Registry reporting is disabled'));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
console.log(`API base URL: ${config.apiBaseUrl}`);
|
|
200
|
+
console.log(`RC account ID: ${config.rcAccountId || '(empty)'}`);
|
|
201
|
+
console.log(`RC extension ID: ${config.rcExtensionId || '(empty)'}`);
|
|
202
|
+
console.log(`RC username: ${config.rcUsername || '(empty)'}`);
|
|
203
|
+
console.log(`TLS verification: ${config.tlsInsecureSkipVerify ? 'skip for this URL' : 'strict'}`);
|
|
204
|
+
});
|
|
205
|
+
|
|
149
206
|
// Start command
|
|
150
207
|
program
|
|
151
208
|
.command('start')
|
|
@@ -158,6 +215,7 @@ program
|
|
|
158
215
|
try {
|
|
159
216
|
const mode = resolveRequestedMode(options) || 'native';
|
|
160
217
|
const modeResult = configureRequestedMode(mode);
|
|
218
|
+
syncRegistryConfigForDaemonStart();
|
|
161
219
|
start();
|
|
162
220
|
await reportRegistryLifecycle('start');
|
|
163
221
|
if (mode === 'cli-anything' && modeResult?.runtimeInfo?.cliAnythingPath) {
|
|
@@ -257,6 +315,7 @@ program
|
|
|
257
315
|
try {
|
|
258
316
|
const mode = resolveRequestedMode(options);
|
|
259
317
|
const modeResult = configureRequestedMode(mode);
|
|
318
|
+
syncRegistryConfigForDaemonStart();
|
|
260
319
|
restart();
|
|
261
320
|
await reportRegistryLifecycle('restart');
|
|
262
321
|
if (mode === 'cli-anything' && modeResult?.runtimeInfo?.cliAnythingPath) {
|
package/lib/daemon-registry.js
CHANGED
|
@@ -25,16 +25,44 @@ function parseTruthyEnv(value) {
|
|
|
25
25
|
return raw === '1' || raw === 'true' || raw === 'yes' || raw === 'on';
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
function isPrivateRegistryHost(hostname) {
|
|
29
|
+
const host = trim(hostname).toLowerCase();
|
|
30
|
+
return (
|
|
31
|
+
host === 'localhost' ||
|
|
32
|
+
host === '127.0.0.1' ||
|
|
33
|
+
host.endsWith('.local') ||
|
|
34
|
+
/^10\./.test(host) ||
|
|
35
|
+
/^192\.168\./.test(host) ||
|
|
36
|
+
/^172\.(1[6-9]|2\d|3[0-1])\./.test(host)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function inferTLSInsecureSkipVerify(apiBaseUrl) {
|
|
41
|
+
try {
|
|
42
|
+
const url = new URL(normalizeApiBaseUrl(apiBaseUrl));
|
|
43
|
+
if (url.protocol !== 'https:') return false;
|
|
44
|
+
if (url.hostname === 'desk.int.rclabenv.com') return false;
|
|
45
|
+
return isPrivateRegistryHost(url.hostname);
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
28
51
|
function readRegistrySessionIdentity(homeDir = os.homedir()) {
|
|
29
52
|
const sessionPath = path.join(homeDir, '.aidesktop', 'session.json');
|
|
30
53
|
try {
|
|
31
54
|
if (!fs.existsSync(sessionPath)) return null;
|
|
32
55
|
const session = JSON.parse(fs.readFileSync(sessionPath, 'utf8'));
|
|
33
56
|
if (!session || typeof session !== 'object') return null;
|
|
57
|
+
const apiBaseUrl = normalizeApiBaseUrl(session.api_base_url || session.apiBaseUrl);
|
|
34
58
|
const rcAccountId = trim(session.account_id || session.accountId);
|
|
35
59
|
const rcExtensionId = trim(session.extension_id || session.extensionId);
|
|
36
|
-
|
|
37
|
-
|
|
60
|
+
const rcUsername = trim(session.rc_username || session.rcUsername);
|
|
61
|
+
const tlsInsecureSkipVerify = Boolean(
|
|
62
|
+
session.tls_insecure_skip_verify || session.tlsInsecureSkipVerify,
|
|
63
|
+
);
|
|
64
|
+
if (!apiBaseUrl && !rcAccountId && !rcExtensionId && !rcUsername) return null;
|
|
65
|
+
return { apiBaseUrl, rcAccountId, rcExtensionId, rcUsername, tlsInsecureSkipVerify };
|
|
38
66
|
} catch {
|
|
39
67
|
return null;
|
|
40
68
|
}
|
|
@@ -55,12 +83,12 @@ function readRegistryConfigFromDaemonConfig(homeDir = os.homedir()) {
|
|
|
55
83
|
sessionIdentity?.rcAccountId || '';
|
|
56
84
|
const rcExtensionId = trim(registry.rc_extension_id || registry.rcExtensionId) ||
|
|
57
85
|
sessionIdentity?.rcExtensionId || '';
|
|
58
|
-
if (!apiBaseUrl
|
|
86
|
+
if (!apiBaseUrl) return null;
|
|
59
87
|
return {
|
|
60
88
|
apiBaseUrl,
|
|
61
89
|
rcAccountId,
|
|
62
90
|
rcExtensionId,
|
|
63
|
-
rcUsername: trim(registry.rc_username || registry.rcUsername),
|
|
91
|
+
rcUsername: trim(registry.rc_username || registry.rcUsername) || sessionIdentity?.rcUsername || '',
|
|
64
92
|
tlsInsecureSkipVerify: Boolean(registry.tls_insecure_skip_verify || registry.tlsInsecureSkipVerify),
|
|
65
93
|
};
|
|
66
94
|
} catch {
|
|
@@ -71,32 +99,121 @@ function readRegistryConfigFromDaemonConfig(homeDir = os.homedir()) {
|
|
|
71
99
|
function getRegistryConfig(env = process.env, homeDir = os.homedir()) {
|
|
72
100
|
const daemonConfig = readRegistryConfigFromDaemonConfig(homeDir);
|
|
73
101
|
const sessionIdentity = readRegistrySessionIdentity(homeDir);
|
|
74
|
-
const
|
|
102
|
+
const envApiBaseUrl = normalizeApiBaseUrl(
|
|
75
103
|
env.AI_DESK_API_BASE_URL || env.AI_DESK_BACKEND_API_URL || env.AI_DESK_BACKEND_URL,
|
|
76
|
-
)
|
|
104
|
+
);
|
|
105
|
+
const apiBaseUrl = normalizeApiBaseUrl(
|
|
106
|
+
envApiBaseUrl ||
|
|
107
|
+
daemonConfig?.apiBaseUrl ||
|
|
108
|
+
sessionIdentity?.apiBaseUrl ||
|
|
109
|
+
DEFAULT_REGISTRY_API_BASE_URL,
|
|
110
|
+
);
|
|
77
111
|
const rcAccountId = trim(env.AI_DESK_RC_ACCOUNT_ID || env.rcAccountId) ||
|
|
78
|
-
daemonConfig?.rcAccountId ||
|
|
79
112
|
sessionIdentity?.rcAccountId ||
|
|
113
|
+
daemonConfig?.rcAccountId ||
|
|
80
114
|
'';
|
|
81
115
|
const rcExtensionId = trim(env.AI_DESK_RC_EXTENSION_ID || env.rcExtensionId) ||
|
|
82
|
-
daemonConfig?.rcExtensionId ||
|
|
83
116
|
sessionIdentity?.rcExtensionId ||
|
|
117
|
+
daemonConfig?.rcExtensionId ||
|
|
84
118
|
'';
|
|
85
|
-
if (apiBaseUrl
|
|
119
|
+
if (apiBaseUrl) {
|
|
86
120
|
const tlsEnvValue = parseTruthyEnv(env.AI_DESK_TLS_INSECURE_SKIP_VERIFY);
|
|
87
121
|
return {
|
|
88
122
|
apiBaseUrl,
|
|
89
123
|
rcAccountId,
|
|
90
124
|
rcExtensionId,
|
|
91
|
-
rcUsername: trim(env.AI_DESK_RC_USERNAME || env.rcUsername) ||
|
|
125
|
+
rcUsername: trim(env.AI_DESK_RC_USERNAME || env.rcUsername) ||
|
|
126
|
+
sessionIdentity?.rcUsername ||
|
|
127
|
+
daemonConfig?.rcUsername ||
|
|
128
|
+
'',
|
|
92
129
|
tlsInsecureSkipVerify: tlsEnvValue === null
|
|
93
|
-
? Boolean(daemonConfig?.tlsInsecureSkipVerify)
|
|
130
|
+
? Boolean(daemonConfig?.tlsInsecureSkipVerify ?? sessionIdentity?.tlsInsecureSkipVerify ?? inferTLSInsecureSkipVerify(apiBaseUrl))
|
|
94
131
|
: tlsEnvValue,
|
|
95
132
|
};
|
|
96
133
|
}
|
|
97
134
|
return null;
|
|
98
135
|
}
|
|
99
136
|
|
|
137
|
+
function daemonConfigPath(homeDir = os.homedir()) {
|
|
138
|
+
return path.join(homeDir, '.aidesktop', 'daemon-config.json');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function syncRegistryConfigToDaemonConfig(env = process.env, homeDir = os.homedir()) {
|
|
142
|
+
const config = getRegistryConfig(env, homeDir);
|
|
143
|
+
if (!config) return null;
|
|
144
|
+
|
|
145
|
+
const configPath = daemonConfigPath(homeDir);
|
|
146
|
+
let daemonConfig = {};
|
|
147
|
+
try {
|
|
148
|
+
if (fs.existsSync(configPath)) {
|
|
149
|
+
const parsed = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
150
|
+
if (parsed && typeof parsed === 'object') daemonConfig = parsed;
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
daemonConfig = {};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
daemonConfig.registry = {
|
|
157
|
+
...(daemonConfig.registry && typeof daemonConfig.registry === 'object' ? daemonConfig.registry : {}),
|
|
158
|
+
api_base_url: config.apiBaseUrl,
|
|
159
|
+
rc_account_id: config.rcAccountId,
|
|
160
|
+
rc_extension_id: config.rcExtensionId,
|
|
161
|
+
rc_username: config.rcUsername,
|
|
162
|
+
tls_insecure_skip_verify: Boolean(config.tlsInsecureSkipVerify),
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
166
|
+
fs.writeFileSync(configPath, `${JSON.stringify(daemonConfig, null, 2)}\n`, 'utf8');
|
|
167
|
+
return config;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function configureRegistryUrl(apiBaseUrl, options = {}) {
|
|
171
|
+
const homeDir = options.homeDir || os.homedir();
|
|
172
|
+
const normalizedApiBaseUrl = normalizeApiBaseUrl(apiBaseUrl);
|
|
173
|
+
if (!normalizedApiBaseUrl) {
|
|
174
|
+
throw new Error('Registry URL is required');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
let parsedUrl;
|
|
178
|
+
try {
|
|
179
|
+
parsedUrl = new URL(normalizedApiBaseUrl);
|
|
180
|
+
} catch {
|
|
181
|
+
throw new Error(`Invalid registry URL: ${apiBaseUrl}`);
|
|
182
|
+
}
|
|
183
|
+
if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
|
|
184
|
+
throw new Error(`Registry URL must use http or https: ${apiBaseUrl}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const configPath = daemonConfigPath(homeDir);
|
|
188
|
+
let daemonConfig = {};
|
|
189
|
+
try {
|
|
190
|
+
if (fs.existsSync(configPath)) {
|
|
191
|
+
const parsedConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
192
|
+
if (parsedConfig && typeof parsedConfig === 'object') daemonConfig = parsedConfig;
|
|
193
|
+
}
|
|
194
|
+
} catch {
|
|
195
|
+
daemonConfig = {};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const tlsInsecureSkipVerify = typeof options.tlsInsecureSkipVerify === 'boolean'
|
|
199
|
+
? options.tlsInsecureSkipVerify
|
|
200
|
+
: inferTLSInsecureSkipVerify(normalizedApiBaseUrl);
|
|
201
|
+
|
|
202
|
+
daemonConfig.registry = {
|
|
203
|
+
...(daemonConfig.registry && typeof daemonConfig.registry === 'object' ? daemonConfig.registry : {}),
|
|
204
|
+
api_base_url: normalizedApiBaseUrl,
|
|
205
|
+
tls_insecure_skip_verify: tlsInsecureSkipVerify,
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
209
|
+
fs.writeFileSync(configPath, `${JSON.stringify(daemonConfig, null, 2)}\n`, 'utf8');
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
apiBaseUrl: normalizedApiBaseUrl,
|
|
213
|
+
tlsInsecureSkipVerify,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
100
217
|
function registryStatePaths(homeDir = os.homedir()) {
|
|
101
218
|
const root = path.join(homeDir, '.aidesktop');
|
|
102
219
|
return {
|
|
@@ -206,8 +323,8 @@ function postJSON(urlString, payload, config) {
|
|
|
206
323
|
headers: {
|
|
207
324
|
'Content-Type': 'application/json',
|
|
208
325
|
'Content-Length': Buffer.byteLength(body),
|
|
209
|
-
rcAccountId: config.rcAccountId,
|
|
210
|
-
rcExtensionId: config.rcExtensionId,
|
|
326
|
+
...(config.rcAccountId ? { rcAccountId: config.rcAccountId } : {}),
|
|
327
|
+
...(config.rcExtensionId ? { rcExtensionId: config.rcExtensionId } : {}),
|
|
211
328
|
...(config.rcUsername ? { rcUsername: config.rcUsername } : {}),
|
|
212
329
|
},
|
|
213
330
|
timeout: 3000,
|
|
@@ -259,8 +376,11 @@ async function reportLifecycle(event, { port, version, seq = 1 } = {}) {
|
|
|
259
376
|
|
|
260
377
|
module.exports = {
|
|
261
378
|
buildLifecyclePayload,
|
|
379
|
+
configureRegistryUrl,
|
|
262
380
|
DEFAULT_REGISTRY_API_BASE_URL,
|
|
381
|
+
inferTLSInsecureSkipVerify,
|
|
263
382
|
getRegistryConfig,
|
|
383
|
+
syncRegistryConfigToDaemonConfig,
|
|
264
384
|
readRegistrySessionIdentity,
|
|
265
385
|
readRegistryConfigFromDaemonConfig,
|
|
266
386
|
registryStatePaths,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-webui/ai-desk-daemon",
|
|
3
|
-
"version": "1.0.61-
|
|
3
|
+
"version": "1.0.61-beta7",
|
|
4
4
|
"description": "AI Desk Daemon - CLI tool for managing the AI Desk daemon service",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
"packages/*"
|
|
@@ -39,16 +39,16 @@
|
|
|
39
39
|
"chalk": "^4.1.2"
|
|
40
40
|
},
|
|
41
41
|
"optionalDependencies": {
|
|
42
|
-
"@agent-webui/ai-desk-daemon-darwin-arm64": "1.0.61-
|
|
43
|
-
"@agent-webui/ai-desk-daemon-darwin-x64": "1.0.61-
|
|
44
|
-
"@agent-webui/ai-desk-daemon-linux-arm64": "1.0.61-
|
|
45
|
-
"@agent-webui/ai-desk-daemon-linux-x64": "1.0.61-
|
|
46
|
-
"@agent-webui/ai-desk-daemon-win32-x64": "1.0.61-
|
|
47
|
-
"@agent-webui/ai-desk-python-darwin-arm64": "1.0.61-
|
|
48
|
-
"@agent-webui/ai-desk-python-darwin-x64": "1.0.61-
|
|
49
|
-
"@agent-webui/ai-desk-python-linux-arm64": "1.0.61-
|
|
50
|
-
"@agent-webui/ai-desk-python-linux-x64": "1.0.61-
|
|
51
|
-
"@agent-webui/ai-desk-python-win32-x64": "1.0.61-
|
|
42
|
+
"@agent-webui/ai-desk-daemon-darwin-arm64": "1.0.61-beta7",
|
|
43
|
+
"@agent-webui/ai-desk-daemon-darwin-x64": "1.0.61-beta7",
|
|
44
|
+
"@agent-webui/ai-desk-daemon-linux-arm64": "1.0.61-beta7",
|
|
45
|
+
"@agent-webui/ai-desk-daemon-linux-x64": "1.0.61-beta7",
|
|
46
|
+
"@agent-webui/ai-desk-daemon-win32-x64": "1.0.61-beta7",
|
|
47
|
+
"@agent-webui/ai-desk-python-darwin-arm64": "1.0.61-beta7",
|
|
48
|
+
"@agent-webui/ai-desk-python-darwin-x64": "1.0.61-beta7",
|
|
49
|
+
"@agent-webui/ai-desk-python-linux-arm64": "1.0.61-beta7",
|
|
50
|
+
"@agent-webui/ai-desk-python-linux-x64": "1.0.61-beta7",
|
|
51
|
+
"@agent-webui/ai-desk-python-win32-x64": "1.0.61-beta7"
|
|
52
52
|
},
|
|
53
53
|
"repository": {
|
|
54
54
|
"type": "git",
|