@agent-webui/ai-desk 1.0.66 → 1.0.67
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/aidesk.js +196 -37
- package/package.json +3 -3
package/bin/aidesk.js
CHANGED
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const { spawnSync } = require('child_process');
|
|
5
|
+
const { spawn, spawnSync } = require('child_process');
|
|
6
6
|
|
|
7
7
|
const PACKAGE_NAME = '@agent-webui/ai-desk';
|
|
8
8
|
const SKIP_UPDATE_ENV = 'AI_DESK_SKIP_SELF_UPDATE';
|
|
9
9
|
const UPDATE_COMMANDS = new Set(['start', 'restart', 'upgrade']);
|
|
10
|
-
const
|
|
10
|
+
const DEFAULT_NPM_REGISTRIES = [
|
|
11
|
+
'https://mirrors.cloud.tencent.com/npm/',
|
|
12
|
+
'https://r.cnpmjs.org/',
|
|
13
|
+
'https://mirrors.huaweicloud.com/repository/npm/',
|
|
14
|
+
'https://nexus-xmn02.int.rclabenv.com/nexus/content/groups/npm-all/',
|
|
15
|
+
];
|
|
16
|
+
const NPM_REGISTRIES_ENV = 'AI_DESK_NPM_REGISTRIES';
|
|
17
|
+
const NPM_REGISTRY_TIMEOUT_MS = 5000;
|
|
11
18
|
|
|
12
19
|
function readJSON(filePath) {
|
|
13
20
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
@@ -69,43 +76,189 @@ function runNpm(args, options = {}) {
|
|
|
69
76
|
});
|
|
70
77
|
}
|
|
71
78
|
|
|
79
|
+
function runNpmAsync(args, options = {}) {
|
|
80
|
+
const npm = npmCommand();
|
|
81
|
+
const timeoutMs = options.timeoutMs || 0;
|
|
82
|
+
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
const child = spawn(npm.command, [...npm.args, ...args], {
|
|
85
|
+
cwd: options.cwd,
|
|
86
|
+
env: process.env,
|
|
87
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
88
|
+
});
|
|
89
|
+
let stdout = '';
|
|
90
|
+
let stderr = '';
|
|
91
|
+
let settled = false;
|
|
92
|
+
|
|
93
|
+
const finish = (result) => {
|
|
94
|
+
if (settled) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
settled = true;
|
|
98
|
+
if (timer) {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
}
|
|
101
|
+
resolve({
|
|
102
|
+
stdout,
|
|
103
|
+
stderr,
|
|
104
|
+
...result,
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const timer = timeoutMs > 0
|
|
109
|
+
? setTimeout(() => {
|
|
110
|
+
child.kill();
|
|
111
|
+
finish({
|
|
112
|
+
status: null,
|
|
113
|
+
signal: 'SIGTERM',
|
|
114
|
+
error: new Error(`npm command timed out after ${timeoutMs}ms`),
|
|
115
|
+
});
|
|
116
|
+
}, timeoutMs)
|
|
117
|
+
: null;
|
|
118
|
+
|
|
119
|
+
child.stdout.on('data', (chunk) => {
|
|
120
|
+
stdout += chunk;
|
|
121
|
+
});
|
|
122
|
+
child.stderr.on('data', (chunk) => {
|
|
123
|
+
stderr += chunk;
|
|
124
|
+
});
|
|
125
|
+
child.on('error', (error) => {
|
|
126
|
+
finish({
|
|
127
|
+
status: null,
|
|
128
|
+
error,
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
child.on('close', (status, signal) => {
|
|
132
|
+
finish({
|
|
133
|
+
status,
|
|
134
|
+
signal,
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
72
140
|
function npmOutput(result) {
|
|
73
141
|
return `${result.stderr || ''}${result.stdout || ''}`.trim();
|
|
74
142
|
}
|
|
75
143
|
|
|
76
|
-
function
|
|
77
|
-
|
|
144
|
+
function normalizeRegistryUrl(registry) {
|
|
145
|
+
const value = String(registry || '').trim();
|
|
146
|
+
if (!value) {
|
|
147
|
+
return '';
|
|
148
|
+
}
|
|
149
|
+
return value.endsWith('/') ? value : `${value}/`;
|
|
78
150
|
}
|
|
79
151
|
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
152
|
+
function configuredNpmRegistries() {
|
|
153
|
+
const configured = String(process.env[NPM_REGISTRIES_ENV] || '')
|
|
154
|
+
.split(',')
|
|
155
|
+
.map(normalizeRegistryUrl)
|
|
156
|
+
.filter(Boolean);
|
|
157
|
+
return Array.from(new Set([
|
|
158
|
+
...DEFAULT_NPM_REGISTRIES,
|
|
159
|
+
...configured,
|
|
160
|
+
]));
|
|
161
|
+
}
|
|
85
162
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
163
|
+
function packageScope(packageName) {
|
|
164
|
+
const match = String(packageName || '').match(/^(@[^/]+)\//);
|
|
165
|
+
return match ? match[1] : '';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function registryArgsForPackage(packageName, registry) {
|
|
169
|
+
const normalizedRegistry = normalizeRegistryUrl(registry);
|
|
170
|
+
const args = [`--registry=${normalizedRegistry}`];
|
|
171
|
+
const scope = packageScope(packageName);
|
|
172
|
+
if (scope) {
|
|
173
|
+
args.push(`--${scope}:registry=${normalizedRegistry}`);
|
|
89
174
|
}
|
|
175
|
+
return args;
|
|
176
|
+
}
|
|
90
177
|
|
|
91
|
-
|
|
92
|
-
return
|
|
178
|
+
function withPackageRegistry(args, packageName, registry) {
|
|
179
|
+
return [
|
|
180
|
+
...args,
|
|
181
|
+
...registryArgsForPackage(packageName, registry),
|
|
182
|
+
];
|
|
93
183
|
}
|
|
94
184
|
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
|
|
185
|
+
function timeoutError(registry, timeoutMs) {
|
|
186
|
+
return new Error(`npm registry ${registry} timed out after ${timeoutMs}ms`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function withTimeout(promise, timeoutMs, error) {
|
|
190
|
+
let timer;
|
|
191
|
+
const timeout = new Promise((_, reject) => {
|
|
192
|
+
timer = setTimeout(() => reject(error), timeoutMs);
|
|
98
193
|
});
|
|
99
194
|
|
|
195
|
+
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function latestVersionFromRegistry(registry) {
|
|
199
|
+
const normalizedRegistry = normalizeRegistryUrl(registry);
|
|
200
|
+
const args = withPackageRegistry(['view', PACKAGE_NAME, 'version'], PACKAGE_NAME, normalizedRegistry);
|
|
201
|
+
const result = await withTimeout(runNpmAsync(args, {
|
|
202
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
203
|
+
timeoutMs: NPM_REGISTRY_TIMEOUT_MS,
|
|
204
|
+
}), NPM_REGISTRY_TIMEOUT_MS, timeoutError(normalizedRegistry, NPM_REGISTRY_TIMEOUT_MS));
|
|
205
|
+
|
|
206
|
+
if (result.error) {
|
|
207
|
+
throw result.error;
|
|
208
|
+
}
|
|
100
209
|
if (result.status !== 0) {
|
|
101
210
|
const output = npmOutput(result);
|
|
102
|
-
|
|
103
|
-
const fallbackError = output ? `Fallback registry error: ${output}` : '';
|
|
104
|
-
const errorMessage = `${primaryError}${fallbackError}`.trim();
|
|
105
|
-
throw new Error(errorMessage || 'Unable to check npm registry');
|
|
211
|
+
throw new Error(output || `Unable to check npm registry ${normalizedRegistry}`);
|
|
106
212
|
}
|
|
107
213
|
|
|
108
|
-
|
|
214
|
+
const version = String(result.stdout || '').trim();
|
|
215
|
+
if (!version) {
|
|
216
|
+
throw new Error(`npm registry ${normalizedRegistry} returned an empty version`);
|
|
217
|
+
}
|
|
218
|
+
return version;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function chooseLatestPackageSource(currentBest, candidate) {
|
|
222
|
+
if (!currentBest) {
|
|
223
|
+
return candidate;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return compareVersions(candidate.version, currentBest.version) > 0 ? candidate : currentBest;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function latestPublishedPackageSource() {
|
|
230
|
+
const checks = await Promise.all(configuredNpmRegistries().map(async (registry) => {
|
|
231
|
+
try {
|
|
232
|
+
return {
|
|
233
|
+
registry,
|
|
234
|
+
version: await latestVersionFromRegistry(registry),
|
|
235
|
+
};
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return {
|
|
238
|
+
registry,
|
|
239
|
+
error,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}));
|
|
243
|
+
|
|
244
|
+
const errors = [];
|
|
245
|
+
let selected = null;
|
|
246
|
+
for (const check of checks) {
|
|
247
|
+
if (check.version) {
|
|
248
|
+
selected = chooseLatestPackageSource(selected, {
|
|
249
|
+
version: check.version,
|
|
250
|
+
registry: check.registry,
|
|
251
|
+
});
|
|
252
|
+
} else {
|
|
253
|
+
errors.push(`${check.registry}: ${check.error.message}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (selected) {
|
|
258
|
+
return selected;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
throw new Error(`Unable to check npm registries.\n${errors.join('\n')}`.trim());
|
|
109
262
|
}
|
|
110
263
|
|
|
111
264
|
function realpathIfExists(targetPath) {
|
|
@@ -154,19 +307,20 @@ function findLocalProjectRoot(packageRoot) {
|
|
|
154
307
|
return '';
|
|
155
308
|
}
|
|
156
309
|
|
|
157
|
-
function installLatestVersion(latestVersion) {
|
|
310
|
+
function installLatestVersion(latestVersion, registry = DEFAULT_NPM_REGISTRIES[0]) {
|
|
158
311
|
const packageRoot = currentPackageRoot();
|
|
159
312
|
const projectRoot = findLocalProjectRoot(packageRoot);
|
|
160
313
|
const installTarget = `${PACKAGE_NAME}@${latestVersion}`;
|
|
314
|
+
const installArgs = withPackageRegistry(['install', installTarget, '--include=optional'], PACKAGE_NAME, registry);
|
|
161
315
|
|
|
162
316
|
if (projectRoot) {
|
|
163
|
-
return
|
|
317
|
+
return runNpm(installArgs, {
|
|
164
318
|
cwd: projectRoot,
|
|
165
319
|
stdio: 'inherit',
|
|
166
320
|
});
|
|
167
321
|
}
|
|
168
322
|
|
|
169
|
-
return
|
|
323
|
+
return runNpm(withPackageRegistry(['install', '-g', installTarget, '--include=optional'], PACKAGE_NAME, registry), {
|
|
170
324
|
stdio: 'inherit',
|
|
171
325
|
});
|
|
172
326
|
}
|
|
@@ -217,7 +371,7 @@ function restartWithUpdatedCli(args) {
|
|
|
217
371
|
process.exit(typeof result.status === 'number' ? result.status : 1);
|
|
218
372
|
}
|
|
219
373
|
|
|
220
|
-
function updateBeforeCommand(args) {
|
|
374
|
+
async function updateBeforeCommand(args) {
|
|
221
375
|
if (!shouldCheckForUpdate(args)) {
|
|
222
376
|
return;
|
|
223
377
|
}
|
|
@@ -225,14 +379,15 @@ function updateBeforeCommand(args) {
|
|
|
225
379
|
const command = requestedCommand(args);
|
|
226
380
|
console.log('Checking for AI Desk updates...');
|
|
227
381
|
|
|
228
|
-
let
|
|
382
|
+
let latestSource;
|
|
229
383
|
try {
|
|
230
|
-
|
|
384
|
+
latestSource = await latestPublishedPackageSource();
|
|
231
385
|
} catch (error) {
|
|
232
386
|
console.warn(`Unable to check for AI Desk updates: ${error.message}`);
|
|
233
387
|
return;
|
|
234
388
|
}
|
|
235
389
|
|
|
390
|
+
const latestVersion = latestSource.version;
|
|
236
391
|
const installedVersion = currentVersion();
|
|
237
392
|
const forceUpgrade = command === 'upgrade' && args.includes('--force');
|
|
238
393
|
const alreadyLatest = compareVersions(latestVersion, installedVersion) <= 0;
|
|
@@ -246,7 +401,7 @@ function updateBeforeCommand(args) {
|
|
|
246
401
|
|
|
247
402
|
const verb = alreadyLatest ? 'Reinstalling' : 'Updating';
|
|
248
403
|
console.log(`${verb} AI Desk from ${installedVersion} to ${latestVersion}...`);
|
|
249
|
-
const result = installLatestVersion(latestVersion);
|
|
404
|
+
const result = installLatestVersion(latestVersion, latestSource.registry);
|
|
250
405
|
if (result.error) {
|
|
251
406
|
throw result.error;
|
|
252
407
|
}
|
|
@@ -263,13 +418,6 @@ function updateBeforeCommand(args) {
|
|
|
263
418
|
restartWithUpdatedCli(args);
|
|
264
419
|
}
|
|
265
420
|
|
|
266
|
-
try {
|
|
267
|
-
updateBeforeCommand(process.argv.slice(2));
|
|
268
|
-
} catch (error) {
|
|
269
|
-
console.error(`Failed to update AI Desk: ${error.message}`);
|
|
270
|
-
process.exit(1);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
421
|
function loadDaemonCli() {
|
|
274
422
|
if (!isPackagedInstall()) {
|
|
275
423
|
require('../../../bin/cli.js');
|
|
@@ -283,4 +431,15 @@ function loadDaemonCli() {
|
|
|
283
431
|
}
|
|
284
432
|
}
|
|
285
433
|
|
|
286
|
-
|
|
434
|
+
async function main() {
|
|
435
|
+
try {
|
|
436
|
+
await updateBeforeCommand(process.argv.slice(2));
|
|
437
|
+
} catch (error) {
|
|
438
|
+
console.error(`Failed to update AI Desk: ${error.message}`);
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
loadDaemonCli();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-webui/ai-desk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.67",
|
|
4
4
|
"description": "Single-install AI Desk package with daemon and default harnesses",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aidesk": "bin/aidesk.js"
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"README.md"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@agent-webui/ai-desk-daemon": "1.0.
|
|
18
|
-
"@agent-webui/ai-desk-harness-gimp": "1.0.
|
|
17
|
+
"@agent-webui/ai-desk-daemon": "1.0.67",
|
|
18
|
+
"@agent-webui/ai-desk-harness-gimp": "1.0.67"
|
|
19
19
|
},
|
|
20
20
|
"license": "MIT"
|
|
21
21
|
}
|