@nocobase/cli 2.1.0-beta.16 → 2.1.0-beta.17

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.
@@ -12,13 +12,14 @@ import * as p from '@clack/prompts';
12
12
  import path from 'node:path';
13
13
  import { stdin as stdinStream, stdout as stdoutStream } from 'node:process';
14
14
  import { runPromptCatalog, } from "../lib/prompt-catalog.js";
15
- import { applyCliLocale, CLI_LOCALE_FLAG_DESCRIPTION, CLI_LOCALE_FLAG_OPTIONS, localeText, } from "../lib/cli-locale.js";
15
+ import { applyCliLocale, CLI_LOCALE_FLAG_DESCRIPTION, CLI_LOCALE_FLAG_OPTIONS, localeText, translateCli, } from "../lib/cli-locale.js";
16
16
  import { run } from "../lib/run-npm.js";
17
17
  import { printVerbose, setVerboseMode, startTask, stopTask, updateTask } from '../lib/ui.js';
18
18
  const DEFAULT_DOCKER_REGISTRY = 'nocobase/nocobase';
19
19
  const DEFAULT_DOCKER_REGISTRY_ZH_CN = 'registry.cn-shanghai.aliyuncs.com/nocobase/nocobase';
20
20
  const DEFAULT_DOCKER_PLATFORM = 'auto';
21
21
  const downloadText = (key, values) => localeText(`commands.download.${key}`, values);
22
+ const downloadTranslatedText = (key, values, fallback) => translateCli(`commands.download.${key}`, values, { fallback });
22
23
  function defaultOutputDirForVersion(versionTag) {
23
24
  const safe = versionTag.replace(/[/\\]/g, '-');
24
25
  return `./nocobase-${safe}`;
@@ -81,6 +82,41 @@ function dockerPlatformArg(value) {
81
82
  }
82
83
  return platform;
83
84
  }
85
+ function formatDownloadStageFailure(stage) {
86
+ return [
87
+ downloadTranslatedText(`failures.${stage}.title`),
88
+ downloadTranslatedText(`failures.${stage}.body`),
89
+ downloadTranslatedText(`failures.${stage}.hint`),
90
+ ].join('\n');
91
+ }
92
+ function formatDownloadFailure(message, verbose) {
93
+ if (verbose) {
94
+ return message;
95
+ }
96
+ const lower = message.toLowerCase();
97
+ if (lower.includes('yarn install')) {
98
+ return formatDownloadStageFailure('dependencyInstall');
99
+ }
100
+ if (lower.includes('git clone')) {
101
+ return formatDownloadStageFailure('gitClone');
102
+ }
103
+ if (lower.includes('docker pull')) {
104
+ return formatDownloadStageFailure('dockerPull');
105
+ }
106
+ if (lower.includes('docker save')) {
107
+ return formatDownloadStageFailure('dockerSave');
108
+ }
109
+ if (lower.includes('create-nocobase-app') || lower.includes('npx create-nocobase-app')) {
110
+ return formatDownloadStageFailure('scaffold');
111
+ }
112
+ if (lower.includes('nocobase command')) {
113
+ return formatDownloadStageFailure('build');
114
+ }
115
+ if (lower.includes('exited with code') || lower.includes('exited due to signal')) {
116
+ return formatDownloadStageFailure('generic');
117
+ }
118
+ return message;
119
+ }
84
120
  const EXTERNAL_COMMAND_LOADING_DELAY_MS = 8_000;
85
121
  const EXTERNAL_COMMAND_LOADING_UPDATE_MS = 15_000;
86
122
  export default class Download extends Command {
@@ -737,7 +773,7 @@ export default class Download extends Command {
737
773
  }
738
774
  catch (error) {
739
775
  const message = error instanceof Error ? error.message : String(error);
740
- this.error(message);
776
+ this.error(formatDownloadFailure(message, this.isVerbose()));
741
777
  }
742
778
  }
743
779
  }
@@ -238,6 +238,10 @@ Prompt modes:
238
238
  description: 'Open the guided setup flow in a local browser form (not valid with --yes)',
239
239
  default: false,
240
240
  }),
241
+ verbose: Flags.boolean({
242
+ description: 'Show detailed command output',
243
+ default: false,
244
+ }),
241
245
  'ui-host': Flags.string({
242
246
  description: 'Host for the local --ui setup server (default: 127.0.0.1)',
243
247
  }),
@@ -675,6 +679,9 @@ Prompt modes:
675
679
  if (options?.resume) {
676
680
  argv.push('--resume');
677
681
  }
682
+ if (Boolean(flags.verbose)) {
683
+ argv.push('--verbose');
684
+ }
678
685
  const lang = String(results.lang ?? '').trim();
679
686
  if (lang) {
680
687
  argv.push('--lang', lang);
@@ -254,6 +254,10 @@ export default class Install extends Command {
254
254
  description: 'Resume a previous unfinished setup for this env using the saved workspace env config',
255
255
  default: false,
256
256
  }),
257
+ verbose: Flags.boolean({
258
+ description: 'Show detailed command output',
259
+ default: false,
260
+ }),
257
261
  env: Flags.string({
258
262
  char: 'e',
259
263
  description: 'App/env name to create or update. Defaults app paths to ./<envName>/source/ and ./<envName>/storage/.',
@@ -1365,8 +1369,11 @@ export default class Install extends Command {
1365
1369
  argv.push(flag, text);
1366
1370
  }
1367
1371
  }
1368
- static buildDownloadArgvFromResults(results) {
1372
+ static buildDownloadArgvFromResults(results, options) {
1369
1373
  const argv = ['-y', '--no-intro'];
1374
+ if (options?.verbose) {
1375
+ argv.push('--verbose');
1376
+ }
1370
1377
  Install.pushDownloadArgIfValue(argv, '--source', results.source);
1371
1378
  Install.pushDownloadArgIfValue(argv, '--version', results.version);
1372
1379
  Install.pushDownloadArgIfValue(argv, '--output-dir', results.outputDir);
@@ -1402,7 +1409,9 @@ export default class Install extends Command {
1402
1409
  return path.resolve(process.cwd(), outputDir);
1403
1410
  }
1404
1411
  async downloadLocalApp(params) {
1405
- const argv = Install.buildDownloadArgvFromResults(params.downloadResults);
1412
+ const argv = Install.buildDownloadArgvFromResults(params.downloadResults, {
1413
+ verbose: params.verbose,
1414
+ });
1406
1415
  p.log.step('Downloading local NocoBase app files');
1407
1416
  const result = await this.config.runCommand('download', argv);
1408
1417
  const projectRoot = Install.resolveLocalProjectRoot({
@@ -1799,6 +1808,7 @@ export default class Install extends Command {
1799
1808
  envName,
1800
1809
  appResults,
1801
1810
  downloadResults,
1811
+ verbose: parsed.verbose,
1802
1812
  });
1803
1813
  localAppPlan = await this.startLocalApp({
1804
1814
  envName,
@@ -6,15 +6,9 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
- import { spawn } from 'node:child_process';
10
9
  import path from 'node:path';
10
+ import spawn from 'cross-spawn';
11
11
  function resolveCommandName(name) {
12
- if (process.platform !== 'win32' || path.extname(name) || name.includes(path.sep)) {
13
- return name;
14
- }
15
- if (['npm', 'npx', 'pnpm', 'yarn'].includes(name)) {
16
- return `${name}.cmd`;
17
- }
18
12
  return name;
19
13
  }
20
14
  function resolveCwd(cwd) {
@@ -27,14 +21,16 @@ function resolveCwd(cwd) {
27
21
  export function run(name, args, options) {
28
22
  const cwd = resolveCwd(options?.cwd);
29
23
  const label = options?.errorName ?? name;
24
+ const command = resolveCommandName(name);
30
25
  return new Promise((resolve, reject) => {
31
- const child = spawn(resolveCommandName(name), [...args], {
26
+ const child = spawn(command, [...args], {
32
27
  stdio: options?.stdio ?? 'inherit',
33
28
  cwd,
34
29
  env: {
35
30
  ...process.env,
36
31
  ...options?.env,
37
32
  },
33
+ windowsHide: process.platform === 'win32',
38
34
  });
39
35
  child.once('error', reject);
40
36
  child.once('close', (code, signal) => {
@@ -52,14 +48,16 @@ export function run(name, args, options) {
52
48
  }
53
49
  export function commandSucceeds(name, args, options) {
54
50
  const cwd = resolveCwd(options?.cwd);
51
+ const command = resolveCommandName(name);
55
52
  return new Promise((resolve) => {
56
- const child = spawn(resolveCommandName(name), [...args], {
53
+ const child = spawn(command, [...args], {
57
54
  cwd,
58
55
  env: {
59
56
  ...process.env,
60
57
  ...options?.env,
61
58
  },
62
59
  stdio: 'ignore',
60
+ windowsHide: process.platform === 'win32',
63
61
  });
64
62
  child.once('error', () => resolve(false));
65
63
  child.once('close', (code) => resolve(code === 0));
@@ -68,14 +66,16 @@ export function commandSucceeds(name, args, options) {
68
66
  export function commandOutput(name, args, options) {
69
67
  const cwd = resolveCwd(options?.cwd);
70
68
  const label = options?.errorName ?? name;
69
+ const command = resolveCommandName(name);
71
70
  return new Promise((resolve, reject) => {
72
- const child = spawn(resolveCommandName(name), [...args], {
71
+ const child = spawn(command, [...args], {
73
72
  cwd,
74
73
  env: {
75
74
  ...process.env,
76
75
  ...options?.env,
77
76
  },
78
77
  stdio: ['ignore', 'pipe', 'pipe'],
78
+ windowsHide: process.platform === 'win32',
79
79
  });
80
80
  let stdout = '';
81
81
  let stderr = '';
@@ -95,6 +95,43 @@
95
95
  }
96
96
  },
97
97
  "download": {
98
+ "failures": {
99
+ "dependencyInstall": {
100
+ "title": "Couldn't finish preparing the local NocoBase app.",
101
+ "body": "The download completed, but dependency installation did not finish successfully.",
102
+ "hint": "Run the same command again with `--verbose` to see the full install logs."
103
+ },
104
+ "gitClone": {
105
+ "title": "Couldn't download NocoBase from Git.",
106
+ "body": "The CLI was not able to clone the selected NocoBase repository.",
107
+ "hint": "Run the same command again with `--verbose` to see the full clone logs."
108
+ },
109
+ "dockerPull": {
110
+ "title": "Couldn't download the Docker image.",
111
+ "body": "The CLI was not able to pull the selected NocoBase image.",
112
+ "hint": "Run the same command again with `--verbose` to see the full Docker pull logs."
113
+ },
114
+ "dockerSave": {
115
+ "title": "The Docker image was pulled, but saving the tar file failed.",
116
+ "body": "The CLI could not finish exporting the image to the target tarball path.",
117
+ "hint": "Run the same command again with `--verbose` to see the full Docker save logs."
118
+ },
119
+ "scaffold": {
120
+ "title": "Couldn't create the local NocoBase app scaffold.",
121
+ "body": "The CLI was not able to finish generating the initial app files.",
122
+ "hint": "Run the same command again with `--verbose` to see the full scaffold logs."
123
+ },
124
+ "build": {
125
+ "title": "The local NocoBase app was downloaded, but the build step failed.",
126
+ "body": "The CLI could not finish building the downloaded source code.",
127
+ "hint": "Run the same command again with `--verbose` to see the full build logs."
128
+ },
129
+ "generic": {
130
+ "title": "Couldn't finish downloading NocoBase.",
131
+ "body": "The CLI hit an unexpected command failure while preparing the download.",
132
+ "hint": "Run the same command again with `--verbose` to see the full command logs."
133
+ }
134
+ },
98
135
  "prompts": {
99
136
  "source": {
100
137
  "message": "How would you like to get NocoBase?",
@@ -95,6 +95,43 @@
95
95
  }
96
96
  },
97
97
  "download": {
98
+ "failures": {
99
+ "dependencyInstall": {
100
+ "title": "本地 NocoBase 应用还没有准备完成。",
101
+ "body": "下载已经完成,但依赖安装没有成功结束。",
102
+ "hint": "请使用相同命令加上 `--verbose` 重试,以查看完整安装日志。"
103
+ },
104
+ "gitClone": {
105
+ "title": "无法通过 Git 下载 NocoBase。",
106
+ "body": "CLI 没有成功克隆你选择的 NocoBase 仓库。",
107
+ "hint": "请使用相同命令加上 `--verbose` 重试,以查看完整克隆日志。"
108
+ },
109
+ "dockerPull": {
110
+ "title": "无法下载 Docker 镜像。",
111
+ "body": "CLI 没有成功拉取你选择的 NocoBase 镜像。",
112
+ "hint": "请使用相同命令加上 `--verbose` 重试,以查看完整 Docker pull 日志。"
113
+ },
114
+ "dockerSave": {
115
+ "title": "Docker 镜像已经拉取完成,但导出 tar 文件失败了。",
116
+ "body": "CLI 没有成功将镜像导出到目标 tar 包路径。",
117
+ "hint": "请使用相同命令加上 `--verbose` 重试,以查看完整 Docker save 日志。"
118
+ },
119
+ "scaffold": {
120
+ "title": "无法创建本地 NocoBase 应用骨架。",
121
+ "body": "CLI 没有成功生成初始应用文件。",
122
+ "hint": "请使用相同命令加上 `--verbose` 重试,以查看完整 scaffold 日志。"
123
+ },
124
+ "build": {
125
+ "title": "本地 NocoBase 应用已经下载完成,但构建步骤失败了。",
126
+ "body": "CLI 没有成功完成已下载源码的构建。",
127
+ "hint": "请使用相同命令加上 `--verbose` 重试,以查看完整构建日志。"
128
+ },
129
+ "generic": {
130
+ "title": "无法完成 NocoBase 下载。",
131
+ "body": "CLI 在准备下载内容时遇到了未预期的命令失败。",
132
+ "hint": "请使用相同命令加上 `--verbose` 重试,以查看完整命令日志。"
133
+ }
134
+ },
98
135
  "prompts": {
99
136
  "source": {
100
137
  "message": "你想通过哪种方式获取 NocoBase?",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/cli",
3
- "version": "2.1.0-beta.16",
3
+ "version": "2.1.0-beta.17",
4
4
  "description": "NocoBase Command Line Tool",
5
5
  "type": "module",
6
6
  "main": "dist/generated/command-registry.js",
@@ -47,6 +47,7 @@
47
47
  "dependencies": {
48
48
  "@clack/prompts": "^0.9.1",
49
49
  "@oclif/core": "^4.10.4",
50
+ "cross-spawn": "^7.0.6",
50
51
  "lodash": "^4.17.21",
51
52
  "openapi-types": "^12.1.3",
52
53
  "ora": "^8.2.0",
@@ -61,5 +62,5 @@
61
62
  "type": "git",
62
63
  "url": "git+https://github.com/nocobase/nocobase.git"
63
64
  },
64
- "gitHead": "b9a191705a440a336c85d82fd877fdf152bec70f"
65
+ "gitHead": "227d625e47174ab7b3a90170e7c6c67bbdf36e23"
65
66
  }