@nocobase/cli 2.1.0-beta.43 → 2.1.0-beta.44.test.1
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/LICENSE +201 -0
- package/README.md +63 -380
- package/assets/env-proxy/nginx/app.conf.tpl +23 -0
- package/assets/env-proxy/nginx/nocobase.conf.tpl +5 -0
- package/assets/env-proxy/nginx/snippets/dist-location.conf +5 -0
- package/assets/env-proxy/nginx/snippets/gzip.conf +17 -0
- package/assets/env-proxy/nginx/snippets/log-format-http.conf +13 -0
- package/assets/env-proxy/nginx/snippets/maps-http.conf +14 -0
- package/assets/env-proxy/nginx/snippets/mime-types.conf +98 -0
- package/assets/env-proxy/nginx/snippets/proxy-location.conf +17 -0
- package/assets/env-proxy/nginx/snippets/spa-location.conf +6 -0
- package/assets/env-proxy/nginx/snippets/uploads-location.conf +21 -0
- package/dist/commands/app/autostart/disable.js +55 -0
- package/dist/commands/app/autostart/enable.js +55 -0
- package/dist/commands/app/autostart/list.js +37 -0
- package/dist/commands/app/autostart/run.js +84 -0
- package/dist/commands/app/autostart/shared.js +49 -0
- package/dist/commands/app/destroy.js +8 -6
- package/dist/commands/app/down.js +2 -2
- package/dist/commands/app/logs.js +2 -1
- package/dist/commands/app/restart.js +79 -23
- package/dist/commands/app/shared.js +1 -1
- package/dist/commands/app/start.js +134 -38
- package/dist/commands/app/stop.js +31 -2
- package/dist/commands/app/upgrade.js +3 -1
- package/dist/commands/config/delete.js +4 -1
- package/dist/commands/config/get.js +4 -1
- package/dist/commands/config/set.js +5 -2
- package/dist/commands/env/add.js +19 -39
- package/dist/commands/env/info.js +3 -2
- package/dist/commands/env/proxy/caddy.js +28 -0
- package/dist/commands/env/proxy/index.js +353 -0
- package/dist/commands/env/proxy/nginx.js +28 -0
- package/dist/commands/env/remove.js +112 -22
- package/dist/commands/env/shared.js +17 -9
- package/dist/commands/env/update.js +385 -21
- package/dist/commands/init.js +233 -91
- package/dist/commands/install.js +174 -68
- package/dist/commands/license/activate.js +63 -244
- package/dist/commands/license/plugins/shared.js +64 -13
- package/dist/commands/plugin/import.js +108 -0
- package/dist/commands/revision/create.js +89 -0
- package/dist/locale/en-US.json +105 -19
- package/dist/locale/zh-CN.json +102 -16
- package/package.json +5 -8
- package/scripts/build.mjs +34 -0
- package/scripts/clean.mjs +9 -0
- package/tsconfig.json +19 -0
- package/LICENSE.txt +0 -107
- package/README.zh-CN.md +0 -355
- package/dist/lib/api-client.js +0 -335
- package/dist/lib/api-command-compat.js +0 -641
- package/dist/lib/app-health.js +0 -139
- package/dist/lib/app-managed-resources.js +0 -316
- package/dist/lib/app-runtime.js +0 -180
- package/dist/lib/auth-store.js +0 -405
- package/dist/lib/backup.js +0 -171
- package/dist/lib/bootstrap.js +0 -409
- package/dist/lib/build-config.js +0 -18
- package/dist/lib/builtin-db.js +0 -86
- package/dist/lib/cli-config.js +0 -309
- package/dist/lib/cli-entry-error.js +0 -44
- package/dist/lib/cli-home.js +0 -47
- package/dist/lib/cli-locale.js +0 -141
- package/dist/lib/command-discovery.js +0 -39
- package/dist/lib/db-connection-check.js +0 -219
- package/dist/lib/docker-env-file.js +0 -52
- package/dist/lib/docker-image.js +0 -37
- package/dist/lib/docker-log-stream.js +0 -45
- package/dist/lib/env-auth.js +0 -960
- package/dist/lib/env-config.js +0 -95
- package/dist/lib/env-guard.js +0 -62
- package/dist/lib/generated-command.js +0 -203
- package/dist/lib/http-request.js +0 -49
- package/dist/lib/inquirer-theme.js +0 -17
- package/dist/lib/inquirer.js +0 -244
- package/dist/lib/naming.js +0 -70
- package/dist/lib/object-utils.js +0 -76
- package/dist/lib/openapi.js +0 -62
- package/dist/lib/plugin-storage.js +0 -64
- package/dist/lib/post-processors.js +0 -23
- package/dist/lib/prompt-catalog-core.js +0 -185
- package/dist/lib/prompt-catalog-terminal.js +0 -375
- package/dist/lib/prompt-catalog.js +0 -10
- package/dist/lib/prompt-validators.js +0 -258
- package/dist/lib/prompt-web-ui.js +0 -2227
- package/dist/lib/resource-command.js +0 -357
- package/dist/lib/resource-request.js +0 -104
- package/dist/lib/run-npm.js +0 -385
- package/dist/lib/runtime-env-vars.js +0 -32
- package/dist/lib/runtime-generator.js +0 -498
- package/dist/lib/runtime-store.js +0 -56
- package/dist/lib/self-manager.js +0 -301
- package/dist/lib/session-id.js +0 -17
- package/dist/lib/session-integration.js +0 -703
- package/dist/lib/session-store.js +0 -118
- package/dist/lib/skills-manager.js +0 -436
- package/dist/lib/source-publish.js +0 -309
- package/dist/lib/source-registry.js +0 -188
- package/dist/lib/startup-update.js +0 -309
- package/dist/lib/ui.js +0 -158
package/dist/commands/init.js
CHANGED
|
@@ -16,6 +16,7 @@ import { getEnv, upsertEnv } from "../lib/auth-store.js";
|
|
|
16
16
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
17
17
|
import { applyCliLocale, localeText, translateCli } from "../lib/cli-locale.js";
|
|
18
18
|
import { resolveDefaultConfigScope } from '../lib/cli-home.js';
|
|
19
|
+
import { areConfiguredPathsEquivalent, deriveConfiguredSourcePath, deriveConfiguredStoragePath, inferConfiguredAppPathFromLegacyConfig, } from '../lib/env-paths.js';
|
|
19
20
|
import { runPromptCatalogWebUI } from "../lib/prompt-web-ui.js";
|
|
20
21
|
import { validateApiBaseUrl, validateEnvKey } from "../lib/prompt-validators.js";
|
|
21
22
|
import { installNocoBaseSkills, isNpmRegistryUnavailable } from '../lib/skills-manager.js';
|
|
@@ -27,6 +28,7 @@ import Install, { defaultDbPortForDialect } from "./install.js";
|
|
|
27
28
|
const DEFAULT_INIT_API_BASE_URL = 'http://localhost:13000/api';
|
|
28
29
|
const DEFAULT_INIT_APP_NAME = 'local';
|
|
29
30
|
const DOWNLOAD_OUTPUT_DIR_PROMPT = Download.prompts.outputDir;
|
|
31
|
+
const INIT_SETUP_MODES = ['install-new', 'manage-local', 'connect-remote'];
|
|
30
32
|
const INIT_ENV_ADD_FLAG_NAMES = [
|
|
31
33
|
'locale',
|
|
32
34
|
'default-api-base-url',
|
|
@@ -48,14 +50,42 @@ function withExtraHidden(def, extraHidden) {
|
|
|
48
50
|
hidden: (values) => extraHidden(values) || (def.hidden?.(values) ?? false),
|
|
49
51
|
};
|
|
50
52
|
}
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
+
function normalizeInitSetupMode(value) {
|
|
54
|
+
const mode = String(value ?? '').trim();
|
|
55
|
+
if (mode === 'manage-local' || mode === 'connect-remote' || mode === 'install-new') {
|
|
56
|
+
return mode;
|
|
57
|
+
}
|
|
58
|
+
if (mode === 'yes') {
|
|
59
|
+
return 'connect-remote';
|
|
60
|
+
}
|
|
61
|
+
if (mode === 'no') {
|
|
62
|
+
return 'install-new';
|
|
63
|
+
}
|
|
64
|
+
return 'install-new';
|
|
65
|
+
}
|
|
66
|
+
function resolveInitSetupMode(values) {
|
|
67
|
+
return normalizeInitSetupMode(values.setupMode ?? values.hasNocobase);
|
|
68
|
+
}
|
|
69
|
+
function isRemoteSetupMode(values) {
|
|
70
|
+
return resolveInitSetupMode(values) === 'connect-remote';
|
|
71
|
+
}
|
|
72
|
+
function isInstallNewSetupMode(values) {
|
|
73
|
+
return resolveInitSetupMode(values) === 'install-new';
|
|
74
|
+
}
|
|
75
|
+
function isInstallLikeSetupMode(values) {
|
|
76
|
+
return !isRemoteSetupMode(values);
|
|
77
|
+
}
|
|
78
|
+
function remoteConnectionOnly(def) {
|
|
79
|
+
return withExtraHidden(def, (values) => !isRemoteSetupMode(values));
|
|
53
80
|
}
|
|
54
|
-
function
|
|
55
|
-
return withExtraHidden(def, (values) => values
|
|
81
|
+
function installLikeOnly(def) {
|
|
82
|
+
return withExtraHidden(def, (values) => !isInstallLikeSetupMode(values));
|
|
56
83
|
}
|
|
57
|
-
function
|
|
58
|
-
return withExtraHidden(def, (values) => values
|
|
84
|
+
function installNewOnly(def) {
|
|
85
|
+
return withExtraHidden(def, (values) => !isInstallNewSetupMode(values));
|
|
86
|
+
}
|
|
87
|
+
function installLikeDownloadExecutionOnly(def) {
|
|
88
|
+
return withExtraHidden(def, (values) => !isInstallLikeSetupMode(values) || values.skipDownload === true);
|
|
59
89
|
}
|
|
60
90
|
function argvHasToken(argv, tokens) {
|
|
61
91
|
return tokens.some((token) => argv.includes(token));
|
|
@@ -85,6 +115,26 @@ function explicitApiBaseUrlFlag(flags) {
|
|
|
85
115
|
function explicitDbHostFlag(flags) {
|
|
86
116
|
return String(flags['db-host'] ?? '').trim();
|
|
87
117
|
}
|
|
118
|
+
function explicitSetupModeFlag(flags) {
|
|
119
|
+
const mode = String(flags['setup-mode'] ?? '').trim();
|
|
120
|
+
return mode ? normalizeInitSetupMode(mode) : undefined;
|
|
121
|
+
}
|
|
122
|
+
function applyLegacyHasNocobaseAlias(values) {
|
|
123
|
+
if (!Object.prototype.hasOwnProperty.call(values, 'setupMode') &&
|
|
124
|
+
!Object.prototype.hasOwnProperty.call(values, 'hasNocobase')) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const setupMode = resolveInitSetupMode(values);
|
|
128
|
+
if (setupMode === 'connect-remote') {
|
|
129
|
+
values.hasNocobase = 'yes';
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (setupMode === 'install-new') {
|
|
133
|
+
values.hasNocobase = 'no';
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
delete values.hasNocobase;
|
|
137
|
+
}
|
|
88
138
|
function optionalInitString(value) {
|
|
89
139
|
const text = String(value ?? '').trim();
|
|
90
140
|
return text || undefined;
|
|
@@ -161,10 +211,11 @@ export default class Init extends Command {
|
|
|
161
211
|
static summary = 'Set up NocoBase so coding agents can connect and work with it';
|
|
162
212
|
static description = `Set up NocoBase for coding agents in the current workspace.
|
|
163
213
|
|
|
164
|
-
\`nb init\` prepares a NocoBase environment that coding agents can use. It supports
|
|
214
|
+
\`nb init\` prepares a NocoBase environment that coding agents can use. It supports three setup paths:
|
|
165
215
|
|
|
166
|
-
- Connect an existing NocoBase app and save it as a CLI env.
|
|
167
216
|
- Install a new NocoBase app, then save it as a CLI env.
|
|
217
|
+
- Take over managing an app that already exists on this machine by reusing its database.
|
|
218
|
+
- Connect a remote NocoBase app and save it as a CLI env.
|
|
168
219
|
|
|
169
220
|
It can also install NocoBase AI coding skills (\`nocobase/skills\`) so agents get the project-specific workflow guidance.
|
|
170
221
|
|
|
@@ -173,7 +224,7 @@ If setup was interrupted earlier, use \`--resume\` with an existing env name to
|
|
|
173
224
|
Prompt modes:
|
|
174
225
|
- Default: guided prompts in the terminal.
|
|
175
226
|
- \`--ui\`: open the same setup flow in a local browser form.
|
|
176
|
-
- \`-y\`, \`--yes\`: skip prompts. In this mode \`--env <envName>\` is required, and init
|
|
227
|
+
- \`-y\`, \`--yes\`: skip prompts. In this mode \`--env <envName>\` is required, and init uses flags plus safe defaults for the selected setup mode.
|
|
177
228
|
|
|
178
229
|
\`--ui\` cannot be combined with \`--yes\`.`;
|
|
179
230
|
static examples = [
|
|
@@ -184,8 +235,10 @@ Prompt modes:
|
|
|
184
235
|
'<%= config.bin %> <%= command.id %> --env app1 --yes',
|
|
185
236
|
'<%= config.bin %> <%= command.id %> --env app1 --resume',
|
|
186
237
|
'<%= config.bin %> <%= command.id %> --env app1 --yes --source docker --version alpha',
|
|
238
|
+
'<%= config.bin %> <%= command.id %> --env app1 --yes --setup-mode manage-local --source npm --version beta',
|
|
187
239
|
'<%= config.bin %> <%= command.id %> --env app1 --yes --source npm --version alpha --app-port 13080',
|
|
188
240
|
'<%= config.bin %> <%= command.id %> --env app1 --yes --source git --version fix/cli-v2',
|
|
241
|
+
'<%= config.bin %> <%= command.id %> --env staging --yes --setup-mode connect-remote --api-base-url https://demo.example.com/api',
|
|
189
242
|
'<%= config.bin %> <%= command.id %> --ui --ui-port 3000',
|
|
190
243
|
];
|
|
191
244
|
static prompts = {
|
|
@@ -216,53 +269,61 @@ Prompt modes:
|
|
|
216
269
|
required: true,
|
|
217
270
|
validate: validateInitAppName,
|
|
218
271
|
},
|
|
219
|
-
|
|
272
|
+
setupMode: {
|
|
220
273
|
type: 'select',
|
|
221
274
|
variant: 'radio',
|
|
222
|
-
message: initText('prompts.
|
|
275
|
+
message: initText('prompts.setupMode.message'),
|
|
223
276
|
options: [
|
|
224
277
|
{
|
|
225
|
-
value: '
|
|
226
|
-
label: initText('prompts.
|
|
278
|
+
value: 'install-new',
|
|
279
|
+
label: initText('prompts.setupMode.installNewLabel'),
|
|
280
|
+
hint: initText('prompts.setupMode.installNewHint'),
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
value: 'connect-remote',
|
|
284
|
+
label: initText('prompts.setupMode.connectRemoteLabel'),
|
|
285
|
+
hint: initText('prompts.setupMode.connectRemoteHint'),
|
|
227
286
|
},
|
|
228
287
|
{
|
|
229
|
-
value: '
|
|
230
|
-
label: initText('prompts.
|
|
288
|
+
value: 'manage-local',
|
|
289
|
+
label: initText('prompts.setupMode.manageLocalLabel'),
|
|
290
|
+
hint: initText('prompts.setupMode.manageLocalHint'),
|
|
291
|
+
disabled: true,
|
|
231
292
|
},
|
|
232
293
|
],
|
|
233
|
-
initialValue: '
|
|
234
|
-
yesInitialValue: '
|
|
294
|
+
initialValue: 'install-new',
|
|
295
|
+
yesInitialValue: 'install-new',
|
|
235
296
|
required: true,
|
|
236
297
|
},
|
|
237
|
-
apiBaseUrl:
|
|
298
|
+
apiBaseUrl: remoteConnectionOnly({
|
|
238
299
|
type: 'text',
|
|
239
300
|
message: initText('prompts.apiBaseUrl.message'),
|
|
240
301
|
placeholder: initText('prompts.apiBaseUrl.placeholder'),
|
|
241
302
|
required: true,
|
|
242
303
|
validate: validateApiBaseUrl,
|
|
243
304
|
}),
|
|
244
|
-
authType:
|
|
245
|
-
username:
|
|
246
|
-
password:
|
|
247
|
-
accessToken:
|
|
248
|
-
lang:
|
|
249
|
-
|
|
250
|
-
appPort:
|
|
251
|
-
|
|
252
|
-
skipDownload:
|
|
305
|
+
authType: remoteConnectionOnly(EnvAdd.prompts.authType),
|
|
306
|
+
username: remoteConnectionOnly(EnvAdd.prompts.username),
|
|
307
|
+
password: remoteConnectionOnly(EnvAdd.prompts.password),
|
|
308
|
+
accessToken: remoteConnectionOnly(EnvAdd.prompts.accessToken),
|
|
309
|
+
lang: installLikeOnly(Install.appPrompts.lang),
|
|
310
|
+
appPath: installLikeOnly(Install.appPrompts.appPath),
|
|
311
|
+
appPort: installLikeOnly(Install.appPrompts.appPort),
|
|
312
|
+
appPublicPath: installLikeOnly(Install.appPrompts.appPublicPath),
|
|
313
|
+
skipDownload: installNewOnly({
|
|
253
314
|
type: 'boolean',
|
|
254
315
|
message: initText('prompts.skipDownload.message'),
|
|
255
316
|
initialValue: false,
|
|
256
317
|
yesInitialValue: false,
|
|
257
318
|
}),
|
|
258
|
-
source:
|
|
259
|
-
version:
|
|
260
|
-
otherVersion:
|
|
261
|
-
dockerRegistry:
|
|
262
|
-
dockerPlatform:
|
|
263
|
-
dockerSave:
|
|
264
|
-
gitUrl:
|
|
265
|
-
outputDir:
|
|
319
|
+
source: installLikeOnly(Download.prompts.source),
|
|
320
|
+
version: installLikeOnly(Download.prompts.version),
|
|
321
|
+
otherVersion: installLikeOnly(Download.prompts.otherVersion),
|
|
322
|
+
dockerRegistry: installLikeOnly(Download.prompts.dockerRegistry),
|
|
323
|
+
dockerPlatform: installLikeOnly(Download.prompts.dockerPlatform),
|
|
324
|
+
dockerSave: installLikeDownloadExecutionOnly(Download.prompts.dockerSave),
|
|
325
|
+
gitUrl: installLikeOnly(Download.prompts.gitUrl),
|
|
326
|
+
outputDir: installLikeDownloadExecutionOnly({
|
|
266
327
|
...DOWNLOAD_OUTPUT_DIR_PROMPT,
|
|
267
328
|
hidden: (values) => {
|
|
268
329
|
const source = String(values.source ?? '').trim();
|
|
@@ -274,7 +335,8 @@ Prompt modes:
|
|
|
274
335
|
initialValue: (values) => {
|
|
275
336
|
const source = String(values.source ?? '').trim();
|
|
276
337
|
if (source === 'npm' || source === 'git') {
|
|
277
|
-
const
|
|
338
|
+
const appPath = String(values.appPath ?? inferConfiguredAppPathFromLegacyConfig(values) ?? '').trim();
|
|
339
|
+
const appRootPath = String(values.appRootPath ?? '').trim() || (appPath ? deriveConfiguredSourcePath(appPath) : '');
|
|
278
340
|
if (appRootPath) {
|
|
279
341
|
return appRootPath;
|
|
280
342
|
}
|
|
@@ -283,26 +345,26 @@ Prompt modes:
|
|
|
283
345
|
return typeof initialValue === 'function' ? initialValue(values) : String(initialValue ?? '');
|
|
284
346
|
},
|
|
285
347
|
}),
|
|
286
|
-
npmRegistry:
|
|
287
|
-
replace:
|
|
288
|
-
devDependencies:
|
|
289
|
-
build:
|
|
290
|
-
buildDts:
|
|
291
|
-
dbDialect:
|
|
292
|
-
builtinDb:
|
|
293
|
-
builtinDbImage:
|
|
294
|
-
dbHost:
|
|
295
|
-
dbPort:
|
|
296
|
-
dbDatabase:
|
|
297
|
-
dbUser:
|
|
298
|
-
dbPassword:
|
|
299
|
-
dbSchema:
|
|
300
|
-
dbTablePrefix:
|
|
301
|
-
dbUnderscored:
|
|
302
|
-
rootUsername:
|
|
303
|
-
rootEmail:
|
|
304
|
-
rootPassword:
|
|
305
|
-
rootNickname:
|
|
348
|
+
npmRegistry: installLikeOnly(Download.prompts.npmRegistry),
|
|
349
|
+
replace: installLikeDownloadExecutionOnly(Download.prompts.replace),
|
|
350
|
+
devDependencies: installLikeDownloadExecutionOnly(Download.prompts.devDependencies),
|
|
351
|
+
build: installLikeDownloadExecutionOnly(Download.prompts.build),
|
|
352
|
+
buildDts: installLikeDownloadExecutionOnly(Download.prompts.buildDts),
|
|
353
|
+
dbDialect: installLikeOnly(Install.dbPrompts.dbDialect),
|
|
354
|
+
builtinDb: installLikeOnly(Install.dbPrompts.builtinDb),
|
|
355
|
+
builtinDbImage: installLikeOnly(Install.dbPrompts.builtinDbImage),
|
|
356
|
+
dbHost: installLikeOnly(Install.dbPrompts.dbHost),
|
|
357
|
+
dbPort: installLikeOnly(Install.dbPrompts.dbPort),
|
|
358
|
+
dbDatabase: installLikeOnly(Install.dbPrompts.dbDatabase),
|
|
359
|
+
dbUser: installLikeOnly(Install.dbPrompts.dbUser),
|
|
360
|
+
dbPassword: installLikeOnly(Install.dbPrompts.dbPassword),
|
|
361
|
+
dbSchema: installLikeOnly(Install.dbPrompts.dbSchema),
|
|
362
|
+
dbTablePrefix: installLikeOnly(Install.dbPrompts.dbTablePrefix),
|
|
363
|
+
dbUnderscored: installLikeOnly(Install.dbPrompts.dbUnderscored),
|
|
364
|
+
rootUsername: installNewOnly(Install.rootUserPrompts.rootUsername),
|
|
365
|
+
rootEmail: installNewOnly(Install.rootUserPrompts.rootEmail),
|
|
366
|
+
rootPassword: installNewOnly(Install.rootUserPrompts.rootPassword),
|
|
367
|
+
rootNickname: installNewOnly(Install.rootUserPrompts.rootNickname),
|
|
306
368
|
};
|
|
307
369
|
buildPromptCatalog(flags) {
|
|
308
370
|
const prompts = {
|
|
@@ -321,9 +383,9 @@ Prompt modes:
|
|
|
321
383
|
...EnvAdd.prompts.password,
|
|
322
384
|
hidden: () => true,
|
|
323
385
|
};
|
|
324
|
-
prompts.username =
|
|
325
|
-
prompts.password =
|
|
326
|
-
prompts.accessToken =
|
|
386
|
+
prompts.username = remoteConnectionOnly(usernamePrompt);
|
|
387
|
+
prompts.password = remoteConnectionOnly(passwordPrompt);
|
|
388
|
+
prompts.accessToken = remoteConnectionOnly(accessTokenPrompt);
|
|
327
389
|
}
|
|
328
390
|
return prompts;
|
|
329
391
|
}
|
|
@@ -331,13 +393,17 @@ Prompt modes:
|
|
|
331
393
|
static flags = {
|
|
332
394
|
yes: Flags.boolean({
|
|
333
395
|
char: 'y',
|
|
334
|
-
description: 'Skip prompts and
|
|
396
|
+
description: 'Skip prompts and use flags plus defaults for the selected setup mode. Requires an env name.',
|
|
335
397
|
default: false,
|
|
336
398
|
}),
|
|
337
399
|
env: Flags.string({
|
|
338
400
|
char: 'e',
|
|
339
401
|
description: 'Env name for this setup. Required with --yes and --resume',
|
|
340
402
|
}),
|
|
403
|
+
'setup-mode': Flags.string({
|
|
404
|
+
description: 'Setup mode: install a new app, manage a local app by reusing its database, or connect a remote app',
|
|
405
|
+
options: [...INIT_SETUP_MODES],
|
|
406
|
+
}),
|
|
341
407
|
ui: Flags.boolean({
|
|
342
408
|
description: 'Open the guided setup flow in a local browser form (not valid with --yes)',
|
|
343
409
|
default: false,
|
|
@@ -465,7 +531,12 @@ Prompt modes:
|
|
|
465
531
|
});
|
|
466
532
|
}
|
|
467
533
|
const results = await runPromptCatalog(promptCatalog, {
|
|
468
|
-
initialValues:
|
|
534
|
+
initialValues: {
|
|
535
|
+
...dynamicInitialValues,
|
|
536
|
+
...(presetValues.setupMode === undefined && presetValues.hasNocobase !== undefined
|
|
537
|
+
? { setupMode: normalizeInitSetupMode(presetValues.hasNocobase) }
|
|
538
|
+
: {}),
|
|
539
|
+
},
|
|
469
540
|
values: presetValues,
|
|
470
541
|
yes: normalizedFlags.yes || useBrowserUi || !interactive,
|
|
471
542
|
hooks: {
|
|
@@ -480,7 +551,7 @@ Prompt modes:
|
|
|
480
551
|
},
|
|
481
552
|
command: this,
|
|
482
553
|
});
|
|
483
|
-
const normalizedResults = {
|
|
554
|
+
const normalizedResults = this.normalizeInitResults({
|
|
484
555
|
...pickKeys(presetValues, [
|
|
485
556
|
'authType',
|
|
486
557
|
'accessToken',
|
|
@@ -492,9 +563,9 @@ Prompt modes:
|
|
|
492
563
|
'password',
|
|
493
564
|
]),
|
|
494
565
|
...results,
|
|
495
|
-
};
|
|
496
|
-
const
|
|
497
|
-
const existingEnv =
|
|
566
|
+
});
|
|
567
|
+
const setupMode = resolveInitSetupMode(normalizedResults);
|
|
568
|
+
const existingEnv = isInstallLikeSetupMode(normalizedResults)
|
|
498
569
|
? await getEnv(String(normalizedResults.appName ?? '').trim(), { scope: resolveDefaultConfigScope() })
|
|
499
570
|
: undefined;
|
|
500
571
|
if (existingEnv && Boolean(normalizedFlags.force)) {
|
|
@@ -506,7 +577,7 @@ Prompt modes:
|
|
|
506
577
|
let managedInstallResults;
|
|
507
578
|
try {
|
|
508
579
|
// oclif explicit registry keys use `:` (e.g. `env:add`); users still type `nb env add`.
|
|
509
|
-
if (
|
|
580
|
+
if (setupMode === 'connect-remote') {
|
|
510
581
|
logInitStage('Connecting to the env');
|
|
511
582
|
printVerbose('Running nb env add');
|
|
512
583
|
await this.config.runCommand('env:add', this.buildEnvAddArgv(normalizedResults));
|
|
@@ -536,6 +607,7 @@ Prompt modes:
|
|
|
536
607
|
envName: String(presetValues.appName ?? '').trim(),
|
|
537
608
|
flags: {
|
|
538
609
|
...flags,
|
|
610
|
+
'app-path': flags['app-path'] ?? '',
|
|
539
611
|
'app-root-path': flags['app-root-path'] ?? '',
|
|
540
612
|
'storage-path': flags['storage-path'] ?? '',
|
|
541
613
|
},
|
|
@@ -569,7 +641,7 @@ Prompt modes:
|
|
|
569
641
|
sectionDescription: initText('webUi.gettingStarted.description'),
|
|
570
642
|
catalog: {
|
|
571
643
|
appName: c.appName,
|
|
572
|
-
|
|
644
|
+
setupMode: c.setupMode,
|
|
573
645
|
},
|
|
574
646
|
},
|
|
575
647
|
{
|
|
@@ -588,9 +660,8 @@ Prompt modes:
|
|
|
588
660
|
sectionDescription: initText('webUi.createNewApp.description'),
|
|
589
661
|
catalog: {
|
|
590
662
|
lang: c.lang,
|
|
591
|
-
|
|
663
|
+
appPath: c.appPath,
|
|
592
664
|
appPort: c.appPort,
|
|
593
|
-
storagePath: c.storagePath,
|
|
594
665
|
skipDownload: c.skipDownload,
|
|
595
666
|
},
|
|
596
667
|
},
|
|
@@ -645,12 +716,16 @@ Prompt modes:
|
|
|
645
716
|
buildPresetValuesFromFlags(flags) {
|
|
646
717
|
const preset = {};
|
|
647
718
|
const argv = process.argv.slice(2);
|
|
719
|
+
const setupMode = explicitSetupModeFlag(flags);
|
|
648
720
|
if (flags.env !== undefined && String(flags.env).trim() !== '') {
|
|
649
721
|
preset.appName = String(flags.env).trim();
|
|
650
722
|
}
|
|
723
|
+
if (setupMode) {
|
|
724
|
+
preset.setupMode = setupMode;
|
|
725
|
+
}
|
|
651
726
|
const apiBaseUrl = explicitApiBaseUrlFlag(flags);
|
|
652
727
|
if (apiBaseUrl) {
|
|
653
|
-
preset.
|
|
728
|
+
preset.setupMode ??= 'connect-remote';
|
|
654
729
|
preset.apiBaseUrl = apiBaseUrl;
|
|
655
730
|
}
|
|
656
731
|
else if (flags['default-api-base-url'] !== undefined && String(flags['default-api-base-url']).trim() !== '') {
|
|
@@ -675,6 +750,9 @@ Prompt modes:
|
|
|
675
750
|
if (flags.lang !== undefined && String(flags.lang).trim() !== '') {
|
|
676
751
|
preset.lang = String(flags.lang).trim();
|
|
677
752
|
}
|
|
753
|
+
if (flags['app-path'] !== undefined && String(flags['app-path']).trim() !== '') {
|
|
754
|
+
preset.appPath = String(flags['app-path']).trim();
|
|
755
|
+
}
|
|
678
756
|
if (flags['app-root-path'] !== undefined && String(flags['app-root-path']).trim() !== '') {
|
|
679
757
|
preset.appRootPath = String(flags['app-root-path']).trim();
|
|
680
758
|
}
|
|
@@ -684,6 +762,9 @@ Prompt modes:
|
|
|
684
762
|
if (flags['storage-path'] !== undefined && String(flags['storage-path']).trim() !== '') {
|
|
685
763
|
preset.storagePath = String(flags['storage-path']).trim();
|
|
686
764
|
}
|
|
765
|
+
if (flags['app-public-path'] !== undefined && String(flags['app-public-path']).trim() !== '') {
|
|
766
|
+
preset.appPublicPath = String(flags['app-public-path']).trim();
|
|
767
|
+
}
|
|
687
768
|
if (flags['root-username'] !== undefined) {
|
|
688
769
|
preset.rootUsername = String(flags['root-username'] ?? '').trim();
|
|
689
770
|
}
|
|
@@ -783,9 +864,13 @@ Prompt modes:
|
|
|
783
864
|
if (explicitDbHostFlag(flags)) {
|
|
784
865
|
preset.builtinDb = false;
|
|
785
866
|
}
|
|
786
|
-
if (!preset.
|
|
787
|
-
preset.
|
|
867
|
+
if (!preset.setupMode && hasDownloadOverride(flags)) {
|
|
868
|
+
preset.setupMode = 'install-new';
|
|
869
|
+
}
|
|
870
|
+
if (preset.setupMode === 'manage-local') {
|
|
871
|
+
preset.skipDownload = false;
|
|
788
872
|
}
|
|
873
|
+
applyLegacyHasNocobaseAlias(preset);
|
|
789
874
|
return preset;
|
|
790
875
|
}
|
|
791
876
|
hasAgentsDirInCwd() {
|
|
@@ -822,8 +907,16 @@ Prompt modes:
|
|
|
822
907
|
const dockerPlatform = String(results.dockerPlatform ?? '').trim();
|
|
823
908
|
const gitUrl = String(results.gitUrl ?? '').trim();
|
|
824
909
|
const npmRegistry = String(results.npmRegistry ?? '').trim();
|
|
910
|
+
const appPath = String(results.appPath ?? '').trim() ||
|
|
911
|
+
inferConfiguredAppPathFromLegacyConfig({
|
|
912
|
+
appRootPath: results.appRootPath,
|
|
913
|
+
storagePath: results.storagePath,
|
|
914
|
+
}) ||
|
|
915
|
+
'';
|
|
825
916
|
const appRootPath = String(results.appRootPath ?? '').trim();
|
|
826
917
|
const storagePath = String(results.storagePath ?? '').trim();
|
|
918
|
+
const derivedAppRootPath = appPath ? deriveConfiguredSourcePath(appPath) : '';
|
|
919
|
+
const derivedStoragePath = appPath ? deriveConfiguredStoragePath(appPath) : '';
|
|
827
920
|
const dbDialect = String(results.dbDialect ?? '').trim();
|
|
828
921
|
const builtinDbImage = String(results.builtinDbImage ?? '').trim();
|
|
829
922
|
const dbHost = String(results.dbHost ?? '').trim();
|
|
@@ -850,7 +943,7 @@ Prompt modes:
|
|
|
850
943
|
await upsertEnv(envName, {
|
|
851
944
|
...(source === 'docker'
|
|
852
945
|
? { kind: 'docker' }
|
|
853
|
-
: source || appRootPath
|
|
946
|
+
: source || appPath || appRootPath
|
|
854
947
|
? { kind: 'local' }
|
|
855
948
|
: appPort
|
|
856
949
|
? { kind: 'http' }
|
|
@@ -865,8 +958,9 @@ Prompt modes:
|
|
|
865
958
|
...(dockerPlatform ? { dockerPlatform } : {}),
|
|
866
959
|
...(gitUrl ? { gitUrl } : {}),
|
|
867
960
|
...(npmRegistry ? { npmRegistry } : {}),
|
|
868
|
-
...(
|
|
869
|
-
...(
|
|
961
|
+
...(appPath ? { appPath } : {}),
|
|
962
|
+
...(appRootPath && !areConfiguredPathsEquivalent(appRootPath, derivedAppRootPath) ? { appRootPath } : {}),
|
|
963
|
+
...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
|
|
870
964
|
...(appPort ? { appPort } : {}),
|
|
871
965
|
...(appKey ? { appKey } : {}),
|
|
872
966
|
...(timeZone ? { timezone: timeZone } : {}),
|
|
@@ -919,8 +1013,11 @@ Prompt modes:
|
|
|
919
1013
|
const processArgv = process.argv.slice(2);
|
|
920
1014
|
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
921
1015
|
const source = String(results.source ?? '').trim();
|
|
922
|
-
const
|
|
923
|
-
|
|
1016
|
+
const setupMode = resolveInitSetupMode({
|
|
1017
|
+
setupMode: results.setupMode ?? flags['setup-mode'],
|
|
1018
|
+
hasNocobase: results.hasNocobase,
|
|
1019
|
+
});
|
|
1020
|
+
const skipDownload = setupMode === 'manage-local' ? false : Boolean(flags['skip-download']) || results.skipDownload === true;
|
|
924
1021
|
const apiBaseUrl = String(results.apiBaseUrl ?? '').trim();
|
|
925
1022
|
const authType = String(results.authType ?? '').trim();
|
|
926
1023
|
const accessToken = String(results.accessToken ?? '');
|
|
@@ -933,7 +1030,7 @@ Prompt modes:
|
|
|
933
1030
|
if (flags.verbose) {
|
|
934
1031
|
argv.push('--verbose');
|
|
935
1032
|
}
|
|
936
|
-
if (
|
|
1033
|
+
if (setupMode === 'connect-remote' && apiBaseUrl) {
|
|
937
1034
|
argv.push('--api-base-url', apiBaseUrl);
|
|
938
1035
|
}
|
|
939
1036
|
if (authType) {
|
|
@@ -955,8 +1052,17 @@ Prompt modes:
|
|
|
955
1052
|
if (lang) {
|
|
956
1053
|
argv.push('--lang', lang);
|
|
957
1054
|
}
|
|
1055
|
+
const appPath = String(results.appPath ?? '').trim() ||
|
|
1056
|
+
inferConfiguredAppPathFromLegacyConfig({
|
|
1057
|
+
appRootPath: results.appRootPath,
|
|
1058
|
+
storagePath: results.storagePath,
|
|
1059
|
+
}) ||
|
|
1060
|
+
'';
|
|
1061
|
+
if (appPath) {
|
|
1062
|
+
argv.push('--app-path', appPath);
|
|
1063
|
+
}
|
|
958
1064
|
const appRootPath = String(results.appRootPath ?? '').trim();
|
|
959
|
-
if (appRootPath) {
|
|
1065
|
+
if (appRootPath && (!appPath || !areConfiguredPathsEquivalent(appRootPath, deriveConfiguredSourcePath(appPath)))) {
|
|
960
1066
|
argv.push('--app-root-path', appRootPath);
|
|
961
1067
|
}
|
|
962
1068
|
const appPort = String(results.appPort ?? '').trim();
|
|
@@ -964,9 +1070,13 @@ Prompt modes:
|
|
|
964
1070
|
argv.push('--app-port', appPort);
|
|
965
1071
|
}
|
|
966
1072
|
const storagePath = String(results.storagePath ?? '').trim();
|
|
967
|
-
if (storagePath) {
|
|
1073
|
+
if (storagePath && (!appPath || !areConfiguredPathsEquivalent(storagePath, deriveConfiguredStoragePath(appPath)))) {
|
|
968
1074
|
argv.push('--storage-path', storagePath);
|
|
969
1075
|
}
|
|
1076
|
+
const appPublicPath = String(results.appPublicPath ?? '').trim();
|
|
1077
|
+
if (appPublicPath) {
|
|
1078
|
+
argv.push('--app-public-path', appPublicPath);
|
|
1079
|
+
}
|
|
970
1080
|
if (flags.force) {
|
|
971
1081
|
argv.push('--force');
|
|
972
1082
|
}
|
|
@@ -1072,20 +1182,21 @@ Prompt modes:
|
|
|
1072
1182
|
if (results.dbUnderscored !== undefined) {
|
|
1073
1183
|
argv.push(results.dbUnderscored ? '--db-underscored' : '--no-db-underscored');
|
|
1074
1184
|
}
|
|
1185
|
+
const includeRootUser = setupMode === 'install-new';
|
|
1075
1186
|
const rootUsername = String(results.rootUsername ?? '').trim();
|
|
1076
|
-
if (rootUsername) {
|
|
1187
|
+
if (includeRootUser && rootUsername) {
|
|
1077
1188
|
argv.push('--root-username', rootUsername);
|
|
1078
1189
|
}
|
|
1079
1190
|
const rootEmail = String(results.rootEmail ?? '').trim();
|
|
1080
|
-
if (rootEmail) {
|
|
1191
|
+
if (includeRootUser && rootEmail) {
|
|
1081
1192
|
argv.push('--root-email', rootEmail);
|
|
1082
1193
|
}
|
|
1083
1194
|
const rootPassword = String(results.rootPassword ?? '');
|
|
1084
|
-
if (rootPassword) {
|
|
1195
|
+
if (includeRootUser && rootPassword) {
|
|
1085
1196
|
argv.push('--root-password', rootPassword);
|
|
1086
1197
|
}
|
|
1087
1198
|
const rootNickname = String(results.rootNickname ?? '').trim();
|
|
1088
|
-
if (rootNickname) {
|
|
1199
|
+
if (includeRootUser && rootNickname) {
|
|
1089
1200
|
argv.push('--root-nickname', rootNickname);
|
|
1090
1201
|
}
|
|
1091
1202
|
return argv;
|
|
@@ -1097,8 +1208,12 @@ Prompt modes:
|
|
|
1097
1208
|
}
|
|
1098
1209
|
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
1099
1210
|
argv.push('--env', envName);
|
|
1211
|
+
const setupMode = resolveInitSetupMode(results);
|
|
1212
|
+
if (setupMode === 'manage-local') {
|
|
1213
|
+
argv.push('--setup-mode', 'manage-local');
|
|
1214
|
+
}
|
|
1100
1215
|
const source = String(results.source ?? '').trim();
|
|
1101
|
-
const skipDownload = Boolean(flags['skip-download']) || results.skipDownload === true;
|
|
1216
|
+
const skipDownload = setupMode === 'manage-local' ? false : Boolean(flags['skip-download']) || results.skipDownload === true;
|
|
1102
1217
|
if (source) {
|
|
1103
1218
|
argv.push('--source', source);
|
|
1104
1219
|
}
|
|
@@ -1127,7 +1242,14 @@ Prompt modes:
|
|
|
1127
1242
|
}
|
|
1128
1243
|
else {
|
|
1129
1244
|
const outputDir = String(results.outputDir ?? '').trim();
|
|
1130
|
-
|
|
1245
|
+
const appPath = String(results.appPath ?? '').trim() ||
|
|
1246
|
+
inferConfiguredAppPathFromLegacyConfig({
|
|
1247
|
+
appRootPath: results.appRootPath,
|
|
1248
|
+
storagePath: results.storagePath,
|
|
1249
|
+
}) ||
|
|
1250
|
+
'';
|
|
1251
|
+
const expectedOutputDir = String(results.appRootPath ?? '').trim() || (appPath ? deriveConfiguredSourcePath(appPath) : '');
|
|
1252
|
+
if (outputDir && outputDir !== expectedOutputDir) {
|
|
1131
1253
|
argv.push('--output-dir', outputDir);
|
|
1132
1254
|
}
|
|
1133
1255
|
if (results.devDependencies) {
|
|
@@ -1152,14 +1274,20 @@ Prompt modes:
|
|
|
1152
1274
|
}
|
|
1153
1275
|
buildResumeInstallArgv(flags) {
|
|
1154
1276
|
const preset = this.buildPresetValuesFromFlags(flags);
|
|
1277
|
+
const setupMode = resolveInitSetupMode(preset);
|
|
1155
1278
|
if (flags.yes) {
|
|
1156
1279
|
preset.lang ??= yesInitialValue(Install.appPrompts.lang, 'en-US');
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1280
|
+
if (setupMode === 'install-new') {
|
|
1281
|
+
preset.rootUsername ??= yesInitialValue(Install.rootUserPrompts.rootUsername, 'nocobase');
|
|
1282
|
+
preset.rootEmail ??= yesInitialValue(Install.rootUserPrompts.rootEmail, 'admin@nocobase.com');
|
|
1283
|
+
preset.rootPassword ??= yesInitialValue(Install.rootUserPrompts.rootPassword, 'admin123');
|
|
1284
|
+
preset.rootNickname ??= yesInitialValue(Install.rootUserPrompts.rootNickname, 'Super Admin');
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
if (setupMode === 'manage-local') {
|
|
1288
|
+
preset.skipDownload = false;
|
|
1161
1289
|
}
|
|
1162
|
-
if (!flags['skip-download']) {
|
|
1290
|
+
else if (!flags['skip-download']) {
|
|
1163
1291
|
preset.replace ??= true;
|
|
1164
1292
|
}
|
|
1165
1293
|
return this.buildInstallArgv(preset, flags, {
|
|
@@ -1167,4 +1295,18 @@ Prompt modes:
|
|
|
1167
1295
|
resume: true,
|
|
1168
1296
|
});
|
|
1169
1297
|
}
|
|
1298
|
+
normalizeInitResults(results) {
|
|
1299
|
+
const normalized = { ...results };
|
|
1300
|
+
const setupMode = resolveInitSetupMode(normalized);
|
|
1301
|
+
normalized.setupMode = setupMode;
|
|
1302
|
+
applyLegacyHasNocobaseAlias(normalized);
|
|
1303
|
+
if (setupMode === 'manage-local') {
|
|
1304
|
+
normalized.skipDownload = false;
|
|
1305
|
+
delete normalized.rootUsername;
|
|
1306
|
+
delete normalized.rootEmail;
|
|
1307
|
+
delete normalized.rootPassword;
|
|
1308
|
+
delete normalized.rootNickname;
|
|
1309
|
+
}
|
|
1310
|
+
return normalized;
|
|
1311
|
+
}
|
|
1170
1312
|
}
|