@nocobase/cli 2.1.0-beta.17 → 2.1.0-beta.19
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 +31 -0
- package/bin/run.js +13 -11
- package/dist/commands/download.js +106 -20
- package/dist/commands/init.js +16 -7
- package/dist/commands/install.js +56 -18
- package/dist/commands/self/check.js +71 -0
- package/dist/commands/self/index.js +20 -0
- package/dist/commands/self/update.js +76 -0
- package/dist/commands/skills/check.js +63 -0
- package/dist/commands/skills/index.js +20 -0
- package/dist/commands/skills/install.js +58 -0
- package/dist/commands/skills/update.js +58 -0
- package/dist/commands/test.js +466 -0
- package/dist/lib/prompt-catalog.js +11 -4
- package/dist/lib/prompt-web-ui.js +45 -10
- package/dist/lib/run-npm.js +82 -8
- package/dist/lib/self-manager.js +246 -0
- package/dist/lib/skills-manager.js +202 -0
- package/dist/locale/en-US.json +19 -5
- package/dist/locale/zh-CN.json +20 -6
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -147,6 +147,8 @@ In non-interactive mode, pass these setup-only flags again because they are not
|
|
|
147
147
|
| `nb env` | Manage saved CLI env connections. |
|
|
148
148
|
| `nb api` | Call NocoBase API resources from the CLI. |
|
|
149
149
|
| `nb pm` | Manage plugins for the selected NocoBase env. |
|
|
150
|
+
| `nb self` | Check or update the installed NocoBase CLI. |
|
|
151
|
+
| `nb skills` | Check, install, or update NocoBase AI coding skills for the current workspace. |
|
|
150
152
|
|
|
151
153
|
Recommended style: use `--env` explicitly for app/runtime commands. `-e` is the short form:
|
|
152
154
|
|
|
@@ -166,6 +168,35 @@ nb upgrade -e app1
|
|
|
166
168
|
nb db start -e app1
|
|
167
169
|
```
|
|
168
170
|
|
|
171
|
+
## CLI And Skills Updates
|
|
172
|
+
|
|
173
|
+
Check whether the installed CLI itself is up to date:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
nb self check
|
|
177
|
+
nb self check --json
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Update the CLI when it is installed globally with npm:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
nb self update
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Check whether the current workspace already has the NocoBase AI coding skills:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
nb skills check
|
|
190
|
+
nb skills check --json
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Install the skills for the first time, or update an existing `nocobase/skills` install:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
nb skills install
|
|
197
|
+
nb skills update
|
|
198
|
+
```
|
|
199
|
+
|
|
169
200
|
## Runtime Types
|
|
170
201
|
|
|
171
202
|
### Docker
|
package/bin/run.js
CHANGED
|
@@ -38,18 +38,20 @@ function reexecWithTsx() {
|
|
|
38
38
|
process.exit(1);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
41
|
+
const reexecArgs = ['--import', pathToFileURL(tsxEntry).href];
|
|
42
|
+
const supportedFlags = Array.from(process.allowedNodeEnvironmentFlags);
|
|
43
|
+
if (supportedFlags.some((flag) => flag === '--disable-warning' || flag.startsWith('--disable-warning='))) {
|
|
44
|
+
reexecArgs.push('--disable-warning=ExperimentalWarning');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const result = spawnSync(process.execPath, [...reexecArgs, ...process.argv.slice(1)], {
|
|
48
|
+
stdio: 'inherit',
|
|
49
|
+
env: {
|
|
50
|
+
...process.env,
|
|
51
|
+
_NOCO_CLI_TSX_CHILD: '1',
|
|
52
|
+
NODE_ENV: 'development',
|
|
51
53
|
},
|
|
52
|
-
);
|
|
54
|
+
});
|
|
53
55
|
process.exit(result.status === null ? 1 : result.status);
|
|
54
56
|
}
|
|
55
57
|
|
|
@@ -12,12 +12,13 @@ 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, translateCli, } 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);
|
|
22
23
|
const downloadTranslatedText = (key, values, fallback) => translateCli(`commands.download.${key}`, values, { fallback });
|
|
23
24
|
function defaultOutputDirForVersion(versionTag) {
|
|
@@ -34,10 +35,13 @@ async function pathExists(target) {
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
export function defaultDockerRegistryForLang(lang) {
|
|
37
|
-
return String(lang ?? '').trim() === 'zh-CN'
|
|
38
|
+
return resolveCliLocale(String(lang ?? '').trim() || undefined) === 'zh-CN'
|
|
38
39
|
? DEFAULT_DOCKER_REGISTRY_ZH_CN
|
|
39
40
|
: DEFAULT_DOCKER_REGISTRY;
|
|
40
41
|
}
|
|
42
|
+
function defaultDockerRegistryForPromptValues(_values) {
|
|
43
|
+
return defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
44
|
+
}
|
|
41
45
|
function argvHasToken(argv, tokens) {
|
|
42
46
|
return tokens.some((t) => argv.includes(t));
|
|
43
47
|
}
|
|
@@ -119,6 +123,27 @@ function formatDownloadFailure(message, verbose) {
|
|
|
119
123
|
}
|
|
120
124
|
const EXTERNAL_COMMAND_LOADING_DELAY_MS = 8_000;
|
|
121
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
|
+
}
|
|
122
147
|
export default class Download extends Command {
|
|
123
148
|
_flags;
|
|
124
149
|
preparationTaskActive = false;
|
|
@@ -212,30 +237,72 @@ export default class Download extends Command {
|
|
|
212
237
|
static prompts = {
|
|
213
238
|
source: {
|
|
214
239
|
type: 'select',
|
|
240
|
+
variant: 'radio',
|
|
215
241
|
message: downloadText('prompts.source.message'),
|
|
216
242
|
options: [
|
|
217
|
-
{
|
|
218
|
-
|
|
219
|
-
|
|
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
|
+
},
|
|
220
258
|
],
|
|
221
259
|
yesInitialValue: 'docker',
|
|
222
260
|
initialValue: 'docker',
|
|
223
261
|
required: true,
|
|
224
262
|
},
|
|
225
263
|
version: {
|
|
226
|
-
type: '
|
|
264
|
+
type: 'select',
|
|
265
|
+
variant: 'radio',
|
|
227
266
|
message: downloadText('prompts.version.message'),
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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,
|
|
231
292
|
required: true,
|
|
232
293
|
},
|
|
294
|
+
otherVersion: {
|
|
295
|
+
type: 'text',
|
|
296
|
+
message: downloadText('prompts.otherVersion.message'),
|
|
297
|
+
placeholder: downloadText('prompts.otherVersion.placeholder'),
|
|
298
|
+
required: true,
|
|
299
|
+
hidden: (values) => normalizeVersionPreset(values.version) !== 'other',
|
|
300
|
+
},
|
|
233
301
|
dockerRegistry: {
|
|
234
302
|
type: 'text',
|
|
235
303
|
message: downloadText('prompts.dockerRegistry.message'),
|
|
236
304
|
placeholder: downloadText('prompts.dockerRegistry.placeholder'),
|
|
237
|
-
initialValue:
|
|
238
|
-
yesInitialValue: DEFAULT_DOCKER_REGISTRY,
|
|
305
|
+
initialValue: defaultDockerRegistryForPromptValues,
|
|
239
306
|
required: true,
|
|
240
307
|
hidden: (values) => values.source !== 'docker',
|
|
241
308
|
},
|
|
@@ -275,7 +342,10 @@ export default class Download extends Command {
|
|
|
275
342
|
type: 'text',
|
|
276
343
|
message: downloadText('prompts.outputDir.message'),
|
|
277
344
|
placeholder: downloadText('prompts.outputDir.placeholder'),
|
|
278
|
-
initialValue: (values) =>
|
|
345
|
+
initialValue: (values) => {
|
|
346
|
+
const version = resolveVersionFromResults(values, DEFAULT_DOWNLOAD_VERSION) || DEFAULT_DOWNLOAD_VERSION;
|
|
347
|
+
return defaultOutputDirForVersion(version);
|
|
348
|
+
},
|
|
279
349
|
required: true,
|
|
280
350
|
hidden: (values) => {
|
|
281
351
|
const s = values.source;
|
|
@@ -351,7 +421,7 @@ export default class Download extends Command {
|
|
|
351
421
|
return outputAbs;
|
|
352
422
|
}
|
|
353
423
|
dockerTarPath(flags, outputAbs) {
|
|
354
|
-
const image = flags['docker-registry'] ??
|
|
424
|
+
const image = String(flags['docker-registry'] ?? '').trim() || defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
355
425
|
const tag = flags.version ?? 'latest';
|
|
356
426
|
const safeBase = `${image.replace(/[/:]/g, '-')}-${tag.replace(/[/\\]/g, '-')}`;
|
|
357
427
|
return path.join(outputAbs, `${safeBase}.tar`);
|
|
@@ -362,12 +432,15 @@ export default class Download extends Command {
|
|
|
362
432
|
*/
|
|
363
433
|
buildInitialValuesFromParsed(flags, preset) {
|
|
364
434
|
const initialValues = {};
|
|
435
|
+
const localeDefaultDockerRegistry = defaultDockerRegistryForLang(flags.locale ?? process.env.NB_LOCALE);
|
|
365
436
|
const source = flags.source?.trim();
|
|
366
437
|
if (source) {
|
|
367
438
|
initialValues.source = source;
|
|
368
439
|
}
|
|
369
440
|
if (flags.version !== undefined) {
|
|
370
|
-
|
|
441
|
+
const version = flags.version.trim() || 'latest';
|
|
442
|
+
initialValues.version = versionPresetForValue(version);
|
|
443
|
+
initialValues.otherVersion = otherVersionValue(version);
|
|
371
444
|
}
|
|
372
445
|
initialValues.replace = flags.replace;
|
|
373
446
|
initialValues.devDependencies = flags['dev-dependencies'];
|
|
@@ -382,6 +455,9 @@ export default class Download extends Command {
|
|
|
382
455
|
if (flags['docker-registry'] !== undefined) {
|
|
383
456
|
initialValues.dockerRegistry = String(flags['docker-registry'] ?? '').trim();
|
|
384
457
|
}
|
|
458
|
+
else {
|
|
459
|
+
initialValues.dockerRegistry = localeDefaultDockerRegistry;
|
|
460
|
+
}
|
|
385
461
|
initialValues.dockerPlatform = normalizeDockerPlatform(flags['docker-platform']);
|
|
386
462
|
initialValues.dockerSave = flags['docker-save'];
|
|
387
463
|
if (flags['npm-registry'] !== undefined) {
|
|
@@ -406,7 +482,11 @@ export default class Download extends Command {
|
|
|
406
482
|
preset.source = String(flags.source).trim();
|
|
407
483
|
}
|
|
408
484
|
if (flags.version !== undefined) {
|
|
409
|
-
|
|
485
|
+
const version = String(flags.version).trim() || 'latest';
|
|
486
|
+
preset.version = versionPresetForValue(version);
|
|
487
|
+
if (normalizeVersionPreset(version) === 'other') {
|
|
488
|
+
preset.otherVersion = version;
|
|
489
|
+
}
|
|
410
490
|
}
|
|
411
491
|
if (flags['docker-registry'] !== undefined) {
|
|
412
492
|
const v = String(flags['docker-registry'] ?? '').trim();
|
|
@@ -460,7 +540,7 @@ export default class Download extends Command {
|
|
|
460
540
|
}
|
|
461
541
|
mapCatalogResultsToResolved(results, flags) {
|
|
462
542
|
const source = String(results.source);
|
|
463
|
-
const version =
|
|
543
|
+
const version = resolveVersionFromResults(results, flags.version) || 'latest';
|
|
464
544
|
const devDependencies = source === 'npm' ? Boolean(results.devDependencies) : undefined;
|
|
465
545
|
const effectiveBuild = this.resolveEffectiveBuild(source, results, flags);
|
|
466
546
|
const buildDtsWant = results.buildDts !== undefined ? Boolean(results.buildDts) : flags['build-dts'];
|
|
@@ -471,9 +551,11 @@ export default class Download extends Command {
|
|
|
471
551
|
const gitUrl = results.gitUrl !== undefined
|
|
472
552
|
? String(results.gitUrl).trim() || undefined
|
|
473
553
|
: flags['git-url']?.trim() || undefined;
|
|
474
|
-
const dockerRegistry =
|
|
475
|
-
?
|
|
476
|
-
|
|
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;
|
|
477
559
|
const dockerPlatform = source === 'docker'
|
|
478
560
|
? normalizeDockerPlatform(results.dockerPlatform !== undefined
|
|
479
561
|
? results.dockerPlatform
|
|
@@ -526,9 +608,13 @@ export default class Download extends Command {
|
|
|
526
608
|
},
|
|
527
609
|
});
|
|
528
610
|
const source = String(results.source ?? '').trim();
|
|
611
|
+
const version = resolveVersionFromResults(results, flags.version);
|
|
529
612
|
if (!source || !['docker', 'npm', 'git'].includes(source)) {
|
|
530
613
|
this.error('Download source is required. Choose npm, git, or docker.');
|
|
531
614
|
}
|
|
615
|
+
if (!version) {
|
|
616
|
+
this.error('Version is required. Choose alpha, beta, latest, or enter another version.');
|
|
617
|
+
}
|
|
532
618
|
if (flags['docker-save'] && source !== 'docker') {
|
|
533
619
|
this.error('--docker-save is only available when --source docker is selected.');
|
|
534
620
|
}
|
|
@@ -622,7 +708,7 @@ export default class Download extends Command {
|
|
|
622
708
|
return argv;
|
|
623
709
|
}
|
|
624
710
|
async downloadFromDocker(flags) {
|
|
625
|
-
const image = flags['docker-registry'] ??
|
|
711
|
+
const image = String(flags['docker-registry'] ?? '').trim() || defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
626
712
|
const tag = flags.version ?? 'latest';
|
|
627
713
|
const imageRef = `${image}:${tag}`;
|
|
628
714
|
const platform = dockerPlatformArg(flags['docker-platform']);
|
package/dist/commands/init.js
CHANGED
|
@@ -17,7 +17,7 @@ import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
|
17
17
|
import { applyCliLocale, localeText, translateCli } from "../lib/cli-locale.js";
|
|
18
18
|
import { runPromptCatalogWebUI, } from "../lib/prompt-web-ui.js";
|
|
19
19
|
import { validateApiBaseUrl, validateEnvKey } from "../lib/prompt-validators.js";
|
|
20
|
-
import {
|
|
20
|
+
import { installNocoBaseSkills } from '../lib/skills-manager.js';
|
|
21
21
|
import Download from "./download.js";
|
|
22
22
|
import EnvAdd from "./env/add.js";
|
|
23
23
|
import Install, { defaultDbPortForDialect } from "./install.js";
|
|
@@ -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),
|
|
@@ -276,8 +284,8 @@ Prompt modes:
|
|
|
276
284
|
p.intro(initTitle());
|
|
277
285
|
if (Boolean(normalizedFlags['install-skills'])) {
|
|
278
286
|
try {
|
|
279
|
-
p.log.step('Installing NocoBase agent skills (
|
|
280
|
-
await
|
|
287
|
+
p.log.step('Installing NocoBase agent skills (nb skills install)');
|
|
288
|
+
await installNocoBaseSkills();
|
|
281
289
|
}
|
|
282
290
|
catch (error) {
|
|
283
291
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -367,8 +375,8 @@ Prompt modes:
|
|
|
367
375
|
}
|
|
368
376
|
if (installSkills) {
|
|
369
377
|
try {
|
|
370
|
-
p.log.step('Installing NocoBase agent skills (
|
|
371
|
-
await
|
|
378
|
+
p.log.step('Installing NocoBase agent skills (nb skills install)');
|
|
379
|
+
await installNocoBaseSkills();
|
|
372
380
|
}
|
|
373
381
|
catch (error) {
|
|
374
382
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -472,6 +480,7 @@ Prompt modes:
|
|
|
472
480
|
catalog: {
|
|
473
481
|
source: c.source,
|
|
474
482
|
version: c.version,
|
|
483
|
+
otherVersion: c.otherVersion,
|
|
475
484
|
dockerRegistry: c.dockerRegistry,
|
|
476
485
|
dockerPlatform: c.dockerPlatform,
|
|
477
486
|
dockerSave: c.dockerSave,
|
|
@@ -618,7 +627,7 @@ Prompt modes:
|
|
|
618
627
|
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
619
628
|
const appPort = String(results.appPort ?? '').trim();
|
|
620
629
|
const source = String(results.source ?? '').trim();
|
|
621
|
-
const version =
|
|
630
|
+
const version = resolveInitDownloadVersion(results);
|
|
622
631
|
const dockerRegistry = String(results.dockerRegistry ?? '').trim();
|
|
623
632
|
const dockerPlatform = String(results.dockerPlatform ?? '').trim();
|
|
624
633
|
const gitUrl = String(results.gitUrl ?? '').trim();
|
|
@@ -706,7 +715,7 @@ Prompt modes:
|
|
|
706
715
|
if (source) {
|
|
707
716
|
argv.push('--source', source);
|
|
708
717
|
}
|
|
709
|
-
const version =
|
|
718
|
+
const version = resolveInitDownloadVersion(results);
|
|
710
719
|
if (version) {
|
|
711
720
|
argv.push('--version', version);
|
|
712
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'
|
|
@@ -808,15 +817,15 @@ export default class Install extends Command {
|
|
|
808
817
|
};
|
|
809
818
|
}
|
|
810
819
|
/**
|
|
811
|
-
* When install runs {@link Download.prompts} after app prompts, align
|
|
812
|
-
* 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.
|
|
813
822
|
*/
|
|
814
823
|
static buildDownloadPromptOptionsForInstall(appResults, envName) {
|
|
815
824
|
const appRoot = String(appResults.appRootPath ?? '').trim() || defaultInstallAppRootPath(envName);
|
|
816
825
|
const lang = String(appResults.lang ?? DEFAULT_INSTALL_LANG).trim() || DEFAULT_INSTALL_LANG;
|
|
817
826
|
const initialValues = {
|
|
818
827
|
lang,
|
|
819
|
-
dockerRegistry: defaultDockerRegistryForLang(
|
|
828
|
+
dockerRegistry: defaultDockerRegistryForLang(process.env.NB_LOCALE),
|
|
820
829
|
outputDir: appRoot,
|
|
821
830
|
};
|
|
822
831
|
const values = {
|
|
@@ -974,7 +983,7 @@ export default class Install extends Command {
|
|
|
974
983
|
? dbHostInput
|
|
975
984
|
: containerName);
|
|
976
985
|
if (dbDialect === 'postgres') {
|
|
977
|
-
const image = String(params.builtinDbImage ?? '').trim() ||
|
|
986
|
+
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
978
987
|
const dataDir = path.resolve(params.storagePath, 'db', 'postgres');
|
|
979
988
|
const args = [
|
|
980
989
|
'run',
|
|
@@ -1018,7 +1027,7 @@ export default class Install extends Command {
|
|
|
1018
1027
|
};
|
|
1019
1028
|
}
|
|
1020
1029
|
if (dbDialect === 'mysql') {
|
|
1021
|
-
const image = String(params.builtinDbImage ?? '').trim() ||
|
|
1030
|
+
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1022
1031
|
const dataDir = path.resolve(params.storagePath, 'db', 'mysql');
|
|
1023
1032
|
const dbUser = String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1024
1033
|
const dbDatabase = String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase;
|
|
@@ -1064,7 +1073,7 @@ export default class Install extends Command {
|
|
|
1064
1073
|
};
|
|
1065
1074
|
}
|
|
1066
1075
|
if (dbDialect === 'mariadb') {
|
|
1067
|
-
const image = String(params.builtinDbImage ?? '').trim() ||
|
|
1076
|
+
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1068
1077
|
const dataDir = path.resolve(params.storagePath, 'db', 'mariadb');
|
|
1069
1078
|
const dbUser = String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1070
1079
|
const dbDatabase = String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase;
|
|
@@ -1110,7 +1119,7 @@ export default class Install extends Command {
|
|
|
1110
1119
|
};
|
|
1111
1120
|
}
|
|
1112
1121
|
if (dbDialect === 'kingbase') {
|
|
1113
|
-
const image = String(params.builtinDbImage ?? '').trim() ||
|
|
1122
|
+
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1114
1123
|
const dataDir = path.resolve(params.storagePath, 'db', 'kingbase');
|
|
1115
1124
|
const dbUser = String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1116
1125
|
const dbDatabase = String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase;
|
|
@@ -1198,6 +1207,7 @@ export default class Install extends Command {
|
|
|
1198
1207
|
async removeDockerContainer(name) {
|
|
1199
1208
|
await run('docker', ['rm', '-f', name], {
|
|
1200
1209
|
errorName: 'docker rm',
|
|
1210
|
+
stdio: 'ignore',
|
|
1201
1211
|
});
|
|
1202
1212
|
}
|
|
1203
1213
|
async removeDockerContainerIfForced(params) {
|
|
@@ -1229,7 +1239,7 @@ export default class Install extends Command {
|
|
|
1229
1239
|
}
|
|
1230
1240
|
return env;
|
|
1231
1241
|
}
|
|
1232
|
-
async ensureBuiltinDbContainer(plan) {
|
|
1242
|
+
async ensureBuiltinDbContainer(plan, options) {
|
|
1233
1243
|
const exists = await this.dockerContainerExists(plan.containerName);
|
|
1234
1244
|
if (exists) {
|
|
1235
1245
|
p.log.info(`Built-in ${plan.dbDialect} container already exists: ${plan.containerName}`);
|
|
@@ -1238,6 +1248,7 @@ export default class Install extends Command {
|
|
|
1238
1248
|
await mkdir(plan.dataDir, { recursive: true });
|
|
1239
1249
|
await run('docker', plan.args, {
|
|
1240
1250
|
errorName: 'docker run',
|
|
1251
|
+
stdio: options?.stdio ?? 'ignore',
|
|
1241
1252
|
});
|
|
1242
1253
|
}
|
|
1243
1254
|
async startBuiltinDb(params) {
|
|
@@ -1269,13 +1280,15 @@ export default class Install extends Command {
|
|
|
1269
1280
|
throw new Error(`Built-in ${plan.dbDialect} needs host port ${plan.dbPort}, but ${portError}`);
|
|
1270
1281
|
}
|
|
1271
1282
|
}
|
|
1272
|
-
await this.ensureBuiltinDbContainer(plan
|
|
1283
|
+
await this.ensureBuiltinDbContainer(plan, {
|
|
1284
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
1285
|
+
});
|
|
1273
1286
|
p.log.info(`Built-in ${plan.dbDialect} database is ready at ${plan.dbHost}:${plan.dbPort}`);
|
|
1274
1287
|
return plan;
|
|
1275
1288
|
}
|
|
1276
1289
|
static buildDockerAppPlan(params) {
|
|
1277
1290
|
const dockerRegistry = String(downloadResultsValue(params.downloadResults, 'dockerRegistry') ?? '').trim()
|
|
1278
|
-
|| defaultDockerRegistryForLang(
|
|
1291
|
+
|| defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
1279
1292
|
const version = String(downloadResultsValue(params.downloadResults, 'version') ?? '').trim() || 'latest';
|
|
1280
1293
|
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
1281
1294
|
const storagePath = path.resolve(String(params.appResults.storagePath ?? '').trim()
|
|
@@ -1323,7 +1336,7 @@ export default class Install extends Command {
|
|
|
1323
1336
|
args,
|
|
1324
1337
|
};
|
|
1325
1338
|
}
|
|
1326
|
-
async ensureDockerAppContainer(plan) {
|
|
1339
|
+
async ensureDockerAppContainer(plan, options) {
|
|
1327
1340
|
const exists = await this.dockerContainerExists(plan.containerName);
|
|
1328
1341
|
if (exists) {
|
|
1329
1342
|
p.log.info(`App container already exists: ${plan.containerName}`);
|
|
@@ -1332,6 +1345,7 @@ export default class Install extends Command {
|
|
|
1332
1345
|
await mkdir(plan.storagePath, { recursive: true });
|
|
1333
1346
|
await run('docker', plan.args, {
|
|
1334
1347
|
errorName: 'docker run',
|
|
1348
|
+
stdio: options?.stdio ?? 'ignore',
|
|
1335
1349
|
});
|
|
1336
1350
|
return 'created';
|
|
1337
1351
|
}
|
|
@@ -1354,7 +1368,9 @@ export default class Install extends Command {
|
|
|
1354
1368
|
displayName: 'app container',
|
|
1355
1369
|
force: params.force,
|
|
1356
1370
|
});
|
|
1357
|
-
const containerState = await this.ensureDockerAppContainer(plan
|
|
1371
|
+
const containerState = await this.ensureDockerAppContainer(plan, {
|
|
1372
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
1373
|
+
});
|
|
1358
1374
|
if (containerState === 'existing') {
|
|
1359
1375
|
const env = await this.inspectDockerContainerEnv(plan.containerName);
|
|
1360
1376
|
plan.appKey = env.APP_KEY || plan.appKey;
|
|
@@ -1408,12 +1424,24 @@ export default class Install extends Command {
|
|
|
1408
1424
|
|| defaultInstallAppRootPath(params.envName);
|
|
1409
1425
|
return path.resolve(process.cwd(), outputDir);
|
|
1410
1426
|
}
|
|
1411
|
-
|
|
1427
|
+
commandStdio(verbose) {
|
|
1428
|
+
return verbose ? 'inherit' : 'ignore';
|
|
1429
|
+
}
|
|
1430
|
+
async downloadManagedSource(params) {
|
|
1412
1431
|
const argv = Install.buildDownloadArgvFromResults(params.downloadResults, {
|
|
1413
1432
|
verbose: params.verbose,
|
|
1414
1433
|
});
|
|
1415
|
-
|
|
1416
|
-
|
|
1434
|
+
const source = String(params.downloadResults.source ?? '').trim();
|
|
1435
|
+
p.log.step(source === 'docker'
|
|
1436
|
+
? 'Downloading Docker image'
|
|
1437
|
+
: 'Downloading local NocoBase app files');
|
|
1438
|
+
return await this.config.runCommand('download', argv);
|
|
1439
|
+
}
|
|
1440
|
+
async downloadLocalApp(params) {
|
|
1441
|
+
const result = await this.downloadManagedSource({
|
|
1442
|
+
downloadResults: params.downloadResults,
|
|
1443
|
+
verbose: params.verbose,
|
|
1444
|
+
});
|
|
1417
1445
|
const projectRoot = Install.resolveLocalProjectRoot({
|
|
1418
1446
|
envName: params.envName,
|
|
1419
1447
|
appResults: params.appResults,
|
|
@@ -1467,6 +1495,7 @@ export default class Install extends Command {
|
|
|
1467
1495
|
await runNocoBaseCommand(['pm2', 'kill'], {
|
|
1468
1496
|
cwd: params.projectRoot,
|
|
1469
1497
|
env,
|
|
1498
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
1470
1499
|
});
|
|
1471
1500
|
}
|
|
1472
1501
|
catch (error) {
|
|
@@ -1477,6 +1506,7 @@ export default class Install extends Command {
|
|
|
1477
1506
|
await runNocoBaseCommand(args, {
|
|
1478
1507
|
cwd: params.projectRoot,
|
|
1479
1508
|
env,
|
|
1509
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
1480
1510
|
});
|
|
1481
1511
|
p.log.info(`Local app is starting at http://127.0.0.1:${env.APP_PORT}`);
|
|
1482
1512
|
return {
|
|
@@ -1752,6 +1782,7 @@ export default class Install extends Command {
|
|
|
1752
1782
|
const parsed = {
|
|
1753
1783
|
...flags,
|
|
1754
1784
|
};
|
|
1785
|
+
const commandStdio = this.commandStdio(parsed.verbose);
|
|
1755
1786
|
if (!parsed['no-intro']) {
|
|
1756
1787
|
p.intro('Set Up NocoBase');
|
|
1757
1788
|
}
|
|
@@ -1778,6 +1809,7 @@ export default class Install extends Command {
|
|
|
1778
1809
|
downloadResults,
|
|
1779
1810
|
dbResults,
|
|
1780
1811
|
force: parsed.force,
|
|
1812
|
+
commandStdio,
|
|
1781
1813
|
});
|
|
1782
1814
|
dbResults.dbHost = builtinDbPlan.dbHost;
|
|
1783
1815
|
dbResults.dbPort = builtinDbPlan.dbPort;
|
|
@@ -1790,6 +1822,10 @@ export default class Install extends Command {
|
|
|
1790
1822
|
let localAppPlan;
|
|
1791
1823
|
if (Boolean(appResults.fetchSource)) {
|
|
1792
1824
|
if (source === 'docker') {
|
|
1825
|
+
await this.downloadManagedSource({
|
|
1826
|
+
downloadResults,
|
|
1827
|
+
verbose: parsed.verbose,
|
|
1828
|
+
});
|
|
1793
1829
|
dockerAppPlan = await this.installDockerApp({
|
|
1794
1830
|
envName,
|
|
1795
1831
|
workspaceName,
|
|
@@ -1799,6 +1835,7 @@ export default class Install extends Command {
|
|
|
1799
1835
|
rootResults,
|
|
1800
1836
|
builtinDbPlan,
|
|
1801
1837
|
force: parsed.force,
|
|
1838
|
+
commandStdio,
|
|
1802
1839
|
});
|
|
1803
1840
|
appResults.appKey = dockerAppPlan.appKey;
|
|
1804
1841
|
appResults.timeZone = dockerAppPlan.timeZone;
|
|
@@ -1817,6 +1854,7 @@ export default class Install extends Command {
|
|
|
1817
1854
|
appResults,
|
|
1818
1855
|
dbResults,
|
|
1819
1856
|
rootResults,
|
|
1857
|
+
commandStdio,
|
|
1820
1858
|
});
|
|
1821
1859
|
appResults.appKey = localAppPlan.appKey;
|
|
1822
1860
|
appResults.timeZone = localAppPlan.timeZone;
|