@agent-webui/ai-desk-daemon 1.0.52-beta5 → 1.0.53
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 +3 -0
- package/bin/cli.js +22 -0
- package/lib/daemon-manager.js +5 -20
- package/lib/self-update.js +260 -0
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -49,6 +49,7 @@ aidesk status
|
|
|
49
49
|
|
|
50
50
|
**可用命令**:
|
|
51
51
|
- `aidesk start` - 启动守护进程(后台运行,沿用当前已保存 mode)
|
|
52
|
+
- `aidesk start --no-update` - 跳过启动前的稳定版更新检查
|
|
52
53
|
- `aidesk start --mode native` - 切到 Native mode 并启动
|
|
53
54
|
- `aidesk start --mode cli-anything` - 切到 Bundled CLI-Anything runtime mode 并启动
|
|
54
55
|
- `aidesk start --log` - 启动守护进程(前台运行,跟随日志)
|
|
@@ -63,6 +64,8 @@ aidesk status
|
|
|
63
64
|
- `Native mode`:检测、模型查询、命令执行走 daemon 原生实现。
|
|
64
65
|
- `Bundled CLI-Anything runtime mode`:使用 npm 安装时随包准备好的 Python runtime 和 `cli_anything` 入口;如果某个功能当前 runtime 不支持,daemon 会按配置回退到 native。
|
|
65
66
|
|
|
67
|
+
**更新说明**:`aidesk start` 默认会检查并安装 npm 上最新的稳定版 `@agent-webui/ai-desk`,会自动忽略 beta/prerelease 版本。可用 `--no-update` 或 `AIDESK_DISABLE_AUTO_UPDATE=1` 跳过。
|
|
68
|
+
|
|
66
69
|
📖 详细使用说明:[NPM_CLI.md](NPM_CLI.md)
|
|
67
70
|
|
|
68
71
|
---
|
package/bin/cli.js
CHANGED
|
@@ -11,6 +11,7 @@ const path = require('path');
|
|
|
11
11
|
const { start, stop, restart, status } = require('../lib/daemon-manager');
|
|
12
12
|
const { getLogPath } = require('../lib/platform');
|
|
13
13
|
const { VERSION } = require('../lib/platform');
|
|
14
|
+
const { ensureLatestStableAIDesk, reexecAideskCommand } = require('../lib/self-update');
|
|
14
15
|
|
|
15
16
|
function wait(ms) {
|
|
16
17
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -139,9 +140,30 @@ program
|
|
|
139
140
|
.option('-m, --mode <mode>', 'Implementation mode: native or cli-anything')
|
|
140
141
|
.option('--cli-anything', 'Enable CLI-Anything mode before starting')
|
|
141
142
|
.option('--native', 'Force native mode before starting')
|
|
143
|
+
.option('--no-update', 'Skip checking for the latest stable AI Desk package before starting')
|
|
142
144
|
.option('--log', 'Follow daemon logs in foreground (Ctrl+C to stop daemon)')
|
|
143
145
|
.action(async (options) => {
|
|
144
146
|
try {
|
|
147
|
+
if (options.update !== false) {
|
|
148
|
+
const updateResult = ensureLatestStableAIDesk({
|
|
149
|
+
currentVersion: VERSION,
|
|
150
|
+
logger: {
|
|
151
|
+
info: (message) => console.log(chalk.cyan(message)),
|
|
152
|
+
warn: (message) => console.warn(chalk.yellow(message)),
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
if (updateResult.updated) {
|
|
157
|
+
console.log(chalk.cyan('Restarting aidesk start with the updated CLI...'));
|
|
158
|
+
try {
|
|
159
|
+
process.exit(reexecAideskCommand(process.argv.slice(2)));
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.warn(chalk.yellow(`Failed to restart updated CLI: ${error.message}`));
|
|
162
|
+
console.warn(chalk.yellow('Continuing with the current process.'));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
145
167
|
const mode = resolveRequestedMode(options) || 'native';
|
|
146
168
|
const modeResult = configureRequestedMode(mode);
|
|
147
169
|
start();
|
package/lib/daemon-manager.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const { spawn, execSync } = require('child_process');
|
|
7
7
|
const http = require('http');
|
|
8
|
-
const { getDaemonBinaryPath, getPidPath, getConfiguredLogPath, getLogPath
|
|
8
|
+
const { getDaemonBinaryPath, getPidPath, getConfiguredLogPath, getLogPath } = require('./platform');
|
|
9
9
|
const { getPort, getConfigPath } = require('./config');
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -67,15 +67,6 @@ function getHealth() {
|
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
function formatStartOutput({ pid, port, version, logPath }) {
|
|
71
|
-
return [
|
|
72
|
-
`Daemon started (PID: ${pid})`,
|
|
73
|
-
`Version: ${version || 'unknown'}`,
|
|
74
|
-
`Port: ${port}`,
|
|
75
|
-
`Logs: ${logPath}`
|
|
76
|
-
];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
70
|
/**
|
|
80
71
|
* Start daemon
|
|
81
72
|
*/
|
|
@@ -131,14 +122,9 @@ function start() {
|
|
|
131
122
|
// Save PID
|
|
132
123
|
fs.writeFileSync(getPidPath(), child.pid.toString());
|
|
133
124
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
version: VERSION,
|
|
138
|
-
logPath: getLogPath()
|
|
139
|
-
})) {
|
|
140
|
-
console.log(line);
|
|
141
|
-
}
|
|
125
|
+
console.log(`Daemon started (PID: ${child.pid})`);
|
|
126
|
+
console.log(`Port: ${portNumber}`);
|
|
127
|
+
console.log(`Logs: ${getLogPath()}`);
|
|
142
128
|
|
|
143
129
|
return child.pid;
|
|
144
130
|
}
|
|
@@ -198,6 +184,5 @@ module.exports = {
|
|
|
198
184
|
start,
|
|
199
185
|
stop,
|
|
200
186
|
restart,
|
|
201
|
-
status
|
|
202
|
-
_formatStartOutputForTest: formatStartOutput
|
|
187
|
+
status
|
|
203
188
|
};
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-update helpers for the public `aidesk` npm package.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const DEFAULT_PACKAGE_NAME = '@agent-webui/ai-desk';
|
|
8
|
+
const DEFAULT_REGISTRY = 'https://registry.npmjs.org/';
|
|
9
|
+
const SKIP_AUTO_UPDATE_ENV = 'AIDESK_SKIP_AUTO_UPDATE';
|
|
10
|
+
const DISABLE_AUTO_UPDATE_ENV = 'AIDESK_DISABLE_AUTO_UPDATE';
|
|
11
|
+
const STRICT_AUTO_UPDATE_ENV = 'AIDESK_STRICT_AUTO_UPDATE';
|
|
12
|
+
|
|
13
|
+
function getNpmCommand() {
|
|
14
|
+
return process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getRegistry() {
|
|
18
|
+
return (
|
|
19
|
+
process.env.AIDESK_NPM_REGISTRY ||
|
|
20
|
+
process.env.npm_config_registry ||
|
|
21
|
+
DEFAULT_REGISTRY
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseVersion(version) {
|
|
26
|
+
const raw = String(version || '').trim().replace(/^v/, '');
|
|
27
|
+
const match = raw.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z][0-9A-Za-z.-]*))?(?:\+[0-9A-Za-z.-]+)?$/);
|
|
28
|
+
if (!match) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
major: Number.parseInt(match[1], 10),
|
|
34
|
+
minor: Number.parseInt(match[2], 10),
|
|
35
|
+
patch: Number.parseInt(match[3], 10),
|
|
36
|
+
prerelease: match[4] || '',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isStableVersion(version) {
|
|
41
|
+
const parsed = parseVersion(version);
|
|
42
|
+
return Boolean(parsed && !parsed.prerelease);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function compareVersionCore(left, right) {
|
|
46
|
+
const leftParsed = parseVersion(left);
|
|
47
|
+
const rightParsed = parseVersion(right);
|
|
48
|
+
if (!leftParsed || !rightParsed) {
|
|
49
|
+
return String(left || '').localeCompare(String(right || ''));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (const key of ['major', 'minor', 'patch']) {
|
|
53
|
+
if (leftParsed[key] !== rightParsed[key]) {
|
|
54
|
+
return leftParsed[key] - rightParsed[key];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function normalizeVersions(value) {
|
|
62
|
+
if (Array.isArray(value)) {
|
|
63
|
+
return value.map((item) => String(item));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (typeof value === 'string' && value.trim()) {
|
|
67
|
+
return [value.trim()];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function findLatestStableVersion(versions) {
|
|
74
|
+
const stableVersions = normalizeVersions(versions)
|
|
75
|
+
.filter(isStableVersion)
|
|
76
|
+
.sort(compareVersionCore);
|
|
77
|
+
|
|
78
|
+
return stableVersions[stableVersions.length - 1] || '';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function shouldInstallStableVersion(currentVersion, latestStableVersion) {
|
|
82
|
+
const latestParsed = parseVersion(latestStableVersion);
|
|
83
|
+
if (!latestParsed || latestParsed.prerelease) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const currentParsed = parseVersion(currentVersion);
|
|
88
|
+
if (!currentParsed) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (currentParsed.prerelease) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return compareVersionCore(latestStableVersion, currentVersion) > 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function runNpm(args, options = {}) {
|
|
100
|
+
const result = spawnSync(getNpmCommand(), args, {
|
|
101
|
+
encoding: options.encoding || 'utf8',
|
|
102
|
+
env: {
|
|
103
|
+
...process.env,
|
|
104
|
+
npm_config_update_notifier: 'false',
|
|
105
|
+
},
|
|
106
|
+
shell: process.platform === 'win32',
|
|
107
|
+
stdio: options.stdio || ['ignore', 'pipe', 'pipe'],
|
|
108
|
+
timeout: options.timeout || 30000,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (result.error) {
|
|
112
|
+
throw result.error;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (result.status !== 0) {
|
|
116
|
+
const stderr = result.stderr ? String(result.stderr).trim() : '';
|
|
117
|
+
const stdout = result.stdout ? String(result.stdout).trim() : '';
|
|
118
|
+
throw new Error(stderr || stdout || `npm exited with status ${result.status}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return result.stdout || '';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function fetchPublishedVersions(packageName, registry) {
|
|
125
|
+
const output = runNpm(
|
|
126
|
+
['view', packageName, 'versions', '--json', `--registry=${registry}`],
|
|
127
|
+
{ timeout: 15000 }
|
|
128
|
+
);
|
|
129
|
+
const parsed = JSON.parse(output);
|
|
130
|
+
return normalizeVersions(parsed);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function installPackageVersion(packageName, version, registry) {
|
|
134
|
+
runNpm(
|
|
135
|
+
['install', '-g', `${packageName}@${version}`, `--registry=${registry}`],
|
|
136
|
+
{ stdio: 'inherit', timeout: 120000 }
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function writeInfo(logger, message) {
|
|
141
|
+
if (logger && typeof logger.info === 'function') {
|
|
142
|
+
logger.info(message);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function writeWarn(logger, message) {
|
|
147
|
+
if (logger && typeof logger.warn === 'function') {
|
|
148
|
+
logger.warn(message);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function isAutoUpdateDisabled(options = {}) {
|
|
153
|
+
return (
|
|
154
|
+
options.enabled === false ||
|
|
155
|
+
process.env[SKIP_AUTO_UPDATE_ENV] === '1' ||
|
|
156
|
+
process.env[DISABLE_AUTO_UPDATE_ENV] === '1'
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function ensureLatestStableAIDesk(options = {}) {
|
|
161
|
+
const logger = options.logger || console;
|
|
162
|
+
const packageName = options.packageName || DEFAULT_PACKAGE_NAME;
|
|
163
|
+
const registry = options.registry || getRegistry();
|
|
164
|
+
const currentVersion = options.currentVersion || '';
|
|
165
|
+
|
|
166
|
+
if (isAutoUpdateDisabled(options)) {
|
|
167
|
+
return {
|
|
168
|
+
checked: false,
|
|
169
|
+
skipped: true,
|
|
170
|
+
updated: false,
|
|
171
|
+
reason: 'disabled',
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
writeInfo(logger, 'Checking for AI Desk updates...');
|
|
177
|
+
const versions = fetchPublishedVersions(packageName, registry);
|
|
178
|
+
const latestStableVersion = findLatestStableVersion(versions);
|
|
179
|
+
|
|
180
|
+
if (!latestStableVersion) {
|
|
181
|
+
throw new Error(`No stable versions found for ${packageName}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (!shouldInstallStableVersion(currentVersion, latestStableVersion)) {
|
|
185
|
+
writeInfo(logger, `AI Desk is up to date (${currentVersion || latestStableVersion}).`);
|
|
186
|
+
return {
|
|
187
|
+
checked: true,
|
|
188
|
+
latestVersion: latestStableVersion,
|
|
189
|
+
updated: false,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const fromVersion = currentVersion ? ` from ${currentVersion}` : '';
|
|
194
|
+
writeInfo(logger, `Updating AI Desk${fromVersion} to ${latestStableVersion}...`);
|
|
195
|
+
installPackageVersion(packageName, latestStableVersion, registry);
|
|
196
|
+
writeInfo(logger, `AI Desk updated to ${latestStableVersion}.`);
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
checked: true,
|
|
200
|
+
latestVersion: latestStableVersion,
|
|
201
|
+
updated: true,
|
|
202
|
+
};
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (process.env[STRICT_AUTO_UPDATE_ENV] === '1') {
|
|
205
|
+
throw new Error(`AI Desk auto-update failed: ${error.message}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
writeWarn(logger, `AI Desk update check failed: ${error.message}`);
|
|
209
|
+
writeWarn(logger, 'Starting the currently installed version.');
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
checked: false,
|
|
213
|
+
error,
|
|
214
|
+
updated: false,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function reexecAideskCommand(args = process.argv.slice(2)) {
|
|
220
|
+
const scriptPath = process.argv[1];
|
|
221
|
+
if (!scriptPath) {
|
|
222
|
+
throw new Error('Unable to resolve current aidesk executable path');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const result = spawnSync(process.execPath, [scriptPath, ...args], {
|
|
226
|
+
env: {
|
|
227
|
+
...process.env,
|
|
228
|
+
[SKIP_AUTO_UPDATE_ENV]: '1',
|
|
229
|
+
},
|
|
230
|
+
stdio: 'inherit',
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
if (result.error) {
|
|
234
|
+
throw result.error;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (typeof result.status === 'number') {
|
|
238
|
+
return result.status;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return result.signal ? 1 : 0;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
module.exports = {
|
|
245
|
+
DEFAULT_PACKAGE_NAME,
|
|
246
|
+
DEFAULT_REGISTRY,
|
|
247
|
+
SKIP_AUTO_UPDATE_ENV,
|
|
248
|
+
DISABLE_AUTO_UPDATE_ENV,
|
|
249
|
+
STRICT_AUTO_UPDATE_ENV,
|
|
250
|
+
ensureLatestStableAIDesk,
|
|
251
|
+
reexecAideskCommand,
|
|
252
|
+
_internals: {
|
|
253
|
+
compareVersionCore,
|
|
254
|
+
findLatestStableVersion,
|
|
255
|
+
isStableVersion,
|
|
256
|
+
normalizeVersions,
|
|
257
|
+
parseVersion,
|
|
258
|
+
shouldInstallStableVersion,
|
|
259
|
+
},
|
|
260
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-webui/ai-desk-daemon",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.53",
|
|
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.
|
|
43
|
-
"@agent-webui/ai-desk-daemon-darwin-x64": "1.0.
|
|
44
|
-
"@agent-webui/ai-desk-daemon-linux-arm64": "1.0.
|
|
45
|
-
"@agent-webui/ai-desk-daemon-linux-x64": "1.0.
|
|
46
|
-
"@agent-webui/ai-desk-daemon-win32-x64": "1.0.
|
|
47
|
-
"@agent-webui/ai-desk-python-darwin-arm64": "1.0.
|
|
48
|
-
"@agent-webui/ai-desk-python-darwin-x64": "1.0.
|
|
49
|
-
"@agent-webui/ai-desk-python-linux-arm64": "1.0.
|
|
50
|
-
"@agent-webui/ai-desk-python-linux-x64": "1.0.
|
|
51
|
-
"@agent-webui/ai-desk-python-win32-x64": "1.0.
|
|
42
|
+
"@agent-webui/ai-desk-daemon-darwin-arm64": "1.0.53",
|
|
43
|
+
"@agent-webui/ai-desk-daemon-darwin-x64": "1.0.53",
|
|
44
|
+
"@agent-webui/ai-desk-daemon-linux-arm64": "1.0.53",
|
|
45
|
+
"@agent-webui/ai-desk-daemon-linux-x64": "1.0.53",
|
|
46
|
+
"@agent-webui/ai-desk-daemon-win32-x64": "1.0.53",
|
|
47
|
+
"@agent-webui/ai-desk-python-darwin-arm64": "1.0.53",
|
|
48
|
+
"@agent-webui/ai-desk-python-darwin-x64": "1.0.53",
|
|
49
|
+
"@agent-webui/ai-desk-python-linux-arm64": "1.0.53",
|
|
50
|
+
"@agent-webui/ai-desk-python-linux-x64": "1.0.53",
|
|
51
|
+
"@agent-webui/ai-desk-python-win32-x64": "1.0.53"
|
|
52
52
|
},
|
|
53
53
|
"repository": {
|
|
54
54
|
"type": "git",
|