@nocobase/cli 2.1.0-beta.36 → 2.1.0-beta.37
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/bin/run.js +3 -2
- package/dist/commands/config/delete.js +4 -0
- package/dist/commands/config/get.js +4 -0
- package/dist/commands/config/set.js +5 -1
- package/dist/commands/env/add.js +66 -6
- package/dist/commands/env/auth.js +86 -27
- package/dist/commands/env/info.js +52 -8
- package/dist/commands/env/list.js +2 -2
- package/dist/commands/env/shared.js +41 -3
- package/dist/commands/init.js +196 -136
- package/dist/commands/install.js +311 -265
- package/dist/lib/auth-store.js +47 -19
- package/dist/lib/cli-config.js +99 -4
- package/dist/lib/cli-locale.js +19 -7
- package/dist/lib/db-connection-check.js +61 -0
- package/dist/lib/env-auth.js +79 -0
- package/dist/lib/env-config.js +3 -2
- package/dist/lib/prompt-validators.js +23 -5
- package/dist/lib/prompt-web-ui.js +143 -19
- package/dist/lib/run-npm.js +133 -23
- package/dist/lib/skills-manager.js +74 -4
- package/dist/locale/en-US.json +36 -5
- package/dist/locale/zh-CN.json +36 -5
- package/package.json +2 -2
|
@@ -17,6 +17,72 @@ import { commandOutput, commandOutputViaFile, run } from './run-npm.js';
|
|
|
17
17
|
export const NOCOBASE_SKILLS_SOURCE = 'nocobase/skills';
|
|
18
18
|
export const NOCOBASE_SKILLS_PACKAGE_NAME = '@nocobase/skills';
|
|
19
19
|
const NOCOBASE_SKILLS_NAME_PREFIX = 'nocobase-';
|
|
20
|
+
const SKILLS_LIST_TIMEOUT_MS = 5000;
|
|
21
|
+
const SKILLS_NPM_VIEW_TIMEOUT_MS = 3000;
|
|
22
|
+
const SKILLS_PACK_TIMEOUT_MS = 30000;
|
|
23
|
+
const SKILLS_ADD_TIMEOUT_MS = 20000;
|
|
24
|
+
const NPM_REGISTRY_UNAVAILABLE_PATTERNS = [
|
|
25
|
+
'enotfound',
|
|
26
|
+
'eai_again',
|
|
27
|
+
'etimedout',
|
|
28
|
+
'esockettimedout',
|
|
29
|
+
'econnreset',
|
|
30
|
+
'econnrefused',
|
|
31
|
+
'ehostunreach',
|
|
32
|
+
'enetunreach',
|
|
33
|
+
'socket hang up',
|
|
34
|
+
'getaddrinfo',
|
|
35
|
+
'fetch failed',
|
|
36
|
+
'network request to',
|
|
37
|
+
'self_signed_cert',
|
|
38
|
+
'depth_zero_self_signed_cert',
|
|
39
|
+
'unable_to_verify_leaf_signature',
|
|
40
|
+
'cert_has_expired',
|
|
41
|
+
'timed out after',
|
|
42
|
+
];
|
|
43
|
+
function collectErrorMessages(error) {
|
|
44
|
+
const messages = [];
|
|
45
|
+
const queue = [error];
|
|
46
|
+
const seen = new Set();
|
|
47
|
+
while (queue.length > 0) {
|
|
48
|
+
const current = queue.shift();
|
|
49
|
+
if (current === undefined || current === null || seen.has(current)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
seen.add(current);
|
|
53
|
+
if (current instanceof Error) {
|
|
54
|
+
if (current.message) {
|
|
55
|
+
messages.push(current.message);
|
|
56
|
+
}
|
|
57
|
+
const cause = current.cause;
|
|
58
|
+
if (cause !== undefined) {
|
|
59
|
+
queue.push(cause);
|
|
60
|
+
}
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (typeof current === 'string') {
|
|
64
|
+
messages.push(current);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (typeof current === 'object') {
|
|
68
|
+
if ('message' in current && typeof current.message === 'string') {
|
|
69
|
+
messages.push(current.message);
|
|
70
|
+
}
|
|
71
|
+
if ('cause' in current) {
|
|
72
|
+
queue.push(current.cause);
|
|
73
|
+
}
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
messages.push(String(current));
|
|
77
|
+
}
|
|
78
|
+
return messages;
|
|
79
|
+
}
|
|
80
|
+
export function isNpmRegistryUnavailable(error) {
|
|
81
|
+
return collectErrorMessages(error).some((message) => {
|
|
82
|
+
const normalized = message.toLowerCase();
|
|
83
|
+
return NPM_REGISTRY_UNAVAILABLE_PATTERNS.some((pattern) => normalized.includes(pattern));
|
|
84
|
+
});
|
|
85
|
+
}
|
|
20
86
|
function normalizePath(value) {
|
|
21
87
|
return path.resolve(value);
|
|
22
88
|
}
|
|
@@ -72,6 +138,7 @@ export async function listGlobalSkills(options = {}) {
|
|
|
72
138
|
const output = await (options.commandOutputFn ?? commandOutputViaFile)('npx', ['-y', 'skills', 'list', '-g', '--json'], {
|
|
73
139
|
cwd: globalRoot,
|
|
74
140
|
errorName: 'skills list',
|
|
141
|
+
timeoutMs: SKILLS_LIST_TIMEOUT_MS,
|
|
75
142
|
});
|
|
76
143
|
const parsed = JSON.parse(output);
|
|
77
144
|
return Array.isArray(parsed) ? parsed : [];
|
|
@@ -95,6 +162,7 @@ async function readPublishedSkillsVersion(options = {}) {
|
|
|
95
162
|
const output = await (options.commandOutputFn ?? commandOutput)('npm', ['view', NOCOBASE_SKILLS_PACKAGE_NAME, 'version', '--json'], {
|
|
96
163
|
cwd: globalRoot,
|
|
97
164
|
errorName: 'npm view',
|
|
165
|
+
timeoutMs: SKILLS_NPM_VIEW_TIMEOUT_MS,
|
|
98
166
|
});
|
|
99
167
|
const parsed = JSON.parse(output);
|
|
100
168
|
const version = String(parsed ?? '').trim();
|
|
@@ -187,6 +255,7 @@ async function prepareLocalSkillsPackage(globalRoot, options = {}, targetVersion
|
|
|
187
255
|
cwd: packRoot,
|
|
188
256
|
stdio: options.verbose ? 'inherit' : 'ignore',
|
|
189
257
|
errorName: 'npm pack',
|
|
258
|
+
timeoutMs: SKILLS_PACK_TIMEOUT_MS,
|
|
190
259
|
});
|
|
191
260
|
const tarballPath = await resolvePackedSkillsTarball(packRoot);
|
|
192
261
|
await extractPackedSkillsTarball(tarballPath, cacheRoot, targetVersion);
|
|
@@ -276,6 +345,7 @@ async function reinstallManagedSkills(globalRoot, options = {}, targetVersion) {
|
|
|
276
345
|
cwd: globalRoot,
|
|
277
346
|
stdio: options.verbose ? 'inherit' : 'ignore',
|
|
278
347
|
errorName: 'skills add',
|
|
348
|
+
timeoutMs: SKILLS_ADD_TIMEOUT_MS,
|
|
279
349
|
});
|
|
280
350
|
}
|
|
281
351
|
finally {
|
|
@@ -314,10 +384,10 @@ export async function updateNocoBaseSkills(options = {}) {
|
|
|
314
384
|
status,
|
|
315
385
|
};
|
|
316
386
|
}
|
|
317
|
-
if (status.managedByNb
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
387
|
+
if (status.managedByNb &&
|
|
388
|
+
status.latestVersion &&
|
|
389
|
+
status.installedVersion &&
|
|
390
|
+
compareVersions(status.latestVersion, status.installedVersion) <= 0) {
|
|
321
391
|
return {
|
|
322
392
|
action: 'noop',
|
|
323
393
|
reason: 'up-to-date',
|
package/dist/locale/en-US.json
CHANGED
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"back": "Back",
|
|
35
35
|
"next": "Next",
|
|
36
36
|
"submit": "Submit & continue in terminal",
|
|
37
|
+
"showPassword": "Show password",
|
|
38
|
+
"hidePassword": "Hide password",
|
|
37
39
|
"checking": "Checking...",
|
|
38
40
|
"sending": "Sending...",
|
|
39
41
|
"successTitle": "Success",
|
|
@@ -73,7 +75,8 @@
|
|
|
73
75
|
"timeout": "Timed out connecting to the database at {{host}}:{{port}} after about {{seconds}} seconds.",
|
|
74
76
|
"authenticationFailed": "Failed to sign in to database \"{{database}}\" with user \"{{user}}\". Check the username and password.",
|
|
75
77
|
"databaseNotFound": "Database \"{{database}}\" does not exist or is not accessible with the current connection settings.",
|
|
76
|
-
"connectionFailed": "Database connection check failed. Details: {{details}}"
|
|
78
|
+
"connectionFailed": "Database connection check failed. Details: {{details}}",
|
|
79
|
+
"lowerCaseTableNamesRequiresUnderscored": "MySQL lower_case_table_names=1 requires DB_UNDERSCORED=true."
|
|
77
80
|
}
|
|
78
81
|
},
|
|
79
82
|
"commands": {
|
|
@@ -94,16 +97,28 @@
|
|
|
94
97
|
},
|
|
95
98
|
"authType": {
|
|
96
99
|
"message": "How would you like to sign in?",
|
|
100
|
+
"basicLabel": "Basic login (username + password)",
|
|
101
|
+
"basicHint": "uses your credentials to fetch a token after save",
|
|
97
102
|
"oauthLabel": "OAuth (browser login)",
|
|
98
103
|
"oauthHint": "runs nb env auth after save",
|
|
99
104
|
"tokenLabel": "API token / API key"
|
|
100
105
|
},
|
|
106
|
+
"username": {
|
|
107
|
+
"message": "Enter the username for basic login",
|
|
108
|
+
"placeholder": "admin"
|
|
109
|
+
},
|
|
110
|
+
"password": {
|
|
111
|
+
"message": "Enter the password for basic login"
|
|
112
|
+
},
|
|
101
113
|
"accessToken": {
|
|
102
114
|
"message": "Enter an API token or API key",
|
|
103
115
|
"placeholder": "Enter your API token / API key"
|
|
104
116
|
}
|
|
105
117
|
}
|
|
106
118
|
},
|
|
119
|
+
"shared": {
|
|
120
|
+
"missingCommand": "Couldn't run `{{action}}` because the {{displayName}} executable could not be found. Install {{displayName}} or update `nb config set {{configKey}} <path>` and try again."
|
|
121
|
+
},
|
|
107
122
|
"download": {
|
|
108
123
|
"failures": {
|
|
109
124
|
"dependencyInstall": {
|
|
@@ -206,6 +221,10 @@
|
|
|
206
221
|
}
|
|
207
222
|
},
|
|
208
223
|
"install": {
|
|
224
|
+
"messages": {
|
|
225
|
+
"skipDownloadDockerImageMissing": "Cannot continue with `--skip-download` because Docker image \"{{imageRef}}\" is not available locally. Load or pull the image first, or run the command again without `--skip-download`.",
|
|
226
|
+
"skipDownloadLocalAppMissing": "Cannot continue with `--skip-download` because \"{{projectRoot}}\" is missing or does not contain a package.json file. Point `--app-root-path` to an existing NocoBase app, or run the command again without `--skip-download`."
|
|
227
|
+
},
|
|
209
228
|
"validation": {
|
|
210
229
|
"builtinDbUnsupported": "Built-in database does not support \"{{dialect}}\" yet. Choose PostgreSQL, MySQL, or MariaDB, or turn off built-in database."
|
|
211
230
|
},
|
|
@@ -229,9 +248,6 @@
|
|
|
229
248
|
"message": "Where should uploads and local files be stored?",
|
|
230
249
|
"placeholder": "./<env>/storage/"
|
|
231
250
|
},
|
|
232
|
-
"fetchSource": {
|
|
233
|
-
"message": "Download NocoBase automatically if the app directory is empty?"
|
|
234
|
-
},
|
|
235
251
|
"dbDialect": {
|
|
236
252
|
"message": "Which database would you like to use?"
|
|
237
253
|
},
|
|
@@ -259,6 +275,17 @@
|
|
|
259
275
|
"dbPassword": {
|
|
260
276
|
"message": "What is the database password?"
|
|
261
277
|
},
|
|
278
|
+
"dbSchema": {
|
|
279
|
+
"message": "What is the database schema? (PostgreSQL only, optional)",
|
|
280
|
+
"placeholder": "Leave empty to use the default schema"
|
|
281
|
+
},
|
|
282
|
+
"dbTablePrefix": {
|
|
283
|
+
"message": "What table prefix should be used? (optional)",
|
|
284
|
+
"placeholder": "For example: nb_"
|
|
285
|
+
},
|
|
286
|
+
"dbUnderscored": {
|
|
287
|
+
"message": "Use underscored names for database tables and columns?"
|
|
288
|
+
},
|
|
262
289
|
"rootUsername": {
|
|
263
290
|
"message": "Choose the initial admin username",
|
|
264
291
|
"placeholder": "nocobase"
|
|
@@ -290,7 +317,8 @@
|
|
|
290
317
|
"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.",
|
|
291
318
|
"uiReady": "Local setup form is ready.",
|
|
292
319
|
"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.",
|
|
293
|
-
"uiOpenBrowserFallback": "We could not open your browser automatically. Copy the URL above into your browser to continue setup, and keep this terminal session running. If you are using an AI agent, do not stop the current process."
|
|
320
|
+
"uiOpenBrowserFallback": "We could not open your browser automatically. Copy the URL above into your browser to continue setup, and keep this terminal session running. If you are using an AI agent, do not stop the current process.",
|
|
321
|
+
"skillsSyncRegistryUnavailable": "Couldn't reach the npm registry to sync NocoBase AI coding skills. Skipping skills install and continuing init. Run `nb skills install` later when registry access is available."
|
|
294
322
|
},
|
|
295
323
|
"prompts": {
|
|
296
324
|
"appName": {
|
|
@@ -308,6 +336,9 @@
|
|
|
308
336
|
"apiBaseUrl": {
|
|
309
337
|
"message": "API base URL",
|
|
310
338
|
"placeholder": "https://demo.example.com/api or https://demo.example.com/api/__app/<subapp>"
|
|
339
|
+
},
|
|
340
|
+
"skipDownload": {
|
|
341
|
+
"message": "Skip downloading NocoBase and reuse existing local app files or Docker images?"
|
|
311
342
|
}
|
|
312
343
|
},
|
|
313
344
|
"webUi": {
|
package/dist/locale/zh-CN.json
CHANGED
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"back": "上一步",
|
|
35
35
|
"next": "下一步",
|
|
36
36
|
"submit": "提交并回到终端继续",
|
|
37
|
+
"showPassword": "显示密码",
|
|
38
|
+
"hidePassword": "隐藏密码",
|
|
37
39
|
"checking": "检查中...",
|
|
38
40
|
"sending": "提交中...",
|
|
39
41
|
"successTitle": "成功",
|
|
@@ -73,7 +75,8 @@
|
|
|
73
75
|
"timeout": "连接数据库 {{host}}:{{port}} 超时,约 {{seconds}} 秒内未成功建立连接。",
|
|
74
76
|
"authenticationFailed": "无法使用用户 \"{{user}}\" 登录数据库 \"{{database}}\"。请检查用户名和密码。",
|
|
75
77
|
"databaseNotFound": "数据库 \"{{database}}\" 不存在,或当前连接配置无权访问该数据库。",
|
|
76
|
-
"connectionFailed": "数据库连接检查失败。详情:{{details}}"
|
|
78
|
+
"connectionFailed": "数据库连接检查失败。详情:{{details}}",
|
|
79
|
+
"lowerCaseTableNamesRequiresUnderscored": "当 MySQL 的 lower_case_table_names=1 时,必须设置 DB_UNDERSCORED=true。"
|
|
77
80
|
}
|
|
78
81
|
},
|
|
79
82
|
"commands": {
|
|
@@ -94,16 +97,28 @@
|
|
|
94
97
|
},
|
|
95
98
|
"authType": {
|
|
96
99
|
"message": "你想使用哪种登录方式?",
|
|
100
|
+
"basicLabel": "Basic 登录(用户名 + 密码)",
|
|
101
|
+
"basicHint": "保存后会用用户名和密码换取 Token",
|
|
97
102
|
"oauthLabel": "OAuth(浏览器登录)",
|
|
98
103
|
"oauthHint": "保存后会自动执行 nb env auth",
|
|
99
104
|
"tokenLabel": "API Token / API Key"
|
|
100
105
|
},
|
|
106
|
+
"username": {
|
|
107
|
+
"message": "请输入 Basic 登录用户名",
|
|
108
|
+
"placeholder": "admin"
|
|
109
|
+
},
|
|
110
|
+
"password": {
|
|
111
|
+
"message": "请输入 Basic 登录密码"
|
|
112
|
+
},
|
|
101
113
|
"accessToken": {
|
|
102
114
|
"message": "请输入 API Token 或 API Key",
|
|
103
115
|
"placeholder": "请输入你的 API Token / API Key"
|
|
104
116
|
}
|
|
105
117
|
}
|
|
106
118
|
},
|
|
119
|
+
"shared": {
|
|
120
|
+
"missingCommand": "无法执行 `{{action}}`,因为找不到 {{displayName}} 可执行文件。请先安装 {{displayName}},或更新 `nb config set {{configKey}} <path>` 后重试。"
|
|
121
|
+
},
|
|
107
122
|
"download": {
|
|
108
123
|
"failures": {
|
|
109
124
|
"dependencyInstall": {
|
|
@@ -206,6 +221,10 @@
|
|
|
206
221
|
}
|
|
207
222
|
},
|
|
208
223
|
"install": {
|
|
224
|
+
"messages": {
|
|
225
|
+
"skipDownloadDockerImageMissing": "无法继续执行 `--skip-download`,因为本地不存在 Docker 镜像 \"{{imageRef}}\"。请先手动加载或拉取这个镜像,或者去掉 `--skip-download` 后重试。",
|
|
226
|
+
"skipDownloadLocalAppMissing": "无法继续执行 `--skip-download`,因为 \"{{projectRoot}}\" 不存在,或者其中缺少 package.json。请把 `--app-root-path` 指向一个现有的 NocoBase 应用目录,或者去掉 `--skip-download` 后重试。"
|
|
227
|
+
},
|
|
209
228
|
"validation": {
|
|
210
229
|
"builtinDbUnsupported": "内置数据库暂不支持 \"{{dialect}}\"。请选择 PostgreSQL、MySQL 或 MariaDB,或者关闭内置数据库。"
|
|
211
230
|
},
|
|
@@ -229,9 +248,6 @@
|
|
|
229
248
|
"message": "上传文件和本地存储目录要放到哪里?",
|
|
230
249
|
"placeholder": "./<env>/storage/"
|
|
231
250
|
},
|
|
232
|
-
"fetchSource": {
|
|
233
|
-
"message": "如果应用目录为空,是否自动下载 NocoBase?"
|
|
234
|
-
},
|
|
235
251
|
"dbDialect": {
|
|
236
252
|
"message": "你想使用哪种数据库?"
|
|
237
253
|
},
|
|
@@ -259,6 +275,17 @@
|
|
|
259
275
|
"dbPassword": {
|
|
260
276
|
"message": "数据库密码是什么?"
|
|
261
277
|
},
|
|
278
|
+
"dbSchema": {
|
|
279
|
+
"message": "数据库 schema 是什么?(仅 PostgreSQL,可选)",
|
|
280
|
+
"placeholder": "留空则使用默认 schema"
|
|
281
|
+
},
|
|
282
|
+
"dbTablePrefix": {
|
|
283
|
+
"message": "要使用什么数据表前缀?(可选)",
|
|
284
|
+
"placeholder": "例如:nb_"
|
|
285
|
+
},
|
|
286
|
+
"dbUnderscored": {
|
|
287
|
+
"message": "数据库表名和字段名是否使用下划线风格?"
|
|
288
|
+
},
|
|
262
289
|
"rootUsername": {
|
|
263
290
|
"message": "设置初始管理员用户名",
|
|
264
291
|
"placeholder": "nocobase"
|
|
@@ -290,7 +317,8 @@
|
|
|
290
317
|
"uiOpening": "本地 setup 表单即将在浏览器中打开。这个表单需要等待人工填写。如果你正在使用 AI agent,请不要停止当前进程,CLI 会继续等待表单提交结果。",
|
|
291
318
|
"uiReady": "本地 setup 表单已就绪。",
|
|
292
319
|
"uiReadyHelp": "如果没有自动打开浏览器,请复制下面的地址到浏览器中继续。CLI 会继续等待表单提交,请保持当前终端会话继续运行。",
|
|
293
|
-
"uiOpenBrowserFallback": "无法自动打开浏览器。请复制上面的地址到浏览器中继续 setup,并保持当前终端会话继续运行。如果你正在使用 AI agent,请不要停止当前进程。"
|
|
320
|
+
"uiOpenBrowserFallback": "无法自动打开浏览器。请复制上面的地址到浏览器中继续 setup,并保持当前终端会话继续运行。如果你正在使用 AI agent,请不要停止当前进程。",
|
|
321
|
+
"skillsSyncRegistryUnavailable": "无法访问 npm registry 来同步 NocoBase AI coding skills。将跳过 skills 安装并继续执行 init。等 registry 可访问后,再运行 `nb skills install` 即可。"
|
|
294
322
|
},
|
|
295
323
|
"prompts": {
|
|
296
324
|
"appName": {
|
|
@@ -308,6 +336,9 @@
|
|
|
308
336
|
"apiBaseUrl": {
|
|
309
337
|
"message": "API 基础地址",
|
|
310
338
|
"placeholder": "https://demo.example.com/api 或 https://demo.example.com/api/__app/<subapp>"
|
|
339
|
+
},
|
|
340
|
+
"skipDownload": {
|
|
341
|
+
"message": "是否跳过下载 NocoBase,直接复用已有的本地应用文件或 Docker 镜像?"
|
|
311
342
|
}
|
|
312
343
|
},
|
|
313
344
|
"webUi": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/cli",
|
|
3
|
-
"version": "2.1.0-beta.
|
|
3
|
+
"version": "2.1.0-beta.37",
|
|
4
4
|
"description": "NocoBase Command Line Tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/generated/command-registry.js",
|
|
@@ -108,5 +108,5 @@
|
|
|
108
108
|
"type": "git",
|
|
109
109
|
"url": "git+https://github.com/nocobase/nocobase.git"
|
|
110
110
|
},
|
|
111
|
-
"gitHead": "
|
|
111
|
+
"gitHead": "7132e5b83ecc0e42b54715eaf1429c72bcef34ae"
|
|
112
112
|
}
|