superun-ai-cli 0.1.8 → 0.1.10
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.en.md +2 -0
- package/README.md +5 -1
- package/dist/program.js +1 -1
- package/dist/program.js.map +1 -1
- package/dist/update/npm-registry.d.ts +13 -0
- package/dist/update/npm-registry.js +89 -0
- package/dist/update/npm-registry.js.map +1 -0
- package/dist/update/version-gate.d.ts +1 -1
- package/dist/update/version-gate.js +54 -84
- package/dist/update/version-gate.js.map +1 -1
- package/package.json +2 -2
package/README.en.md
CHANGED
|
@@ -267,6 +267,8 @@ Business commands write one JSON result to stdout. Diagnostics and update progre
|
|
|
267
267
|
|
|
268
268
|
The CLI checks npm's `latest` version before business commands. If it differs from the local version, the CLI installs that version and resumes the command. If an update or verification fails, the CLI stops; resolve the reported issue before retrying. Help, `version`, and `auth logout` work offline.
|
|
269
269
|
|
|
270
|
+
Version checks and installation both run through npm, inheriting its proxy and certificate configuration and retrying transient network failures. If the official Registry is unavailable, the CLI tries the user's configured Registry and uses the successful source for installation. Recovery does not print errors or installation logs. If all sources fail, `error.checks` provides reason codes without raw npm logs or credentials. The CLI does not disable certificate verification or skip the version check to allow business requests.
|
|
271
|
+
|
|
270
272
|
Run `superun-ai update` to sync with npm `latest` explicitly. Source installations use the same version check. Rebuild after changing the source; if the global command is not linked to that checkout, run `npm install -g .` again.
|
|
271
273
|
|
|
272
274
|
```bash
|
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.en.md) | [中文](README.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
通过需求梳理、架构设计与开发协作,将网站和应用的想法转化为可持续迭代、可部署运维的生产级系统。
|
|
6
|
+
|
|
7
|
+
人和自动化程序使用同一组命令;业务结果以 JSON 输出。
|
|
6
8
|
|
|
7
9
|
## 安装
|
|
8
10
|
|
|
@@ -267,6 +269,8 @@ superun-ai chat publish visibility <sessionId> private
|
|
|
267
269
|
|
|
268
270
|
CLI 会在执行业务命令前检查 npm `latest` 版本,与本地版本不同时自动安装该版本并继续执行。更新或校验失败时会停止执行,请根据错误提示处理后重试。帮助、`version` 和 `auth logout` 可离线使用。
|
|
269
271
|
|
|
272
|
+
版本预检和安装统一通过 npm 执行,沿用 npm 的代理和证书配置,并自动重试短暂的网络故障。官方 Registry 不可用时,会尝试用户已配置的 Registry,安装沿用查询成功的源;恢复过程不输出报错或安装日志。所有源均失败时才返回错误,`error.checks` 包含各次检查的原因码,不包含原始 npm 日志或凭据。不会通过关闭证书校验或忽略版本检查来放行业务请求。
|
|
273
|
+
|
|
270
274
|
可以执行 `superun-ai update` 主动同步 npm `latest`。从源码安装也遵循相同的版本校验;修改源码后需要重新构建,如果全局命令不是链接到该目录,再执行 `npm install -g .`。
|
|
271
275
|
|
|
272
276
|
```bash
|
package/dist/program.js
CHANGED
|
@@ -10,7 +10,7 @@ import { registerVersion } from './commands/system/version.js';
|
|
|
10
10
|
export function createProgram(context, hooks) {
|
|
11
11
|
const program = new Command()
|
|
12
12
|
.name(COMMAND_NAME)
|
|
13
|
-
.description('
|
|
13
|
+
.description('通过需求梳理、架构设计与开发协作,将网站和应用的想法转化为可持续迭代、可部署运维的生产级系统。')
|
|
14
14
|
.version(PACKAGE_VERSION)
|
|
15
15
|
.option('--endpoint <URL>', 'API 地址')
|
|
16
16
|
.option('--locale <language>', '回复语言', 'zh-CN')
|
package/dist/program.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,MAAM,UAAU,aAAa,CAC3B,OAAuB,EACvB,KAGC;IAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;SAC1B,IAAI,CAAC,YAAY,CAAC;SAClB,WAAW,
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,MAAM,UAAU,aAAa,CAC3B,OAAuB,EACvB,KAGC;IAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;SAC1B,IAAI,CAAC,YAAY,CAAC;SAClB,WAAW,CACV,iDAAiD,CAClD;SACA,OAAO,CAAC,eAAe,CAAC;SACxB,MAAM,CAAC,kBAAkB,EAAE,QAAQ,CAAC;SACpC,MAAM,CAAC,qBAAqB,EAAE,MAAM,EAAE,OAAO,CAAC;SAC9C,YAAY,EAAE;SACd,eAAe,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAChD,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;QAC/B,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC;QAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC;QACzF,MAAM,OAAO,GACX,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,QAAQ,CAAC,CAAC;YAC5E,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,QAAQ,CAAC,CAAC;QAC9C,IAAI,OAAO,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO;QAC1C,MAAM,KAAK,CAAC,cAAc,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,OAAO,CAAC;YAC7C,MAAM,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IACH,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/B,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACtD,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const NPM_FETCH_OPTIONS: string[];
|
|
2
|
+
export declare class NpmCommandError extends Error {
|
|
3
|
+
readonly reason: string;
|
|
4
|
+
constructor(reason: string);
|
|
5
|
+
}
|
|
6
|
+
export declare function runNpm(args: Array<string>, options?: {
|
|
7
|
+
registry?: string;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}): Promise<string>;
|
|
10
|
+
export declare function latestVersion(): Promise<{
|
|
11
|
+
version: string;
|
|
12
|
+
registry: string;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** npm 版本查询与安装共用网络配置,恢复过程不打断业务输出。@author xiuyu.yi */
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { valid } from 'semver';
|
|
5
|
+
import { NPM_REGISTRY, PACKAGE_NAME, PACKAGE_PRIVATE } from '../config/constants.js';
|
|
6
|
+
import { object, text } from '../contracts/value.js';
|
|
7
|
+
import { CliError } from '../output/exit-codes.js';
|
|
8
|
+
const execute = promisify(execFile);
|
|
9
|
+
export const NPM_FETCH_OPTIONS = [
|
|
10
|
+
'--fetch-retries=2',
|
|
11
|
+
'--fetch-retry-mintimeout=1000',
|
|
12
|
+
'--fetch-retry-maxtimeout=3000',
|
|
13
|
+
'--fetch-timeout=15000',
|
|
14
|
+
];
|
|
15
|
+
export class NpmCommandError extends Error {
|
|
16
|
+
reason;
|
|
17
|
+
constructor(reason) {
|
|
18
|
+
super(reason);
|
|
19
|
+
this.reason = reason;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function runNpm(args, options = {}) {
|
|
23
|
+
const env = { ...process.env };
|
|
24
|
+
if (options.registry) {
|
|
25
|
+
delete env.NPM_CONFIG_REGISTRY;
|
|
26
|
+
env.npm_config_registry = options.registry;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const { stdout } = await execute('npm', args, {
|
|
30
|
+
encoding: 'utf8',
|
|
31
|
+
timeout: options.timeoutMs ?? 55_000,
|
|
32
|
+
killSignal: 'SIGKILL',
|
|
33
|
+
maxBuffer: 2_000_000,
|
|
34
|
+
// Registry 可能包含认证信息,只通过环境传入,不回显命令或 npm 原始诊断。
|
|
35
|
+
env,
|
|
36
|
+
});
|
|
37
|
+
return stdout.trim();
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
const failure = object(error);
|
|
41
|
+
const stderr = text(failure.stderr) ?? '';
|
|
42
|
+
const reason = failure.killed
|
|
43
|
+
? 'ETIMEDOUT'
|
|
44
|
+
: typeof failure.code === 'string'
|
|
45
|
+
? failure.code
|
|
46
|
+
: /npm (?:ERR!|error) code ([A-Z0-9_]+)/.exec(stderr)?.[1];
|
|
47
|
+
throw new NpmCommandError(reason && /^[A-Z0-9_]+$/.test(reason) ? reason : 'NPM_REQUEST_FAILED');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function latestVersion() {
|
|
51
|
+
if (PACKAGE_PRIVATE)
|
|
52
|
+
throw new CliError('UPDATE_REQUIRED', '当前为未发布的私有开发包;正式包名和 Registry 确认并发布后才能启用业务命令');
|
|
53
|
+
const registries = [NPM_REGISTRY];
|
|
54
|
+
try {
|
|
55
|
+
const configured = new URL(await runNpm(['config', 'get', 'registry'], { timeoutMs: 5000 }));
|
|
56
|
+
if (['https:', 'http:'].includes(configured.protocol) &&
|
|
57
|
+
!configured.search &&
|
|
58
|
+
!configured.hash &&
|
|
59
|
+
configured.href !== new URL(NPM_REGISTRY).href)
|
|
60
|
+
registries.push(configured.href);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// 读取配置失败不妨碍官方源查询;npm 缺失等问题由下面的正式检查统一报告。
|
|
64
|
+
}
|
|
65
|
+
const failures = [];
|
|
66
|
+
for (const [index, registry] of registries.entries()) {
|
|
67
|
+
try {
|
|
68
|
+
const raw = await runNpm(['view', PACKAGE_NAME, 'dist-tags.latest', '--json', '--prefer-online', ...NPM_FETCH_OPTIONS], { registry });
|
|
69
|
+
let version;
|
|
70
|
+
try {
|
|
71
|
+
version = JSON.parse(raw);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
throw new NpmCommandError('INVALID_VERSION_RESPONSE');
|
|
75
|
+
}
|
|
76
|
+
if (typeof version !== 'string' || valid(version) !== version)
|
|
77
|
+
throw new NpmCommandError('INVALID_VERSION_RESPONSE');
|
|
78
|
+
return { version, registry };
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
failures.push({
|
|
82
|
+
source: index === 0 ? 'official' : 'configured',
|
|
83
|
+
reason: error instanceof NpmCommandError ? error.reason : 'NPM_REQUEST_FAILED',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
throw new CliError('VERSION_CHECK_FAILED', '版本检查在自动重试后仍失败,请检查 npm 网络、代理或证书配置;业务请求未发送', { checks: failures });
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=npm-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-registry.js","sourceRoot":"","sources":["../../src/update/npm-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OutputWriter } from '../output/writer.js';
|
|
2
|
-
export declare function versionGate(argv: Array<string>,
|
|
2
|
+
export declare function versionGate(argv: Array<string>, _output: OutputWriter, updateOnly?: boolean): Promise<{
|
|
3
3
|
reexecuted: boolean;
|
|
4
4
|
version: string;
|
|
5
5
|
exitCode?: number;
|
|
@@ -4,104 +4,74 @@ import { readFile, mkdir, mkdtemp, rename, rm, stat } from 'node:fs/promises';
|
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { randomUUID } from 'node:crypto';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { object, text } from '../contracts/value.js';
|
|
7
|
+
import { PACKAGE_NAME, PACKAGE_VERSION } from '../config/constants.js';
|
|
8
|
+
import { object } from '../contracts/value.js';
|
|
10
9
|
import { CliError } from '../output/exit-codes.js';
|
|
11
10
|
import { withUpdateLock } from './update-lock.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
let captured = '';
|
|
16
|
-
child.stdout.on('data', (chunk) => {
|
|
17
|
-
if (capture)
|
|
18
|
-
captured += chunk.toString();
|
|
19
|
-
else
|
|
20
|
-
output.log(chunk.toString().trimEnd());
|
|
21
|
-
});
|
|
22
|
-
child.stderr.on('data', (chunk) => output.log(chunk.toString().trimEnd()));
|
|
23
|
-
child.once('error', () => reject(new CliError('UPDATE_FAILED', '无法执行 npm,请检查安装与 PATH')));
|
|
24
|
-
child.once('close', (code) => code === 0
|
|
25
|
-
? resolve(captured.trim())
|
|
26
|
-
: reject(new CliError('UPDATE_FAILED', 'npm 更新失败,业务请求未发送')));
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
async function latestVersion() {
|
|
30
|
-
if (PACKAGE_PRIVATE)
|
|
31
|
-
throw new CliError('UPDATE_REQUIRED', '当前为未发布的私有开发包;正式包名和 Registry 确认并发布后才能启用业务命令');
|
|
11
|
+
import { latestVersion, runNpm, NPM_FETCH_OPTIONS, NpmCommandError } from './npm-registry.js';
|
|
12
|
+
async function verifiedEntry(directory, version) {
|
|
13
|
+
const packageDirectory = join(directory, 'node_modules', PACKAGE_NAME);
|
|
32
14
|
try {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!response.ok)
|
|
38
|
-
throw new Error('registry');
|
|
39
|
-
const data = await response.json();
|
|
40
|
-
const latest = text(object(object(data)['dist-tags']).latest);
|
|
41
|
-
if (!latest || valid(latest) !== latest)
|
|
42
|
-
throw new Error('version');
|
|
43
|
-
return latest;
|
|
15
|
+
const metadata = object(JSON.parse(await readFile(join(packageDirectory, 'package.json'), 'utf8')));
|
|
16
|
+
const candidate = join(packageDirectory, 'dist', 'cli.js');
|
|
17
|
+
if (metadata.name === PACKAGE_NAME && metadata.version === version && (await stat(candidate)).isFile())
|
|
18
|
+
return candidate;
|
|
44
19
|
}
|
|
45
20
|
catch {
|
|
46
|
-
|
|
21
|
+
/* 未完成安装的目录不作为可执行版本。 */
|
|
47
22
|
}
|
|
23
|
+
return undefined;
|
|
48
24
|
}
|
|
49
|
-
export async function versionGate(argv,
|
|
50
|
-
let
|
|
25
|
+
export async function versionGate(argv, _output, updateOnly = false) {
|
|
26
|
+
let source = await latestVersion();
|
|
27
|
+
let required = source.version;
|
|
51
28
|
if (required === PACKAGE_VERSION)
|
|
52
29
|
return { reexecuted: false, version: required };
|
|
53
30
|
if (process.env.SUPERUN_AI_CLI_REEXEC === '1')
|
|
54
31
|
throw new CliError('UPDATE_FAILED', '重启后版本仍不匹配,已停止重复更新');
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
32
|
+
const root = join(homedir(), '.cache', PACKAGE_NAME, 'versions');
|
|
33
|
+
// 已安装的目标版本直接复用,避免每次执行都创建、删除更新锁。
|
|
34
|
+
let entry = await verifiedEntry(join(root, required), required);
|
|
35
|
+
if (!entry)
|
|
36
|
+
entry = await withUpdateLock(async () => {
|
|
37
|
+
source = await latestVersion();
|
|
38
|
+
required = source.version;
|
|
39
|
+
const destination = join(root, required);
|
|
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}-`));
|
|
62
46
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
69
|
}
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
finally {
|
|
71
|
+
// 只清理本次 mkdtemp 创建的安装暂存目录。
|
|
72
|
+
await rm(staging, { recursive: true, force: true });
|
|
72
73
|
}
|
|
73
|
-
|
|
74
|
-
};
|
|
75
|
-
const cached = await verifiedEntry(destination);
|
|
76
|
-
if (cached)
|
|
77
|
-
return cached;
|
|
78
|
-
const staging = await mkdtemp(join(root, `.${required}-`));
|
|
79
|
-
try {
|
|
80
|
-
await npm([
|
|
81
|
-
'install',
|
|
82
|
-
'--prefix',
|
|
83
|
-
staging,
|
|
84
|
-
'--no-save',
|
|
85
|
-
'--package-lock=false',
|
|
86
|
-
`${PACKAGE_NAME}@${required}`,
|
|
87
|
-
'--registry',
|
|
88
|
-
NPM_REGISTRY,
|
|
89
|
-
'--ignore-scripts',
|
|
90
|
-
'--no-audit',
|
|
91
|
-
'--no-fund',
|
|
92
|
-
], output);
|
|
93
|
-
if (!(await verifiedEntry(staging)))
|
|
94
|
-
throw new CliError('UPDATE_FAILED', '安装后的版本或执行入口校验失败');
|
|
95
|
-
if (await stat(destination).catch(() => undefined))
|
|
96
|
-
await rename(destination, `${destination}.invalid-${randomUUID()}`);
|
|
97
|
-
await rename(staging, destination);
|
|
98
|
-
return join(destination, 'node_modules', PACKAGE_NAME, 'dist', 'cli.js');
|
|
99
|
-
}
|
|
100
|
-
finally {
|
|
101
|
-
// 只清理本次 mkdtemp 创建的安装暂存目录。
|
|
102
|
-
await rm(staging, { recursive: true, force: true });
|
|
103
|
-
}
|
|
104
|
-
});
|
|
74
|
+
});
|
|
105
75
|
if (updateOnly)
|
|
106
76
|
return { reexecuted: false, version: required };
|
|
107
77
|
const exitCode = await new Promise((resolve, reject) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-gate.js","sourceRoot":"","sources":["../../src/update/version-gate.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"version-gate.js","sourceRoot":"","sources":["../../src/update/version-gate.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superun-ai-cli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.10",
|
|
4
|
+
"description": "通过需求梳理、架构设计与开发协作,将网站和应用的想法转化为可持续迭代、可部署运维的生产级系统。",
|
|
5
5
|
"author": "xiuyu.yi",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"type": "module",
|