@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/lib/auth-store.js
CHANGED
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { promises as fs } from 'node:fs';
|
|
10
10
|
import path from 'node:path';
|
|
11
|
+
import { resolveAppPublicPath } from './app-public-path.js';
|
|
11
12
|
import { resolveCliHomeDir, resolveConfiguredEnvPath, resolveEnvRelativePath } from './cli-home.js';
|
|
12
13
|
import { normalizeCliLocale } from './cli-locale.js';
|
|
14
|
+
import { inferConfiguredAppPathFromLegacyConfig, resolveConfiguredAppPath, resolveConfiguredSourcePath, resolveConfiguredStoragePath, } from './env-paths.js';
|
|
13
15
|
import { cleanupCurrentSessionAfterEnvRemoval, resolveEffectiveCurrentEnv, setSessionCurrentEnv, } from './session-store.js';
|
|
14
16
|
function normalizeStoredEnvKind(value) {
|
|
15
17
|
const kind = String(value ?? '').trim();
|
|
@@ -32,6 +34,13 @@ function normalizeOptionalCliLocale(value) {
|
|
|
32
34
|
}
|
|
33
35
|
return normalizeCliLocale(normalized);
|
|
34
36
|
}
|
|
37
|
+
function normalizeOptionalCliUpdatePolicy(value) {
|
|
38
|
+
const normalized = normalizeOptionalString(value);
|
|
39
|
+
if (normalized === 'prompt' || normalized === 'auto' || normalized === 'off') {
|
|
40
|
+
return normalized;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
35
44
|
export function readEnvApiBaseUrl(config) {
|
|
36
45
|
if (!config) {
|
|
37
46
|
return undefined;
|
|
@@ -55,7 +64,7 @@ export function resolveEnvKind(config) {
|
|
|
55
64
|
if (source === 'npm' || source === 'git' || source === 'local') {
|
|
56
65
|
return 'local';
|
|
57
66
|
}
|
|
58
|
-
if (String(config.appRootPath ?? '').trim()) {
|
|
67
|
+
if (String(config.appPath ?? '').trim() || String(config.appRootPath ?? '').trim()) {
|
|
59
68
|
return 'local';
|
|
60
69
|
}
|
|
61
70
|
if (readEnvApiBaseUrl(config) || config.auth) {
|
|
@@ -74,15 +83,32 @@ function normalizeEnvConfigEntry(entry) {
|
|
|
74
83
|
...rest,
|
|
75
84
|
...(normalizedKind ? { kind: normalizedKind } : {}),
|
|
76
85
|
...(apiBaseUrl !== undefined ? { apiBaseUrl } : {}),
|
|
86
|
+
...(normalizeOptionalString(entry.appPublicPath) ? { appPublicPath: resolveAppPublicPath(entry.appPublicPath) } : {}),
|
|
77
87
|
};
|
|
78
88
|
}
|
|
79
89
|
function normalizeAuthConfig(config) {
|
|
80
90
|
const settings = config.settings ?? {};
|
|
81
91
|
const locale = normalizeOptionalCliLocale(settings.locale);
|
|
92
|
+
const defaultUiHost = normalizeOptionalString(settings.init?.defaultUiHost);
|
|
93
|
+
const defaultApiHost = normalizeOptionalString(settings.init?.defaultApiHost);
|
|
94
|
+
const updatePolicy = normalizeOptionalCliUpdatePolicy(settings.update?.policy);
|
|
95
|
+
const logRetentionDays = typeof settings.log?.retentionDays === 'number' && Number.isInteger(settings.log.retentionDays)
|
|
96
|
+
? settings.log.retentionDays
|
|
97
|
+
: undefined;
|
|
98
|
+
const logEnabled = typeof settings.log?.enabled === 'boolean' ? settings.log.enabled : undefined;
|
|
82
99
|
return {
|
|
83
100
|
name: config.name || config.dockerResourcePrefix,
|
|
84
101
|
settings: {
|
|
85
102
|
...(locale ? { locale } : {}),
|
|
103
|
+
...(defaultUiHost || defaultApiHost
|
|
104
|
+
? {
|
|
105
|
+
init: {
|
|
106
|
+
...(defaultUiHost ? { defaultUiHost } : {}),
|
|
107
|
+
...(defaultApiHost ? { defaultApiHost } : {}),
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
: {}),
|
|
111
|
+
...(updatePolicy ? { update: { policy: updatePolicy } } : {}),
|
|
86
112
|
...(settings.license?.pkgUrl ? { license: { pkgUrl: normalizeOptionalString(settings.license.pkgUrl) } } : {}),
|
|
87
113
|
...(settings.docker?.network || settings.docker?.containerPrefix
|
|
88
114
|
? {
|
|
@@ -94,15 +120,39 @@ function normalizeAuthConfig(config) {
|
|
|
94
120
|
},
|
|
95
121
|
}
|
|
96
122
|
: {}),
|
|
97
|
-
...(settings.bin?.docker || settings.bin?.git || settings.bin?.yarn
|
|
123
|
+
...(settings.bin?.docker || settings.bin?.caddy || settings.bin?.git || settings.bin?.nginx || settings.bin?.yarn
|
|
98
124
|
? {
|
|
99
125
|
bin: {
|
|
100
126
|
...(settings.bin?.docker ? { docker: normalizeOptionalString(settings.bin.docker) } : {}),
|
|
127
|
+
...(settings.bin?.caddy ? { caddy: normalizeOptionalString(settings.bin.caddy) } : {}),
|
|
101
128
|
...(settings.bin?.git ? { git: normalizeOptionalString(settings.bin.git) } : {}),
|
|
129
|
+
...(settings.bin?.nginx ? { nginx: normalizeOptionalString(settings.bin.nginx) } : {}),
|
|
102
130
|
...(settings.bin?.yarn ? { yarn: normalizeOptionalString(settings.bin.yarn) } : {}),
|
|
103
131
|
},
|
|
104
132
|
}
|
|
105
133
|
: {}),
|
|
134
|
+
...(settings.proxy?.nbCliRoot ||
|
|
135
|
+
settings.proxy?.upstreamHost ||
|
|
136
|
+
settings.proxy?.host
|
|
137
|
+
? {
|
|
138
|
+
proxy: {
|
|
139
|
+
...(settings.proxy?.nbCliRoot ? { nbCliRoot: normalizeOptionalString(settings.proxy.nbCliRoot) } : {}),
|
|
140
|
+
...(settings.proxy?.upstreamHost || settings.proxy?.host
|
|
141
|
+
? {
|
|
142
|
+
upstreamHost: normalizeOptionalString(settings.proxy?.upstreamHost ?? settings.proxy.host),
|
|
143
|
+
}
|
|
144
|
+
: {}),
|
|
145
|
+
},
|
|
146
|
+
}
|
|
147
|
+
: {}),
|
|
148
|
+
...(logEnabled !== undefined || logRetentionDays !== undefined
|
|
149
|
+
? {
|
|
150
|
+
log: {
|
|
151
|
+
...(logEnabled !== undefined ? { enabled: logEnabled } : {}),
|
|
152
|
+
...(logRetentionDays !== undefined ? { retentionDays: logRetentionDays } : {}),
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
: {}),
|
|
106
156
|
},
|
|
107
157
|
lastEnv: config.lastEnv ||
|
|
108
158
|
config.currentEnv ||
|
|
@@ -196,7 +246,29 @@ export class Env {
|
|
|
196
246
|
return configuredPath;
|
|
197
247
|
}
|
|
198
248
|
}
|
|
199
|
-
|
|
249
|
+
const legacyPath = resolveConfiguredEnvPath(this.config.appRootPath);
|
|
250
|
+
if (legacyPath) {
|
|
251
|
+
return legacyPath;
|
|
252
|
+
}
|
|
253
|
+
return this.kind === 'local' ? this.sourcePath : resolveEnvRelativePath('.');
|
|
254
|
+
}
|
|
255
|
+
get appPath() {
|
|
256
|
+
if (this.kind === 'ssh') {
|
|
257
|
+
const configuredPath = String(this.config.appPath ?? inferConfiguredAppPathFromLegacyConfig(this.config) ?? '').trim();
|
|
258
|
+
if (configuredPath) {
|
|
259
|
+
return configuredPath;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return resolveConfiguredAppPath(this.config) ?? resolveEnvRelativePath('.');
|
|
263
|
+
}
|
|
264
|
+
get sourcePath() {
|
|
265
|
+
if (this.kind === 'ssh') {
|
|
266
|
+
const configuredPath = String(this.config.appRootPath ?? '').trim();
|
|
267
|
+
if (configuredPath) {
|
|
268
|
+
return configuredPath;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return resolveConfiguredSourcePath(this.config) ?? path.join(this.appPath, 'source');
|
|
200
272
|
}
|
|
201
273
|
get storagePath() {
|
|
202
274
|
if (this.kind === 'ssh') {
|
|
@@ -205,7 +277,13 @@ export class Env {
|
|
|
205
277
|
return configuredPath;
|
|
206
278
|
}
|
|
207
279
|
}
|
|
208
|
-
|
|
280
|
+
const resolvedStoragePath = resolveConfiguredStoragePath(this.config);
|
|
281
|
+
if (resolvedStoragePath) {
|
|
282
|
+
return resolvedStoragePath;
|
|
283
|
+
}
|
|
284
|
+
return this.kind === 'local' || this.kind === 'docker'
|
|
285
|
+
? path.join(this.appPath, 'storage')
|
|
286
|
+
: resolveEnvRelativePath('.');
|
|
209
287
|
}
|
|
210
288
|
get appPort() {
|
|
211
289
|
return this.config.appPort;
|
|
@@ -221,6 +299,8 @@ export class Env {
|
|
|
221
299
|
out[key] = String(value);
|
|
222
300
|
};
|
|
223
301
|
put('APP_PORT', this.appPort);
|
|
302
|
+
put('APP_PUBLIC_PATH', this.config.appPublicPath ? resolveAppPublicPath(this.config.appPublicPath) : undefined);
|
|
303
|
+
put('CDN_BASE_URL', this.config.cdnBaseUrl);
|
|
224
304
|
put('APP_KEY', this.config.appKey);
|
|
225
305
|
put('TZ', this.config.timezone);
|
|
226
306
|
put('DB_DIALECT', this.config.dbDialect);
|
|
@@ -349,6 +429,39 @@ export async function updateEnvConnection(envName, updates, options = {}) {
|
|
|
349
429
|
};
|
|
350
430
|
}, options);
|
|
351
431
|
}
|
|
432
|
+
export async function replaceEnvConfig(envName, config, options = {}) {
|
|
433
|
+
await writeEnv(envName, (previous) => {
|
|
434
|
+
if (!previous) {
|
|
435
|
+
throw new Error(`Env "${envName}" is not configured`);
|
|
436
|
+
}
|
|
437
|
+
const { apiBaseUrl: _apiBaseUrl, baseUrl: _baseUrl, apibaseUrl: _legacyApiBaseUrl, accessToken, authType, authUsername, ...rest } = config;
|
|
438
|
+
const nextApiBaseUrl = readEnvApiBaseUrl(config);
|
|
439
|
+
const previousApiBaseUrl = readEnvApiBaseUrl(previous);
|
|
440
|
+
const baseUrlChanged = previousApiBaseUrl !== nextApiBaseUrl;
|
|
441
|
+
const previousAuthType = resolveConfiguredAuthType(previous);
|
|
442
|
+
const nextAuthType = normalizeConfiguredAuthType(authType) ?? (accessToken ? 'token' : undefined);
|
|
443
|
+
const nextAuthUsername = nextAuthType === 'basic' ? normalizeOptionalString(authUsername) : undefined;
|
|
444
|
+
const nextAuth = accessToken
|
|
445
|
+
? {
|
|
446
|
+
type: 'token',
|
|
447
|
+
accessToken,
|
|
448
|
+
}
|
|
449
|
+
: nextAuthType === 'oauth' && !baseUrlChanged && previous?.auth?.type === 'oauth'
|
|
450
|
+
? previous.auth
|
|
451
|
+
: undefined;
|
|
452
|
+
const authChanged = !areAuthConfigsEquivalent(previous?.auth, nextAuth);
|
|
453
|
+
const authTypeChanged = previousAuthType !== nextAuthType;
|
|
454
|
+
const authUsernameChanged = previous?.authUsername !== nextAuthUsername;
|
|
455
|
+
return {
|
|
456
|
+
...rest,
|
|
457
|
+
...(nextApiBaseUrl !== undefined ? { apiBaseUrl: nextApiBaseUrl } : {}),
|
|
458
|
+
...(nextAuthType ? { authType: nextAuthType } : {}),
|
|
459
|
+
...(nextAuthUsername ? { authUsername: nextAuthUsername } : {}),
|
|
460
|
+
...(nextAuth ? { auth: nextAuth } : {}),
|
|
461
|
+
runtime: baseUrlChanged || authChanged || authTypeChanged || authUsernameChanged ? undefined : previous?.runtime,
|
|
462
|
+
};
|
|
463
|
+
}, options);
|
|
464
|
+
}
|
|
352
465
|
export async function setEnvOauthSession(envName, auth, options = {}) {
|
|
353
466
|
await writeEnv(envName, (previous) => ({
|
|
354
467
|
...previous,
|
|
@@ -366,6 +479,17 @@ export async function setEnvRuntime(envName, runtime, options = {}) {
|
|
|
366
479
|
};
|
|
367
480
|
await saveAuthConfig(config, options);
|
|
368
481
|
}
|
|
482
|
+
export async function clearEnvRootSetup(envName, options = {}) {
|
|
483
|
+
const config = await loadExactAuthConfig(options);
|
|
484
|
+
const current = config.envs[envName];
|
|
485
|
+
if (!current) {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
const { rootUsername: _rootUsername, rootEmail: _rootEmail, rootPassword: _rootPassword, rootNickname: _rootNickname, ...rest } = current;
|
|
489
|
+
config.envs[envName] = rest;
|
|
490
|
+
await saveAuthConfig(config, options);
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
369
493
|
export async function removeEnv(envName, options = {}) {
|
|
370
494
|
const config = await loadExactAuthConfig(options);
|
|
371
495
|
if (!config.envs[envName]) {
|
package/dist/lib/backup.js
CHANGED
|
@@ -62,14 +62,14 @@ export async function resolveBackupTargetEnv(requestedEnv) {
|
|
|
62
62
|
const { envs } = await listEnvs({ scope });
|
|
63
63
|
const configuredEnvNames = Object.keys(envs);
|
|
64
64
|
if (!configuredEnvNames.length) {
|
|
65
|
-
throw new Error('No env is configured. Run `nb
|
|
65
|
+
throw new Error('No env is configured. Run `nb init --ui` first.');
|
|
66
66
|
}
|
|
67
67
|
if (requestedEnv?.trim()) {
|
|
68
|
-
throw new Error(`Env "${envName}" is not configured. Run \`nb env
|
|
68
|
+
throw new Error(`Env "${envName}" is not configured. Run \`nb init --ui --env ${envName}\` first.`);
|
|
69
69
|
}
|
|
70
70
|
throw new Error([
|
|
71
71
|
`Current env "${envName}" is not configured.`,
|
|
72
|
-
|
|
72
|
+
`Switch to an existing env with \`nb env use <name>\`, or run \`nb init --ui --env ${envName}\` to create or connect it.`,
|
|
73
73
|
].join('\n'));
|
|
74
74
|
}
|
|
75
75
|
export async function ensureBackupRuntimeCommands(params) {
|
package/dist/lib/bootstrap.js
CHANGED
|
@@ -254,25 +254,31 @@ export function formatSwaggerSchemaError(response, context) {
|
|
|
254
254
|
})
|
|
255
255
|
.join('\n');
|
|
256
256
|
const envLabel = context.envName ? ` for env "${context.envName}"` : '';
|
|
257
|
+
const tokenHint = context.envName
|
|
258
|
+
? `Update the API key with \`nb env update ${context.envName} --token <api-key>\`, log in with \`nb env auth ${context.envName}\`, or rerun the command with \`--access-token <api-key>\`.`
|
|
259
|
+
: 'Update the API key with `nb env update <name> --token <api-key>`, log in with `nb env auth <name>`, or rerun the command with `--access-token <api-key>`.';
|
|
257
260
|
const commandHint = context.commandToken
|
|
258
|
-
? `If \`${context.commandToken}\` is a runtime command,
|
|
259
|
-
: 'Run `nb --help` to inspect built-in commands, then
|
|
261
|
+
? `If \`${context.commandToken}\` is a runtime command, retry it after updating the token. If it is a typo, run \`nb --help\` to inspect available commands.`
|
|
262
|
+
: 'Run `nb --help` to inspect built-in commands, then retry the original command after updating the token.';
|
|
260
263
|
return [
|
|
261
264
|
`Authentication failed while loading the command runtime from \`swagger:get\`${envLabel}.`,
|
|
262
265
|
`Base URL: ${context.baseUrl}`,
|
|
263
266
|
details,
|
|
264
|
-
|
|
267
|
+
tokenHint,
|
|
265
268
|
commandHint,
|
|
266
269
|
].join('\n');
|
|
267
270
|
}
|
|
268
271
|
if (isNetworkFetchFailure(response)) {
|
|
269
272
|
const rawMessage = response.data?.error?.message || 'fetch failed';
|
|
273
|
+
const updateConnectionHint = context.envName
|
|
274
|
+
? `If you recently changed the server address, update env "${context.envName}" with \`nb env update ${context.envName} --api-base-url <url>\` and retry the original command.`
|
|
275
|
+
: 'If you recently changed the server address, update the saved env connection with `nb env update <name> --api-base-url <url>` and retry the original command.';
|
|
270
276
|
return [
|
|
271
277
|
'Failed to reach the NocoBase server while loading the command runtime from `swagger:get`.',
|
|
272
278
|
`Base URL: ${context.baseUrl}`,
|
|
273
279
|
`Network error: ${rawMessage}`,
|
|
274
280
|
'Check that the NocoBase app is running, the base URL is correct, and the server is reachable from this machine.',
|
|
275
|
-
|
|
281
|
+
updateConnectionHint,
|
|
276
282
|
'Use `nb env list` to inspect the current env configuration.',
|
|
277
283
|
].join('\n');
|
|
278
284
|
}
|
|
@@ -282,7 +288,7 @@ export function formatMissingRuntimeEnvError(commandToken) {
|
|
|
282
288
|
if (!commandToken) {
|
|
283
289
|
return [
|
|
284
290
|
'No env is configured for runtime commands.',
|
|
285
|
-
'Run `nb
|
|
291
|
+
'Run `nb init --ui` first.',
|
|
286
292
|
'If you configure multiple environments later, switch with `nb env use <name>`.',
|
|
287
293
|
].join('\n');
|
|
288
294
|
}
|
|
@@ -290,7 +296,7 @@ export function formatMissingRuntimeEnvError(commandToken) {
|
|
|
290
296
|
`Unable to resolve runtime command \`${commandToken}\`.`,
|
|
291
297
|
'No env is configured, so the CLI cannot load runtime commands from `swagger:get`.',
|
|
292
298
|
'If this is a built-in command or a typo, run `nb --help` to inspect available commands.',
|
|
293
|
-
'If this should be an application runtime command, run `nb
|
|
299
|
+
'If this should be an application runtime command, run `nb init --ui` to create or connect a NocoBase app first.',
|
|
294
300
|
].join('\n');
|
|
295
301
|
}
|
|
296
302
|
export async function ensureRuntimeFromArgv(argv, options) {
|
|
@@ -366,8 +372,8 @@ export async function updateEnvRuntime(options) {
|
|
|
366
372
|
throw new Error([
|
|
367
373
|
env
|
|
368
374
|
? `Env "${envName}" is missing a base URL.`
|
|
369
|
-
: `Env "${envName}" is not configured. Run \`nb env
|
|
370
|
-
env ?
|
|
375
|
+
: `Env "${envName}" is not configured. Run \`nb init --ui --env ${envName}\` first.`,
|
|
376
|
+
env ? `Update env "${envName}" with \`nb env update ${envName} --api-base-url <url>\` first.` : '',
|
|
371
377
|
]
|
|
372
378
|
.filter(Boolean)
|
|
373
379
|
.join('\n'));
|