@nocobase/cli 2.1.0-beta.36 → 2.1.0-beta.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -8
- package/README.zh-CN.md +20 -8
- package/bin/run.js +3 -2
- package/dist/commands/app/destroy.js +225 -0
- package/dist/commands/app/down.js +24 -254
- package/dist/commands/app/shared.js +122 -0
- package/dist/commands/app/start.js +40 -59
- package/dist/commands/app/stop.js +72 -26
- package/dist/commands/app/upgrade.js +310 -427
- package/dist/commands/config/delete.js +4 -0
- package/dist/commands/config/get.js +4 -0
- package/dist/commands/config/set.js +5 -1
- package/dist/commands/db/start.js +23 -8
- package/dist/commands/env/add.js +66 -6
- package/dist/commands/env/auth.js +86 -27
- package/dist/commands/env/info.js +52 -8
- package/dist/commands/env/list.js +2 -2
- package/dist/commands/env/shared.js +41 -3
- package/dist/commands/init.js +196 -136
- package/dist/commands/install.js +311 -265
- package/dist/commands/license/plugins/shared.js +9 -3
- package/dist/commands/license/plugins/sync.js +54 -25
- package/dist/commands/source/download.js +29 -25
- package/dist/generated/command-registry.js +3 -2
- package/dist/lib/api-client.js +6 -0
- package/dist/lib/api-command-compat.js +641 -0
- package/dist/lib/app-health.js +27 -21
- package/dist/lib/auth-store.js +47 -19
- package/dist/lib/cli-config.js +99 -4
- package/dist/lib/cli-locale.js +19 -7
- package/dist/lib/db-connection-check.js +61 -0
- package/dist/lib/env-auth.js +79 -0
- package/dist/lib/env-config.js +3 -2
- package/dist/lib/env-guard.js +1 -1
- package/dist/lib/generated-command.js +17 -0
- package/dist/lib/prompt-validators.js +23 -5
- package/dist/lib/prompt-web-ui.js +143 -19
- package/dist/lib/run-npm.js +133 -23
- package/dist/lib/skills-manager.js +80 -4
- package/dist/lib/ui.js +4 -1
- package/dist/locale/en-US.json +86 -5
- package/dist/locale/zh-CN.json +86 -5
- package/package.json +34 -2
package/dist/lib/run-npm.js
CHANGED
|
@@ -19,9 +19,39 @@ import fsp from 'node:fs/promises';
|
|
|
19
19
|
import os from 'node:os';
|
|
20
20
|
import path from 'node:path';
|
|
21
21
|
import spawn from 'cross-spawn';
|
|
22
|
+
import { translateCli } from './cli-locale.js';
|
|
23
|
+
import { resolveConfiguredCommandName } from './cli-config.js';
|
|
22
24
|
const FORWARDED_SIGNALS = ['SIGINT', 'SIGTERM'];
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const PROCESS_TIMEOUT_FORCE_KILL_DELAY_MS = 1000;
|
|
26
|
+
const MISSING_COMMAND_SPECS = {
|
|
27
|
+
docker: {
|
|
28
|
+
displayName: 'Docker',
|
|
29
|
+
configKey: 'bin.docker',
|
|
30
|
+
},
|
|
31
|
+
git: {
|
|
32
|
+
displayName: 'Git',
|
|
33
|
+
configKey: 'bin.git',
|
|
34
|
+
},
|
|
35
|
+
yarn: {
|
|
36
|
+
displayName: 'Yarn',
|
|
37
|
+
configKey: 'bin.yarn',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
async function resolveCommandName(name) {
|
|
41
|
+
return await resolveConfiguredCommandName(name);
|
|
42
|
+
}
|
|
43
|
+
function createMissingCommandError(name, label, error) {
|
|
44
|
+
const code = error && typeof error === 'object' && 'code' in error ? String(error.code) : undefined;
|
|
45
|
+
if (code !== 'ENOENT') {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
if (!Object.prototype.hasOwnProperty.call(MISSING_COMMAND_SPECS, name)) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const spec = MISSING_COMMAND_SPECS[name];
|
|
52
|
+
return new Error(translateCli('commands.shared.missingCommand', { action: label, displayName: spec.displayName, configKey: spec.configKey }, {
|
|
53
|
+
fallback: `Couldn't run \`${label}\` because the ${spec.displayName} executable could not be found. Install ${spec.displayName} or update \`nb config set ${spec.configKey} <path>\` and try again.`,
|
|
54
|
+
}));
|
|
25
55
|
}
|
|
26
56
|
function pathExists(candidate) {
|
|
27
57
|
try {
|
|
@@ -40,8 +70,8 @@ function isDirectory(candidate) {
|
|
|
40
70
|
}
|
|
41
71
|
}
|
|
42
72
|
function hasLocalNocoBaseBinary(candidate) {
|
|
43
|
-
return (pathExists(path.join(candidate, 'node_modules', '.bin', 'nocobase-v1'))
|
|
44
|
-
|
|
73
|
+
return (pathExists(path.join(candidate, 'node_modules', '.bin', 'nocobase-v1')) ||
|
|
74
|
+
pathExists(path.join(candidate, 'node_modules', '.bin', 'nocobase-v1.cmd')));
|
|
45
75
|
}
|
|
46
76
|
export function resolveCwd(cwd) {
|
|
47
77
|
const next = cwd ?? process.cwd();
|
|
@@ -61,10 +91,7 @@ export function resolveProjectCwd(cwd) {
|
|
|
61
91
|
throw new Error(`The specified --cwd is not a directory: ${fallback}`);
|
|
62
92
|
}
|
|
63
93
|
let current = hasExplicitInput ? fallback : process.cwd();
|
|
64
|
-
while (
|
|
65
|
-
if (hasLocalNocoBaseBinary(current)) {
|
|
66
|
-
return current;
|
|
67
|
-
}
|
|
94
|
+
while (!hasLocalNocoBaseBinary(current)) {
|
|
68
95
|
const parent = path.dirname(current);
|
|
69
96
|
if (parent === current) {
|
|
70
97
|
if (hasExplicitInput) {
|
|
@@ -74,12 +101,13 @@ export function resolveProjectCwd(cwd) {
|
|
|
74
101
|
}
|
|
75
102
|
current = parent;
|
|
76
103
|
}
|
|
104
|
+
return current;
|
|
77
105
|
}
|
|
78
|
-
export function run(name, args, options) {
|
|
106
|
+
export async function run(name, args, options) {
|
|
79
107
|
const cwd = resolveCwd(options?.cwd);
|
|
80
108
|
const label = options?.errorName ?? name;
|
|
81
|
-
const command = resolveCommandName(name);
|
|
82
|
-
return new Promise((resolve, reject) => {
|
|
109
|
+
const command = await resolveCommandName(name);
|
|
110
|
+
return await new Promise((resolve, reject) => {
|
|
83
111
|
const child = spawn(command, [...args], {
|
|
84
112
|
stdio: options?.stdio ?? 'inherit',
|
|
85
113
|
cwd,
|
|
@@ -104,12 +132,19 @@ export function run(name, args, options) {
|
|
|
104
132
|
}
|
|
105
133
|
}
|
|
106
134
|
const cleanupSignalForwarding = forwardSignalsToChild(child);
|
|
135
|
+
const timeoutController = attachProcessTimeout(child, options?.timeoutMs);
|
|
107
136
|
child.once('error', (error) => {
|
|
137
|
+
timeoutController.cleanup();
|
|
108
138
|
cleanupSignalForwarding();
|
|
109
|
-
reject(error);
|
|
139
|
+
reject(createMissingCommandError(name, label, error) ?? error);
|
|
110
140
|
});
|
|
111
141
|
child.once('close', (code, signal) => {
|
|
142
|
+
timeoutController.cleanup();
|
|
112
143
|
cleanupSignalForwarding();
|
|
144
|
+
if (timeoutController.didTimeout()) {
|
|
145
|
+
reject(new Error(`${label} timed out after ${options?.timeoutMs}ms`));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
113
148
|
if (code === 0) {
|
|
114
149
|
resolve();
|
|
115
150
|
return;
|
|
@@ -122,6 +157,46 @@ export function run(name, args, options) {
|
|
|
122
157
|
});
|
|
123
158
|
});
|
|
124
159
|
}
|
|
160
|
+
function attachProcessTimeout(child, timeoutMs) {
|
|
161
|
+
if (!timeoutMs || timeoutMs <= 0) {
|
|
162
|
+
return {
|
|
163
|
+
cleanup: () => undefined,
|
|
164
|
+
didTimeout: () => false,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
let didTimeout = false;
|
|
168
|
+
let forceKillTimer;
|
|
169
|
+
const isChildRunning = () => child.exitCode === null && child.signalCode === null;
|
|
170
|
+
const terminateChild = (signal) => {
|
|
171
|
+
if (!isChildRunning()) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
child.kill(signal);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// Ignore kill errors here and let the child close/error handlers surface the failure.
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const timeoutTimer = setTimeout(() => {
|
|
182
|
+
didTimeout = true;
|
|
183
|
+
terminateChild('SIGTERM');
|
|
184
|
+
forceKillTimer = setTimeout(() => {
|
|
185
|
+
terminateChild('SIGKILL');
|
|
186
|
+
}, PROCESS_TIMEOUT_FORCE_KILL_DELAY_MS);
|
|
187
|
+
forceKillTimer.unref?.();
|
|
188
|
+
}, timeoutMs);
|
|
189
|
+
timeoutTimer.unref?.();
|
|
190
|
+
return {
|
|
191
|
+
cleanup: () => {
|
|
192
|
+
clearTimeout(timeoutTimer);
|
|
193
|
+
if (forceKillTimer) {
|
|
194
|
+
clearTimeout(forceKillTimer);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
didTimeout: () => didTimeout,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
125
200
|
function forwardSignalsToChild(child) {
|
|
126
201
|
let forwardedSignalCount = 0;
|
|
127
202
|
const listeners = new Map();
|
|
@@ -149,10 +224,11 @@ function forwardSignalsToChild(child) {
|
|
|
149
224
|
}
|
|
150
225
|
};
|
|
151
226
|
}
|
|
152
|
-
export function commandSucceeds(name, args, options) {
|
|
227
|
+
export async function commandSucceeds(name, args, options) {
|
|
153
228
|
const cwd = resolveCwd(options?.cwd);
|
|
154
|
-
const
|
|
155
|
-
|
|
229
|
+
const label = options?.errorName ?? name;
|
|
230
|
+
const command = await resolveCommandName(name);
|
|
231
|
+
return await new Promise((resolve, reject) => {
|
|
156
232
|
const child = spawn(command, [...args], {
|
|
157
233
|
cwd,
|
|
158
234
|
env: {
|
|
@@ -162,15 +238,31 @@ export function commandSucceeds(name, args, options) {
|
|
|
162
238
|
stdio: 'ignore',
|
|
163
239
|
windowsHide: process.platform === 'win32',
|
|
164
240
|
});
|
|
165
|
-
|
|
166
|
-
child.once('
|
|
241
|
+
const timeoutController = attachProcessTimeout(child, options?.timeoutMs);
|
|
242
|
+
child.once('error', (error) => {
|
|
243
|
+
timeoutController.cleanup();
|
|
244
|
+
const missingCommandError = createMissingCommandError(name, label, error);
|
|
245
|
+
if (missingCommandError) {
|
|
246
|
+
reject(missingCommandError);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
resolve(false);
|
|
250
|
+
});
|
|
251
|
+
child.once('close', (code) => {
|
|
252
|
+
timeoutController.cleanup();
|
|
253
|
+
if (timeoutController.didTimeout()) {
|
|
254
|
+
resolve(false);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
resolve(code === 0);
|
|
258
|
+
});
|
|
167
259
|
});
|
|
168
260
|
}
|
|
169
|
-
export function commandOutput(name, args, options) {
|
|
261
|
+
export async function commandOutput(name, args, options) {
|
|
170
262
|
const cwd = resolveCwd(options?.cwd);
|
|
171
263
|
const label = options?.errorName ?? name;
|
|
172
|
-
const command = resolveCommandName(name);
|
|
173
|
-
return new Promise((resolve, reject) => {
|
|
264
|
+
const command = await resolveCommandName(name);
|
|
265
|
+
return await new Promise((resolve, reject) => {
|
|
174
266
|
const child = spawn(command, [...args], {
|
|
175
267
|
cwd,
|
|
176
268
|
env: {
|
|
@@ -190,8 +282,17 @@ export function commandOutput(name, args, options) {
|
|
|
190
282
|
child.stderr.on('data', (chunk) => {
|
|
191
283
|
stderr += chunk;
|
|
192
284
|
});
|
|
193
|
-
child
|
|
285
|
+
const timeoutController = attachProcessTimeout(child, options?.timeoutMs);
|
|
286
|
+
child.once('error', (error) => {
|
|
287
|
+
timeoutController.cleanup();
|
|
288
|
+
reject(createMissingCommandError(name, label, error) ?? error);
|
|
289
|
+
});
|
|
194
290
|
child.once('close', (code, signal) => {
|
|
291
|
+
timeoutController.cleanup();
|
|
292
|
+
if (timeoutController.didTimeout()) {
|
|
293
|
+
reject(new Error(`${label} timed out after ${options?.timeoutMs}ms`));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
195
296
|
if (code === 0) {
|
|
196
297
|
resolve(stdout.trim());
|
|
197
298
|
return;
|
|
@@ -216,7 +317,7 @@ async function readCommandOutputFile(filePath) {
|
|
|
216
317
|
export async function commandOutputViaFile(name, args, options) {
|
|
217
318
|
const cwd = resolveCwd(options?.cwd);
|
|
218
319
|
const label = options?.errorName ?? name;
|
|
219
|
-
const command = resolveCommandName(name);
|
|
320
|
+
const command = await resolveCommandName(name);
|
|
220
321
|
const captureDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'nocobase-cli-output-'));
|
|
221
322
|
const stdoutPath = path.join(captureDir, 'stdout.log');
|
|
222
323
|
const stderrPath = path.join(captureDir, 'stderr.log');
|
|
@@ -233,8 +334,17 @@ export async function commandOutputViaFile(name, args, options) {
|
|
|
233
334
|
stdio: ['ignore', stdoutHandle.fd, stderrHandle.fd],
|
|
234
335
|
windowsHide: process.platform === 'win32',
|
|
235
336
|
});
|
|
236
|
-
child
|
|
337
|
+
const timeoutController = attachProcessTimeout(child, options?.timeoutMs);
|
|
338
|
+
child.once('error', (error) => {
|
|
339
|
+
timeoutController.cleanup();
|
|
340
|
+
reject(createMissingCommandError(name, label, error) ?? error);
|
|
341
|
+
});
|
|
237
342
|
child.once('close', (code, signal) => {
|
|
343
|
+
timeoutController.cleanup();
|
|
344
|
+
if (timeoutController.didTimeout()) {
|
|
345
|
+
reject(new Error(`${label} timed out after ${options?.timeoutMs}ms`));
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
238
348
|
resolve({ code, signal });
|
|
239
349
|
});
|
|
240
350
|
});
|
|
@@ -17,6 +17,72 @@ import { commandOutput, commandOutputViaFile, run } from './run-npm.js';
|
|
|
17
17
|
export const NOCOBASE_SKILLS_SOURCE = 'nocobase/skills';
|
|
18
18
|
export const NOCOBASE_SKILLS_PACKAGE_NAME = '@nocobase/skills';
|
|
19
19
|
const NOCOBASE_SKILLS_NAME_PREFIX = 'nocobase-';
|
|
20
|
+
const SKILLS_LIST_TIMEOUT_MS = 5000;
|
|
21
|
+
const SKILLS_NPM_VIEW_TIMEOUT_MS = 3000;
|
|
22
|
+
const SKILLS_PACK_TIMEOUT_MS = 30000;
|
|
23
|
+
const SKILLS_ADD_TIMEOUT_MS = 20000;
|
|
24
|
+
const NPM_REGISTRY_UNAVAILABLE_PATTERNS = [
|
|
25
|
+
'enotfound',
|
|
26
|
+
'eai_again',
|
|
27
|
+
'etimedout',
|
|
28
|
+
'esockettimedout',
|
|
29
|
+
'econnreset',
|
|
30
|
+
'econnrefused',
|
|
31
|
+
'ehostunreach',
|
|
32
|
+
'enetunreach',
|
|
33
|
+
'socket hang up',
|
|
34
|
+
'getaddrinfo',
|
|
35
|
+
'fetch failed',
|
|
36
|
+
'network request to',
|
|
37
|
+
'self_signed_cert',
|
|
38
|
+
'depth_zero_self_signed_cert',
|
|
39
|
+
'unable_to_verify_leaf_signature',
|
|
40
|
+
'cert_has_expired',
|
|
41
|
+
'timed out after',
|
|
42
|
+
];
|
|
43
|
+
function collectErrorMessages(error) {
|
|
44
|
+
const messages = [];
|
|
45
|
+
const queue = [error];
|
|
46
|
+
const seen = new Set();
|
|
47
|
+
while (queue.length > 0) {
|
|
48
|
+
const current = queue.shift();
|
|
49
|
+
if (current === undefined || current === null || seen.has(current)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
seen.add(current);
|
|
53
|
+
if (current instanceof Error) {
|
|
54
|
+
if (current.message) {
|
|
55
|
+
messages.push(current.message);
|
|
56
|
+
}
|
|
57
|
+
const cause = current.cause;
|
|
58
|
+
if (cause !== undefined) {
|
|
59
|
+
queue.push(cause);
|
|
60
|
+
}
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (typeof current === 'string') {
|
|
64
|
+
messages.push(current);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (typeof current === 'object') {
|
|
68
|
+
if ('message' in current && typeof current.message === 'string') {
|
|
69
|
+
messages.push(current.message);
|
|
70
|
+
}
|
|
71
|
+
if ('cause' in current) {
|
|
72
|
+
queue.push(current.cause);
|
|
73
|
+
}
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
messages.push(String(current));
|
|
77
|
+
}
|
|
78
|
+
return messages;
|
|
79
|
+
}
|
|
80
|
+
export function isNpmRegistryUnavailable(error) {
|
|
81
|
+
return collectErrorMessages(error).some((message) => {
|
|
82
|
+
const normalized = message.toLowerCase();
|
|
83
|
+
return NPM_REGISTRY_UNAVAILABLE_PATTERNS.some((pattern) => normalized.includes(pattern));
|
|
84
|
+
});
|
|
85
|
+
}
|
|
20
86
|
function normalizePath(value) {
|
|
21
87
|
return path.resolve(value);
|
|
22
88
|
}
|
|
@@ -61,6 +127,12 @@ async function readManagedSkillsState(workspaceRoot) {
|
|
|
61
127
|
return undefined;
|
|
62
128
|
}
|
|
63
129
|
}
|
|
130
|
+
export async function readInstalledManagedSkillsVersion(options = {}) {
|
|
131
|
+
const globalRoot = resolveSkillsRoot(options);
|
|
132
|
+
const state = await readManagedSkillsState(globalRoot);
|
|
133
|
+
const installedVersion = String(state?.installedVersion ?? state?.installedRef ?? '').trim();
|
|
134
|
+
return installedVersion || undefined;
|
|
135
|
+
}
|
|
64
136
|
async function writeManagedSkillsState(workspaceRoot, state) {
|
|
65
137
|
const filePath = getManagedSkillsStateFile(workspaceRoot);
|
|
66
138
|
await fsp.mkdir(path.dirname(filePath), { recursive: true });
|
|
@@ -72,6 +144,7 @@ export async function listGlobalSkills(options = {}) {
|
|
|
72
144
|
const output = await (options.commandOutputFn ?? commandOutputViaFile)('npx', ['-y', 'skills', 'list', '-g', '--json'], {
|
|
73
145
|
cwd: globalRoot,
|
|
74
146
|
errorName: 'skills list',
|
|
147
|
+
timeoutMs: SKILLS_LIST_TIMEOUT_MS,
|
|
75
148
|
});
|
|
76
149
|
const parsed = JSON.parse(output);
|
|
77
150
|
return Array.isArray(parsed) ? parsed : [];
|
|
@@ -95,6 +168,7 @@ async function readPublishedSkillsVersion(options = {}) {
|
|
|
95
168
|
const output = await (options.commandOutputFn ?? commandOutput)('npm', ['view', NOCOBASE_SKILLS_PACKAGE_NAME, 'version', '--json'], {
|
|
96
169
|
cwd: globalRoot,
|
|
97
170
|
errorName: 'npm view',
|
|
171
|
+
timeoutMs: SKILLS_NPM_VIEW_TIMEOUT_MS,
|
|
98
172
|
});
|
|
99
173
|
const parsed = JSON.parse(output);
|
|
100
174
|
const version = String(parsed ?? '').trim();
|
|
@@ -187,6 +261,7 @@ async function prepareLocalSkillsPackage(globalRoot, options = {}, targetVersion
|
|
|
187
261
|
cwd: packRoot,
|
|
188
262
|
stdio: options.verbose ? 'inherit' : 'ignore',
|
|
189
263
|
errorName: 'npm pack',
|
|
264
|
+
timeoutMs: SKILLS_PACK_TIMEOUT_MS,
|
|
190
265
|
});
|
|
191
266
|
const tarballPath = await resolvePackedSkillsTarball(packRoot);
|
|
192
267
|
await extractPackedSkillsTarball(tarballPath, cacheRoot, targetVersion);
|
|
@@ -276,6 +351,7 @@ async function reinstallManagedSkills(globalRoot, options = {}, targetVersion) {
|
|
|
276
351
|
cwd: globalRoot,
|
|
277
352
|
stdio: options.verbose ? 'inherit' : 'ignore',
|
|
278
353
|
errorName: 'skills add',
|
|
354
|
+
timeoutMs: SKILLS_ADD_TIMEOUT_MS,
|
|
279
355
|
});
|
|
280
356
|
}
|
|
281
357
|
finally {
|
|
@@ -314,10 +390,10 @@ export async function updateNocoBaseSkills(options = {}) {
|
|
|
314
390
|
status,
|
|
315
391
|
};
|
|
316
392
|
}
|
|
317
|
-
if (status.managedByNb
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
393
|
+
if (status.managedByNb &&
|
|
394
|
+
status.latestVersion &&
|
|
395
|
+
status.installedVersion &&
|
|
396
|
+
compareVersions(status.latestVersion, status.installedVersion) <= 0) {
|
|
321
397
|
return {
|
|
322
398
|
action: 'noop',
|
|
323
399
|
reason: 'up-to-date',
|
package/dist/lib/ui.js
CHANGED
|
@@ -54,7 +54,10 @@ export function printInfo(message) {
|
|
|
54
54
|
console.log(pc.cyan(message));
|
|
55
55
|
}
|
|
56
56
|
export function announceTargetEnv(envName) {
|
|
57
|
-
|
|
57
|
+
if (process.env.NB_SKIP_TARGET_ENV_LOG === '1') {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
printInfo(`Using env "${envName}".`);
|
|
58
61
|
}
|
|
59
62
|
export function printVerbose(message) {
|
|
60
63
|
if (!verboseMode) {
|
package/dist/locale/en-US.json
CHANGED
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"back": "Back",
|
|
35
35
|
"next": "Next",
|
|
36
36
|
"submit": "Submit & continue in terminal",
|
|
37
|
+
"showPassword": "Show password",
|
|
38
|
+
"hidePassword": "Hide password",
|
|
37
39
|
"checking": "Checking...",
|
|
38
40
|
"sending": "Sending...",
|
|
39
41
|
"successTitle": "Success",
|
|
@@ -73,7 +75,8 @@
|
|
|
73
75
|
"timeout": "Timed out connecting to the database at {{host}}:{{port}} after about {{seconds}} seconds.",
|
|
74
76
|
"authenticationFailed": "Failed to sign in to database \"{{database}}\" with user \"{{user}}\". Check the username and password.",
|
|
75
77
|
"databaseNotFound": "Database \"{{database}}\" does not exist or is not accessible with the current connection settings.",
|
|
76
|
-
"connectionFailed": "Database connection check failed. Details: {{details}}"
|
|
78
|
+
"connectionFailed": "Database connection check failed. Details: {{details}}",
|
|
79
|
+
"lowerCaseTableNamesRequiresUnderscored": "MySQL lower_case_table_names=1 requires DB_UNDERSCORED=true."
|
|
77
80
|
}
|
|
78
81
|
},
|
|
79
82
|
"commands": {
|
|
@@ -94,16 +97,28 @@
|
|
|
94
97
|
},
|
|
95
98
|
"authType": {
|
|
96
99
|
"message": "How would you like to sign in?",
|
|
100
|
+
"basicLabel": "Basic login (username + password)",
|
|
101
|
+
"basicHint": "uses your credentials to fetch a token after save",
|
|
97
102
|
"oauthLabel": "OAuth (browser login)",
|
|
98
103
|
"oauthHint": "runs nb env auth after save",
|
|
99
104
|
"tokenLabel": "API token / API key"
|
|
100
105
|
},
|
|
106
|
+
"username": {
|
|
107
|
+
"message": "Enter the username for basic login",
|
|
108
|
+
"placeholder": "admin"
|
|
109
|
+
},
|
|
110
|
+
"password": {
|
|
111
|
+
"message": "Enter the password for basic login"
|
|
112
|
+
},
|
|
101
113
|
"accessToken": {
|
|
102
114
|
"message": "Enter an API token or API key",
|
|
103
115
|
"placeholder": "Enter your API token / API key"
|
|
104
116
|
}
|
|
105
117
|
}
|
|
106
118
|
},
|
|
119
|
+
"shared": {
|
|
120
|
+
"missingCommand": "Couldn't run `{{action}}` because the {{displayName}} executable could not be found. Install {{displayName}} or update `nb config set {{configKey}} <path>` and try again."
|
|
121
|
+
},
|
|
107
122
|
"download": {
|
|
108
123
|
"failures": {
|
|
109
124
|
"dependencyInstall": {
|
|
@@ -206,6 +221,10 @@
|
|
|
206
221
|
}
|
|
207
222
|
},
|
|
208
223
|
"install": {
|
|
224
|
+
"messages": {
|
|
225
|
+
"skipDownloadDockerImageMissing": "Cannot continue with `--skip-download` because Docker image \"{{imageRef}}\" is not available locally. Load or pull the image first, or run the command again without `--skip-download`.",
|
|
226
|
+
"skipDownloadLocalAppMissing": "Cannot continue with `--skip-download` because \"{{projectRoot}}\" is missing or does not contain a package.json file. Point `--app-root-path` to an existing NocoBase app, or run the command again without `--skip-download`."
|
|
227
|
+
},
|
|
209
228
|
"validation": {
|
|
210
229
|
"builtinDbUnsupported": "Built-in database does not support \"{{dialect}}\" yet. Choose PostgreSQL, MySQL, or MariaDB, or turn off built-in database."
|
|
211
230
|
},
|
|
@@ -229,9 +248,6 @@
|
|
|
229
248
|
"message": "Where should uploads and local files be stored?",
|
|
230
249
|
"placeholder": "./<env>/storage/"
|
|
231
250
|
},
|
|
232
|
-
"fetchSource": {
|
|
233
|
-
"message": "Download NocoBase automatically if the app directory is empty?"
|
|
234
|
-
},
|
|
235
251
|
"dbDialect": {
|
|
236
252
|
"message": "Which database would you like to use?"
|
|
237
253
|
},
|
|
@@ -259,6 +275,17 @@
|
|
|
259
275
|
"dbPassword": {
|
|
260
276
|
"message": "What is the database password?"
|
|
261
277
|
},
|
|
278
|
+
"dbSchema": {
|
|
279
|
+
"message": "What is the database schema? (PostgreSQL only, optional)",
|
|
280
|
+
"placeholder": "Leave empty to use the default schema"
|
|
281
|
+
},
|
|
282
|
+
"dbTablePrefix": {
|
|
283
|
+
"message": "What table prefix should be used? (optional)",
|
|
284
|
+
"placeholder": "For example: nb_"
|
|
285
|
+
},
|
|
286
|
+
"dbUnderscored": {
|
|
287
|
+
"message": "Use underscored names for database tables and columns?"
|
|
288
|
+
},
|
|
262
289
|
"rootUsername": {
|
|
263
290
|
"message": "Choose the initial admin username",
|
|
264
291
|
"placeholder": "nocobase"
|
|
@@ -290,7 +317,8 @@
|
|
|
290
317
|
"uiOpening": "A local setup form will open in your browser. That form needs a person to fill it in. If you are using an AI agent, do not stop this process while the CLI waits for the submission.",
|
|
291
318
|
"uiReady": "Local setup form is ready.",
|
|
292
319
|
"uiReadyHelp": "If your browser does not open automatically, copy the URL below into your browser to continue. Keep this terminal session running while the CLI waits for the submission.",
|
|
293
|
-
"uiOpenBrowserFallback": "We could not open your browser automatically. Copy the URL above into your browser to continue setup, and keep this terminal session running. If you are using an AI agent, do not stop the current process."
|
|
320
|
+
"uiOpenBrowserFallback": "We could not open your browser automatically. Copy the URL above into your browser to continue setup, and keep this terminal session running. If you are using an AI agent, do not stop the current process.",
|
|
321
|
+
"skillsSyncRegistryUnavailable": "Couldn't reach the npm registry to sync NocoBase AI coding skills. Skipping skills install and continuing init. Run `nb skills install` later when registry access is available."
|
|
294
322
|
},
|
|
295
323
|
"prompts": {
|
|
296
324
|
"appName": {
|
|
@@ -308,6 +336,9 @@
|
|
|
308
336
|
"apiBaseUrl": {
|
|
309
337
|
"message": "API base URL",
|
|
310
338
|
"placeholder": "https://demo.example.com/api or https://demo.example.com/api/__app/<subapp>"
|
|
339
|
+
},
|
|
340
|
+
"skipDownload": {
|
|
341
|
+
"message": "Skip downloading NocoBase and reuse existing local app files or Docker images"
|
|
311
342
|
}
|
|
312
343
|
},
|
|
313
344
|
"webUi": {
|
|
@@ -340,5 +371,55 @@
|
|
|
340
371
|
}
|
|
341
372
|
}
|
|
342
373
|
}
|
|
374
|
+
},
|
|
375
|
+
"apiCommandCompat": {
|
|
376
|
+
"refusalTitle": "Refusing to run `nb api {{commandId}}` because the current CLI version is {{cliVersion}} while the target app version is {{appVersion}}.",
|
|
377
|
+
"refusalTitleMissingVersion": "Refusing to run `nb api {{commandId}}` because the {{versionLabel}} is unavailable.",
|
|
378
|
+
"refusalTitleGeneric": "Refusing to run `nb api {{commandId}}` because the current version combination is not compatible.",
|
|
379
|
+
"currentVersionsLine": "Current versions: {{versions}}.",
|
|
380
|
+
"refusalBodyWithRequirements": "This API command is blocked when used with {{requirements}}.",
|
|
381
|
+
"refusalBody": "This API command may not be compatible with the current CLI and app version combination.",
|
|
382
|
+
"channel": {
|
|
383
|
+
"stable": "stable",
|
|
384
|
+
"beta": "beta",
|
|
385
|
+
"alpha": "alpha",
|
|
386
|
+
"rc": "rc",
|
|
387
|
+
"unknownPrerelease": "unsupported prerelease"
|
|
388
|
+
},
|
|
389
|
+
"requirement": {
|
|
390
|
+
"cli": "CLI version {{condition}}",
|
|
391
|
+
"app": "app version {{condition}}",
|
|
392
|
+
"skills": "NocoBase AI skills version {{condition}}",
|
|
393
|
+
"appChannel": "{{channelLabel}} app version {{condition}}",
|
|
394
|
+
"appUnknownPrereleaseBlocked": "{{channelLabel}} app versions are blocked"
|
|
395
|
+
},
|
|
396
|
+
"currentVersion": {
|
|
397
|
+
"cli": "CLI {{version}}",
|
|
398
|
+
"app": "app {{version}}",
|
|
399
|
+
"appUnavailable": "app unavailable",
|
|
400
|
+
"skills": "NocoBase AI skills {{version}}",
|
|
401
|
+
"skillsUnavailable": "NocoBase AI skills unavailable"
|
|
402
|
+
},
|
|
403
|
+
"versionLabel": {
|
|
404
|
+
"cli": "CLI version",
|
|
405
|
+
"app": "target app version",
|
|
406
|
+
"skills": "installed NocoBase AI skills version"
|
|
407
|
+
},
|
|
408
|
+
"join": {
|
|
409
|
+
"two": "{{left}} and {{right}}",
|
|
410
|
+
"many": "{{head}}, and {{tail}}"
|
|
411
|
+
},
|
|
412
|
+
"continueTitle": "To continue:",
|
|
413
|
+
"continueUpgradeApp": "- upgrade the app to a compatible version",
|
|
414
|
+
"continueUpgradeAppToVersion": "- upgrade the app to {{suggestedUpgradeTarget}}",
|
|
415
|
+
"continueUseSupportedAppVersion": "- use a supported app version: {{supportedTargets}}",
|
|
416
|
+
"continueRefreshAppVersion": "- refresh the target env runtime so the current app version can be detected, then retry",
|
|
417
|
+
"continueUseCompatibleCli": "- or use a compatible CLI version",
|
|
418
|
+
"continueUseCompatibleCliVersion": "- or use a CLI version {{suggestedCliTarget}}",
|
|
419
|
+
"continueUpdateSkillsToVersion": "- install or update the NocoBase AI coding skills to {{suggestedSkillsUpgradeTarget}}. Run `nb skills update --yes` to refresh the managed skills.",
|
|
420
|
+
"continueUseCompatibleSkillsVersion": "- or use a NocoBase AI skills version {{suggestedSkillsTarget}}",
|
|
421
|
+
"continueInstallOrUpdateSkillsToVersion": "- run `nb skills install --yes` or `nb skills update --yes`, and make sure the managed skills version is {{suggestedSkillsUpgradeTarget}} before retrying",
|
|
422
|
+
"continueInstallOrUpdateSkills": "- run `nb skills install --yes` or `nb skills update --yes`, then retry once the managed skills version is available",
|
|
423
|
+
"supportedAppTarget": "{{channelLabel}} {{target}}"
|
|
343
424
|
}
|
|
344
425
|
}
|