@nocobase/cli 2.1.0-beta.20 → 2.1.0-beta.21
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 +4 -4
- package/README.zh-CN.md +2 -2
- package/bin/run.js +15 -0
- package/dist/commands/db/shared.js +19 -5
- package/dist/commands/dev.js +8 -1
- package/dist/commands/down.js +10 -6
- package/dist/commands/env/add.js +14 -34
- package/dist/commands/env/auth.js +6 -13
- package/dist/commands/env/list.js +10 -15
- package/dist/commands/env/remove.js +4 -10
- package/dist/commands/env/update.js +7 -13
- package/dist/commands/env/use.js +5 -13
- package/dist/commands/init.js +190 -62
- package/dist/commands/install.js +65 -26
- package/dist/commands/logs.js +8 -1
- package/dist/commands/pm/list.js +8 -1
- package/dist/commands/ps.js +18 -15
- package/dist/commands/self/check.js +1 -1
- package/dist/commands/self/update.js +13 -3
- package/dist/commands/skills/check.js +11 -5
- package/dist/commands/skills/index.js +1 -1
- package/dist/commands/skills/install.js +20 -7
- package/dist/commands/skills/update.js +20 -7
- package/dist/commands/start.js +8 -1
- package/dist/commands/stop.js +8 -1
- package/dist/commands/upgrade.js +12 -1
- package/dist/lib/api-client.js +3 -2
- package/dist/lib/app-runtime.js +16 -5
- package/dist/lib/auth-store.js +159 -43
- package/dist/lib/bootstrap.js +13 -12
- package/dist/lib/cli-home.js +33 -2
- package/dist/lib/env-auth.js +3 -3
- package/dist/lib/generated-command.js +10 -2
- package/dist/lib/http-request.js +49 -0
- package/dist/lib/resource-command.js +10 -2
- package/dist/lib/runtime-generator.js +1 -1
- package/dist/lib/self-manager.js +1 -1
- package/dist/lib/skills-manager.js +140 -73
- package/dist/lib/startup-update.js +203 -0
- package/dist/locale/en-US.json +4 -1
- package/dist/locale/zh-CN.json +4 -1
- package/package.json +2 -2
package/dist/commands/install.js
CHANGED
|
@@ -16,6 +16,7 @@ import path from 'node:path';
|
|
|
16
16
|
import { exit } from 'node:process';
|
|
17
17
|
import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
18
18
|
import { applyCliLocale, localeText, resolveCliLocale, translateCli, } from "../lib/cli-locale.js";
|
|
19
|
+
import { resolveConfiguredEnvPath, resolveDefaultConfigScope, resolveEnvRelativePath, } from '../lib/cli-home.js';
|
|
19
20
|
import { findAvailableTcpPort, validateAvailableTcpPort, validateTcpPort, validateEnvKey, } from "../lib/prompt-validators.js";
|
|
20
21
|
import { formatMissingManagedAppEnvMessage } from '../lib/app-runtime.js';
|
|
21
22
|
import { run, runNocoBaseCommand } from '../lib/run-npm.js';
|
|
@@ -53,7 +54,6 @@ const DEFAULT_INSTALL_ROOT_USERNAME = 'nocobase';
|
|
|
53
54
|
const DEFAULT_INSTALL_ROOT_EMAIL = 'admin@nocobase.com';
|
|
54
55
|
const DEFAULT_INSTALL_ROOT_PASSWORD = 'admin123';
|
|
55
56
|
const DEFAULT_INSTALL_ROOT_NICKNAME = 'Super Admin';
|
|
56
|
-
const CONFIG_SCOPE = 'project';
|
|
57
57
|
const APP_HEALTH_CHECK_INTERVAL_MS = 2_000;
|
|
58
58
|
const APP_HEALTH_CHECK_TIMEOUT_MS = 600_000;
|
|
59
59
|
const APP_HEALTH_CHECK_REQUEST_TIMEOUT_MS = 5_000;
|
|
@@ -137,6 +137,11 @@ function argvHasToken(argv, tokens) {
|
|
|
137
137
|
function isInstallDbDialect(value) {
|
|
138
138
|
return INSTALL_DB_DIALECTS.includes(value);
|
|
139
139
|
}
|
|
140
|
+
function downloadVersionPromptValue(version) {
|
|
141
|
+
return version === 'latest' || version === 'beta' || version === 'alpha'
|
|
142
|
+
? version
|
|
143
|
+
: 'other';
|
|
144
|
+
}
|
|
140
145
|
function supportsBuiltinDbDialect(value) {
|
|
141
146
|
const dialect = String(value ?? '').trim();
|
|
142
147
|
return Object.prototype.hasOwnProperty.call(DEFAULT_INSTALL_BUILTIN_DB_IMAGES, dialect);
|
|
@@ -303,6 +308,7 @@ export default class Install extends Command {
|
|
|
303
308
|
required: false,
|
|
304
309
|
}),
|
|
305
310
|
'builtin-db': Flags.boolean({
|
|
311
|
+
allowNo: true,
|
|
306
312
|
description: 'Create and connect a CLI-managed built-in database for the app',
|
|
307
313
|
default: false,
|
|
308
314
|
}),
|
|
@@ -569,7 +575,7 @@ export default class Install extends Command {
|
|
|
569
575
|
if (argvHasToken(argv, ['--fetch-source'])) {
|
|
570
576
|
preset.fetchSource = flags['fetch-source'];
|
|
571
577
|
}
|
|
572
|
-
if (argvHasToken(argv, ['--builtin-db'])) {
|
|
578
|
+
if (argvHasToken(argv, ['--builtin-db', '--no-builtin-db'])) {
|
|
573
579
|
preset.builtinDb = flags['builtin-db'];
|
|
574
580
|
}
|
|
575
581
|
if (flags['db-dialect'] !== undefined) {
|
|
@@ -588,6 +594,7 @@ export default class Install extends Command {
|
|
|
588
594
|
const v = String(flags['db-host'] ?? '').trim();
|
|
589
595
|
if (v) {
|
|
590
596
|
preset.dbHost = v;
|
|
597
|
+
preset.builtinDb = false;
|
|
591
598
|
}
|
|
592
599
|
}
|
|
593
600
|
if (flags['db-port'] !== undefined) {
|
|
@@ -682,7 +689,14 @@ export default class Install extends Command {
|
|
|
682
689
|
};
|
|
683
690
|
const downloadPreset = {
|
|
684
691
|
...(source ? { source } : {}),
|
|
685
|
-
...(downloadVersion
|
|
692
|
+
...(downloadVersion
|
|
693
|
+
? {
|
|
694
|
+
version: downloadVersionPromptValue(downloadVersion),
|
|
695
|
+
...(downloadVersionPromptValue(downloadVersion) === 'other'
|
|
696
|
+
? { otherVersion: downloadVersion }
|
|
697
|
+
: {}),
|
|
698
|
+
}
|
|
699
|
+
: {}),
|
|
686
700
|
...(dockerRegistry ? { dockerRegistry } : {}),
|
|
687
701
|
...(dockerPlatform ? { dockerPlatform } : {}),
|
|
688
702
|
...(gitUrl ? { gitUrl } : {}),
|
|
@@ -746,7 +760,7 @@ export default class Install extends Command {
|
|
|
746
760
|
if (!parsed.resume) {
|
|
747
761
|
return undefined;
|
|
748
762
|
}
|
|
749
|
-
const env = await getEnv(parsed.env, { scope:
|
|
763
|
+
const env = await getEnv(parsed.env, { scope: resolveDefaultConfigScope() });
|
|
750
764
|
if (!env) {
|
|
751
765
|
throw new Error(formatMissingManagedAppEnvMessage(parsed.env));
|
|
752
766
|
}
|
|
@@ -861,7 +875,11 @@ export default class Install extends Command {
|
|
|
861
875
|
preset.source = String(flags.source).trim();
|
|
862
876
|
}
|
|
863
877
|
if (flags.version !== undefined) {
|
|
864
|
-
|
|
878
|
+
const version = String(flags.version).trim() || 'latest';
|
|
879
|
+
preset.version = downloadVersionPromptValue(version);
|
|
880
|
+
if (preset.version === 'other') {
|
|
881
|
+
preset.otherVersion = version;
|
|
882
|
+
}
|
|
865
883
|
}
|
|
866
884
|
if (flags['docker-registry'] !== undefined) {
|
|
867
885
|
const value = String(flags['docker-registry'] ?? '').trim();
|
|
@@ -891,7 +909,10 @@ export default class Install extends Command {
|
|
|
891
909
|
preset.npmRegistry =
|
|
892
910
|
typeof flags['npm-registry'] === 'string' ? flags['npm-registry'] : '';
|
|
893
911
|
}
|
|
894
|
-
if (argvHasToken(argv, ['--replace', '-r'])) {
|
|
912
|
+
if (flags.resume && !argvHasToken(argv, ['--replace', '-r'])) {
|
|
913
|
+
preset.replace = true;
|
|
914
|
+
}
|
|
915
|
+
else if (argvHasToken(argv, ['--replace', '-r'])) {
|
|
895
916
|
preset.replace = flags.replace;
|
|
896
917
|
}
|
|
897
918
|
if (argvHasToken(argv, ['--dev-dependencies', '--no-dev-dependencies', '-D'])) {
|
|
@@ -933,7 +954,7 @@ export default class Install extends Command {
|
|
|
933
954
|
: Install.defaultWorkspaceName();
|
|
934
955
|
}
|
|
935
956
|
static async ensureWorkspaceName() {
|
|
936
|
-
return await ensureWorkspaceName(Install.defaultWorkspaceName(), { scope:
|
|
957
|
+
return await ensureWorkspaceName(Install.defaultWorkspaceName(), { scope: resolveDefaultConfigScope() });
|
|
937
958
|
}
|
|
938
959
|
static buildBuiltinDbNetworkName(envName, workspaceName) {
|
|
939
960
|
return Install.buildBuiltinDbResourcePrefix(envName, workspaceName);
|
|
@@ -982,9 +1003,11 @@ export default class Install extends Command {
|
|
|
982
1003
|
&& dbHostInput !== 'localhost'
|
|
983
1004
|
? dbHostInput
|
|
984
1005
|
: containerName);
|
|
1006
|
+
const storagePath = resolveConfiguredEnvPath(params.storagePath)
|
|
1007
|
+
?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
985
1008
|
if (dbDialect === 'postgres') {
|
|
986
1009
|
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
987
|
-
const dataDir = path.resolve(
|
|
1010
|
+
const dataDir = path.resolve(storagePath, 'db', 'postgres');
|
|
988
1011
|
const args = [
|
|
989
1012
|
'run',
|
|
990
1013
|
'-d',
|
|
@@ -1028,7 +1051,7 @@ export default class Install extends Command {
|
|
|
1028
1051
|
}
|
|
1029
1052
|
if (dbDialect === 'mysql') {
|
|
1030
1053
|
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1031
|
-
const dataDir = path.resolve(
|
|
1054
|
+
const dataDir = path.resolve(storagePath, 'db', 'mysql');
|
|
1032
1055
|
const dbUser = String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1033
1056
|
const dbDatabase = String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase;
|
|
1034
1057
|
const dbPassword = String(params.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD;
|
|
@@ -1074,7 +1097,7 @@ export default class Install extends Command {
|
|
|
1074
1097
|
}
|
|
1075
1098
|
if (dbDialect === 'mariadb') {
|
|
1076
1099
|
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1077
|
-
const dataDir = path.resolve(
|
|
1100
|
+
const dataDir = path.resolve(storagePath, 'db', 'mariadb');
|
|
1078
1101
|
const dbUser = String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1079
1102
|
const dbDatabase = String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase;
|
|
1080
1103
|
const dbPassword = String(params.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD;
|
|
@@ -1120,7 +1143,7 @@ export default class Install extends Command {
|
|
|
1120
1143
|
}
|
|
1121
1144
|
if (dbDialect === 'kingbase') {
|
|
1122
1145
|
const image = String(params.builtinDbImage ?? '').trim() || defaultBuiltinDbImageForDialect(dbDialect);
|
|
1123
|
-
const dataDir = path.resolve(
|
|
1146
|
+
const dataDir = path.resolve(storagePath, 'db', 'kingbase');
|
|
1124
1147
|
const dbUser = String(params.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
|
|
1125
1148
|
const dbDatabase = String(params.dbDatabase ?? defaultDbDatabase).trim() || defaultDbDatabase;
|
|
1126
1149
|
const dbPassword = String(params.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD;
|
|
@@ -1269,12 +1292,12 @@ export default class Install extends Command {
|
|
|
1269
1292
|
});
|
|
1270
1293
|
p.log.step(`Preparing built-in ${plan.dbDialect} database`);
|
|
1271
1294
|
await this.ensureDockerNetwork(plan.networkName);
|
|
1272
|
-
await this.removeDockerContainerIfForced({
|
|
1295
|
+
const existingContainerKept = await this.removeDockerContainerIfForced({
|
|
1273
1296
|
containerName: plan.containerName,
|
|
1274
1297
|
displayName: `built-in ${plan.dbDialect} container`,
|
|
1275
1298
|
force: params.force,
|
|
1276
1299
|
});
|
|
1277
|
-
if (Install.shouldPublishBuiltinDbPort(params.downloadResults.source)) {
|
|
1300
|
+
if (!existingContainerKept && Install.shouldPublishBuiltinDbPort(params.downloadResults.source)) {
|
|
1278
1301
|
const portError = await validateAvailableTcpPort(plan.dbPort);
|
|
1279
1302
|
if (portError) {
|
|
1280
1303
|
throw new Error(`Built-in ${plan.dbDialect} needs host port ${plan.dbPort}, but ${portError}`);
|
|
@@ -1291,8 +1314,9 @@ export default class Install extends Command {
|
|
|
1291
1314
|
|| defaultDockerRegistryForLang(process.env.NB_LOCALE);
|
|
1292
1315
|
const version = String(downloadResultsValue(params.downloadResults, 'version') ?? '').trim() || 'latest';
|
|
1293
1316
|
const appPort = String(params.appResults.appPort ?? DEFAULT_INSTALL_APP_PORT).trim() || DEFAULT_INSTALL_APP_PORT;
|
|
1294
|
-
const storagePath =
|
|
1295
|
-
|| defaultInstallStoragePath(params.envName))
|
|
1317
|
+
const storagePath = resolveConfiguredEnvPath(String(params.appResults.storagePath ?? '').trim()
|
|
1318
|
+
|| defaultInstallStoragePath(params.envName))
|
|
1319
|
+
?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1296
1320
|
const dbDialect = String(params.dbResults.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
1297
1321
|
const dbHost = String(params.dbResults.dbHost ?? DEFAULT_INSTALL_DB_HOST).trim() || DEFAULT_INSTALL_DB_HOST;
|
|
1298
1322
|
const dbPort = String(params.dbResults.dbPort ?? defaultDbPortForDialect(dbDialect)).trim()
|
|
@@ -1387,12 +1411,16 @@ export default class Install extends Command {
|
|
|
1387
1411
|
}
|
|
1388
1412
|
static buildDownloadArgvFromResults(results, options) {
|
|
1389
1413
|
const argv = ['-y', '--no-intro'];
|
|
1414
|
+
const source = String(results.source ?? '').trim();
|
|
1390
1415
|
if (options?.verbose) {
|
|
1391
1416
|
argv.push('--verbose');
|
|
1392
1417
|
}
|
|
1393
1418
|
Install.pushDownloadArgIfValue(argv, '--source', results.source);
|
|
1394
|
-
Install.pushDownloadArgIfValue(argv, '--version', results
|
|
1395
|
-
Install.pushDownloadArgIfValue(argv, '--output-dir',
|
|
1419
|
+
Install.pushDownloadArgIfValue(argv, '--version', downloadResultsValue(results, 'version'));
|
|
1420
|
+
Install.pushDownloadArgIfValue(argv, '--output-dir', source === 'npm' || source === 'git'
|
|
1421
|
+
? (resolveConfiguredEnvPath(results.outputDir)
|
|
1422
|
+
?? resolveConfiguredEnvPath(String(results.outputDir ?? '').trim() || defaultInstallAppRootPath(results.env)))
|
|
1423
|
+
: results.outputDir);
|
|
1396
1424
|
Install.pushDownloadArgIfValue(argv, '--git-url', results.gitUrl);
|
|
1397
1425
|
Install.pushDownloadArgIfValue(argv, '--docker-registry', results.dockerRegistry);
|
|
1398
1426
|
Install.pushDownloadArgIfValue(argv, '--docker-platform', results.dockerPlatform);
|
|
@@ -1422,7 +1450,12 @@ export default class Install extends Command {
|
|
|
1422
1450
|
const outputDir = String(params.downloadResults.outputDir ?? '').trim()
|
|
1423
1451
|
|| String(params.appResults.appRootPath ?? '').trim()
|
|
1424
1452
|
|| defaultInstallAppRootPath(params.envName);
|
|
1425
|
-
return
|
|
1453
|
+
return resolveConfiguredEnvPath(outputDir) ?? resolveEnvRelativePath(defaultInstallAppRootPath(params.envName));
|
|
1454
|
+
}
|
|
1455
|
+
static resolveLocalProjectConfigPath(params) {
|
|
1456
|
+
return (String(params.downloadResults.outputDir ?? '').trim()
|
|
1457
|
+
|| String(params.appResults.appRootPath ?? '').trim()
|
|
1458
|
+
|| defaultInstallAppRootPath(params.envName));
|
|
1426
1459
|
}
|
|
1427
1460
|
commandStdio(verbose) {
|
|
1428
1461
|
return verbose ? 'inherit' : 'ignore';
|
|
@@ -1442,18 +1475,24 @@ export default class Install extends Command {
|
|
|
1442
1475
|
downloadResults: params.downloadResults,
|
|
1443
1476
|
verbose: params.verbose,
|
|
1444
1477
|
});
|
|
1445
|
-
const
|
|
1478
|
+
const downloadedProjectRoot = Install.resolveLocalProjectRoot({
|
|
1446
1479
|
envName: params.envName,
|
|
1447
1480
|
appResults: params.appResults,
|
|
1448
1481
|
downloadResults: params.downloadResults,
|
|
1449
1482
|
downloadCommandResult: result,
|
|
1450
1483
|
});
|
|
1451
|
-
params.appResults.appRootPath =
|
|
1452
|
-
|
|
1484
|
+
params.appResults.appRootPath = Install.resolveLocalProjectConfigPath({
|
|
1485
|
+
envName: params.envName,
|
|
1486
|
+
appResults: params.appResults,
|
|
1487
|
+
downloadResults: params.downloadResults,
|
|
1488
|
+
});
|
|
1489
|
+
return downloadedProjectRoot;
|
|
1453
1490
|
}
|
|
1454
1491
|
static buildLocalAppEnvVars(params) {
|
|
1455
|
-
const
|
|
1456
|
-
|| defaultInstallStoragePath(params.envName)
|
|
1492
|
+
const configuredStoragePath = String(params.appResults.storagePath ?? '').trim()
|
|
1493
|
+
|| defaultInstallStoragePath(params.envName);
|
|
1494
|
+
const storagePath = resolveConfiguredEnvPath(configuredStoragePath)
|
|
1495
|
+
?? resolveEnvRelativePath(defaultInstallStoragePath(params.envName));
|
|
1457
1496
|
const dbDialect = String(params.dbResults.dbDialect ?? 'postgres').trim()
|
|
1458
1497
|
|| 'postgres';
|
|
1459
1498
|
const appKey = crypto.randomBytes(32).toString('hex');
|
|
@@ -1646,8 +1685,6 @@ export default class Install extends Command {
|
|
|
1646
1685
|
const argv = [
|
|
1647
1686
|
params.envName,
|
|
1648
1687
|
'--no-intro',
|
|
1649
|
-
'--scope',
|
|
1650
|
-
CONFIG_SCOPE,
|
|
1651
1688
|
'--api-base-url',
|
|
1652
1689
|
apiBaseUrl,
|
|
1653
1690
|
'--auth-type',
|
|
@@ -1760,7 +1797,6 @@ export default class Install extends Command {
|
|
|
1760
1797
|
},
|
|
1761
1798
|
values: {
|
|
1762
1799
|
name: envName,
|
|
1763
|
-
scope: 'project',
|
|
1764
1800
|
...(resumePreset?.envAddPreset ?? {}),
|
|
1765
1801
|
},
|
|
1766
1802
|
yes,
|
|
@@ -1884,5 +1920,8 @@ export default class Install extends Command {
|
|
|
1884
1920
|
}
|
|
1885
1921
|
}
|
|
1886
1922
|
function downloadResultsValue(downloadResults, key) {
|
|
1923
|
+
if (key === 'version' && String(downloadResults.version ?? '').trim() === 'other') {
|
|
1924
|
+
return downloadResults.otherVersion;
|
|
1925
|
+
}
|
|
1887
1926
|
return downloadResults[key];
|
|
1888
1927
|
}
|
package/dist/commands/logs.js
CHANGED
|
@@ -49,13 +49,20 @@ export default class Logs extends Command {
|
|
|
49
49
|
if (!runtime) {
|
|
50
50
|
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
51
51
|
}
|
|
52
|
-
if (runtime.kind === '
|
|
52
|
+
if (runtime.kind === 'http') {
|
|
53
53
|
this.error([
|
|
54
54
|
`Can't show runtime logs for "${runtime.envName}" from this machine.`,
|
|
55
55
|
'This env only has an API connection, so there is no saved local app or Docker container to read logs from.',
|
|
56
56
|
'Connect it to a local checkout or reinstall it with npm, git, or Docker if you want CLI-managed logs.',
|
|
57
57
|
].join('\n'));
|
|
58
58
|
}
|
|
59
|
+
if (runtime.kind === 'ssh') {
|
|
60
|
+
this.error([
|
|
61
|
+
`Can't show runtime logs for "${runtime.envName}" yet.`,
|
|
62
|
+
'SSH env support is reserved but not implemented yet.',
|
|
63
|
+
'Use a local or Docker env for CLI-managed logs for now.',
|
|
64
|
+
].join('\n'));
|
|
65
|
+
}
|
|
59
66
|
const tail = String(flags.tail ?? 100);
|
|
60
67
|
const follow = flags.follow !== false;
|
|
61
68
|
printInfo(follow
|
package/dist/commands/pm/list.js
CHANGED
|
@@ -11,7 +11,7 @@ import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, runDockerN
|
|
|
11
11
|
export default class PmList extends Command {
|
|
12
12
|
static args = {};
|
|
13
13
|
static summary = 'List plugins for the selected env';
|
|
14
|
-
static description = 'List installed plugins in the selected env (npm/git runs locally, Docker runs inside the saved app container,
|
|
14
|
+
static description = 'List installed plugins in the selected env (npm/git runs locally, Docker runs inside the saved app container, HTTP envs fall back to the API)';
|
|
15
15
|
static examples = [
|
|
16
16
|
'<%= config.bin %> <%= command.id %>',
|
|
17
17
|
'<%= config.bin %> <%= command.id %> -e local',
|
|
@@ -49,6 +49,13 @@ export default class PmList extends Command {
|
|
|
49
49
|
}
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
|
+
if (runtime.kind === 'ssh') {
|
|
53
|
+
this.error([
|
|
54
|
+
`Can't list plugins for "${runtime.envName}" yet.`,
|
|
55
|
+
'SSH env support is reserved but not implemented yet.',
|
|
56
|
+
'Use a local, Docker, or HTTP env for plugin inspection right now.',
|
|
57
|
+
].join('\n'));
|
|
58
|
+
}
|
|
52
59
|
await this.config.runCommand('api:pm:list', ['--mode=summary']);
|
|
53
60
|
}
|
|
54
61
|
}
|
package/dist/commands/ps.js
CHANGED
|
@@ -10,12 +10,15 @@ import { Command, Flags } from '@oclif/core';
|
|
|
10
10
|
import { buildDockerDbContainerName, dockerContainerExists, dockerContainerIsRunning, formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, } from '../lib/app-runtime.js';
|
|
11
11
|
import { listEnvs } from '../lib/auth-store.js';
|
|
12
12
|
import { renderTable } from '../lib/ui.js';
|
|
13
|
+
function resolveApiBaseUrl(config) {
|
|
14
|
+
return String(config.apiBaseUrl ?? config.baseUrl ?? config.apibaseUrl ?? '').trim();
|
|
15
|
+
}
|
|
13
16
|
function appUrl(runtime) {
|
|
14
17
|
const port = String(runtime.env.config.appPort ?? '').trim();
|
|
15
18
|
if (port) {
|
|
16
19
|
return `http://127.0.0.1:${port}`;
|
|
17
20
|
}
|
|
18
|
-
const baseUrl =
|
|
21
|
+
const baseUrl = resolveApiBaseUrl(runtime.env.config);
|
|
19
22
|
return baseUrl.replace(/\/api\/?$/, '');
|
|
20
23
|
}
|
|
21
24
|
async function isLocalAppHealthy(runtime) {
|
|
@@ -47,30 +50,30 @@ async function dockerStatus(containerName) {
|
|
|
47
50
|
}
|
|
48
51
|
async function dbStatus(runtime) {
|
|
49
52
|
if (!runtime.env.config.builtinDb) {
|
|
50
|
-
return runtime.kind === '
|
|
53
|
+
return runtime.kind === 'http' ? 'external' : '-';
|
|
51
54
|
}
|
|
52
|
-
if (runtime.kind === '
|
|
55
|
+
if (runtime.kind === 'http') {
|
|
53
56
|
return 'external';
|
|
54
57
|
}
|
|
58
|
+
if (runtime.kind === 'ssh') {
|
|
59
|
+
return '-';
|
|
60
|
+
}
|
|
55
61
|
const dbDialect = String(runtime.env.config.dbDialect ?? 'postgres').trim() || 'postgres';
|
|
56
62
|
const containerName = buildDockerDbContainerName(runtime.envName, dbDialect, runtime.workspaceName);
|
|
57
63
|
return await dockerStatus(containerName);
|
|
58
64
|
}
|
|
59
|
-
async function
|
|
60
|
-
if (runtime.kind === '
|
|
61
|
-
return '
|
|
65
|
+
async function runtimeStatus(runtime) {
|
|
66
|
+
if (runtime.kind === 'http') {
|
|
67
|
+
return 'http';
|
|
68
|
+
}
|
|
69
|
+
if (runtime.kind === 'ssh') {
|
|
70
|
+
return 'ssh';
|
|
62
71
|
}
|
|
63
72
|
if (runtime.kind === 'docker') {
|
|
64
73
|
return await dockerStatus(runtime.containerName);
|
|
65
74
|
}
|
|
66
75
|
return await isLocalAppHealthy(runtime) ? 'running' : 'stopped';
|
|
67
76
|
}
|
|
68
|
-
function sourceLabel(runtime) {
|
|
69
|
-
if (runtime.kind === 'remote') {
|
|
70
|
-
return 'remote';
|
|
71
|
-
}
|
|
72
|
-
return runtime.source;
|
|
73
|
-
}
|
|
74
77
|
export default class Ps extends Command {
|
|
75
78
|
static description = 'Show NocoBase runtime status for configured envs without starting or stopping anything.';
|
|
76
79
|
static examples = [
|
|
@@ -105,12 +108,12 @@ export default class Ps extends Command {
|
|
|
105
108
|
}
|
|
106
109
|
rows.push([
|
|
107
110
|
runtime.envName,
|
|
108
|
-
|
|
109
|
-
await
|
|
111
|
+
runtime.kind,
|
|
112
|
+
await runtimeStatus(runtime),
|
|
110
113
|
await dbStatus(runtime),
|
|
111
114
|
appUrl(runtime),
|
|
112
115
|
]);
|
|
113
116
|
}
|
|
114
|
-
this.log(renderTable(['Env', '
|
|
117
|
+
this.log(renderTable(['Env', 'Kind', 'Status', 'Database', 'URL'], rows));
|
|
115
118
|
}
|
|
116
119
|
}
|
|
@@ -59,7 +59,7 @@ export default class SelfCheck extends Command {
|
|
|
59
59
|
['Update available', status.updateAvailable ? 'yes' : 'no'],
|
|
60
60
|
]));
|
|
61
61
|
if (status.updateAvailable && status.updatable) {
|
|
62
|
-
printInfo('Run `nb self update
|
|
62
|
+
printInfo('Run `nb self update`.');
|
|
63
63
|
}
|
|
64
64
|
else if (status.updateAvailable && status.updateBlockedReason) {
|
|
65
65
|
printInfo(status.updateBlockedReason);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
|
-
import { confirmAction } from '../../lib/ui.js';
|
|
10
|
+
import { confirmAction, setVerboseMode } from '../../lib/ui.js';
|
|
11
11
|
import { formatSelfUpdateUnavailableMessage, formatUnsupportedSelfUpdateMessage, inspectSelfStatus, updateSelf, } from '../../lib/self-manager.js';
|
|
12
12
|
export default class SelfUpdate extends Command {
|
|
13
13
|
static summary = 'Update the globally installed NocoBase CLI';
|
|
@@ -32,9 +32,14 @@ export default class SelfUpdate extends Command {
|
|
|
32
32
|
description: 'Output the result as JSON',
|
|
33
33
|
default: false,
|
|
34
34
|
}),
|
|
35
|
+
verbose: Flags.boolean({
|
|
36
|
+
description: 'Show detailed update output',
|
|
37
|
+
default: false,
|
|
38
|
+
}),
|
|
35
39
|
};
|
|
36
40
|
async run() {
|
|
37
41
|
const { flags } = await this.parse(SelfUpdate);
|
|
42
|
+
setVerboseMode(flags.verbose);
|
|
38
43
|
const status = await inspectSelfStatus({
|
|
39
44
|
channel: flags.channel,
|
|
40
45
|
});
|
|
@@ -53,6 +58,7 @@ export default class SelfUpdate extends Command {
|
|
|
53
58
|
}
|
|
54
59
|
const result = await updateSelf({
|
|
55
60
|
channel: flags.channel,
|
|
61
|
+
verbose: flags.verbose,
|
|
56
62
|
});
|
|
57
63
|
if (flags.json) {
|
|
58
64
|
this.log(JSON.stringify({
|
|
@@ -68,9 +74,13 @@ export default class SelfUpdate extends Command {
|
|
|
68
74
|
return;
|
|
69
75
|
}
|
|
70
76
|
if (result.action === 'noop') {
|
|
71
|
-
this.log(
|
|
77
|
+
this.log(flags.verbose
|
|
78
|
+
? `NocoBase CLI is already up to date at ${result.status.currentVersion}.`
|
|
79
|
+
: `NocoBase CLI is up to date: ${result.status.currentVersion}.`);
|
|
72
80
|
return;
|
|
73
81
|
}
|
|
74
|
-
this.log(
|
|
82
|
+
this.log(flags.verbose
|
|
83
|
+
? `Updated NocoBase CLI from ${result.status.currentVersion} using ${result.packageSpec}${result.targetVersion ? ` (latest ${result.status.channel} resolves to ${result.targetVersion})` : ''}.`
|
|
84
|
+
: `Updated NocoBase CLI: ${result.status.currentVersion} -> ${result.targetVersion}.`);
|
|
75
85
|
}
|
|
76
86
|
}
|
|
@@ -10,8 +10,8 @@ import { Command, Flags } from '@oclif/core';
|
|
|
10
10
|
import { inspectSkillsStatus } from '../../lib/skills-manager.js';
|
|
11
11
|
import { printInfo, renderTable } from '../../lib/ui.js';
|
|
12
12
|
export default class SkillsCheck extends Command {
|
|
13
|
-
static summary = 'Check the NocoBase AI coding skills
|
|
14
|
-
static description = 'Inspect the
|
|
13
|
+
static summary = 'Check the globally installed NocoBase AI coding skills';
|
|
14
|
+
static description = 'Inspect the global NocoBase AI coding skills and report whether they are managed by the CLI and whether an update is available.';
|
|
15
15
|
static examples = [
|
|
16
16
|
'<%= config.bin %> <%= command.id %>',
|
|
17
17
|
'<%= config.bin %> <%= command.id %> --json',
|
|
@@ -29,11 +29,15 @@ export default class SkillsCheck extends Command {
|
|
|
29
29
|
this.log(JSON.stringify({
|
|
30
30
|
ok: true,
|
|
31
31
|
kind: 'skills',
|
|
32
|
+
globalRoot: status.globalRoot,
|
|
32
33
|
workspaceRoot: status.workspaceRoot,
|
|
33
34
|
installed: status.installed,
|
|
34
35
|
managedByNb: status.managedByNb,
|
|
35
36
|
sourcePackage: status.sourcePackage,
|
|
37
|
+
npmPackageName: status.npmPackageName,
|
|
36
38
|
installedSkillNames: status.installedSkillNames,
|
|
39
|
+
installedVersion: status.installedVersion,
|
|
40
|
+
latestVersion: status.latestVersion,
|
|
37
41
|
installedRef: status.installedRef,
|
|
38
42
|
latestRef: status.latestRef,
|
|
39
43
|
updateAvailable: status.updateAvailable,
|
|
@@ -43,18 +47,20 @@ export default class SkillsCheck extends Command {
|
|
|
43
47
|
return;
|
|
44
48
|
}
|
|
45
49
|
this.log(renderTable(['Field', 'Value'], [
|
|
46
|
-
['
|
|
50
|
+
['Skills home', status.globalRoot],
|
|
47
51
|
['Installed', status.installed ? 'yes' : 'no'],
|
|
48
52
|
['Managed by nb', status.managedByNb ? 'yes' : 'no'],
|
|
49
53
|
['Installed skills', status.installedSkillNames.length ? status.installedSkillNames.join(', ') : '(none)'],
|
|
54
|
+
['Installed version', status.installedVersion ?? '(unknown)'],
|
|
55
|
+
['Latest version', status.latestVersion ?? '(unknown)'],
|
|
50
56
|
['Update available', status.updateAvailable === null ? 'unknown' : status.updateAvailable ? 'yes' : 'no'],
|
|
51
57
|
]));
|
|
52
58
|
if (!status.installed) {
|
|
53
|
-
printInfo('Run `nb skills install` to install the NocoBase AI coding skills
|
|
59
|
+
printInfo('Run `nb skills install` to install the NocoBase AI coding skills globally.');
|
|
54
60
|
return;
|
|
55
61
|
}
|
|
56
62
|
if (status.updateAvailable) {
|
|
57
|
-
printInfo('Run `nb skills update` to refresh the NocoBase AI coding skills
|
|
63
|
+
printInfo('Run `nb skills update` to refresh the global NocoBase AI coding skills.');
|
|
58
64
|
}
|
|
59
65
|
if (status.registryError) {
|
|
60
66
|
printInfo(`Update check warning: ${status.registryError}`);
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Command, loadHelpClass } from '@oclif/core';
|
|
10
10
|
export default class Skills extends Command {
|
|
11
|
-
static summary = 'Inspect or synchronize NocoBase AI coding skills
|
|
11
|
+
static summary = 'Inspect or synchronize global NocoBase AI coding skills';
|
|
12
12
|
async run() {
|
|
13
13
|
await this.parse(Skills);
|
|
14
14
|
const Help = await loadHelpClass(this.config);
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
|
-
import { confirmAction } from '../../lib/ui.js';
|
|
10
|
+
import { confirmAction, setVerboseMode } from '../../lib/ui.js';
|
|
11
11
|
import { installNocoBaseSkills } from '../../lib/skills-manager.js';
|
|
12
12
|
export default class SkillsInstall extends Command {
|
|
13
|
-
static summary = 'Install the NocoBase AI coding skills
|
|
14
|
-
static description = 'Install the NocoBase AI coding skills
|
|
13
|
+
static summary = 'Install the NocoBase AI coding skills globally';
|
|
14
|
+
static description = 'Install the NocoBase AI coding skills globally. If they are already installed, this command does not update them.';
|
|
15
15
|
static examples = [
|
|
16
16
|
'<%= config.bin %> <%= command.id %>',
|
|
17
17
|
'<%= config.bin %> <%= command.id %> --yes',
|
|
@@ -27,32 +27,45 @@ export default class SkillsInstall extends Command {
|
|
|
27
27
|
description: 'Output the result as JSON',
|
|
28
28
|
default: false,
|
|
29
29
|
}),
|
|
30
|
+
verbose: Flags.boolean({
|
|
31
|
+
description: 'Show detailed install output',
|
|
32
|
+
default: false,
|
|
33
|
+
}),
|
|
30
34
|
};
|
|
31
35
|
async run() {
|
|
32
36
|
const { flags } = await this.parse(SkillsInstall);
|
|
37
|
+
setVerboseMode(flags.verbose);
|
|
33
38
|
if (!flags.yes) {
|
|
34
|
-
const confirmed = await confirmAction('Install the NocoBase AI coding skills
|
|
39
|
+
const confirmed = await confirmAction('Install the NocoBase AI coding skills globally?', { defaultValue: true });
|
|
35
40
|
if (!confirmed) {
|
|
36
41
|
this.log('Skipped skills install.');
|
|
37
42
|
return;
|
|
38
43
|
}
|
|
39
44
|
}
|
|
40
|
-
const result = await installNocoBaseSkills(
|
|
45
|
+
const result = await installNocoBaseSkills({
|
|
46
|
+
verbose: flags.verbose,
|
|
47
|
+
});
|
|
41
48
|
if (flags.json) {
|
|
42
49
|
this.log(JSON.stringify({
|
|
43
50
|
ok: true,
|
|
44
51
|
kind: 'skills',
|
|
45
52
|
action: result.action,
|
|
53
|
+
globalRoot: result.status.globalRoot,
|
|
46
54
|
workspaceRoot: result.status.workspaceRoot,
|
|
47
55
|
installedSkillNames: result.status.installedSkillNames,
|
|
56
|
+
installedVersion: result.status.installedVersion,
|
|
48
57
|
installedRef: result.status.installedRef,
|
|
49
58
|
}, null, 2));
|
|
50
59
|
return;
|
|
51
60
|
}
|
|
52
61
|
if (result.action === 'noop') {
|
|
53
|
-
this.log(
|
|
62
|
+
this.log(flags.verbose
|
|
63
|
+
? 'NocoBase AI coding skills are already installed globally. Run `nb skills update` to refresh them.'
|
|
64
|
+
: 'NocoBase AI coding skills are already installed globally.');
|
|
54
65
|
return;
|
|
55
66
|
}
|
|
56
|
-
this.log(
|
|
67
|
+
this.log(flags.verbose
|
|
68
|
+
? 'Installed the NocoBase AI coding skills globally.'
|
|
69
|
+
: 'Installed NocoBase AI coding skills globally.');
|
|
57
70
|
}
|
|
58
71
|
}
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { Command, Flags } from '@oclif/core';
|
|
10
|
-
import { confirmAction } from '../../lib/ui.js';
|
|
10
|
+
import { confirmAction, setVerboseMode } from '../../lib/ui.js';
|
|
11
11
|
import { updateNocoBaseSkills } from '../../lib/skills-manager.js';
|
|
12
12
|
export default class SkillsUpdate extends Command {
|
|
13
|
-
static summary = 'Update the NocoBase AI coding skills
|
|
14
|
-
static description = 'Refresh the NocoBase AI coding skills
|
|
13
|
+
static summary = 'Update the globally installed NocoBase AI coding skills';
|
|
14
|
+
static description = 'Refresh the globally installed NocoBase AI coding skills. This command only updates an existing @nocobase/skills install.';
|
|
15
15
|
static examples = [
|
|
16
16
|
'<%= config.bin %> <%= command.id %>',
|
|
17
17
|
'<%= config.bin %> <%= command.id %> --yes',
|
|
@@ -27,32 +27,45 @@ export default class SkillsUpdate extends Command {
|
|
|
27
27
|
description: 'Output the result as JSON',
|
|
28
28
|
default: false,
|
|
29
29
|
}),
|
|
30
|
+
verbose: Flags.boolean({
|
|
31
|
+
description: 'Show detailed update output',
|
|
32
|
+
default: false,
|
|
33
|
+
}),
|
|
30
34
|
};
|
|
31
35
|
async run() {
|
|
32
36
|
const { flags } = await this.parse(SkillsUpdate);
|
|
37
|
+
setVerboseMode(flags.verbose);
|
|
33
38
|
if (!flags.yes) {
|
|
34
|
-
const confirmed = await confirmAction('Update the NocoBase AI coding skills
|
|
39
|
+
const confirmed = await confirmAction('Update the globally installed NocoBase AI coding skills?', { defaultValue: true });
|
|
35
40
|
if (!confirmed) {
|
|
36
41
|
this.log('Skipped skills update.');
|
|
37
42
|
return;
|
|
38
43
|
}
|
|
39
44
|
}
|
|
40
|
-
const result = await updateNocoBaseSkills(
|
|
45
|
+
const result = await updateNocoBaseSkills({
|
|
46
|
+
verbose: flags.verbose,
|
|
47
|
+
});
|
|
41
48
|
if (flags.json) {
|
|
42
49
|
this.log(JSON.stringify({
|
|
43
50
|
ok: true,
|
|
44
51
|
kind: 'skills',
|
|
45
52
|
action: result.action,
|
|
53
|
+
globalRoot: result.status.globalRoot,
|
|
46
54
|
workspaceRoot: result.status.workspaceRoot,
|
|
47
55
|
installedSkillNames: result.status.installedSkillNames,
|
|
56
|
+
installedVersion: result.status.installedVersion,
|
|
48
57
|
installedRef: result.status.installedRef,
|
|
49
58
|
}, null, 2));
|
|
50
59
|
return;
|
|
51
60
|
}
|
|
52
61
|
if (result.action === 'noop') {
|
|
53
|
-
this.log(
|
|
62
|
+
this.log(flags.verbose
|
|
63
|
+
? 'NocoBase AI coding skills are already up to date globally.'
|
|
64
|
+
: 'NocoBase AI coding skills are up to date.');
|
|
54
65
|
return;
|
|
55
66
|
}
|
|
56
|
-
this.log(
|
|
67
|
+
this.log(flags.verbose
|
|
68
|
+
? 'Updated the global NocoBase AI coding skills.'
|
|
69
|
+
: 'Updated NocoBase AI coding skills globally.');
|
|
57
70
|
}
|
|
58
71
|
}
|
package/dist/commands/start.js
CHANGED
|
@@ -111,13 +111,20 @@ export default class Start extends Command {
|
|
|
111
111
|
if (!runtime) {
|
|
112
112
|
this.error(formatMissingManagedAppEnvMessage(requestedEnv));
|
|
113
113
|
}
|
|
114
|
-
if (runtime.kind === '
|
|
114
|
+
if (runtime.kind === 'http') {
|
|
115
115
|
this.error([
|
|
116
116
|
`Can't start "${runtime.envName}" from this machine.`,
|
|
117
117
|
'This env only has an API connection, so there is no saved local app or Docker runtime to launch here.',
|
|
118
118
|
'Connect it to a local checkout or reinstall it with npm, git, or Docker if you want CLI-managed start and stop.',
|
|
119
119
|
].join('\n'));
|
|
120
120
|
}
|
|
121
|
+
if (runtime.kind === 'ssh') {
|
|
122
|
+
this.error([
|
|
123
|
+
`Can't start "${runtime.envName}" yet.`,
|
|
124
|
+
'SSH env support is reserved but not implemented yet.',
|
|
125
|
+
'Use a local or Docker env if you need CLI-managed start and stop right now.',
|
|
126
|
+
].join('\n'));
|
|
127
|
+
}
|
|
121
128
|
if (runtime.kind === 'docker') {
|
|
122
129
|
const unsupportedFlags = [
|
|
123
130
|
flags.quickstart ? '--quickstart' : undefined,
|