@nocobase/cli 2.1.0-alpha.22 → 2.1.0-alpha.23
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/dist/commands/download.js +143 -21
- package/dist/commands/init.js +18 -2
- package/dist/commands/install.js +32 -13
- package/dist/lib/prompt-catalog.js +11 -4
- package/dist/lib/prompt-web-ui.js +45 -10
- package/dist/lib/run-npm.js +10 -10
- package/dist/locale/en-US.json +56 -5
- package/dist/locale/zh-CN.json +57 -6
- package/package.json +3 -2
|
@@ -12,13 +12,15 @@ 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, resolveCliLocale, 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
|
+
const DEFAULT_DOWNLOAD_VERSION = 'beta';
|
|
21
22
|
const downloadText = (key, values) => localeText(`commands.download.${key}`, values);
|
|
23
|
+
const downloadTranslatedText = (key, values, fallback) => translateCli(`commands.download.${key}`, values, { fallback });
|
|
22
24
|
function defaultOutputDirForVersion(versionTag) {
|
|
23
25
|
const safe = versionTag.replace(/[/\\]/g, '-');
|
|
24
26
|
return `./nocobase-${safe}`;
|
|
@@ -33,10 +35,13 @@ async function pathExists(target) {
|
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
export function defaultDockerRegistryForLang(lang) {
|
|
36
|
-
return String(lang ?? '').trim() === 'zh-CN'
|
|
38
|
+
return resolveCliLocale(String(lang ?? '').trim() || undefined) === 'zh-CN'
|
|
37
39
|
? DEFAULT_DOCKER_REGISTRY_ZH_CN
|
|
38
40
|
: DEFAULT_DOCKER_REGISTRY;
|
|
39
41
|
}
|
|
42
|
+
function defaultDockerRegistryForPromptValues(_values) {
|
|
43
|
+
return defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
44
|
+
}
|
|
40
45
|
function argvHasToken(argv, tokens) {
|
|
41
46
|
return tokens.some((t) => argv.includes(t));
|
|
42
47
|
}
|
|
@@ -81,8 +86,64 @@ function dockerPlatformArg(value) {
|
|
|
81
86
|
}
|
|
82
87
|
return platform;
|
|
83
88
|
}
|
|
89
|
+
function formatDownloadStageFailure(stage) {
|
|
90
|
+
return [
|
|
91
|
+
downloadTranslatedText(`failures.${stage}.title`),
|
|
92
|
+
downloadTranslatedText(`failures.${stage}.body`),
|
|
93
|
+
downloadTranslatedText(`failures.${stage}.hint`),
|
|
94
|
+
].join('\n');
|
|
95
|
+
}
|
|
96
|
+
function formatDownloadFailure(message, verbose) {
|
|
97
|
+
if (verbose) {
|
|
98
|
+
return message;
|
|
99
|
+
}
|
|
100
|
+
const lower = message.toLowerCase();
|
|
101
|
+
if (lower.includes('yarn install')) {
|
|
102
|
+
return formatDownloadStageFailure('dependencyInstall');
|
|
103
|
+
}
|
|
104
|
+
if (lower.includes('git clone')) {
|
|
105
|
+
return formatDownloadStageFailure('gitClone');
|
|
106
|
+
}
|
|
107
|
+
if (lower.includes('docker pull')) {
|
|
108
|
+
return formatDownloadStageFailure('dockerPull');
|
|
109
|
+
}
|
|
110
|
+
if (lower.includes('docker save')) {
|
|
111
|
+
return formatDownloadStageFailure('dockerSave');
|
|
112
|
+
}
|
|
113
|
+
if (lower.includes('create-nocobase-app') || lower.includes('npx create-nocobase-app')) {
|
|
114
|
+
return formatDownloadStageFailure('scaffold');
|
|
115
|
+
}
|
|
116
|
+
if (lower.includes('nocobase command')) {
|
|
117
|
+
return formatDownloadStageFailure('build');
|
|
118
|
+
}
|
|
119
|
+
if (lower.includes('exited with code') || lower.includes('exited due to signal')) {
|
|
120
|
+
return formatDownloadStageFailure('generic');
|
|
121
|
+
}
|
|
122
|
+
return message;
|
|
123
|
+
}
|
|
84
124
|
const EXTERNAL_COMMAND_LOADING_DELAY_MS = 8_000;
|
|
85
125
|
const EXTERNAL_COMMAND_LOADING_UPDATE_MS = 15_000;
|
|
126
|
+
function normalizeVersionPreset(value) {
|
|
127
|
+
const text = String(value ?? '').trim();
|
|
128
|
+
if (text === 'latest' || text === 'beta' || text === 'alpha') {
|
|
129
|
+
return text;
|
|
130
|
+
}
|
|
131
|
+
return 'other';
|
|
132
|
+
}
|
|
133
|
+
function versionPresetForValue(value) {
|
|
134
|
+
return normalizeVersionPreset(value);
|
|
135
|
+
}
|
|
136
|
+
function otherVersionValue(value) {
|
|
137
|
+
const text = String(value ?? '').trim();
|
|
138
|
+
return normalizeVersionPreset(text) === 'other' ? text : '';
|
|
139
|
+
}
|
|
140
|
+
function resolveVersionFromResults(results, fallback) {
|
|
141
|
+
const preset = normalizeVersionPreset(results.version ?? fallback);
|
|
142
|
+
if (preset === 'other') {
|
|
143
|
+
return String(results.otherVersion ?? fallback ?? '').trim();
|
|
144
|
+
}
|
|
145
|
+
return preset;
|
|
146
|
+
}
|
|
86
147
|
export default class Download extends Command {
|
|
87
148
|
_flags;
|
|
88
149
|
preparationTaskActive = false;
|
|
@@ -176,30 +237,72 @@ export default class Download extends Command {
|
|
|
176
237
|
static prompts = {
|
|
177
238
|
source: {
|
|
178
239
|
type: 'select',
|
|
240
|
+
variant: 'radio',
|
|
179
241
|
message: downloadText('prompts.source.message'),
|
|
180
242
|
options: [
|
|
181
|
-
{
|
|
182
|
-
|
|
183
|
-
|
|
243
|
+
{
|
|
244
|
+
value: 'docker',
|
|
245
|
+
label: downloadText('prompts.source.dockerLabel'),
|
|
246
|
+
hint: downloadText('prompts.source.dockerHint'),
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
value: 'npm',
|
|
250
|
+
label: downloadText('prompts.source.npmLabel'),
|
|
251
|
+
hint: downloadText('prompts.source.npmHint'),
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
value: 'git',
|
|
255
|
+
label: downloadText('prompts.source.gitLabel'),
|
|
256
|
+
hint: downloadText('prompts.source.gitHint'),
|
|
257
|
+
},
|
|
184
258
|
],
|
|
185
259
|
yesInitialValue: 'docker',
|
|
186
260
|
initialValue: 'docker',
|
|
187
261
|
required: true,
|
|
188
262
|
},
|
|
189
263
|
version: {
|
|
190
|
-
type: '
|
|
264
|
+
type: 'select',
|
|
265
|
+
variant: 'radio',
|
|
191
266
|
message: downloadText('prompts.version.message'),
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
267
|
+
options: [
|
|
268
|
+
{
|
|
269
|
+
value: 'latest',
|
|
270
|
+
label: downloadText('prompts.version.latestLabel'),
|
|
271
|
+
hint: downloadText('prompts.version.latestHint'),
|
|
272
|
+
disabled: true,
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
value: 'beta',
|
|
276
|
+
label: downloadText('prompts.version.betaLabel'),
|
|
277
|
+
hint: downloadText('prompts.version.betaHint'),
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
value: 'alpha',
|
|
281
|
+
label: downloadText('prompts.version.alphaLabel'),
|
|
282
|
+
hint: downloadText('prompts.version.alphaHint'),
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
value: 'other',
|
|
286
|
+
label: downloadText('prompts.version.otherLabel'),
|
|
287
|
+
hint: downloadText('prompts.version.otherHint'),
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
initialValue: DEFAULT_DOWNLOAD_VERSION,
|
|
291
|
+
yesInitialValue: DEFAULT_DOWNLOAD_VERSION,
|
|
292
|
+
required: true,
|
|
293
|
+
},
|
|
294
|
+
otherVersion: {
|
|
295
|
+
type: 'text',
|
|
296
|
+
message: downloadText('prompts.otherVersion.message'),
|
|
297
|
+
placeholder: downloadText('prompts.otherVersion.placeholder'),
|
|
195
298
|
required: true,
|
|
299
|
+
hidden: (values) => normalizeVersionPreset(values.version) !== 'other',
|
|
196
300
|
},
|
|
197
301
|
dockerRegistry: {
|
|
198
302
|
type: 'text',
|
|
199
303
|
message: downloadText('prompts.dockerRegistry.message'),
|
|
200
304
|
placeholder: downloadText('prompts.dockerRegistry.placeholder'),
|
|
201
|
-
initialValue:
|
|
202
|
-
yesInitialValue: DEFAULT_DOCKER_REGISTRY,
|
|
305
|
+
initialValue: defaultDockerRegistryForPromptValues,
|
|
203
306
|
required: true,
|
|
204
307
|
hidden: (values) => values.source !== 'docker',
|
|
205
308
|
},
|
|
@@ -239,7 +342,10 @@ export default class Download extends Command {
|
|
|
239
342
|
type: 'text',
|
|
240
343
|
message: downloadText('prompts.outputDir.message'),
|
|
241
344
|
placeholder: downloadText('prompts.outputDir.placeholder'),
|
|
242
|
-
initialValue: (values) =>
|
|
345
|
+
initialValue: (values) => {
|
|
346
|
+
const version = resolveVersionFromResults(values, DEFAULT_DOWNLOAD_VERSION) || DEFAULT_DOWNLOAD_VERSION;
|
|
347
|
+
return defaultOutputDirForVersion(version);
|
|
348
|
+
},
|
|
243
349
|
required: true,
|
|
244
350
|
hidden: (values) => {
|
|
245
351
|
const s = values.source;
|
|
@@ -315,7 +421,7 @@ export default class Download extends Command {
|
|
|
315
421
|
return outputAbs;
|
|
316
422
|
}
|
|
317
423
|
dockerTarPath(flags, outputAbs) {
|
|
318
|
-
const image = flags['docker-registry'] ??
|
|
424
|
+
const image = String(flags['docker-registry'] ?? '').trim() || defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
319
425
|
const tag = flags.version ?? 'latest';
|
|
320
426
|
const safeBase = `${image.replace(/[/:]/g, '-')}-${tag.replace(/[/\\]/g, '-')}`;
|
|
321
427
|
return path.join(outputAbs, `${safeBase}.tar`);
|
|
@@ -326,12 +432,15 @@ export default class Download extends Command {
|
|
|
326
432
|
*/
|
|
327
433
|
buildInitialValuesFromParsed(flags, preset) {
|
|
328
434
|
const initialValues = {};
|
|
435
|
+
const localeDefaultDockerRegistry = defaultDockerRegistryForLang(flags.locale ?? process.env.NB_LOCALE);
|
|
329
436
|
const source = flags.source?.trim();
|
|
330
437
|
if (source) {
|
|
331
438
|
initialValues.source = source;
|
|
332
439
|
}
|
|
333
440
|
if (flags.version !== undefined) {
|
|
334
|
-
|
|
441
|
+
const version = flags.version.trim() || 'latest';
|
|
442
|
+
initialValues.version = versionPresetForValue(version);
|
|
443
|
+
initialValues.otherVersion = otherVersionValue(version);
|
|
335
444
|
}
|
|
336
445
|
initialValues.replace = flags.replace;
|
|
337
446
|
initialValues.devDependencies = flags['dev-dependencies'];
|
|
@@ -346,6 +455,9 @@ export default class Download extends Command {
|
|
|
346
455
|
if (flags['docker-registry'] !== undefined) {
|
|
347
456
|
initialValues.dockerRegistry = String(flags['docker-registry'] ?? '').trim();
|
|
348
457
|
}
|
|
458
|
+
else {
|
|
459
|
+
initialValues.dockerRegistry = localeDefaultDockerRegistry;
|
|
460
|
+
}
|
|
349
461
|
initialValues.dockerPlatform = normalizeDockerPlatform(flags['docker-platform']);
|
|
350
462
|
initialValues.dockerSave = flags['docker-save'];
|
|
351
463
|
if (flags['npm-registry'] !== undefined) {
|
|
@@ -370,7 +482,11 @@ export default class Download extends Command {
|
|
|
370
482
|
preset.source = String(flags.source).trim();
|
|
371
483
|
}
|
|
372
484
|
if (flags.version !== undefined) {
|
|
373
|
-
|
|
485
|
+
const version = String(flags.version).trim() || 'latest';
|
|
486
|
+
preset.version = versionPresetForValue(version);
|
|
487
|
+
if (normalizeVersionPreset(version) === 'other') {
|
|
488
|
+
preset.otherVersion = version;
|
|
489
|
+
}
|
|
374
490
|
}
|
|
375
491
|
if (flags['docker-registry'] !== undefined) {
|
|
376
492
|
const v = String(flags['docker-registry'] ?? '').trim();
|
|
@@ -424,7 +540,7 @@ export default class Download extends Command {
|
|
|
424
540
|
}
|
|
425
541
|
mapCatalogResultsToResolved(results, flags) {
|
|
426
542
|
const source = String(results.source);
|
|
427
|
-
const version =
|
|
543
|
+
const version = resolveVersionFromResults(results, flags.version) || 'latest';
|
|
428
544
|
const devDependencies = source === 'npm' ? Boolean(results.devDependencies) : undefined;
|
|
429
545
|
const effectiveBuild = this.resolveEffectiveBuild(source, results, flags);
|
|
430
546
|
const buildDtsWant = results.buildDts !== undefined ? Boolean(results.buildDts) : flags['build-dts'];
|
|
@@ -435,9 +551,11 @@ export default class Download extends Command {
|
|
|
435
551
|
const gitUrl = results.gitUrl !== undefined
|
|
436
552
|
? String(results.gitUrl).trim() || undefined
|
|
437
553
|
: flags['git-url']?.trim() || undefined;
|
|
438
|
-
const dockerRegistry =
|
|
439
|
-
?
|
|
440
|
-
|
|
554
|
+
const dockerRegistry = source === 'docker'
|
|
555
|
+
? (results.dockerRegistry !== undefined
|
|
556
|
+
? String(results.dockerRegistry).trim() || undefined
|
|
557
|
+
: flags['docker-registry']?.trim() || defaultDockerRegistryForLang(flags.locale ?? process.env.NB_LOCALE))
|
|
558
|
+
: undefined;
|
|
441
559
|
const dockerPlatform = source === 'docker'
|
|
442
560
|
? normalizeDockerPlatform(results.dockerPlatform !== undefined
|
|
443
561
|
? results.dockerPlatform
|
|
@@ -490,9 +608,13 @@ export default class Download extends Command {
|
|
|
490
608
|
},
|
|
491
609
|
});
|
|
492
610
|
const source = String(results.source ?? '').trim();
|
|
611
|
+
const version = resolveVersionFromResults(results, flags.version);
|
|
493
612
|
if (!source || !['docker', 'npm', 'git'].includes(source)) {
|
|
494
613
|
this.error('Download source is required. Choose npm, git, or docker.');
|
|
495
614
|
}
|
|
615
|
+
if (!version) {
|
|
616
|
+
this.error('Version is required. Choose alpha, beta, latest, or enter another version.');
|
|
617
|
+
}
|
|
496
618
|
if (flags['docker-save'] && source !== 'docker') {
|
|
497
619
|
this.error('--docker-save is only available when --source docker is selected.');
|
|
498
620
|
}
|
|
@@ -586,7 +708,7 @@ export default class Download extends Command {
|
|
|
586
708
|
return argv;
|
|
587
709
|
}
|
|
588
710
|
async downloadFromDocker(flags) {
|
|
589
|
-
const image = flags['docker-registry'] ??
|
|
711
|
+
const image = String(flags['docker-registry'] ?? '').trim() || defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
590
712
|
const tag = flags.version ?? 'latest';
|
|
591
713
|
const imageRef = `${image}:${tag}`;
|
|
592
714
|
const platform = dockerPlatformArg(flags['docker-platform']);
|
|
@@ -737,7 +859,7 @@ export default class Download extends Command {
|
|
|
737
859
|
}
|
|
738
860
|
catch (error) {
|
|
739
861
|
const message = error instanceof Error ? error.message : String(error);
|
|
740
|
-
this.error(message);
|
|
862
|
+
this.error(formatDownloadFailure(message, this.isVerbose()));
|
|
741
863
|
}
|
|
742
864
|
}
|
|
743
865
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -48,6 +48,13 @@ function downloadInNewInstallOnly(def) {
|
|
|
48
48
|
function argvHasToken(argv, tokens) {
|
|
49
49
|
return tokens.some((token) => argv.includes(token));
|
|
50
50
|
}
|
|
51
|
+
function resolveInitDownloadVersion(results) {
|
|
52
|
+
const preset = String(results.version ?? '').trim();
|
|
53
|
+
if (preset === 'other') {
|
|
54
|
+
return String(results.otherVersion ?? '').trim();
|
|
55
|
+
}
|
|
56
|
+
return preset;
|
|
57
|
+
}
|
|
51
58
|
function shouldAllowExistingInitEnv() {
|
|
52
59
|
return argvHasToken(process.argv.slice(2), ['--force', '-f']);
|
|
53
60
|
}
|
|
@@ -177,6 +184,7 @@ Prompt modes:
|
|
|
177
184
|
fetchSource: newInstallOnly(Install.appPrompts.fetchSource),
|
|
178
185
|
source: downloadInNewInstallOnly(Download.prompts.source),
|
|
179
186
|
version: downloadInNewInstallOnly(Download.prompts.version),
|
|
187
|
+
otherVersion: downloadInNewInstallOnly(Download.prompts.otherVersion),
|
|
180
188
|
dockerRegistry: downloadInNewInstallOnly(Download.prompts.dockerRegistry),
|
|
181
189
|
dockerPlatform: downloadInNewInstallOnly(Download.prompts.dockerPlatform),
|
|
182
190
|
dockerSave: downloadInNewInstallOnly(Download.prompts.dockerSave),
|
|
@@ -238,6 +246,10 @@ Prompt modes:
|
|
|
238
246
|
description: 'Open the guided setup flow in a local browser form (not valid with --yes)',
|
|
239
247
|
default: false,
|
|
240
248
|
}),
|
|
249
|
+
verbose: Flags.boolean({
|
|
250
|
+
description: 'Show detailed command output',
|
|
251
|
+
default: false,
|
|
252
|
+
}),
|
|
241
253
|
'ui-host': Flags.string({
|
|
242
254
|
description: 'Host for the local --ui setup server (default: 127.0.0.1)',
|
|
243
255
|
}),
|
|
@@ -468,6 +480,7 @@ Prompt modes:
|
|
|
468
480
|
catalog: {
|
|
469
481
|
source: c.source,
|
|
470
482
|
version: c.version,
|
|
483
|
+
otherVersion: c.otherVersion,
|
|
471
484
|
dockerRegistry: c.dockerRegistry,
|
|
472
485
|
dockerPlatform: c.dockerPlatform,
|
|
473
486
|
dockerSave: c.dockerSave,
|
|
@@ -614,7 +627,7 @@ Prompt modes:
|
|
|
614
627
|
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
615
628
|
const appPort = String(results.appPort ?? '').trim();
|
|
616
629
|
const source = String(results.source ?? '').trim();
|
|
617
|
-
const version =
|
|
630
|
+
const version = resolveInitDownloadVersion(results);
|
|
618
631
|
const dockerRegistry = String(results.dockerRegistry ?? '').trim();
|
|
619
632
|
const dockerPlatform = String(results.dockerPlatform ?? '').trim();
|
|
620
633
|
const gitUrl = String(results.gitUrl ?? '').trim();
|
|
@@ -675,6 +688,9 @@ Prompt modes:
|
|
|
675
688
|
if (options?.resume) {
|
|
676
689
|
argv.push('--resume');
|
|
677
690
|
}
|
|
691
|
+
if (Boolean(flags.verbose)) {
|
|
692
|
+
argv.push('--verbose');
|
|
693
|
+
}
|
|
678
694
|
const lang = String(results.lang ?? '').trim();
|
|
679
695
|
if (lang) {
|
|
680
696
|
argv.push('--lang', lang);
|
|
@@ -699,7 +715,7 @@ Prompt modes:
|
|
|
699
715
|
if (source) {
|
|
700
716
|
argv.push('--source', source);
|
|
701
717
|
}
|
|
702
|
-
const version =
|
|
718
|
+
const version = resolveInitDownloadVersion(results);
|
|
703
719
|
if (version) {
|
|
704
720
|
argv.push('--version', version);
|
|
705
721
|
}
|
package/dist/commands/install.js
CHANGED
|
@@ -15,7 +15,7 @@ import { mkdir } from 'node:fs/promises';
|
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { exit } from 'node:process';
|
|
17
17
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
18
|
-
import { applyCliLocale, localeText, translateCli, } from "../lib/cli-locale.js";
|
|
18
|
+
import { applyCliLocale, localeText, resolveCliLocale, translateCli, } from "../lib/cli-locale.js";
|
|
19
19
|
import { findAvailableTcpPort, validateAvailableTcpPort, validateTcpPort, validateEnvKey, } from "../lib/prompt-validators.js";
|
|
20
20
|
import { formatMissingManagedAppEnvMessage } from '../lib/app-runtime.js';
|
|
21
21
|
import { run, runNocoBaseCommand } from '../lib/run-npm.js';
|
|
@@ -40,6 +40,12 @@ const DEFAULT_INSTALL_BUILTIN_DB_IMAGES = {
|
|
|
40
40
|
mariadb: 'mariadb:11',
|
|
41
41
|
kingbase: 'registry.cn-shanghai.aliyuncs.com/nocobase/kingbase:v009r001c001b0030_single_x86',
|
|
42
42
|
};
|
|
43
|
+
const DEFAULT_INSTALL_BUILTIN_DB_IMAGES_ZH_CN = {
|
|
44
|
+
postgres: 'registry.cn-shanghai.aliyuncs.com/nocobase/postgres:16',
|
|
45
|
+
mysql: 'registry.cn-shanghai.aliyuncs.com/nocobase/mysql:8',
|
|
46
|
+
mariadb: 'registry.cn-shanghai.aliyuncs.com/nocobase/mariadb:11',
|
|
47
|
+
kingbase: 'registry.cn-shanghai.aliyuncs.com/nocobase/kingbase:v009r001c001b0030_single_x86',
|
|
48
|
+
};
|
|
43
49
|
const DEFAULT_INSTALL_DB_DATABASE = 'nocobase';
|
|
44
50
|
const DEFAULT_INSTALL_DB_USER = 'nocobase';
|
|
45
51
|
const DEFAULT_INSTALL_DB_PASSWORD = 'nocobase';
|
|
@@ -141,9 +147,12 @@ export function defaultDbPortForDialect(value) {
|
|
|
141
147
|
}
|
|
142
148
|
function defaultBuiltinDbImageForDialect(value) {
|
|
143
149
|
const dialect = String(value ?? 'postgres').trim();
|
|
150
|
+
const defaults = resolveCliLocale(process.env.NB_LOCALE) === 'zh-CN'
|
|
151
|
+
? DEFAULT_INSTALL_BUILTIN_DB_IMAGES_ZH_CN
|
|
152
|
+
: DEFAULT_INSTALL_BUILTIN_DB_IMAGES;
|
|
144
153
|
return supportsBuiltinDbDialect(dialect)
|
|
145
|
-
?
|
|
146
|
-
:
|
|
154
|
+
? defaults[dialect]
|
|
155
|
+
: defaults.postgres;
|
|
147
156
|
}
|
|
148
157
|
function defaultDbDatabaseForDialect(value) {
|
|
149
158
|
return String(value ?? '').trim() === 'kingbase'
|
|
@@ -254,6 +263,10 @@ export default class Install extends Command {
|
|
|
254
263
|
description: 'Resume a previous unfinished setup for this env using the saved workspace env config',
|
|
255
264
|
default: false,
|
|
256
265
|
}),
|
|
266
|
+
verbose: Flags.boolean({
|
|
267
|
+
description: 'Show detailed command output',
|
|
268
|
+
default: false,
|
|
269
|
+
}),
|
|
257
270
|
env: Flags.string({
|
|
258
271
|
char: 'e',
|
|
259
272
|
description: 'App/env name to create or update. Defaults app paths to ./<envName>/source/ and ./<envName>/storage/.',
|
|
@@ -804,15 +817,15 @@ export default class Install extends Command {
|
|
|
804
817
|
};
|
|
805
818
|
}
|
|
806
819
|
/**
|
|
807
|
-
* When install runs {@link Download.prompts} after app prompts, align
|
|
808
|
-
* output directory
|
|
820
|
+
* When install runs {@link Download.prompts} after app prompts, align the download
|
|
821
|
+
* output directory with app settings, while Docker registry defaults follow the CLI locale.
|
|
809
822
|
*/
|
|
810
823
|
static buildDownloadPromptOptionsForInstall(appResults, envName) {
|
|
811
824
|
const appRoot = String(appResults.appRootPath ?? '').trim() || defaultInstallAppRootPath(envName);
|
|
812
825
|
const lang = String(appResults.lang ?? DEFAULT_INSTALL_LANG).trim() || DEFAULT_INSTALL_LANG;
|
|
813
826
|
const initialValues = {
|
|
814
827
|
lang,
|
|
815
|
-
dockerRegistry: defaultDockerRegistryForLang(
|
|
828
|
+
dockerRegistry: defaultDockerRegistryForLang(process.env.NB_LOCALE),
|
|
816
829
|
outputDir: appRoot,
|
|
817
830
|
};
|
|
818
831
|
const values = {
|
|
@@ -970,7 +983,7 @@ export default class Install extends Command {
|
|
|
970
983
|
? dbHostInput
|
|
971
984
|
: containerName);
|
|
972
985
|
if (dbDialect === 'postgres') {
|
|
973
|
-
const image = String(params.builtinDbImage ?? '').trim() ||
|
|
986
|
+
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
974
987
|
const dataDir = path.resolve(params.storagePath, 'db', 'postgres');
|
|
975
988
|
const args = [
|
|
976
989
|
'run',
|
|
@@ -1014,7 +1027,7 @@ export default class Install extends Command {
|
|
|
1014
1027
|
};
|
|
1015
1028
|
}
|
|
1016
1029
|
if (dbDialect === 'mysql') {
|
|
1017
|
-
const image = String(params.builtinDbImage ?? '').trim() ||
|
|
1030
|
+
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1018
1031
|
const dataDir = path.resolve(params.storagePath, 'db', 'mysql');
|
|
1019
1032
|
const dbUser = String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1020
1033
|
const dbDatabase = String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase;
|
|
@@ -1060,7 +1073,7 @@ export default class Install extends Command {
|
|
|
1060
1073
|
};
|
|
1061
1074
|
}
|
|
1062
1075
|
if (dbDialect === 'mariadb') {
|
|
1063
|
-
const image = String(params.builtinDbImage ?? '').trim() ||
|
|
1076
|
+
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1064
1077
|
const dataDir = path.resolve(params.storagePath, 'db', 'mariadb');
|
|
1065
1078
|
const dbUser = String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1066
1079
|
const dbDatabase = String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase;
|
|
@@ -1106,7 +1119,7 @@ export default class Install extends Command {
|
|
|
1106
1119
|
};
|
|
1107
1120
|
}
|
|
1108
1121
|
if (dbDialect === 'kingbase') {
|
|
1109
|
-
const image = String(params.builtinDbImage ?? '').trim() ||
|
|
1122
|
+
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1110
1123
|
const dataDir = path.resolve(params.storagePath, 'db', 'kingbase');
|
|
1111
1124
|
const dbUser = String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1112
1125
|
const dbDatabase = String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase;
|
|
@@ -1271,7 +1284,7 @@ export default class Install extends Command {
|
|
|
1271
1284
|
}
|
|
1272
1285
|
static buildDockerAppPlan(params) {
|
|
1273
1286
|
const dockerRegistry = String(downloadResultsValue(params.downloadResults, 'dockerRegistry') ?? '').trim()
|
|
1274
|
-
|| defaultDockerRegistryForLang(
|
|
1287
|
+
|| defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
1275
1288
|
const version = String(downloadResultsValue(params.downloadResults, 'version') ?? '').trim() || 'latest';
|
|
1276
1289
|
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
1277
1290
|
const storagePath = path.resolve(String(params.appResults.storagePath ?? '').trim()
|
|
@@ -1365,8 +1378,11 @@ export default class Install extends Command {
|
|
|
1365
1378
|
argv.push(flag, text);
|
|
1366
1379
|
}
|
|
1367
1380
|
}
|
|
1368
|
-
static buildDownloadArgvFromResults(results) {
|
|
1381
|
+
static buildDownloadArgvFromResults(results, options) {
|
|
1369
1382
|
const argv = ['-y', '--no-intro'];
|
|
1383
|
+
if (options?.verbose) {
|
|
1384
|
+
argv.push('--verbose');
|
|
1385
|
+
}
|
|
1370
1386
|
Install.pushDownloadArgIfValue(argv, '--source', results.source);
|
|
1371
1387
|
Install.pushDownloadArgIfValue(argv, '--version', results.version);
|
|
1372
1388
|
Install.pushDownloadArgIfValue(argv, '--output-dir', results.outputDir);
|
|
@@ -1402,7 +1418,9 @@ export default class Install extends Command {
|
|
|
1402
1418
|
return path.resolve(process.cwd(), outputDir);
|
|
1403
1419
|
}
|
|
1404
1420
|
async downloadLocalApp(params) {
|
|
1405
|
-
const argv = Install.buildDownloadArgvFromResults(params.downloadResults
|
|
1421
|
+
const argv = Install.buildDownloadArgvFromResults(params.downloadResults, {
|
|
1422
|
+
verbose: params.verbose,
|
|
1423
|
+
});
|
|
1406
1424
|
p.log.step('Downloading local NocoBase app files');
|
|
1407
1425
|
const result = await this.config.runCommand('download', argv);
|
|
1408
1426
|
const projectRoot = Install.resolveLocalProjectRoot({
|
|
@@ -1799,6 +1817,7 @@ export default class Install extends Command {
|
|
|
1799
1817
|
envName,
|
|
1800
1818
|
appResults,
|
|
1801
1819
|
downloadResults,
|
|
1820
|
+
verbose: parsed.verbose,
|
|
1802
1821
|
});
|
|
1803
1822
|
localAppPlan = await this.startLocalApp({
|
|
1804
1823
|
envName,
|
|
@@ -22,8 +22,14 @@ function clackSelectOptions(options, locale) {
|
|
|
22
22
|
value: o.value,
|
|
23
23
|
label: resolvePromptText(o.label, locale, o.value),
|
|
24
24
|
...(o.hint !== undefined ? { hint: resolvePromptText(o.hint, locale) } : {}),
|
|
25
|
+
...(o.disabled !== undefined ? { disabled: o.disabled } : {}),
|
|
25
26
|
});
|
|
26
27
|
}
|
|
28
|
+
function enabledSelectOptionValues(options) {
|
|
29
|
+
return options
|
|
30
|
+
.filter((o) => typeof o === 'string' || o.disabled !== true)
|
|
31
|
+
.map((o) => (typeof o === 'string' ? o : o.value));
|
|
32
|
+
}
|
|
27
33
|
function defaultOnCancel(locale) {
|
|
28
34
|
p.cancel(createCliTranslate(locale)('promptCatalog.common.cancelled'));
|
|
29
35
|
exit(0);
|
|
@@ -63,21 +69,22 @@ function mergedBoolean(key, def, iv, useYesInitial) {
|
|
|
63
69
|
}
|
|
64
70
|
function mergedSelect(key, def, iv, useYesInitial) {
|
|
65
71
|
const valueList = selectOptionValues(def.options);
|
|
72
|
+
const enabledValueList = enabledSelectOptionValues(def.options);
|
|
66
73
|
if (hasIvKey(iv, key)) {
|
|
67
74
|
const s = String(iv[key]);
|
|
68
|
-
if (
|
|
75
|
+
if (enabledValueList.includes(s)) {
|
|
69
76
|
return s;
|
|
70
77
|
}
|
|
71
78
|
return undefined;
|
|
72
79
|
}
|
|
73
|
-
if (useYesInitial && def.yesInitialValue !== undefined &&
|
|
80
|
+
if (useYesInitial && def.yesInitialValue !== undefined && enabledValueList.includes(def.yesInitialValue)) {
|
|
74
81
|
return def.yesInitialValue;
|
|
75
82
|
}
|
|
76
83
|
const d = def.initialValue;
|
|
77
|
-
if (d !== undefined &&
|
|
84
|
+
if (d !== undefined && enabledValueList.includes(d)) {
|
|
78
85
|
return d;
|
|
79
86
|
}
|
|
80
|
-
return
|
|
87
|
+
return enabledValueList[0];
|
|
81
88
|
}
|
|
82
89
|
function mergedInteger(key, def, iv, useYesInitial) {
|
|
83
90
|
if (hasIvKey(iv, key)) {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { spawn } from 'node:child_process';
|
|
10
10
|
import { createServer } from 'node:http';
|
|
11
11
|
import { createCliTranslate, resolveCliLocale, resolveLocalizedText, } from "./cli-locale.js";
|
|
12
|
-
import { isPromptBlockSkipped, runPromptFieldValidate,
|
|
12
|
+
import { isPromptBlockSkipped, runPromptFieldValidate, } from "./prompt-catalog.js";
|
|
13
13
|
const DEFAULT_SUBMIT = '/__pwc_ui_submit';
|
|
14
14
|
const DEFAULT_REFLOW = '/__pwc_ui_reflow';
|
|
15
15
|
const DEFAULT_VALIDATE_STEP = '/__pwc_ui_validate_step';
|
|
@@ -76,12 +76,17 @@ function defaultValueForInput(key, def, out) {
|
|
|
76
76
|
case 'boolean':
|
|
77
77
|
return def.initialValue !== undefined ? Boolean(def.initialValue) : true;
|
|
78
78
|
case 'select': {
|
|
79
|
-
const first =
|
|
79
|
+
const first = def.options
|
|
80
|
+
.find((o) => typeof o === 'string' || o.disabled !== true);
|
|
81
|
+
const firstValue = typeof first === 'string' ? first : first?.value;
|
|
80
82
|
const i = def.initialValue;
|
|
81
|
-
|
|
83
|
+
const enabledValues = def.options
|
|
84
|
+
.filter((o) => typeof o === 'string' || o.disabled !== true)
|
|
85
|
+
.map((o) => (typeof o === 'string' ? o : o.value));
|
|
86
|
+
if (i !== undefined && enabledValues.includes(i)) {
|
|
82
87
|
return i;
|
|
83
88
|
}
|
|
84
|
-
return
|
|
89
|
+
return firstValue ?? '';
|
|
85
90
|
}
|
|
86
91
|
case 'password':
|
|
87
92
|
return def.initialValue ?? '';
|
|
@@ -147,7 +152,9 @@ function normalizeWebRawForBlock(def, raw, key) {
|
|
|
147
152
|
}
|
|
148
153
|
case 'select': {
|
|
149
154
|
const s = String(raw ?? '');
|
|
150
|
-
const list =
|
|
155
|
+
const list = def.options
|
|
156
|
+
.filter((o) => typeof o === 'string' || o.disabled !== true)
|
|
157
|
+
.map((o) => (typeof o === 'string' ? o : o.value));
|
|
151
158
|
if (list.includes(s)) {
|
|
152
159
|
return s;
|
|
153
160
|
}
|
|
@@ -298,11 +305,15 @@ function renderPwcRadioOptions(key, def, defaults, hidden, locale) {
|
|
|
298
305
|
: o.hint
|
|
299
306
|
? `<div class="pwc-radio-option-hint">${escapeHtml(resolveUiText(o.hint, locale))}</div>`
|
|
300
307
|
: '';
|
|
308
|
+
const optionDisabled = typeof o !== 'string' && o.disabled === true;
|
|
301
309
|
const checked = String(defaults[key] ?? '') === val ? ' checked' : '';
|
|
302
310
|
const required = def.required && index === 0 ? ' required' : '';
|
|
303
|
-
const disabled = hidden ? ' disabled' : '';
|
|
304
|
-
|
|
305
|
-
|
|
311
|
+
const disabled = hidden || optionDisabled ? ' disabled' : '';
|
|
312
|
+
const optionClass = optionDisabled ? 'pwc-radio-option pwc-radio-option--disabled' : 'pwc-radio-option';
|
|
313
|
+
const ariaDisabled = optionDisabled ? ' aria-disabled="true"' : '';
|
|
314
|
+
const staticDisabled = optionDisabled ? ' data-pwc-static-disabled="1"' : '';
|
|
315
|
+
return (`<label class="${optionClass}"${ariaDisabled}>` +
|
|
316
|
+
`<input class="pwc-radio-input" name="${escapeHtml(key)}" type="radio" value="${escapeHtml(String(val))}"${checked}${required}${disabled}${staticDisabled} />` +
|
|
306
317
|
`<span class="pwc-radio-option-body">` +
|
|
307
318
|
`<span class="pwc-radio-option-label">${escapeHtml(String(lab))}</span>` +
|
|
308
319
|
hint +
|
|
@@ -361,7 +372,8 @@ function renderPwcFieldRow(key, def, defaults, show, locale) {
|
|
|
361
372
|
const val = typeof o === 'string' ? o : o.value;
|
|
362
373
|
const lab = typeof o === 'string' ? o : resolveUiText(o.label, locale, o.value);
|
|
363
374
|
const sel = String(defaults[key] ?? '') === val ? ' selected' : '';
|
|
364
|
-
|
|
375
|
+
const disabledOpt = typeof o !== 'string' && o.disabled === true ? ' disabled' : '';
|
|
376
|
+
return `<option value="${escapeHtml(String(val))}"${sel}${disabledOpt}>${escapeHtml(String(lab))}</option>`;
|
|
365
377
|
})
|
|
366
378
|
.join('');
|
|
367
379
|
const req = def.required ? ' required' : '';
|
|
@@ -1132,6 +1144,15 @@ function runPromptCatalogWebUIImpl(options) {
|
|
|
1132
1144
|
box-shadow: 0 0 0 2px color-mix(in srgb, var(--pwc-ad-color-primary) 8%, transparent);
|
|
1133
1145
|
background: color-mix(in srgb, var(--pwc-ad-color-primary) 2%, var(--pwc-ad-color-container));
|
|
1134
1146
|
}
|
|
1147
|
+
.pwc-radio-option--disabled {
|
|
1148
|
+
cursor: not-allowed;
|
|
1149
|
+
background: var(--pwc-ad-color-fill-alter);
|
|
1150
|
+
}
|
|
1151
|
+
.pwc-radio-option--disabled:hover {
|
|
1152
|
+
border-color: var(--pwc-ad-color-border);
|
|
1153
|
+
box-shadow: none;
|
|
1154
|
+
background: var(--pwc-ad-color-fill-alter);
|
|
1155
|
+
}
|
|
1135
1156
|
.pwc-radio-input {
|
|
1136
1157
|
margin: 3px 0 0;
|
|
1137
1158
|
width: 16px;
|
|
@@ -1140,6 +1161,9 @@ function runPromptCatalogWebUIImpl(options) {
|
|
|
1140
1161
|
accent-color: var(--pwc-ad-color-primary);
|
|
1141
1162
|
cursor: pointer;
|
|
1142
1163
|
}
|
|
1164
|
+
.pwc-radio-option--disabled .pwc-radio-input {
|
|
1165
|
+
cursor: not-allowed;
|
|
1166
|
+
}
|
|
1143
1167
|
.pwc-radio-option-body { min-width: 0; }
|
|
1144
1168
|
.pwc-radio-option-label {
|
|
1145
1169
|
display: block;
|
|
@@ -1147,12 +1171,18 @@ function runPromptCatalogWebUIImpl(options) {
|
|
|
1147
1171
|
line-height: 1.5715;
|
|
1148
1172
|
color: var(--pwc-ad-color-text);
|
|
1149
1173
|
}
|
|
1174
|
+
.pwc-radio-option--disabled .pwc-radio-option-label {
|
|
1175
|
+
color: color-mix(in srgb, var(--pwc-ad-color-text) 55%, transparent);
|
|
1176
|
+
}
|
|
1150
1177
|
.pwc-radio-option-hint {
|
|
1151
1178
|
margin-top: 2px;
|
|
1152
1179
|
font-size: 12px;
|
|
1153
1180
|
line-height: 1.5;
|
|
1154
1181
|
color: var(--pwc-ad-color-text-description);
|
|
1155
1182
|
}
|
|
1183
|
+
.pwc-radio-option--disabled .pwc-radio-option-hint {
|
|
1184
|
+
color: color-mix(in srgb, var(--pwc-ad-color-text-description) 70%, transparent);
|
|
1185
|
+
}
|
|
1156
1186
|
.pwc-radio-input:focus-visible {
|
|
1157
1187
|
outline: none;
|
|
1158
1188
|
box-shadow: 0 0 0 2px color-mix(in srgb, var(--pwc-ad-color-primary) 20%, transparent);
|
|
@@ -1163,6 +1193,11 @@ function runPromptCatalogWebUIImpl(options) {
|
|
|
1163
1193
|
box-shadow: 0 0 0 2px color-mix(in srgb, var(--pwc-ad-color-primary) 12%, transparent);
|
|
1164
1194
|
background: color-mix(in srgb, var(--pwc-ad-color-primary) 5%, var(--pwc-ad-color-container));
|
|
1165
1195
|
}
|
|
1196
|
+
.pwc-radio-option--disabled:has(.pwc-radio-input:checked) {
|
|
1197
|
+
border-color: var(--pwc-ad-color-border);
|
|
1198
|
+
box-shadow: none;
|
|
1199
|
+
background: var(--pwc-ad-color-fill-alter);
|
|
1200
|
+
}
|
|
1166
1201
|
.pwc-form-item-has-error .pwc-radio-option {
|
|
1167
1202
|
border-color: var(--pwc-form-color-error);
|
|
1168
1203
|
}
|
|
@@ -1570,7 +1605,7 @@ function runPromptCatalogWebUIImpl(options) {
|
|
|
1570
1605
|
w.style.display = hidden ? 'none' : 'block';
|
|
1571
1606
|
var ctrls = w.querySelectorAll('input, select, textarea');
|
|
1572
1607
|
for (var i = 0; i < ctrls.length; i++) {
|
|
1573
|
-
ctrls[i].disabled = hidden;
|
|
1608
|
+
ctrls[i].disabled = hidden || ctrls[i].getAttribute('data-pwc-static-disabled') === '1';
|
|
1574
1609
|
}
|
|
1575
1610
|
if (!hidden && k && !pwcIsFieldDirty(k) && Object.prototype.hasOwnProperty.call(vals, k)) {
|
|
1576
1611
|
setControlValue(form, k, vals[k]);
|
package/dist/lib/run-npm.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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 = '';
|
package/dist/locale/en-US.json
CHANGED
|
@@ -95,16 +95,67 @@
|
|
|
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?",
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
138
|
+
"dockerLabel": "Docker install (Recommended)",
|
|
139
|
+
"dockerHint": "Best for no-code and low-maintenance setups. You can upgrade later by pulling a newer image and restarting the app.",
|
|
140
|
+
"npmLabel": "create-nocobase-app install",
|
|
141
|
+
"npmHint": "Best when you want an app project with business code kept separate from the NocoBase framework, while still supporting low-code development.",
|
|
142
|
+
"gitLabel": "Git source install",
|
|
143
|
+
"gitHint": "Best when you want to try the latest unreleased changes, contribute code, or debug and modify NocoBase source directly. This option is more developer-oriented."
|
|
104
144
|
},
|
|
105
145
|
"version": {
|
|
106
|
-
"message": "Which version would you like to use?
|
|
107
|
-
"
|
|
146
|
+
"message": "Which version would you like to use?",
|
|
147
|
+
"latestLabel": "latest",
|
|
148
|
+
"latestHint": "Stable release. Best for production use and the most predictable experience. Currently unavailable.",
|
|
149
|
+
"betaLabel": "beta",
|
|
150
|
+
"betaHint": "Preview release. Good for trying upcoming features before general release.",
|
|
151
|
+
"alphaLabel": "alpha",
|
|
152
|
+
"alphaHint": "Development release. Includes the newest changes, but may be incomplete or unstable.",
|
|
153
|
+
"otherLabel": "Other",
|
|
154
|
+
"otherHint": "Enter another package version, Docker tag, or Git ref manually, such as a branch name."
|
|
155
|
+
},
|
|
156
|
+
"otherVersion": {
|
|
157
|
+
"message": "Enter the version, Docker tag, or Git ref you want to use.",
|
|
158
|
+
"placeholder": "For example: fix/cli-v2"
|
|
108
159
|
},
|
|
109
160
|
"dockerRegistry": {
|
|
110
161
|
"message": "Which Docker registry would you like to use? The image tag is set separately in Version.",
|
package/dist/locale/zh-CN.json
CHANGED
|
@@ -95,20 +95,71 @@
|
|
|
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?",
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
138
|
+
"dockerLabel": "Docker 安装(推荐)",
|
|
139
|
+
"dockerHint": "适合无代码或低维护成本场景。后续升级时,拉取新镜像并重启应用即可。",
|
|
140
|
+
"npmLabel": "create-nocobase-app 安装",
|
|
141
|
+
"npmHint": "适合希望将业务代码与 NocoBase 框架保持独立的场景,同时仍然支持低代码开发。",
|
|
142
|
+
"gitLabel": "Git 源码安装",
|
|
143
|
+
"gitHint": "适合体验最新未发布版本、参与贡献,或直接修改和调试 NocoBase 源码。这个方式更偏向开发者使用。"
|
|
104
144
|
},
|
|
105
145
|
"version": {
|
|
106
|
-
"message": "
|
|
107
|
-
"
|
|
146
|
+
"message": "你想使用哪个版本?",
|
|
147
|
+
"latestLabel": "latest",
|
|
148
|
+
"latestHint": "稳定版。适合生产环境和希望获得稳定体验的场景。当前暂不可用。",
|
|
149
|
+
"betaLabel": "beta",
|
|
150
|
+
"betaHint": "测试版。包含即将发布的新功能,适合提前体验和反馈。",
|
|
151
|
+
"alphaLabel": "alpha",
|
|
152
|
+
"alphaHint": "开发版。功能更新最快,但可能不完整或不稳定。",
|
|
153
|
+
"otherLabel": "其他",
|
|
154
|
+
"otherHint": "手动填写其他版本号、Docker tag 或 Git ref,例如分支名。"
|
|
155
|
+
},
|
|
156
|
+
"otherVersion": {
|
|
157
|
+
"message": "请输入你想使用的版本号、Docker tag 或 Git ref。",
|
|
158
|
+
"placeholder": "例如:fix/cli-v2"
|
|
108
159
|
},
|
|
109
160
|
"dockerRegistry": {
|
|
110
161
|
"message": "你想使用哪个 Docker registry?镜像 tag 请单独在 Version 中填写。",
|
|
111
|
-
"placeholder": "nocobase/nocobase"
|
|
162
|
+
"placeholder": "registry.cn-shanghai.aliyuncs.com/nocobase/nocobase"
|
|
112
163
|
},
|
|
113
164
|
"dockerPlatform": {
|
|
114
165
|
"message": "要使用哪个 Docker 镜像平台?",
|
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.23",
|
|
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": "
|
|
65
|
+
"gitHead": "baa19dafe25e85b680b2fea7451f202831930c1c"
|
|
65
66
|
}
|