@nocobase/cli 2.1.0-alpha.24 → 2.1.0-alpha.25
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 +8 -4
- package/README.zh-CN.md +6 -2
- package/bin/run.js +15 -0
- package/dist/commands/db/shared.js +19 -5
- package/dist/commands/dev.js +8 -1
- package/dist/commands/down.js +10 -6
- package/dist/commands/env/add.js +14 -34
- package/dist/commands/env/auth.js +6 -13
- package/dist/commands/env/list.js +10 -15
- package/dist/commands/env/remove.js +4 -10
- package/dist/commands/env/update.js +7 -13
- package/dist/commands/env/use.js +5 -13
- package/dist/commands/init.js +190 -62
- package/dist/commands/install.js +65 -26
- package/dist/commands/logs.js +8 -1
- package/dist/commands/pm/list.js +8 -1
- package/dist/commands/ps.js +18 -15
- package/dist/commands/restart.js +74 -0
- package/dist/commands/self/check.js +1 -1
- package/dist/commands/self/update.js +13 -3
- package/dist/commands/skills/check.js +11 -5
- package/dist/commands/skills/index.js +1 -1
- package/dist/commands/skills/install.js +20 -7
- package/dist/commands/skills/update.js +20 -7
- package/dist/commands/start.js +8 -1
- package/dist/commands/stop.js +8 -1
- package/dist/commands/upgrade.js +12 -1
- package/dist/lib/api-client.js +3 -2
- package/dist/lib/app-runtime.js +16 -5
- package/dist/lib/auth-store.js +159 -43
- package/dist/lib/bootstrap.js +13 -12
- package/dist/lib/cli-home.js +33 -2
- package/dist/lib/env-auth.js +3 -3
- package/dist/lib/generated-command.js +10 -2
- package/dist/lib/http-request.js +49 -0
- package/dist/lib/resource-command.js +10 -2
- package/dist/lib/runtime-generator.js +1 -1
- package/dist/lib/self-manager.js +1 -1
- package/dist/lib/skills-manager.js +140 -73
- package/dist/lib/startup-update.js +203 -0
- package/dist/locale/en-US.json +4 -1
- package/dist/locale/zh-CN.json +4 -1
- package/package.json +2 -2
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import fs from 'node:fs/promises';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import * as p from '@clack/prompts';
|
|
12
|
+
import { inspectSelfStatus, } from './self-manager.js';
|
|
13
|
+
import { inspectSkillsStatus } from './skills-manager.js';
|
|
14
|
+
import { resolveCliHomeDir } from './cli-home.js';
|
|
15
|
+
import { isInteractiveTerminal, printWarning } from './ui.js';
|
|
16
|
+
import { run } from './run-npm.js';
|
|
17
|
+
const STARTUP_UPDATE_STATE_FILE = 'startup-update.json';
|
|
18
|
+
const NB_SKIP_STARTUP_UPDATE_ENV = 'NB_SKIP_STARTUP_UPDATE';
|
|
19
|
+
function getStateFile() {
|
|
20
|
+
return path.join(resolveCliHomeDir('global'), STARTUP_UPDATE_STATE_FILE);
|
|
21
|
+
}
|
|
22
|
+
function todayStamp(now = new Date()) {
|
|
23
|
+
return now.toISOString().slice(0, 10);
|
|
24
|
+
}
|
|
25
|
+
function shouldSkipByArgv(argv) {
|
|
26
|
+
const tokens = argv.filter((token) => token && !token.startsWith('-'));
|
|
27
|
+
if (tokens.length === 0) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (tokens[0] === 'self' || tokens[0] === 'skills') {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
async function readState() {
|
|
36
|
+
try {
|
|
37
|
+
const raw = await fs.readFile(getStateFile(), 'utf8');
|
|
38
|
+
return JSON.parse(raw);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function writeState(state) {
|
|
45
|
+
const filePath = getStateFile();
|
|
46
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
47
|
+
await fs.writeFile(filePath, JSON.stringify(state, null, 2));
|
|
48
|
+
}
|
|
49
|
+
async function markChecked(now = new Date()) {
|
|
50
|
+
await writeState({ lastCheckedDate: todayStamp(now) });
|
|
51
|
+
}
|
|
52
|
+
export async function shouldRunStartupUpdateCheck(argv, now = new Date()) {
|
|
53
|
+
if (process.env[NB_SKIP_STARTUP_UPDATE_ENV] === '1') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (shouldSkipByArgv(argv)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const state = await readState();
|
|
60
|
+
return state.lastCheckedDate !== todayStamp(now);
|
|
61
|
+
}
|
|
62
|
+
export function shouldEnableStartupUpdateForInstallMethod(installMethod) {
|
|
63
|
+
return installMethod === 'npm-global';
|
|
64
|
+
}
|
|
65
|
+
function hasPendingUpdates(selfStatus, skillsStatus) {
|
|
66
|
+
return Boolean(selfStatus.updateAvailable || skillsStatus.updateAvailable === true);
|
|
67
|
+
}
|
|
68
|
+
function describeCliUpdate(selfStatus) {
|
|
69
|
+
return selfStatus.latestVersion
|
|
70
|
+
? `NocoBase CLI: ${selfStatus.currentVersion} -> ${selfStatus.latestVersion}`
|
|
71
|
+
: `NocoBase CLI: update available from ${selfStatus.currentVersion}`;
|
|
72
|
+
}
|
|
73
|
+
function describeSkillsUpdate() {
|
|
74
|
+
return 'NocoBase AI skills: update available';
|
|
75
|
+
}
|
|
76
|
+
function describeSkillsUpdateWithVersion(skillsStatus) {
|
|
77
|
+
if (skillsStatus.installedVersion && skillsStatus.latestVersion) {
|
|
78
|
+
return `NocoBase AI skills: ${skillsStatus.installedVersion} -> ${skillsStatus.latestVersion}`;
|
|
79
|
+
}
|
|
80
|
+
if (skillsStatus.latestVersion) {
|
|
81
|
+
return `NocoBase AI skills: latest ${skillsStatus.latestVersion} available`;
|
|
82
|
+
}
|
|
83
|
+
return describeSkillsUpdate();
|
|
84
|
+
}
|
|
85
|
+
function buildPromptMessage(selfStatus, skillsStatus) {
|
|
86
|
+
const lines = [];
|
|
87
|
+
const hasCliUpdate = selfStatus.updateAvailable;
|
|
88
|
+
const hasSkillsUpdate = skillsStatus.updateAvailable === true;
|
|
89
|
+
if (hasCliUpdate && hasSkillsUpdate) {
|
|
90
|
+
lines.push('Updates are available for your NocoBase CLI and AI skills.');
|
|
91
|
+
}
|
|
92
|
+
else if (hasCliUpdate) {
|
|
93
|
+
lines.push('An update is available for your NocoBase CLI.');
|
|
94
|
+
}
|
|
95
|
+
else if (hasSkillsUpdate) {
|
|
96
|
+
lines.push('An update is available for your NocoBase AI skills.');
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
lines.push('A NocoBase CLI or skills update is available.');
|
|
100
|
+
}
|
|
101
|
+
if (hasCliUpdate) {
|
|
102
|
+
lines.push(`- ${describeCliUpdate(selfStatus)}`);
|
|
103
|
+
}
|
|
104
|
+
if (hasSkillsUpdate) {
|
|
105
|
+
lines.push(`- ${describeSkillsUpdateWithVersion(skillsStatus)}`);
|
|
106
|
+
}
|
|
107
|
+
lines.push('Update now?');
|
|
108
|
+
return lines.join('\n');
|
|
109
|
+
}
|
|
110
|
+
function buildUpdateCommands(selfStatus, skillsStatus) {
|
|
111
|
+
const commands = [];
|
|
112
|
+
if (selfStatus.updateAvailable && selfStatus.updatable) {
|
|
113
|
+
commands.push('nb self update --yes');
|
|
114
|
+
}
|
|
115
|
+
if (skillsStatus.updateAvailable === true) {
|
|
116
|
+
commands.push('nb skills update --yes');
|
|
117
|
+
}
|
|
118
|
+
return commands;
|
|
119
|
+
}
|
|
120
|
+
function buildNonInteractiveWarning(selfStatus, skillsStatus) {
|
|
121
|
+
const commands = buildUpdateCommands(selfStatus, skillsStatus);
|
|
122
|
+
const details = [];
|
|
123
|
+
if (selfStatus.updateAvailable) {
|
|
124
|
+
details.push(describeCliUpdate(selfStatus));
|
|
125
|
+
}
|
|
126
|
+
if (skillsStatus.updateAvailable === true) {
|
|
127
|
+
details.push(describeSkillsUpdateWithVersion(skillsStatus));
|
|
128
|
+
}
|
|
129
|
+
return [
|
|
130
|
+
`Updates available${details.length ? `: ${details.join(', ')}` : '.'}`,
|
|
131
|
+
'Non-interactive session, skipped auto-update.',
|
|
132
|
+
commands.length
|
|
133
|
+
? `Run: ${commands.join(' && ')}`
|
|
134
|
+
: 'Check with: `nb self check` and `nb skills check`.',
|
|
135
|
+
'You may run into compatibility issues until you update.',
|
|
136
|
+
].join(' ');
|
|
137
|
+
}
|
|
138
|
+
function buildDeclinedWarning(selfStatus, skillsStatus) {
|
|
139
|
+
const commands = buildUpdateCommands(selfStatus, skillsStatus);
|
|
140
|
+
const details = [];
|
|
141
|
+
if (selfStatus.updateAvailable) {
|
|
142
|
+
details.push(describeCliUpdate(selfStatus));
|
|
143
|
+
}
|
|
144
|
+
if (skillsStatus.updateAvailable === true) {
|
|
145
|
+
details.push(describeSkillsUpdateWithVersion(skillsStatus));
|
|
146
|
+
}
|
|
147
|
+
return [
|
|
148
|
+
`Skipped updates${details.length ? `: ${details.join(', ')}` : '.'}`,
|
|
149
|
+
commands.length
|
|
150
|
+
? `Run: ${commands.join(' && ')}`
|
|
151
|
+
: 'Check with: `nb self check` and `nb skills check`.',
|
|
152
|
+
'You may run into compatibility issues until you update.',
|
|
153
|
+
].join(' ');
|
|
154
|
+
}
|
|
155
|
+
async function runStartupUpdates() {
|
|
156
|
+
await run('nb', ['self', 'update', '--yes'], {
|
|
157
|
+
stdio: 'inherit',
|
|
158
|
+
env: {
|
|
159
|
+
[NB_SKIP_STARTUP_UPDATE_ENV]: '1',
|
|
160
|
+
},
|
|
161
|
+
errorName: 'nb self update',
|
|
162
|
+
});
|
|
163
|
+
await run('nb', ['skills', 'update', '--yes'], {
|
|
164
|
+
stdio: 'inherit',
|
|
165
|
+
env: {
|
|
166
|
+
[NB_SKIP_STARTUP_UPDATE_ENV]: '1',
|
|
167
|
+
},
|
|
168
|
+
errorName: 'nb skills update',
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
export async function maybeRunStartupUpdatePrompt(argv) {
|
|
172
|
+
if (!(await shouldRunStartupUpdateCheck(argv))) {
|
|
173
|
+
return { kind: 'skipped' };
|
|
174
|
+
}
|
|
175
|
+
const selfStatus = await inspectSelfStatus();
|
|
176
|
+
if (!shouldEnableStartupUpdateForInstallMethod(selfStatus.installMethod)) {
|
|
177
|
+
return { kind: 'skipped' };
|
|
178
|
+
}
|
|
179
|
+
const skillsStatus = await inspectSkillsStatus();
|
|
180
|
+
if (!hasPendingUpdates(selfStatus, skillsStatus)) {
|
|
181
|
+
await markChecked();
|
|
182
|
+
return { kind: 'no-update' };
|
|
183
|
+
}
|
|
184
|
+
if (!isInteractiveTerminal()) {
|
|
185
|
+
printWarning(buildNonInteractiveWarning(selfStatus, skillsStatus));
|
|
186
|
+
await markChecked();
|
|
187
|
+
return { kind: 'warned' };
|
|
188
|
+
}
|
|
189
|
+
const answer = await p.confirm({
|
|
190
|
+
message: buildPromptMessage(selfStatus, skillsStatus),
|
|
191
|
+
active: 'Yes',
|
|
192
|
+
inactive: 'No',
|
|
193
|
+
initialValue: true,
|
|
194
|
+
});
|
|
195
|
+
if (p.isCancel(answer) || !answer) {
|
|
196
|
+
printWarning(buildDeclinedWarning(selfStatus, skillsStatus));
|
|
197
|
+
await markChecked();
|
|
198
|
+
return { kind: 'declined' };
|
|
199
|
+
}
|
|
200
|
+
await runStartupUpdates();
|
|
201
|
+
await markChecked();
|
|
202
|
+
return { kind: 'updated' };
|
|
203
|
+
}
|
package/dist/locale/en-US.json
CHANGED
|
@@ -73,6 +73,8 @@
|
|
|
73
73
|
},
|
|
74
74
|
"scope": {
|
|
75
75
|
"message": "Where should this connection be saved?",
|
|
76
|
+
"autoLabel": "Auto",
|
|
77
|
+
"autoHint": "project if this repo already has .nocobase, otherwise global",
|
|
76
78
|
"projectLabel": "Project",
|
|
77
79
|
"projectHint": ".nocobase in this repo",
|
|
78
80
|
"globalLabel": "Global",
|
|
@@ -268,7 +270,7 @@
|
|
|
268
270
|
},
|
|
269
271
|
"init": {
|
|
270
272
|
"validation": {
|
|
271
|
-
"envExists": "Env \"{{envName}}\" already exists
|
|
273
|
+
"envExists": "Env \"{{envName}}\" already exists. Choose another env name."
|
|
272
274
|
},
|
|
273
275
|
"messages": {
|
|
274
276
|
"title": "Set Up Your NocoBase AI Workspace",
|
|
@@ -276,6 +278,7 @@
|
|
|
276
278
|
"appNameEnvHelp": "Use `nb init --yes --env <envName>` to continue.",
|
|
277
279
|
"resumeEnvRequired": "Env name is required when resuming setup.",
|
|
278
280
|
"resumeEnvHelp": "Use `nb init --resume --env <envName>` to continue.",
|
|
281
|
+
"resumeAfterInstallFailure": "Resume this setup with:\n {{command}}",
|
|
279
282
|
"uiOpening": "A local setup form will open in your browser. That form needs a person to fill it in. If you are using an AI agent, do not stop this process while the CLI waits for the submission.",
|
|
280
283
|
"uiReady": "Local setup form is ready.",
|
|
281
284
|
"uiReadyHelp": "If your browser does not open automatically, copy the URL below into your browser to continue. Keep this terminal session running while the CLI waits for the submission.",
|
package/dist/locale/zh-CN.json
CHANGED
|
@@ -73,6 +73,8 @@
|
|
|
73
73
|
},
|
|
74
74
|
"scope": {
|
|
75
75
|
"message": "这个连接要保存到哪里?",
|
|
76
|
+
"autoLabel": "自动",
|
|
77
|
+
"autoHint": "当前仓库已有 .nocobase 时保存到项目内,否则保存到全局",
|
|
76
78
|
"projectLabel": "项目内",
|
|
77
79
|
"projectHint": "保存在当前仓库的 .nocobase 中",
|
|
78
80
|
"globalLabel": "全局",
|
|
@@ -268,7 +270,7 @@
|
|
|
268
270
|
},
|
|
269
271
|
"init": {
|
|
270
272
|
"validation": {
|
|
271
|
-
"envExists": "Env \"{{envName}}\"
|
|
273
|
+
"envExists": "Env \"{{envName}}\" 已存在,请换一个 env name。"
|
|
272
274
|
},
|
|
273
275
|
"messages": {
|
|
274
276
|
"title": "初始化你的 NocoBase AI 工作区",
|
|
@@ -276,6 +278,7 @@
|
|
|
276
278
|
"appNameEnvHelp": "请使用 `nb init --yes --env <envName>` 继续。",
|
|
277
279
|
"resumeEnvRequired": "恢复安装时必须提供 Env name。",
|
|
278
280
|
"resumeEnvHelp": "请使用 `nb init --resume --env <envName>` 继续。",
|
|
281
|
+
"resumeAfterInstallFailure": "继续这次初始化请执行:\n {{command}}",
|
|
279
282
|
"uiOpening": "本地 setup 表单即将在浏览器中打开。这个表单需要等待人工填写。如果你正在使用 AI agent,请不要停止当前进程,CLI 会继续等待表单提交结果。",
|
|
280
283
|
"uiReady": "本地 setup 表单已就绪。",
|
|
281
284
|
"uiReadyHelp": "如果没有自动打开浏览器,请复制下面的地址到浏览器中继续。CLI 会继续等待表单提交,请保持当前终端会话继续运行。",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/cli",
|
|
3
|
-
"version": "2.1.0-alpha.
|
|
3
|
+
"version": "2.1.0-alpha.25",
|
|
4
4
|
"description": "NocoBase Command Line Tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/generated/command-registry.js",
|
|
@@ -68,5 +68,5 @@
|
|
|
68
68
|
"type": "git",
|
|
69
69
|
"url": "git+https://github.com/nocobase/nocobase.git"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "63e4aaa625f3108fe41238e85bb13dee37fe1f48"
|
|
72
72
|
}
|