@agent-webui/ai-desk 1.0.54 → 1.0.56
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 +271 -2
- package/package.json +3 -3
package/bin/aidesk.js
CHANGED
|
@@ -1,7 +1,276 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const PACKAGE_NAME = '@agent-webui/ai-desk';
|
|
8
|
+
const SKIP_UPDATE_ENV = 'AI_DESK_SKIP_SELF_UPDATE';
|
|
9
|
+
const UPDATE_COMMANDS = new Set(['start', 'restart']);
|
|
10
|
+
const OFFICIAL_NPM_REGISTRY = 'https://registry.npmjs.org/';
|
|
11
|
+
|
|
12
|
+
function readJSON(filePath) {
|
|
13
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function currentPackageRoot() {
|
|
17
|
+
return path.resolve(__dirname, '..');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function currentVersion() {
|
|
21
|
+
return readJSON(path.join(currentPackageRoot(), 'package.json')).version;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isPackagedInstall() {
|
|
25
|
+
return currentPackageRoot().split(path.sep).includes('node_modules');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function parseVersion(version) {
|
|
29
|
+
return String(version || '')
|
|
30
|
+
.trim()
|
|
31
|
+
.replace(/^v/, '')
|
|
32
|
+
.split('-')[0]
|
|
33
|
+
.split('.')
|
|
34
|
+
.map((part) => Number.parseInt(part, 10) || 0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function compareVersions(left, right) {
|
|
38
|
+
const leftParts = parseVersion(left);
|
|
39
|
+
const rightParts = parseVersion(right);
|
|
40
|
+
const length = Math.max(leftParts.length, rightParts.length);
|
|
41
|
+
for (let index = 0; index < length; index += 1) {
|
|
42
|
+
const delta = (leftParts[index] || 0) - (rightParts[index] || 0);
|
|
43
|
+
if (delta !== 0) {
|
|
44
|
+
return delta;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function npmCommand() {
|
|
51
|
+
if (process.env.npm_execpath && fs.existsSync(process.env.npm_execpath)) {
|
|
52
|
+
return {
|
|
53
|
+
command: process.execPath,
|
|
54
|
+
args: [process.env.npm_execpath],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
command: process.platform === 'win32' ? 'npm.cmd' : 'npm',
|
|
60
|
+
args: [],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function runNpm(args, options = {}) {
|
|
65
|
+
const npm = npmCommand();
|
|
66
|
+
return spawnSync(npm.command, [...npm.args, ...args], {
|
|
67
|
+
encoding: 'utf8',
|
|
68
|
+
...options,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function npmOutput(result) {
|
|
73
|
+
return `${result.stderr || ''}${result.stdout || ''}`.trim();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function withOfficialRegistry(args) {
|
|
77
|
+
return [...args, `--registry=${OFFICIAL_NPM_REGISTRY}`];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function runNpmWithRegistryFallback(args, options = {}) {
|
|
81
|
+
const primaryResult = runNpm(withOfficialRegistry(args), options);
|
|
82
|
+
if (primaryResult.status === 0) {
|
|
83
|
+
return primaryResult;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const fallbackResult = runNpm(args, options);
|
|
87
|
+
if (fallbackResult.status === 0) {
|
|
88
|
+
return fallbackResult;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fallbackResult.primaryError = npmOutput(primaryResult);
|
|
92
|
+
return fallbackResult;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function latestPublishedVersion() {
|
|
96
|
+
const result = runNpmWithRegistryFallback(['view', PACKAGE_NAME, 'version'], {
|
|
97
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (result.status !== 0) {
|
|
101
|
+
const output = npmOutput(result);
|
|
102
|
+
const primaryError = result.primaryError ? `Official registry error: ${result.primaryError}\n` : '';
|
|
103
|
+
const fallbackError = output ? `Fallback registry error: ${output}` : '';
|
|
104
|
+
const errorMessage = `${primaryError}${fallbackError}`.trim();
|
|
105
|
+
throw new Error(errorMessage || 'Unable to check npm registry');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return String(result.stdout || '').trim();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function realpathIfExists(targetPath) {
|
|
112
|
+
try {
|
|
113
|
+
return fs.realpathSync(targetPath);
|
|
114
|
+
} catch {
|
|
115
|
+
return '';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function isSubPath(childPath, parentPath) {
|
|
120
|
+
const relativePath = path.relative(parentPath, childPath);
|
|
121
|
+
return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function globalNpmRoot() {
|
|
125
|
+
const result = runNpm(['root', '-g'], {
|
|
126
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
127
|
+
});
|
|
128
|
+
if (result.status !== 0) {
|
|
129
|
+
return '';
|
|
130
|
+
}
|
|
131
|
+
return realpathIfExists(String(result.stdout || '').trim());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function packagePathFromProjectRoot(projectRoot) {
|
|
135
|
+
return path.join(projectRoot, 'node_modules', ...PACKAGE_NAME.split('/'));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function findLocalProjectRoot(packageRoot) {
|
|
139
|
+
const realPackageRoot = realpathIfExists(packageRoot);
|
|
140
|
+
const realGlobalRoot = globalNpmRoot();
|
|
141
|
+
if (realGlobalRoot && isSubPath(realPackageRoot, realGlobalRoot)) {
|
|
142
|
+
return '';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let currentDir = packageRoot;
|
|
146
|
+
while (currentDir && currentDir !== path.dirname(currentDir)) {
|
|
147
|
+
const candidate = realpathIfExists(packagePathFromProjectRoot(currentDir));
|
|
148
|
+
if (candidate && candidate === realPackageRoot) {
|
|
149
|
+
return currentDir;
|
|
150
|
+
}
|
|
151
|
+
currentDir = path.dirname(currentDir);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return '';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function installLatestVersion(latestVersion) {
|
|
158
|
+
const packageRoot = currentPackageRoot();
|
|
159
|
+
const projectRoot = findLocalProjectRoot(packageRoot);
|
|
160
|
+
const installTarget = `${PACKAGE_NAME}@${latestVersion}`;
|
|
161
|
+
|
|
162
|
+
if (projectRoot) {
|
|
163
|
+
return runNpmWithRegistryFallback(['install', installTarget, '--include=optional'], {
|
|
164
|
+
cwd: projectRoot,
|
|
165
|
+
stdio: 'inherit',
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return runNpmWithRegistryFallback(['install', '-g', installTarget, '--include=optional'], {
|
|
170
|
+
stdio: 'inherit',
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function requestedCommand(args) {
|
|
175
|
+
for (const arg of args) {
|
|
176
|
+
if (arg === '--') {
|
|
177
|
+
return '';
|
|
178
|
+
}
|
|
179
|
+
if (!arg.startsWith('-')) {
|
|
180
|
+
return arg;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return '';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function shouldCheckForUpdate(args) {
|
|
187
|
+
if (process.env[SKIP_UPDATE_ENV]) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (!isPackagedInstall() || args.includes('--help') || args.includes('-h')) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const command = requestedCommand(args);
|
|
196
|
+
return UPDATE_COMMANDS.has(command);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function restartWithUpdatedCli(args) {
|
|
200
|
+
const scriptPath = path.join(currentPackageRoot(), 'bin', 'aidesk.js');
|
|
201
|
+
const result = spawnSync(process.execPath, [scriptPath, ...args], {
|
|
202
|
+
stdio: 'inherit',
|
|
203
|
+
env: {
|
|
204
|
+
...process.env,
|
|
205
|
+
[SKIP_UPDATE_ENV]: '1',
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
if (result.error) {
|
|
210
|
+
throw result.error;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (result.signal) {
|
|
214
|
+
process.kill(process.pid, result.signal);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
process.exit(typeof result.status === 'number' ? result.status : 1);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function updateBeforeCommand(args) {
|
|
221
|
+
if (!shouldCheckForUpdate(args)) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const command = requestedCommand(args);
|
|
226
|
+
console.log('Checking for AI Desk updates...');
|
|
227
|
+
|
|
228
|
+
let latestVersion;
|
|
229
|
+
try {
|
|
230
|
+
latestVersion = latestPublishedVersion();
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.warn(`Unable to check for AI Desk updates: ${error.message}`);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const installedVersion = currentVersion();
|
|
237
|
+
if (compareVersions(latestVersion, installedVersion) <= 0) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
console.log(`Updating AI Desk from ${installedVersion} to ${latestVersion}...`);
|
|
242
|
+
const result = installLatestVersion(latestVersion);
|
|
243
|
+
if (result.error) {
|
|
244
|
+
throw result.error;
|
|
245
|
+
}
|
|
246
|
+
if (result.status !== 0) {
|
|
247
|
+
process.exit(typeof result.status === 'number' ? result.status : 1);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const updatedVersion = currentVersion();
|
|
251
|
+
console.log(`AI Desk updated to ${updatedVersion}.`);
|
|
252
|
+
console.log(`Restarting aidesk ${command} with the updated CLI...`);
|
|
253
|
+
restartWithUpdatedCli(args);
|
|
254
|
+
}
|
|
255
|
+
|
|
3
256
|
try {
|
|
4
|
-
|
|
257
|
+
updateBeforeCommand(process.argv.slice(2));
|
|
5
258
|
} catch (error) {
|
|
6
|
-
|
|
259
|
+
console.error(`Failed to update AI Desk: ${error.message}`);
|
|
260
|
+
process.exit(1);
|
|
7
261
|
}
|
|
262
|
+
|
|
263
|
+
function loadDaemonCli() {
|
|
264
|
+
if (!isPackagedInstall()) {
|
|
265
|
+
require('../../../bin/cli.js');
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
require(require.resolve('@agent-webui/ai-desk-daemon/bin/cli.js'));
|
|
271
|
+
} catch (error) {
|
|
272
|
+
require('../../../bin/cli.js');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
loadDaemonCli();
|
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.56",
|
|
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.56",
|
|
18
|
+
"@agent-webui/ai-desk-harness-gimp": "1.0.56"
|
|
19
19
|
},
|
|
20
20
|
"license": "MIT"
|
|
21
21
|
}
|