superun-ai-cli 0.1.11 → 0.1.13
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 -1
- package/dist/commands/system/update.d.ts +1 -1
- package/dist/commands/system/update.js +1 -1
- package/dist/commands/system/update.js.map +1 -1
- package/dist/update/version-gate.js +43 -56
- package/dist/update/version-gate.js.map +1 -1
- package/package.json +1 -1
- package/dist/update/update-lock.d.ts +0 -1
- package/dist/update/update-lock.js +0 -57
- package/dist/update/update-lock.js.map +0 -1
package/README.md
CHANGED
|
@@ -391,7 +391,9 @@ superun-ai chat publish visibility <sessionId> private
|
|
|
391
391
|
|
|
392
392
|
## 更新
|
|
393
393
|
|
|
394
|
-
CLI
|
|
394
|
+
CLI 每次执行业务命令前都查询 npm `latest`,检查本机全局安装的版本。版本不一致或安装不完整时,直接通过 npm 全局更新本机 CLI,校验成功后再执行本次业务命令;已经是最新版则直接执行。更新或校验失败时会停止执行,请根据错误提示处理后重试。帮助、`version` 和 `auth logout` 可离线使用。
|
|
395
|
+
|
|
396
|
+
自动更新不创建、读取或删除 `update.lock`,也不再向 CLI 自建的 `versions` 缓存安装或从中选择版本运行;新版会实际更新到 npm 全局安装位置。旧缓存中的 CLI 执行到新版更新逻辑时,同样会检查并升级全局入口,避免每次仍从旧版本启动。
|
|
395
397
|
|
|
396
398
|
版本预检和安装统一通过 npm 执行,沿用 npm 的代理和证书配置,并自动重试短暂的网络故障。官方 Registry 不可用时,会尝试用户已配置的 Registry,安装沿用查询成功的源;恢复过程不输出报错或安装日志。所有源均失败时才返回错误,`error.checks` 包含各次检查的原因码,不包含原始 npm 日志或凭据。不会通过关闭证书校验或忽略版本检查来放行业务请求。
|
|
397
399
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** 将本机 CLI 更新到 npm latest。@author xiuyu.yi */
|
|
2
2
|
import type { Command } from 'commander';
|
|
3
3
|
import type { OutputWriter } from '../../output/writer.js';
|
|
4
4
|
export declare function registerUpdate(program: Command, output: OutputWriter, update: () => Promise<{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export function registerUpdate(program, output, update) {
|
|
2
2
|
program
|
|
3
3
|
.command('update')
|
|
4
|
-
.description('
|
|
4
|
+
.description('检查并将本机 CLI 更新到最新版本')
|
|
5
5
|
.action(async () => {
|
|
6
6
|
const result = await update();
|
|
7
7
|
output.write({ state: 'COMPLETED', version: result.version });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/commands/system/update.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,cAAc,CAC5B,OAAgB,EAChB,MAAoB,EACpB,MAA0C;IAE1C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/commands/system/update.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,cAAc,CAC5B,OAAgB,EAChB,MAAoB,EACpB,MAA0C;IAE1C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,oBAAoB,CAAC;SACjC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,MAAM,MAAM,EAAE,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** 业务请求之前强制更新本机 CLI 到 npm latest。@author xiuyu.yi */
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
|
-
import { readFile,
|
|
4
|
-
import {
|
|
5
|
-
import { randomUUID } from 'node:crypto';
|
|
6
|
-
import { join } from 'node:path';
|
|
3
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
4
|
+
import { isAbsolute, join } from 'node:path';
|
|
7
5
|
import { PACKAGE_NAME, PACKAGE_VERSION } from '../config/constants.js';
|
|
8
6
|
import { object } from '../contracts/value.js';
|
|
9
7
|
import { CliError } from '../output/exit-codes.js';
|
|
10
|
-
import { withUpdateLock } from './update-lock.js';
|
|
11
8
|
import { latestVersion, runNpm, NPM_FETCH_OPTIONS, NpmCommandError } from './npm-registry.js';
|
|
12
|
-
async function
|
|
13
|
-
const packageDirectory = join(
|
|
9
|
+
async function installedEntry(root, version) {
|
|
10
|
+
const packageDirectory = join(root, PACKAGE_NAME);
|
|
14
11
|
try {
|
|
15
12
|
const metadata = object(JSON.parse(await readFile(join(packageDirectory, 'package.json'), 'utf8')));
|
|
16
13
|
const candidate = join(packageDirectory, 'dist', 'cli.js');
|
|
@@ -23,56 +20,46 @@ async function verifiedEntry(directory, version) {
|
|
|
23
20
|
return undefined;
|
|
24
21
|
}
|
|
25
22
|
export async function versionGate(argv, _output, updateOnly = false) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (required ===
|
|
29
|
-
return { reexecuted: false, version: required };
|
|
30
|
-
if (process.env.SUPERUN_AI_CLI_REEXEC === '1')
|
|
23
|
+
const source = await latestVersion();
|
|
24
|
+
const required = source.version;
|
|
25
|
+
if (required !== PACKAGE_VERSION && process.env.SUPERUN_AI_CLI_REEXEC === '1')
|
|
31
26
|
throw new CliError('UPDATE_FAILED', '重启后版本仍不匹配,已停止重复更新');
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const cached = await verifiedEntry(destination, required);
|
|
42
|
-
if (cached)
|
|
43
|
-
return cached;
|
|
44
|
-
await mkdir(root, { recursive: true, mode: 0o700 });
|
|
45
|
-
const staging = await mkdtemp(join(root, `.${required}-`));
|
|
46
|
-
try {
|
|
47
|
-
await runNpm([
|
|
48
|
-
'install',
|
|
49
|
-
'--prefix',
|
|
50
|
-
staging,
|
|
51
|
-
'--no-save',
|
|
52
|
-
'--package-lock=false',
|
|
53
|
-
`${PACKAGE_NAME}@${required}`,
|
|
54
|
-
...NPM_FETCH_OPTIONS,
|
|
55
|
-
'--ignore-scripts',
|
|
56
|
-
'--no-audit',
|
|
57
|
-
'--no-fund',
|
|
58
|
-
], { registry: source.registry, timeoutMs: 180_000 }).catch((error) => {
|
|
59
|
-
throw new CliError('UPDATE_FAILED', 'npm 自动更新失败,业务请求未发送', {
|
|
60
|
-
reason: error instanceof NpmCommandError ? error.reason : 'NPM_REQUEST_FAILED',
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
if (!(await verifiedEntry(staging, required)))
|
|
64
|
-
throw new CliError('UPDATE_FAILED', '安装后的版本或执行入口校验失败');
|
|
65
|
-
if (await stat(destination).catch(() => undefined))
|
|
66
|
-
await rename(destination, `${destination}.invalid-${randomUUID()}`);
|
|
67
|
-
await rename(staging, destination);
|
|
68
|
-
return join(destination, 'node_modules', PACKAGE_NAME, 'dist', 'cli.js');
|
|
69
|
-
}
|
|
70
|
-
finally {
|
|
71
|
-
// 只清理本次 mkdtemp 创建的安装暂存目录。
|
|
72
|
-
await rm(staging, { recursive: true, force: true });
|
|
73
|
-
}
|
|
27
|
+
let root;
|
|
28
|
+
try {
|
|
29
|
+
root = await runNpm(['root', '--global'], { timeoutMs: 5000 });
|
|
30
|
+
if (!isAbsolute(root) || /[\r\n]/.test(root))
|
|
31
|
+
throw new Error();
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw new CliError('UPDATE_FAILED', '无法定位 npm 全局安装目录,业务请求未发送', {
|
|
35
|
+
reason: error instanceof NpmCommandError ? error.reason : 'INVALID_INSTALL_DIRECTORY',
|
|
74
36
|
});
|
|
75
|
-
|
|
37
|
+
}
|
|
38
|
+
// 校验真实安装入口,旧缓存版本启动到这里时也要把本机安装升级,避免下次仍从旧入口启动。
|
|
39
|
+
let entry = await installedEntry(root, required);
|
|
40
|
+
if (!entry) {
|
|
41
|
+
try {
|
|
42
|
+
await runNpm([
|
|
43
|
+
'install',
|
|
44
|
+
'--global',
|
|
45
|
+
`${PACKAGE_NAME}@${required}`,
|
|
46
|
+
'--package-lock=false',
|
|
47
|
+
...NPM_FETCH_OPTIONS,
|
|
48
|
+
'--ignore-scripts',
|
|
49
|
+
'--no-audit',
|
|
50
|
+
'--no-fund',
|
|
51
|
+
], { registry: source.registry, timeoutMs: 180_000 });
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new CliError('UPDATE_FAILED', 'npm 自动更新失败,业务请求未发送', {
|
|
55
|
+
reason: error instanceof NpmCommandError ? error.reason : 'NPM_REQUEST_FAILED',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
entry = await installedEntry(root, required);
|
|
59
|
+
if (!entry)
|
|
60
|
+
throw new CliError('UPDATE_FAILED', '安装后的版本或执行入口校验失败,业务请求未发送');
|
|
61
|
+
}
|
|
62
|
+
if (updateOnly || required === PACKAGE_VERSION)
|
|
76
63
|
return { reexecuted: false, version: required };
|
|
77
64
|
const exitCode = await new Promise((resolve, reject) => {
|
|
78
65
|
const child = spawn(process.execPath, [entry, ...argv], {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-gate.js","sourceRoot":"","sources":["../../src/update/version-gate.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"version-gate.js","sourceRoot":"","sources":["../../src/update/version-gate.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE9F,KAAK,UAAU,cAAc,CAAC,IAAY,EAAE,OAAe;IACzD,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;QACpG,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3D,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE;YACpG,OAAO,SAAS,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAmB,EACnB,OAAqB,EACrB,UAAU,GAAG,KAAK;IAElB,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC;IAChC,IAAI,QAAQ,KAAK,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,GAAG;QAC3E,MAAM,IAAI,QAAQ,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;IAE3D,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,MAAM,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,EAAE,CAAC;IAClE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,QAAQ,CAAC,eAAe,EAAE,yBAAyB,EAAE;YAC7D,MAAM,EAAE,KAAK,YAAY,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,2BAA2B;SACtF,CAAC,CAAC;IACL,CAAC;IAED,6CAA6C;IAC7C,IAAI,KAAK,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,MAAM,CACV;gBACE,SAAS;gBACT,UAAU;gBACV,GAAG,YAAY,IAAI,QAAQ,EAAE;gBAC7B,sBAAsB;gBACtB,GAAG,iBAAiB;gBACpB,kBAAkB;gBAClB,YAAY;gBACZ,WAAW;aACZ,EACD,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,CAClD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,QAAQ,CAAC,eAAe,EAAE,oBAAoB,EAAE;gBACxD,MAAM,EAAE,KAAK,YAAY,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB;aAC/E,CAAC,CAAC;QACL,CAAC;QACD,KAAK,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC7C,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,QAAQ,CAAC,eAAe,EAAE,yBAAyB,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,UAAU,IAAI,QAAQ,KAAK,eAAe;QAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAEhG,MAAM,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,EAAE;YACtD,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,qBAAqB,EAAE,GAAG,EAAE;SACpD,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QAC9E,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC3D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function withUpdateLock<T>(action: () => Promise<T>, directory?: string): Promise<T>;
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/** 本机更新串行锁。@author xiuyu.yi */
|
|
2
|
-
import { mkdir, open, readFile, unlink } from 'node:fs/promises';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { randomUUID } from 'node:crypto';
|
|
5
|
-
import { setTimeout as delay } from 'node:timers/promises';
|
|
6
|
-
import { CREDENTIAL_DIRECTORY } from '../auth/pat-store.js';
|
|
7
|
-
import { object } from '../contracts/value.js';
|
|
8
|
-
import { CliError } from '../output/exit-codes.js';
|
|
9
|
-
export async function withUpdateLock(action, directory = CREDENTIAL_DIRECTORY) {
|
|
10
|
-
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
11
|
-
const path = join(directory, 'update.lock');
|
|
12
|
-
const contents = JSON.stringify({ pid: process.pid, nonce: randomUUID(), createdAt: Date.now() });
|
|
13
|
-
const deadline = Date.now() + 120_000;
|
|
14
|
-
while (true) {
|
|
15
|
-
try {
|
|
16
|
-
const handle = await open(path, 'wx', 0o600);
|
|
17
|
-
try {
|
|
18
|
-
await handle.writeFile(contents);
|
|
19
|
-
}
|
|
20
|
-
finally {
|
|
21
|
-
await handle.close();
|
|
22
|
-
}
|
|
23
|
-
break;
|
|
24
|
-
}
|
|
25
|
-
catch (error) {
|
|
26
|
-
if (object(error).code !== 'EEXIST')
|
|
27
|
-
throw new CliError('UPDATE_FAILED', '无法创建更新锁');
|
|
28
|
-
try {
|
|
29
|
-
const previous = await readFile(path, 'utf8');
|
|
30
|
-
const lock = object(JSON.parse(previous));
|
|
31
|
-
if (typeof lock.pid === 'number' && Number.isSafeInteger(lock.pid) && lock.pid > 0) {
|
|
32
|
-
try {
|
|
33
|
-
process.kill(lock.pid, 0);
|
|
34
|
-
}
|
|
35
|
-
catch (failure) {
|
|
36
|
-
if (object(failure).code === 'ESRCH' && (await readFile(path, 'utf8')) === previous)
|
|
37
|
-
await unlink(path);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
/* 锁正在初始化或被其他进程清理,下一轮重新竞争。 */
|
|
43
|
-
}
|
|
44
|
-
if (Date.now() >= deadline)
|
|
45
|
-
throw new CliError('UPDATE_FAILED', '等待其他 CLI 进程更新超时');
|
|
46
|
-
await delay(500);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
return await action();
|
|
51
|
-
}
|
|
52
|
-
finally {
|
|
53
|
-
if ((await readFile(path, 'utf8').catch(() => '')) === contents)
|
|
54
|
-
await unlink(path);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
//# sourceMappingURL=update-lock.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"update-lock.js","sourceRoot":"","sources":["../../src/update/update-lock.ts"],"names":[],"mappings":"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"}
|