@nocobase/cli 2.1.0-alpha.45 → 2.1.0-alpha.47
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/bin/run.js +40 -32
- 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 +21 -12
- package/dist/commands/app/down.js +2 -2
- package/dist/commands/app/logs.js +2 -1
- package/dist/commands/app/restart.js +92 -20
- package/dist/commands/app/shared.js +3 -2
- package/dist/commands/app/start.js +143 -38
- package/dist/commands/app/stop.js +31 -2
- package/dist/commands/app/upgrade.js +11 -7
- package/dist/commands/config/delete.js +10 -2
- package/dist/commands/config/get.js +7 -1
- package/dist/commands/config/set.js +12 -2
- package/dist/commands/db/ps.js +5 -18
- package/dist/commands/env/add.js +24 -44
- package/dist/commands/env/auth.js +1 -1
- package/dist/commands/env/info.js +3 -2
- package/dist/commands/env/list.js +4 -5
- 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/status.js +10 -7
- package/dist/commands/env/update.js +385 -21
- package/dist/commands/init.js +368 -98
- package/dist/commands/install.js +271 -104
- 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/commands/self/update.js +58 -1
- package/dist/commands/source/dev.js +5 -5
- package/dist/commands/source/test.js +13 -14
- package/dist/lib/app-health.js +39 -32
- package/dist/lib/app-managed-resources.js +25 -9
- package/dist/lib/app-public-path.js +80 -0
- package/dist/lib/app-runtime.js +12 -3
- package/dist/lib/auth-store.js +128 -4
- package/dist/lib/backup.js +3 -3
- package/dist/lib/bootstrap.js +14 -8
- package/dist/lib/cli-config.js +229 -3
- package/dist/lib/cli-entry-error.js +52 -0
- package/dist/lib/command-log.js +284 -0
- package/dist/lib/docker-env-file.js +10 -2
- package/dist/lib/docker-log-stream.js +45 -0
- package/dist/lib/env-auth.js +25 -14
- package/dist/lib/env-command-config.js +45 -0
- package/dist/lib/env-config.js +7 -2
- package/dist/lib/env-guard.js +9 -10
- package/dist/lib/env-paths.js +101 -0
- package/dist/lib/env-proxy.js +1295 -0
- package/dist/lib/inquirer.js +4 -5
- package/dist/lib/managed-env-file.js +98 -0
- package/dist/lib/plugin-import.js +279 -0
- package/dist/lib/prompt-catalog-core.js +3 -2
- package/dist/lib/prompt-validators.js +14 -0
- package/dist/lib/prompt-web-ui.js +8 -1
- package/dist/lib/run-npm.js +56 -12
- package/dist/lib/skills-manager.js +3 -1
- package/dist/lib/source-publish.js +22 -2
- package/dist/lib/startup-update.js +74 -50
- package/dist/lib/ui.js +2 -1
- package/dist/locale/en-US.json +122 -22
- package/dist/locale/zh-CN.json +119 -19
- package/package.json +5 -7
- 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/commands/init.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
10
|
import pc from 'picocolors';
|
|
11
|
+
import crypto from 'node:crypto';
|
|
11
12
|
import { existsSync } from 'node:fs';
|
|
12
13
|
import path from 'node:path';
|
|
13
14
|
import { stdin as stdinStream, stdout as stdoutStream } from 'node:process';
|
|
@@ -15,6 +16,8 @@ import { getEnv, upsertEnv } from "../lib/auth-store.js";
|
|
|
15
16
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
16
17
|
import { applyCliLocale, localeText, translateCli } from "../lib/cli-locale.js";
|
|
17
18
|
import { resolveDefaultConfigScope } from '../lib/cli-home.js';
|
|
19
|
+
import { resolveDefaultApiHost, resolveDefaultUiHost } from '../lib/cli-config.js';
|
|
20
|
+
import { areConfiguredPathsEquivalent, deriveConfiguredSourcePath, deriveConfiguredStoragePath, inferConfiguredAppPathFromLegacyConfig, } from '../lib/env-paths.js';
|
|
18
21
|
import { runPromptCatalogWebUI } from "../lib/prompt-web-ui.js";
|
|
19
22
|
import { validateApiBaseUrl, validateEnvKey } from "../lib/prompt-validators.js";
|
|
20
23
|
import { installNocoBaseSkills, isNpmRegistryUnavailable } from '../lib/skills-manager.js';
|
|
@@ -26,6 +29,7 @@ import Install, { defaultDbPortForDialect } from "./install.js";
|
|
|
26
29
|
const DEFAULT_INIT_API_BASE_URL = 'http://localhost:13000/api';
|
|
27
30
|
const DEFAULT_INIT_APP_NAME = 'local';
|
|
28
31
|
const DOWNLOAD_OUTPUT_DIR_PROMPT = Download.prompts.outputDir;
|
|
32
|
+
const INIT_SETUP_MODES = ['install-new', 'manage-local', 'connect-remote'];
|
|
29
33
|
const INIT_ENV_ADD_FLAG_NAMES = [
|
|
30
34
|
'locale',
|
|
31
35
|
'default-api-base-url',
|
|
@@ -47,14 +51,45 @@ function withExtraHidden(def, extraHidden) {
|
|
|
47
51
|
hidden: (values) => extraHidden(values) || (def.hidden?.(values) ?? false),
|
|
48
52
|
};
|
|
49
53
|
}
|
|
50
|
-
function
|
|
51
|
-
|
|
54
|
+
function normalizeInitSetupMode(value) {
|
|
55
|
+
const mode = String(value ?? '').trim();
|
|
56
|
+
if (mode === 'manage-local' || mode === 'connect-remote' || mode === 'install-new') {
|
|
57
|
+
return mode;
|
|
58
|
+
}
|
|
59
|
+
if (mode === 'yes') {
|
|
60
|
+
return 'connect-remote';
|
|
61
|
+
}
|
|
62
|
+
if (mode === 'no') {
|
|
63
|
+
return 'install-new';
|
|
64
|
+
}
|
|
65
|
+
return 'install-new';
|
|
66
|
+
}
|
|
67
|
+
function resolveInitSetupMode(values) {
|
|
68
|
+
return normalizeInitSetupMode(values.setupMode ?? values.hasNocobase);
|
|
69
|
+
}
|
|
70
|
+
function isRemoteSetupMode(values) {
|
|
71
|
+
return resolveInitSetupMode(values) === 'connect-remote';
|
|
72
|
+
}
|
|
73
|
+
function isInstallNewSetupMode(values) {
|
|
74
|
+
return resolveInitSetupMode(values) === 'install-new';
|
|
75
|
+
}
|
|
76
|
+
function isInstallLikeSetupMode(values) {
|
|
77
|
+
return !isRemoteSetupMode(values);
|
|
52
78
|
}
|
|
53
|
-
function
|
|
54
|
-
return withExtraHidden(def, (values) => values
|
|
79
|
+
function remoteConnectionOnly(def) {
|
|
80
|
+
return withExtraHidden(def, (values) => !isRemoteSetupMode(values));
|
|
55
81
|
}
|
|
56
|
-
function
|
|
57
|
-
return withExtraHidden(def, (values) => values
|
|
82
|
+
function installLikeOnly(def) {
|
|
83
|
+
return withExtraHidden(def, (values) => !isInstallLikeSetupMode(values));
|
|
84
|
+
}
|
|
85
|
+
function installNewOnly(def) {
|
|
86
|
+
return withExtraHidden(def, (values) => !isInstallNewSetupMode(values));
|
|
87
|
+
}
|
|
88
|
+
function installConnectionOnly(def) {
|
|
89
|
+
return withExtraHidden(def, (values) => !isInstallNewSetupMode(values));
|
|
90
|
+
}
|
|
91
|
+
function installLikeDownloadExecutionOnly(def) {
|
|
92
|
+
return withExtraHidden(def, (values) => !isInstallLikeSetupMode(values) || values.skipDownload === true);
|
|
58
93
|
}
|
|
59
94
|
function argvHasToken(argv, tokens) {
|
|
60
95
|
return tokens.some((token) => argv.includes(token));
|
|
@@ -84,6 +119,69 @@ function explicitApiBaseUrlFlag(flags) {
|
|
|
84
119
|
function explicitDbHostFlag(flags) {
|
|
85
120
|
return String(flags['db-host'] ?? '').trim();
|
|
86
121
|
}
|
|
122
|
+
function explicitSetupModeFlag(flags) {
|
|
123
|
+
const mode = String(flags['setup-mode'] ?? '').trim();
|
|
124
|
+
return mode ? normalizeInitSetupMode(mode) : undefined;
|
|
125
|
+
}
|
|
126
|
+
function applyLegacyHasNocobaseAlias(values) {
|
|
127
|
+
if (!Object.prototype.hasOwnProperty.call(values, 'setupMode') &&
|
|
128
|
+
!Object.prototype.hasOwnProperty.call(values, 'hasNocobase')) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const setupMode = resolveInitSetupMode(values);
|
|
132
|
+
if (setupMode === 'connect-remote') {
|
|
133
|
+
values.hasNocobase = 'yes';
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (setupMode === 'install-new') {
|
|
137
|
+
values.hasNocobase = 'no';
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
delete values.hasNocobase;
|
|
141
|
+
}
|
|
142
|
+
function optionalInitString(value) {
|
|
143
|
+
const text = String(value ?? '').trim();
|
|
144
|
+
return text || undefined;
|
|
145
|
+
}
|
|
146
|
+
function resolveManagedAppKey(value) {
|
|
147
|
+
return optionalInitString(value) ?? crypto.randomBytes(32).toString('hex');
|
|
148
|
+
}
|
|
149
|
+
function resolveManagedTimeZone(value) {
|
|
150
|
+
return optionalInitString(value) ?? (Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC');
|
|
151
|
+
}
|
|
152
|
+
function normalizeConnectionString(value) {
|
|
153
|
+
return String(value ?? '').trim();
|
|
154
|
+
}
|
|
155
|
+
function deriveInstallConnectionApiBaseUrl(values, defaultApiHost = '127.0.0.1') {
|
|
156
|
+
const appPort = normalizeConnectionString(values.appPort);
|
|
157
|
+
return appPort ? `http://${defaultApiHost}:${appPort}/api` : DEFAULT_INIT_API_BASE_URL;
|
|
158
|
+
}
|
|
159
|
+
function createInstallConnectionApiBaseUrlPrompt(defaultApiHost) {
|
|
160
|
+
return installConnectionOnly({
|
|
161
|
+
type: 'text',
|
|
162
|
+
message: initText('prompts.apiBaseUrl.message'),
|
|
163
|
+
placeholder: initText('prompts.apiBaseUrl.placeholder'),
|
|
164
|
+
required: true,
|
|
165
|
+
initialValue: (values) => deriveInstallConnectionApiBaseUrl(values, defaultApiHost),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const installConnectionAuthTypePrompt = installConnectionOnly({
|
|
169
|
+
...EnvAdd.prompts.authType,
|
|
170
|
+
});
|
|
171
|
+
const installConnectionUsernamePrompt = installConnectionOnly({
|
|
172
|
+
...Install.rootUserPrompts.rootUsername,
|
|
173
|
+
hidden: () => true,
|
|
174
|
+
initialValue: (values) => normalizeConnectionString(values.rootUsername),
|
|
175
|
+
});
|
|
176
|
+
const installConnectionPasswordPrompt = installConnectionOnly({
|
|
177
|
+
...Install.rootUserPrompts.rootPassword,
|
|
178
|
+
hidden: () => true,
|
|
179
|
+
initialValue: (values) => String(values.rootPassword ?? ''),
|
|
180
|
+
});
|
|
181
|
+
const installConnectionAccessTokenPrompt = installConnectionOnly({
|
|
182
|
+
...EnvAdd.prompts.accessToken,
|
|
183
|
+
hidden: (values) => values.installAuthType !== 'token' || values.skipAuth === true,
|
|
184
|
+
});
|
|
87
185
|
function shouldAllowExistingInitEnv() {
|
|
88
186
|
return argvHasToken(process.argv.slice(2), ['--force', '-f']);
|
|
89
187
|
}
|
|
@@ -150,10 +248,11 @@ export default class Init extends Command {
|
|
|
150
248
|
static summary = 'Set up NocoBase so coding agents can connect and work with it';
|
|
151
249
|
static description = `Set up NocoBase for coding agents in the current workspace.
|
|
152
250
|
|
|
153
|
-
\`nb init\` prepares a NocoBase environment that coding agents can use. It supports
|
|
251
|
+
\`nb init\` prepares a NocoBase environment that coding agents can use. It supports three setup paths:
|
|
154
252
|
|
|
155
|
-
- Connect an existing NocoBase app and save it as a CLI env.
|
|
156
253
|
- Install a new NocoBase app, then save it as a CLI env.
|
|
254
|
+
- Take over managing an app that already exists on this machine by reusing its database.
|
|
255
|
+
- Connect a remote NocoBase app and save it as a CLI env.
|
|
157
256
|
|
|
158
257
|
It can also install NocoBase AI coding skills (\`nocobase/skills\`) so agents get the project-specific workflow guidance.
|
|
159
258
|
|
|
@@ -162,7 +261,7 @@ If setup was interrupted earlier, use \`--resume\` with an existing env name to
|
|
|
162
261
|
Prompt modes:
|
|
163
262
|
- Default: guided prompts in the terminal.
|
|
164
263
|
- \`--ui\`: open the same setup flow in a local browser form.
|
|
165
|
-
- \`-y\`, \`--yes\`: skip prompts. In this mode \`--env <envName>\` is required, and init
|
|
264
|
+
- \`-y\`, \`--yes\`: skip prompts. In this mode \`--env <envName>\` is required, and init uses flags plus safe defaults for the selected setup mode.
|
|
166
265
|
|
|
167
266
|
\`--ui\` cannot be combined with \`--yes\`.`;
|
|
168
267
|
static examples = [
|
|
@@ -173,8 +272,10 @@ Prompt modes:
|
|
|
173
272
|
'<%= config.bin %> <%= command.id %> --env app1 --yes',
|
|
174
273
|
'<%= config.bin %> <%= command.id %> --env app1 --resume',
|
|
175
274
|
'<%= config.bin %> <%= command.id %> --env app1 --yes --source docker --version alpha',
|
|
275
|
+
'<%= config.bin %> <%= command.id %> --env app1 --yes --setup-mode manage-local --source npm --version beta',
|
|
176
276
|
'<%= config.bin %> <%= command.id %> --env app1 --yes --source npm --version alpha --app-port 13080',
|
|
177
277
|
'<%= config.bin %> <%= command.id %> --env app1 --yes --source git --version fix/cli-v2',
|
|
278
|
+
'<%= config.bin %> <%= command.id %> --env staging --yes --setup-mode connect-remote --api-base-url https://demo.example.com/api',
|
|
178
279
|
'<%= config.bin %> <%= command.id %> --ui --ui-port 3000',
|
|
179
280
|
];
|
|
180
281
|
static prompts = {
|
|
@@ -205,53 +306,61 @@ Prompt modes:
|
|
|
205
306
|
required: true,
|
|
206
307
|
validate: validateInitAppName,
|
|
207
308
|
},
|
|
208
|
-
|
|
309
|
+
setupMode: {
|
|
209
310
|
type: 'select',
|
|
210
311
|
variant: 'radio',
|
|
211
|
-
message: initText('prompts.
|
|
312
|
+
message: initText('prompts.setupMode.message'),
|
|
212
313
|
options: [
|
|
213
314
|
{
|
|
214
|
-
value: '
|
|
215
|
-
label: initText('prompts.
|
|
315
|
+
value: 'install-new',
|
|
316
|
+
label: initText('prompts.setupMode.installNewLabel'),
|
|
317
|
+
hint: initText('prompts.setupMode.installNewHint'),
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
value: 'connect-remote',
|
|
321
|
+
label: initText('prompts.setupMode.connectRemoteLabel'),
|
|
322
|
+
hint: initText('prompts.setupMode.connectRemoteHint'),
|
|
216
323
|
},
|
|
217
324
|
{
|
|
218
|
-
value: '
|
|
219
|
-
label: initText('prompts.
|
|
325
|
+
value: 'manage-local',
|
|
326
|
+
label: initText('prompts.setupMode.manageLocalLabel'),
|
|
327
|
+
hint: initText('prompts.setupMode.manageLocalHint'),
|
|
328
|
+
disabled: true,
|
|
220
329
|
},
|
|
221
330
|
],
|
|
222
|
-
initialValue: '
|
|
223
|
-
yesInitialValue: '
|
|
331
|
+
initialValue: 'install-new',
|
|
332
|
+
yesInitialValue: 'install-new',
|
|
224
333
|
required: true,
|
|
225
334
|
},
|
|
226
|
-
apiBaseUrl:
|
|
335
|
+
apiBaseUrl: remoteConnectionOnly({
|
|
227
336
|
type: 'text',
|
|
228
337
|
message: initText('prompts.apiBaseUrl.message'),
|
|
229
338
|
placeholder: initText('prompts.apiBaseUrl.placeholder'),
|
|
230
339
|
required: true,
|
|
231
340
|
validate: validateApiBaseUrl,
|
|
232
341
|
}),
|
|
233
|
-
authType:
|
|
234
|
-
username:
|
|
235
|
-
password:
|
|
236
|
-
accessToken:
|
|
237
|
-
lang:
|
|
238
|
-
|
|
239
|
-
appPort:
|
|
240
|
-
|
|
241
|
-
skipDownload:
|
|
342
|
+
authType: remoteConnectionOnly(EnvAdd.prompts.authType),
|
|
343
|
+
username: remoteConnectionOnly(EnvAdd.prompts.username),
|
|
344
|
+
password: remoteConnectionOnly(EnvAdd.prompts.password),
|
|
345
|
+
accessToken: remoteConnectionOnly(EnvAdd.prompts.accessToken),
|
|
346
|
+
lang: installLikeOnly(Install.appPrompts.lang),
|
|
347
|
+
appPath: installLikeOnly(Install.appPrompts.appPath),
|
|
348
|
+
appPort: installLikeOnly(Install.appPrompts.appPort),
|
|
349
|
+
appPublicPath: installLikeOnly(Install.appPrompts.appPublicPath),
|
|
350
|
+
skipDownload: installNewOnly({
|
|
242
351
|
type: 'boolean',
|
|
243
352
|
message: initText('prompts.skipDownload.message'),
|
|
244
353
|
initialValue: false,
|
|
245
354
|
yesInitialValue: false,
|
|
246
355
|
}),
|
|
247
|
-
source:
|
|
248
|
-
version:
|
|
249
|
-
otherVersion:
|
|
250
|
-
dockerRegistry:
|
|
251
|
-
dockerPlatform:
|
|
252
|
-
dockerSave:
|
|
253
|
-
gitUrl:
|
|
254
|
-
outputDir:
|
|
356
|
+
source: installLikeOnly(Download.prompts.source),
|
|
357
|
+
version: installLikeOnly(Download.prompts.version),
|
|
358
|
+
otherVersion: installLikeOnly(Download.prompts.otherVersion),
|
|
359
|
+
dockerRegistry: installLikeOnly(Download.prompts.dockerRegistry),
|
|
360
|
+
dockerPlatform: installLikeOnly(Download.prompts.dockerPlatform),
|
|
361
|
+
dockerSave: installLikeDownloadExecutionOnly(Download.prompts.dockerSave),
|
|
362
|
+
gitUrl: installLikeOnly(Download.prompts.gitUrl),
|
|
363
|
+
outputDir: installLikeDownloadExecutionOnly({
|
|
255
364
|
...DOWNLOAD_OUTPUT_DIR_PROMPT,
|
|
256
365
|
hidden: (values) => {
|
|
257
366
|
const source = String(values.source ?? '').trim();
|
|
@@ -263,7 +372,8 @@ Prompt modes:
|
|
|
263
372
|
initialValue: (values) => {
|
|
264
373
|
const source = String(values.source ?? '').trim();
|
|
265
374
|
if (source === 'npm' || source === 'git') {
|
|
266
|
-
const
|
|
375
|
+
const appPath = String(values.appPath ?? inferConfiguredAppPathFromLegacyConfig(values) ?? '').trim();
|
|
376
|
+
const appRootPath = String(values.appRootPath ?? '').trim() || (appPath ? deriveConfiguredSourcePath(appPath) : '');
|
|
267
377
|
if (appRootPath) {
|
|
268
378
|
return appRootPath;
|
|
269
379
|
}
|
|
@@ -272,30 +382,35 @@ Prompt modes:
|
|
|
272
382
|
return typeof initialValue === 'function' ? initialValue(values) : String(initialValue ?? '');
|
|
273
383
|
},
|
|
274
384
|
}),
|
|
275
|
-
npmRegistry:
|
|
276
|
-
replace:
|
|
277
|
-
devDependencies:
|
|
278
|
-
build:
|
|
279
|
-
buildDts:
|
|
280
|
-
dbDialect:
|
|
281
|
-
builtinDb:
|
|
282
|
-
builtinDbImage:
|
|
283
|
-
dbHost:
|
|
284
|
-
dbPort:
|
|
285
|
-
dbDatabase:
|
|
286
|
-
dbUser:
|
|
287
|
-
dbPassword:
|
|
288
|
-
dbSchema:
|
|
289
|
-
dbTablePrefix:
|
|
290
|
-
dbUnderscored:
|
|
291
|
-
rootUsername:
|
|
292
|
-
rootEmail:
|
|
293
|
-
rootPassword:
|
|
294
|
-
rootNickname:
|
|
385
|
+
npmRegistry: installLikeOnly(Download.prompts.npmRegistry),
|
|
386
|
+
replace: installLikeDownloadExecutionOnly(Download.prompts.replace),
|
|
387
|
+
devDependencies: installLikeDownloadExecutionOnly(Download.prompts.devDependencies),
|
|
388
|
+
build: installLikeDownloadExecutionOnly(Download.prompts.build),
|
|
389
|
+
buildDts: installLikeDownloadExecutionOnly(Download.prompts.buildDts),
|
|
390
|
+
dbDialect: installLikeOnly(Install.dbPrompts.dbDialect),
|
|
391
|
+
builtinDb: installLikeOnly(Install.dbPrompts.builtinDb),
|
|
392
|
+
builtinDbImage: installLikeOnly(Install.dbPrompts.builtinDbImage),
|
|
393
|
+
dbHost: installLikeOnly(Install.dbPrompts.dbHost),
|
|
394
|
+
dbPort: installLikeOnly(Install.dbPrompts.dbPort),
|
|
395
|
+
dbDatabase: installLikeOnly(Install.dbPrompts.dbDatabase),
|
|
396
|
+
dbUser: installLikeOnly(Install.dbPrompts.dbUser),
|
|
397
|
+
dbPassword: installLikeOnly(Install.dbPrompts.dbPassword),
|
|
398
|
+
dbSchema: installLikeOnly(Install.dbPrompts.dbSchema),
|
|
399
|
+
dbTablePrefix: installLikeOnly(Install.dbPrompts.dbTablePrefix),
|
|
400
|
+
dbUnderscored: installLikeOnly(Install.dbPrompts.dbUnderscored),
|
|
401
|
+
rootUsername: installNewOnly(Install.rootUserPrompts.rootUsername),
|
|
402
|
+
rootEmail: installNewOnly(Install.rootUserPrompts.rootEmail),
|
|
403
|
+
rootPassword: installNewOnly(Install.rootUserPrompts.rootPassword),
|
|
404
|
+
rootNickname: installNewOnly(Install.rootUserPrompts.rootNickname),
|
|
405
|
+
installAuthType: installConnectionAuthTypePrompt,
|
|
406
|
+
installUsername: installConnectionUsernamePrompt,
|
|
407
|
+
installPassword: installConnectionPasswordPrompt,
|
|
408
|
+
installAccessToken: installConnectionAccessTokenPrompt,
|
|
295
409
|
};
|
|
296
|
-
buildPromptCatalog(flags) {
|
|
410
|
+
buildPromptCatalog(flags, options) {
|
|
297
411
|
const prompts = {
|
|
298
412
|
...Init.prompts,
|
|
413
|
+
installApiBaseUrl: createInstallConnectionApiBaseUrlPrompt(options.defaultApiHost),
|
|
299
414
|
};
|
|
300
415
|
if (flags['skip-auth']) {
|
|
301
416
|
const accessTokenPrompt = {
|
|
@@ -310,9 +425,24 @@ Prompt modes:
|
|
|
310
425
|
...EnvAdd.prompts.password,
|
|
311
426
|
hidden: () => true,
|
|
312
427
|
};
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
428
|
+
const installAccessTokenPrompt = {
|
|
429
|
+
...installConnectionAccessTokenPrompt,
|
|
430
|
+
hidden: () => true,
|
|
431
|
+
};
|
|
432
|
+
const installUsernamePrompt = {
|
|
433
|
+
...installConnectionUsernamePrompt,
|
|
434
|
+
hidden: () => true,
|
|
435
|
+
};
|
|
436
|
+
const installPasswordPrompt = {
|
|
437
|
+
...installConnectionPasswordPrompt,
|
|
438
|
+
hidden: () => true,
|
|
439
|
+
};
|
|
440
|
+
prompts.username = remoteConnectionOnly(usernamePrompt);
|
|
441
|
+
prompts.password = remoteConnectionOnly(passwordPrompt);
|
|
442
|
+
prompts.accessToken = remoteConnectionOnly(accessTokenPrompt);
|
|
443
|
+
prompts.installUsername = installUsernamePrompt;
|
|
444
|
+
prompts.installPassword = installPasswordPrompt;
|
|
445
|
+
prompts.installAccessToken = installAccessTokenPrompt;
|
|
316
446
|
}
|
|
317
447
|
return prompts;
|
|
318
448
|
}
|
|
@@ -320,13 +450,17 @@ Prompt modes:
|
|
|
320
450
|
static flags = {
|
|
321
451
|
yes: Flags.boolean({
|
|
322
452
|
char: 'y',
|
|
323
|
-
description: 'Skip prompts and
|
|
453
|
+
description: 'Skip prompts and use flags plus defaults for the selected setup mode. Requires an env name.',
|
|
324
454
|
default: false,
|
|
325
455
|
}),
|
|
326
456
|
env: Flags.string({
|
|
327
457
|
char: 'e',
|
|
328
458
|
description: 'Env name for this setup. Required with --yes and --resume',
|
|
329
459
|
}),
|
|
460
|
+
'setup-mode': Flags.string({
|
|
461
|
+
description: 'Setup mode: install a new app, manage a local app by reusing its database, or connect a remote app',
|
|
462
|
+
options: [...INIT_SETUP_MODES],
|
|
463
|
+
}),
|
|
330
464
|
ui: Flags.boolean({
|
|
331
465
|
description: 'Open the guided setup flow in a local browser form (not valid with --yes)',
|
|
332
466
|
default: false,
|
|
@@ -431,7 +565,9 @@ Prompt modes:
|
|
|
431
565
|
}
|
|
432
566
|
}
|
|
433
567
|
const dynamicInitialValues = await Init.buildDynamicInitialValuesForInstall(normalizedFlags, presetValues);
|
|
434
|
-
const
|
|
568
|
+
const defaultUiHost = await resolveDefaultUiHost();
|
|
569
|
+
const defaultApiHost = await resolveDefaultApiHost();
|
|
570
|
+
const promptCatalog = this.buildPromptCatalog(normalizedFlags, { defaultApiHost });
|
|
435
571
|
if (useBrowserUi) {
|
|
436
572
|
presetValues = await runPromptCatalogWebUI({
|
|
437
573
|
stages: Init.buildWebUiStages(promptCatalog),
|
|
@@ -439,7 +575,7 @@ Prompt modes:
|
|
|
439
575
|
...dynamicInitialValues,
|
|
440
576
|
...presetValues,
|
|
441
577
|
},
|
|
442
|
-
host: normalizedFlags['ui-host']?.trim() ||
|
|
578
|
+
host: normalizedFlags['ui-host']?.trim() || defaultUiHost,
|
|
443
579
|
port: normalizedFlags['ui-port'] ?? 0,
|
|
444
580
|
pageTitle: initText('webUi.pageTitle'),
|
|
445
581
|
documentHeading: initText('webUi.documentHeading'),
|
|
@@ -454,7 +590,12 @@ Prompt modes:
|
|
|
454
590
|
});
|
|
455
591
|
}
|
|
456
592
|
const results = await runPromptCatalog(promptCatalog, {
|
|
457
|
-
initialValues:
|
|
593
|
+
initialValues: {
|
|
594
|
+
...dynamicInitialValues,
|
|
595
|
+
...(presetValues.setupMode === undefined && presetValues.hasNocobase !== undefined
|
|
596
|
+
? { setupMode: normalizeInitSetupMode(presetValues.hasNocobase) }
|
|
597
|
+
: {}),
|
|
598
|
+
},
|
|
458
599
|
values: presetValues,
|
|
459
600
|
yes: normalizedFlags.yes || useBrowserUi || !interactive,
|
|
460
601
|
hooks: {
|
|
@@ -469,21 +610,28 @@ Prompt modes:
|
|
|
469
610
|
},
|
|
470
611
|
command: this,
|
|
471
612
|
});
|
|
472
|
-
const normalizedResults = {
|
|
613
|
+
const normalizedResults = this.normalizeInitResults({
|
|
473
614
|
...pickKeys(presetValues, [
|
|
615
|
+
'defaultApiHost',
|
|
474
616
|
'authType',
|
|
475
617
|
'accessToken',
|
|
476
618
|
'dbSchema',
|
|
477
619
|
'dbTablePrefix',
|
|
478
620
|
'dbUnderscored',
|
|
621
|
+
'installApiBaseUrl',
|
|
622
|
+
'installAuthType',
|
|
623
|
+
'installAccessToken',
|
|
624
|
+
'installUsername',
|
|
625
|
+
'installPassword',
|
|
479
626
|
'skipAuth',
|
|
480
627
|
'username',
|
|
481
628
|
'password',
|
|
482
629
|
]),
|
|
630
|
+
defaultApiHost,
|
|
483
631
|
...results,
|
|
484
|
-
};
|
|
485
|
-
const
|
|
486
|
-
const existingEnv =
|
|
632
|
+
});
|
|
633
|
+
const setupMode = resolveInitSetupMode(normalizedResults);
|
|
634
|
+
const existingEnv = isInstallLikeSetupMode(normalizedResults)
|
|
487
635
|
? await getEnv(String(normalizedResults.appName ?? '').trim(), { scope: resolveDefaultConfigScope() })
|
|
488
636
|
: undefined;
|
|
489
637
|
if (existingEnv && Boolean(normalizedFlags.force)) {
|
|
@@ -495,7 +643,7 @@ Prompt modes:
|
|
|
495
643
|
let managedInstallResults;
|
|
496
644
|
try {
|
|
497
645
|
// oclif explicit registry keys use `:` (e.g. `env:add`); users still type `nb env add`.
|
|
498
|
-
if (
|
|
646
|
+
if (setupMode === 'connect-remote') {
|
|
499
647
|
logInitStage('Connecting to the env');
|
|
500
648
|
printVerbose('Running nb env add');
|
|
501
649
|
await this.config.runCommand('env:add', this.buildEnvAddArgv(normalizedResults));
|
|
@@ -525,6 +673,7 @@ Prompt modes:
|
|
|
525
673
|
envName: String(presetValues.appName ?? '').trim(),
|
|
526
674
|
flags: {
|
|
527
675
|
...flags,
|
|
676
|
+
'app-path': flags['app-path'] ?? '',
|
|
528
677
|
'app-root-path': flags['app-root-path'] ?? '',
|
|
529
678
|
'storage-path': flags['storage-path'] ?? '',
|
|
530
679
|
},
|
|
@@ -558,7 +707,7 @@ Prompt modes:
|
|
|
558
707
|
sectionDescription: initText('webUi.gettingStarted.description'),
|
|
559
708
|
catalog: {
|
|
560
709
|
appName: c.appName,
|
|
561
|
-
|
|
710
|
+
setupMode: c.setupMode,
|
|
562
711
|
},
|
|
563
712
|
},
|
|
564
713
|
{
|
|
@@ -577,9 +726,9 @@ Prompt modes:
|
|
|
577
726
|
sectionDescription: initText('webUi.createNewApp.description'),
|
|
578
727
|
catalog: {
|
|
579
728
|
lang: c.lang,
|
|
580
|
-
|
|
729
|
+
appPath: c.appPath,
|
|
581
730
|
appPort: c.appPort,
|
|
582
|
-
|
|
731
|
+
appPublicPath: c.appPublicPath,
|
|
583
732
|
skipDownload: c.skipDownload,
|
|
584
733
|
},
|
|
585
734
|
},
|
|
@@ -629,24 +778,42 @@ Prompt modes:
|
|
|
629
778
|
rootNickname: c.rootNickname,
|
|
630
779
|
},
|
|
631
780
|
},
|
|
781
|
+
{
|
|
782
|
+
sectionTitle: initText('webUi.connectExistingApp.title'),
|
|
783
|
+
sectionDescription: initText('webUi.connectExistingApp.description'),
|
|
784
|
+
catalog: {
|
|
785
|
+
installApiBaseUrl: c.installApiBaseUrl,
|
|
786
|
+
installAuthType: c.installAuthType,
|
|
787
|
+
installAccessToken: c.installAccessToken,
|
|
788
|
+
},
|
|
789
|
+
},
|
|
632
790
|
];
|
|
633
791
|
}
|
|
634
792
|
buildPresetValuesFromFlags(flags) {
|
|
635
793
|
const preset = {};
|
|
636
794
|
const argv = process.argv.slice(2);
|
|
795
|
+
const setupMode = explicitSetupModeFlag(flags);
|
|
637
796
|
if (flags.env !== undefined && String(flags.env).trim() !== '') {
|
|
638
797
|
preset.appName = String(flags.env).trim();
|
|
639
798
|
}
|
|
799
|
+
if (setupMode) {
|
|
800
|
+
preset.setupMode = setupMode;
|
|
801
|
+
}
|
|
640
802
|
const apiBaseUrl = explicitApiBaseUrlFlag(flags);
|
|
641
803
|
if (apiBaseUrl) {
|
|
642
|
-
preset.
|
|
804
|
+
preset.setupMode ??= 'connect-remote';
|
|
643
805
|
preset.apiBaseUrl = apiBaseUrl;
|
|
806
|
+
preset.installApiBaseUrl = apiBaseUrl;
|
|
644
807
|
}
|
|
645
808
|
else if (flags['default-api-base-url'] !== undefined && String(flags['default-api-base-url']).trim() !== '') {
|
|
646
|
-
|
|
809
|
+
const defaultApiBaseUrl = String(flags['default-api-base-url']).trim();
|
|
810
|
+
preset.apiBaseUrl = defaultApiBaseUrl;
|
|
811
|
+
preset.installApiBaseUrl = defaultApiBaseUrl;
|
|
647
812
|
}
|
|
648
813
|
if (flags['auth-type'] !== undefined && String(flags['auth-type']).trim() !== '') {
|
|
649
|
-
|
|
814
|
+
const authType = String(flags['auth-type']).trim();
|
|
815
|
+
preset.authType = authType;
|
|
816
|
+
preset.installAuthType = authType;
|
|
650
817
|
}
|
|
651
818
|
if (flags['skip-auth']) {
|
|
652
819
|
preset.skipAuth = true;
|
|
@@ -654,16 +821,24 @@ Prompt modes:
|
|
|
654
821
|
const accessToken = String(flags['access-token'] ?? flags.token ?? '');
|
|
655
822
|
if (flags['access-token'] !== undefined || flags.token !== undefined) {
|
|
656
823
|
preset.accessToken = accessToken;
|
|
824
|
+
preset.installAccessToken = accessToken;
|
|
657
825
|
}
|
|
658
826
|
if (flags.username !== undefined) {
|
|
659
|
-
|
|
827
|
+
const username = String(flags.username ?? '').trim();
|
|
828
|
+
preset.username = username;
|
|
829
|
+
preset.installUsername = username;
|
|
660
830
|
}
|
|
661
831
|
if (flags.password !== undefined) {
|
|
662
|
-
|
|
832
|
+
const password = String(flags.password ?? '');
|
|
833
|
+
preset.password = password;
|
|
834
|
+
preset.installPassword = password;
|
|
663
835
|
}
|
|
664
836
|
if (flags.lang !== undefined && String(flags.lang).trim() !== '') {
|
|
665
837
|
preset.lang = String(flags.lang).trim();
|
|
666
838
|
}
|
|
839
|
+
if (flags['app-path'] !== undefined && String(flags['app-path']).trim() !== '') {
|
|
840
|
+
preset.appPath = String(flags['app-path']).trim();
|
|
841
|
+
}
|
|
667
842
|
if (flags['app-root-path'] !== undefined && String(flags['app-root-path']).trim() !== '') {
|
|
668
843
|
preset.appRootPath = String(flags['app-root-path']).trim();
|
|
669
844
|
}
|
|
@@ -673,6 +848,9 @@ Prompt modes:
|
|
|
673
848
|
if (flags['storage-path'] !== undefined && String(flags['storage-path']).trim() !== '') {
|
|
674
849
|
preset.storagePath = String(flags['storage-path']).trim();
|
|
675
850
|
}
|
|
851
|
+
if (flags['app-public-path'] !== undefined && String(flags['app-public-path']).trim() !== '') {
|
|
852
|
+
preset.appPublicPath = String(flags['app-public-path']).trim();
|
|
853
|
+
}
|
|
676
854
|
if (flags['root-username'] !== undefined) {
|
|
677
855
|
preset.rootUsername = String(flags['root-username'] ?? '').trim();
|
|
678
856
|
}
|
|
@@ -772,9 +950,13 @@ Prompt modes:
|
|
|
772
950
|
if (explicitDbHostFlag(flags)) {
|
|
773
951
|
preset.builtinDb = false;
|
|
774
952
|
}
|
|
775
|
-
if (!preset.
|
|
776
|
-
preset.
|
|
953
|
+
if (!preset.setupMode && hasDownloadOverride(flags)) {
|
|
954
|
+
preset.setupMode = 'install-new';
|
|
955
|
+
}
|
|
956
|
+
if (preset.setupMode === 'manage-local') {
|
|
957
|
+
preset.skipDownload = false;
|
|
777
958
|
}
|
|
959
|
+
applyLegacyHasNocobaseAlias(preset);
|
|
778
960
|
return preset;
|
|
779
961
|
}
|
|
780
962
|
hasAgentsDirInCwd() {
|
|
@@ -803,15 +985,25 @@ Prompt modes:
|
|
|
803
985
|
}
|
|
804
986
|
async persistManagedEnvConfig(results, flags = {}) {
|
|
805
987
|
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
988
|
+
const existingEnv = await getEnv(envName, { scope: resolveDefaultConfigScope() });
|
|
806
989
|
const appPort = String(results.appPort ?? '').trim();
|
|
990
|
+
const appPublicPath = String(results.appPublicPath ?? '').trim();
|
|
807
991
|
const source = String(results.source ?? '').trim();
|
|
808
992
|
const version = resolveInitDownloadVersion(results);
|
|
809
993
|
const dockerRegistry = String(results.dockerRegistry ?? '').trim();
|
|
810
994
|
const dockerPlatform = String(results.dockerPlatform ?? '').trim();
|
|
811
995
|
const gitUrl = String(results.gitUrl ?? '').trim();
|
|
812
996
|
const npmRegistry = String(results.npmRegistry ?? '').trim();
|
|
997
|
+
const appPath = String(results.appPath ?? '').trim() ||
|
|
998
|
+
inferConfiguredAppPathFromLegacyConfig({
|
|
999
|
+
appRootPath: results.appRootPath,
|
|
1000
|
+
storagePath: results.storagePath,
|
|
1001
|
+
}) ||
|
|
1002
|
+
'';
|
|
813
1003
|
const appRootPath = String(results.appRootPath ?? '').trim();
|
|
814
1004
|
const storagePath = String(results.storagePath ?? '').trim();
|
|
1005
|
+
const derivedAppRootPath = appPath ? deriveConfiguredSourcePath(appPath) : '';
|
|
1006
|
+
const derivedStoragePath = appPath ? deriveConfiguredStoragePath(appPath) : '';
|
|
815
1007
|
const dbDialect = String(results.dbDialect ?? '').trim();
|
|
816
1008
|
const builtinDbImage = String(results.builtinDbImage ?? '').trim();
|
|
817
1009
|
const dbHost = String(results.dbHost ?? '').trim();
|
|
@@ -826,15 +1018,19 @@ Prompt modes:
|
|
|
826
1018
|
const authUsername = authType === 'basic' ? String(results.username ?? results.rootUsername ?? '').trim() : '';
|
|
827
1019
|
const accessToken = String(results.accessToken ?? '');
|
|
828
1020
|
const skipDownload = results.skipDownload === true;
|
|
1021
|
+
const appKey = resolveManagedAppKey(results.appKey ?? existingEnv?.config.appKey);
|
|
1022
|
+
const timeZone = resolveManagedTimeZone(results.timeZone ?? existingEnv?.config.timezone);
|
|
829
1023
|
const builtinDb = explicitDbHostFlag(flags)
|
|
830
1024
|
? false
|
|
831
1025
|
: results.builtinDb === undefined
|
|
832
1026
|
? undefined
|
|
833
1027
|
: Boolean(results.builtinDb);
|
|
1028
|
+
results.appKey = appKey;
|
|
1029
|
+
results.timeZone = timeZone;
|
|
834
1030
|
await upsertEnv(envName, {
|
|
835
1031
|
...(source === 'docker'
|
|
836
1032
|
? { kind: 'docker' }
|
|
837
|
-
: source || appRootPath
|
|
1033
|
+
: source || appPath || appRootPath
|
|
838
1034
|
? { kind: 'local' }
|
|
839
1035
|
: appPort
|
|
840
1036
|
? { kind: 'http' }
|
|
@@ -849,9 +1045,13 @@ Prompt modes:
|
|
|
849
1045
|
...(dockerPlatform ? { dockerPlatform } : {}),
|
|
850
1046
|
...(gitUrl ? { gitUrl } : {}),
|
|
851
1047
|
...(npmRegistry ? { npmRegistry } : {}),
|
|
852
|
-
...(
|
|
853
|
-
...(
|
|
1048
|
+
...(appPath ? { appPath } : {}),
|
|
1049
|
+
...(appRootPath && !areConfiguredPathsEquivalent(appRootPath, derivedAppRootPath) ? { appRootPath } : {}),
|
|
1050
|
+
...(storagePath && !areConfiguredPathsEquivalent(storagePath, derivedStoragePath) ? { storagePath } : {}),
|
|
854
1051
|
...(appPort ? { appPort } : {}),
|
|
1052
|
+
...(appPublicPath ? { appPublicPath } : {}),
|
|
1053
|
+
...(appKey ? { appKey } : {}),
|
|
1054
|
+
...(timeZone ? { timezone: timeZone } : {}),
|
|
855
1055
|
...(!skipDownload && results.devDependencies !== undefined
|
|
856
1056
|
? { devDependencies: Boolean(results.devDependencies) }
|
|
857
1057
|
: {}),
|
|
@@ -901,8 +1101,11 @@ Prompt modes:
|
|
|
901
1101
|
const processArgv = process.argv.slice(2);
|
|
902
1102
|
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
903
1103
|
const source = String(results.source ?? '').trim();
|
|
904
|
-
const
|
|
905
|
-
|
|
1104
|
+
const setupMode = resolveInitSetupMode({
|
|
1105
|
+
setupMode: results.setupMode ?? flags['setup-mode'],
|
|
1106
|
+
hasNocobase: results.hasNocobase,
|
|
1107
|
+
});
|
|
1108
|
+
const skipDownload = setupMode === 'manage-local' ? false : Boolean(flags['skip-download']) || results.skipDownload === true;
|
|
906
1109
|
const apiBaseUrl = String(results.apiBaseUrl ?? '').trim();
|
|
907
1110
|
const authType = String(results.authType ?? '').trim();
|
|
908
1111
|
const accessToken = String(results.accessToken ?? '');
|
|
@@ -915,7 +1118,7 @@ Prompt modes:
|
|
|
915
1118
|
if (flags.verbose) {
|
|
916
1119
|
argv.push('--verbose');
|
|
917
1120
|
}
|
|
918
|
-
if (
|
|
1121
|
+
if (setupMode === 'connect-remote' && apiBaseUrl) {
|
|
919
1122
|
argv.push('--api-base-url', apiBaseUrl);
|
|
920
1123
|
}
|
|
921
1124
|
if (authType) {
|
|
@@ -937,8 +1140,17 @@ Prompt modes:
|
|
|
937
1140
|
if (lang) {
|
|
938
1141
|
argv.push('--lang', lang);
|
|
939
1142
|
}
|
|
1143
|
+
const appPath = String(results.appPath ?? '').trim() ||
|
|
1144
|
+
inferConfiguredAppPathFromLegacyConfig({
|
|
1145
|
+
appRootPath: results.appRootPath,
|
|
1146
|
+
storagePath: results.storagePath,
|
|
1147
|
+
}) ||
|
|
1148
|
+
'';
|
|
1149
|
+
if (appPath) {
|
|
1150
|
+
argv.push('--app-path', appPath);
|
|
1151
|
+
}
|
|
940
1152
|
const appRootPath = String(results.appRootPath ?? '').trim();
|
|
941
|
-
if (appRootPath) {
|
|
1153
|
+
if (appRootPath && (!appPath || !areConfiguredPathsEquivalent(appRootPath, deriveConfiguredSourcePath(appPath)))) {
|
|
942
1154
|
argv.push('--app-root-path', appRootPath);
|
|
943
1155
|
}
|
|
944
1156
|
const appPort = String(results.appPort ?? '').trim();
|
|
@@ -946,9 +1158,13 @@ Prompt modes:
|
|
|
946
1158
|
argv.push('--app-port', appPort);
|
|
947
1159
|
}
|
|
948
1160
|
const storagePath = String(results.storagePath ?? '').trim();
|
|
949
|
-
if (storagePath) {
|
|
1161
|
+
if (storagePath && (!appPath || !areConfiguredPathsEquivalent(storagePath, deriveConfiguredStoragePath(appPath)))) {
|
|
950
1162
|
argv.push('--storage-path', storagePath);
|
|
951
1163
|
}
|
|
1164
|
+
const appPublicPath = String(results.appPublicPath ?? '').trim();
|
|
1165
|
+
if (appPublicPath) {
|
|
1166
|
+
argv.push('--app-public-path', appPublicPath);
|
|
1167
|
+
}
|
|
952
1168
|
if (flags.force) {
|
|
953
1169
|
argv.push('--force');
|
|
954
1170
|
}
|
|
@@ -1054,20 +1270,21 @@ Prompt modes:
|
|
|
1054
1270
|
if (results.dbUnderscored !== undefined) {
|
|
1055
1271
|
argv.push(results.dbUnderscored ? '--db-underscored' : '--no-db-underscored');
|
|
1056
1272
|
}
|
|
1273
|
+
const includeRootUser = setupMode === 'install-new';
|
|
1057
1274
|
const rootUsername = String(results.rootUsername ?? '').trim();
|
|
1058
|
-
if (rootUsername) {
|
|
1275
|
+
if (includeRootUser && rootUsername) {
|
|
1059
1276
|
argv.push('--root-username', rootUsername);
|
|
1060
1277
|
}
|
|
1061
1278
|
const rootEmail = String(results.rootEmail ?? '').trim();
|
|
1062
|
-
if (rootEmail) {
|
|
1279
|
+
if (includeRootUser && rootEmail) {
|
|
1063
1280
|
argv.push('--root-email', rootEmail);
|
|
1064
1281
|
}
|
|
1065
1282
|
const rootPassword = String(results.rootPassword ?? '');
|
|
1066
|
-
if (rootPassword) {
|
|
1283
|
+
if (includeRootUser && rootPassword) {
|
|
1067
1284
|
argv.push('--root-password', rootPassword);
|
|
1068
1285
|
}
|
|
1069
1286
|
const rootNickname = String(results.rootNickname ?? '').trim();
|
|
1070
|
-
if (rootNickname) {
|
|
1287
|
+
if (includeRootUser && rootNickname) {
|
|
1071
1288
|
argv.push('--root-nickname', rootNickname);
|
|
1072
1289
|
}
|
|
1073
1290
|
return argv;
|
|
@@ -1079,8 +1296,12 @@ Prompt modes:
|
|
|
1079
1296
|
}
|
|
1080
1297
|
const envName = String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME;
|
|
1081
1298
|
argv.push('--env', envName);
|
|
1299
|
+
const setupMode = resolveInitSetupMode(results);
|
|
1300
|
+
if (setupMode === 'manage-local') {
|
|
1301
|
+
argv.push('--setup-mode', 'manage-local');
|
|
1302
|
+
}
|
|
1082
1303
|
const source = String(results.source ?? '').trim();
|
|
1083
|
-
const skipDownload = Boolean(flags['skip-download']) || results.skipDownload === true;
|
|
1304
|
+
const skipDownload = setupMode === 'manage-local' ? false : Boolean(flags['skip-download']) || results.skipDownload === true;
|
|
1084
1305
|
if (source) {
|
|
1085
1306
|
argv.push('--source', source);
|
|
1086
1307
|
}
|
|
@@ -1109,7 +1330,14 @@ Prompt modes:
|
|
|
1109
1330
|
}
|
|
1110
1331
|
else {
|
|
1111
1332
|
const outputDir = String(results.outputDir ?? '').trim();
|
|
1112
|
-
|
|
1333
|
+
const appPath = String(results.appPath ?? '').trim() ||
|
|
1334
|
+
inferConfiguredAppPathFromLegacyConfig({
|
|
1335
|
+
appRootPath: results.appRootPath,
|
|
1336
|
+
storagePath: results.storagePath,
|
|
1337
|
+
}) ||
|
|
1338
|
+
'';
|
|
1339
|
+
const expectedOutputDir = String(results.appRootPath ?? '').trim() || (appPath ? deriveConfiguredSourcePath(appPath) : '');
|
|
1340
|
+
if (outputDir && outputDir !== expectedOutputDir) {
|
|
1113
1341
|
argv.push('--output-dir', outputDir);
|
|
1114
1342
|
}
|
|
1115
1343
|
if (results.devDependencies) {
|
|
@@ -1134,14 +1362,20 @@ Prompt modes:
|
|
|
1134
1362
|
}
|
|
1135
1363
|
buildResumeInstallArgv(flags) {
|
|
1136
1364
|
const preset = this.buildPresetValuesFromFlags(flags);
|
|
1365
|
+
const setupMode = resolveInitSetupMode(preset);
|
|
1137
1366
|
if (flags.yes) {
|
|
1138
1367
|
preset.lang ??= yesInitialValue(Install.appPrompts.lang, 'en-US');
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1368
|
+
if (setupMode === 'install-new') {
|
|
1369
|
+
preset.rootUsername ??= yesInitialValue(Install.rootUserPrompts.rootUsername, 'nocobase');
|
|
1370
|
+
preset.rootEmail ??= yesInitialValue(Install.rootUserPrompts.rootEmail, 'admin@nocobase.com');
|
|
1371
|
+
preset.rootPassword ??= yesInitialValue(Install.rootUserPrompts.rootPassword, 'admin123');
|
|
1372
|
+
preset.rootNickname ??= yesInitialValue(Install.rootUserPrompts.rootNickname, 'Super Admin');
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
if (setupMode === 'manage-local') {
|
|
1376
|
+
preset.skipDownload = false;
|
|
1143
1377
|
}
|
|
1144
|
-
if (!flags['skip-download']) {
|
|
1378
|
+
else if (!flags['skip-download']) {
|
|
1145
1379
|
preset.replace ??= true;
|
|
1146
1380
|
}
|
|
1147
1381
|
return this.buildInstallArgv(preset, flags, {
|
|
@@ -1149,4 +1383,40 @@ Prompt modes:
|
|
|
1149
1383
|
resume: true,
|
|
1150
1384
|
});
|
|
1151
1385
|
}
|
|
1386
|
+
normalizeInitResults(results) {
|
|
1387
|
+
const normalized = { ...results };
|
|
1388
|
+
const setupMode = resolveInitSetupMode(normalized);
|
|
1389
|
+
const defaultApiHost = normalizeConnectionString(normalized.defaultApiHost) || '127.0.0.1';
|
|
1390
|
+
if (setupMode === 'install-new') {
|
|
1391
|
+
normalized.apiBaseUrl =
|
|
1392
|
+
normalizeConnectionString(normalized.installApiBaseUrl) ||
|
|
1393
|
+
deriveInstallConnectionApiBaseUrl(normalized, defaultApiHost);
|
|
1394
|
+
normalized.authType = normalizeConnectionString(normalized.installAuthType) || 'oauth';
|
|
1395
|
+
normalized.username =
|
|
1396
|
+
normalized.authType === 'basic'
|
|
1397
|
+
? normalizeConnectionString(normalized.installUsername) || normalizeConnectionString(normalized.rootUsername)
|
|
1398
|
+
: normalizeConnectionString(normalized.installUsername);
|
|
1399
|
+
normalized.password =
|
|
1400
|
+
normalized.authType === 'basic'
|
|
1401
|
+
? String(normalized.installPassword ?? '') || String(normalized.rootPassword ?? '')
|
|
1402
|
+
: String(normalized.installPassword ?? '');
|
|
1403
|
+
normalized.accessToken = String(normalized.installAccessToken ?? '');
|
|
1404
|
+
}
|
|
1405
|
+
normalized.setupMode = setupMode;
|
|
1406
|
+
applyLegacyHasNocobaseAlias(normalized);
|
|
1407
|
+
if (setupMode === 'manage-local') {
|
|
1408
|
+
normalized.skipDownload = false;
|
|
1409
|
+
delete normalized.rootUsername;
|
|
1410
|
+
delete normalized.rootEmail;
|
|
1411
|
+
delete normalized.rootPassword;
|
|
1412
|
+
delete normalized.rootNickname;
|
|
1413
|
+
}
|
|
1414
|
+
delete normalized.installApiBaseUrl;
|
|
1415
|
+
delete normalized.installAuthType;
|
|
1416
|
+
delete normalized.installUsername;
|
|
1417
|
+
delete normalized.installPassword;
|
|
1418
|
+
delete normalized.installAccessToken;
|
|
1419
|
+
delete normalized.defaultApiHost;
|
|
1420
|
+
return normalized;
|
|
1421
|
+
}
|
|
1152
1422
|
}
|