@nocobase/cli 2.1.0-alpha.23 → 2.1.0-alpha.24
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 +31 -0
- package/bin/run.js +13 -11
- package/dist/commands/init.js +5 -5
- package/dist/commands/install.js +36 -7
- package/dist/commands/self/check.js +71 -0
- package/dist/commands/self/index.js +20 -0
- package/dist/commands/self/update.js +76 -0
- package/dist/commands/skills/check.js +63 -0
- package/dist/commands/skills/index.js +20 -0
- package/dist/commands/skills/install.js +58 -0
- package/dist/commands/skills/update.js +58 -0
- package/dist/commands/test.js +466 -0
- package/dist/lib/run-npm.js +82 -8
- package/dist/lib/self-manager.js +246 -0
- package/dist/lib/skills-manager.js +202 -0
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -147,6 +147,8 @@ In non-interactive mode, pass these setup-only flags again because they are not
|
|
|
147
147
|
| `nb env` | Manage saved CLI env connections. |
|
|
148
148
|
| `nb api` | Call NocoBase API resources from the CLI. |
|
|
149
149
|
| `nb pm` | Manage plugins for the selected NocoBase env. |
|
|
150
|
+
| `nb self` | Check or update the installed NocoBase CLI. |
|
|
151
|
+
| `nb skills` | Check, install, or update NocoBase AI coding skills for the current workspace. |
|
|
150
152
|
|
|
151
153
|
Recommended style: use `--env` explicitly for app/runtime commands. `-e` is the short form:
|
|
152
154
|
|
|
@@ -166,6 +168,35 @@ nb upgrade -e app1
|
|
|
166
168
|
nb db start -e app1
|
|
167
169
|
```
|
|
168
170
|
|
|
171
|
+
## CLI And Skills Updates
|
|
172
|
+
|
|
173
|
+
Check whether the installed CLI itself is up to date:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
nb self check
|
|
177
|
+
nb self check --json
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Update the CLI when it is installed globally with npm:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
nb self update
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Check whether the current workspace already has the NocoBase AI coding skills:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
nb skills check
|
|
190
|
+
nb skills check --json
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Install the skills for the first time, or update an existing `nocobase/skills` install:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
nb skills install
|
|
197
|
+
nb skills update
|
|
198
|
+
```
|
|
199
|
+
|
|
169
200
|
## Runtime Types
|
|
170
201
|
|
|
171
202
|
### Docker
|
package/bin/run.js
CHANGED
|
@@ -38,18 +38,20 @@ function reexecWithTsx() {
|
|
|
38
38
|
process.exit(1);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
41
|
+
const reexecArgs = ['--import', pathToFileURL(tsxEntry).href];
|
|
42
|
+
const supportedFlags = Array.from(process.allowedNodeEnvironmentFlags);
|
|
43
|
+
if (supportedFlags.some((flag) => flag === '--disable-warning' || flag.startsWith('--disable-warning='))) {
|
|
44
|
+
reexecArgs.push('--disable-warning=ExperimentalWarning');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const result = spawnSync(process.execPath, [...reexecArgs, ...process.argv.slice(1)], {
|
|
48
|
+
stdio: 'inherit',
|
|
49
|
+
env: {
|
|
50
|
+
...process.env,
|
|
51
|
+
_NOCO_CLI_TSX_CHILD: '1',
|
|
52
|
+
NODE_ENV: 'development',
|
|
51
53
|
},
|
|
52
|
-
);
|
|
54
|
+
});
|
|
53
55
|
process.exit(result.status === null ? 1 : result.status);
|
|
54
56
|
}
|
|
55
57
|
|
package/dist/commands/init.js
CHANGED
|
@@ -17,7 +17,7 @@ import { runPromptCatalog, } from "../lib/prompt-catalog.js";
|
|
|
17
17
|
import { applyCliLocale, localeText, translateCli } from "../lib/cli-locale.js";
|
|
18
18
|
import { runPromptCatalogWebUI, } from "../lib/prompt-web-ui.js";
|
|
19
19
|
import { validateApiBaseUrl, validateEnvKey } from "../lib/prompt-validators.js";
|
|
20
|
-
import {
|
|
20
|
+
import { installNocoBaseSkills } from '../lib/skills-manager.js';
|
|
21
21
|
import Download from "./download.js";
|
|
22
22
|
import EnvAdd from "./env/add.js";
|
|
23
23
|
import Install, { defaultDbPortForDialect } from "./install.js";
|
|
@@ -284,8 +284,8 @@ Prompt modes:
|
|
|
284
284
|
p.intro(initTitle());
|
|
285
285
|
if (Boolean(normalizedFlags['install-skills'])) {
|
|
286
286
|
try {
|
|
287
|
-
p.log.step('Installing NocoBase agent skills (
|
|
288
|
-
await
|
|
287
|
+
p.log.step('Installing NocoBase agent skills (nb skills install)');
|
|
288
|
+
await installNocoBaseSkills();
|
|
289
289
|
}
|
|
290
290
|
catch (error) {
|
|
291
291
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -375,8 +375,8 @@ Prompt modes:
|
|
|
375
375
|
}
|
|
376
376
|
if (installSkills) {
|
|
377
377
|
try {
|
|
378
|
-
p.log.step('Installing NocoBase agent skills (
|
|
379
|
-
await
|
|
378
|
+
p.log.step('Installing NocoBase agent skills (nb skills install)');
|
|
379
|
+
await installNocoBaseSkills();
|
|
380
380
|
}
|
|
381
381
|
catch (error) {
|
|
382
382
|
const message = error instanceof Error ? error.message : String(error);
|
package/dist/commands/install.js
CHANGED
|
@@ -1207,6 +1207,7 @@ export default class Install extends Command {
|
|
|
1207
1207
|
async removeDockerContainer(name) {
|
|
1208
1208
|
await run('docker', ['rm', '-f', name], {
|
|
1209
1209
|
errorName: 'docker rm',
|
|
1210
|
+
stdio: 'ignore',
|
|
1210
1211
|
});
|
|
1211
1212
|
}
|
|
1212
1213
|
async removeDockerContainerIfForced(params) {
|
|
@@ -1238,7 +1239,7 @@ export default class Install extends Command {
|
|
|
1238
1239
|
}
|
|
1239
1240
|
return env;
|
|
1240
1241
|
}
|
|
1241
|
-
async ensureBuiltinDbContainer(plan) {
|
|
1242
|
+
async ensureBuiltinDbContainer(plan, options) {
|
|
1242
1243
|
const exists = await this.dockerContainerExists(plan.containerName);
|
|
1243
1244
|
if (exists) {
|
|
1244
1245
|
p.log.info(`Built-in ${plan.dbDialect} container already exists: ${plan.containerName}`);
|
|
@@ -1247,6 +1248,7 @@ export default class Install extends Command {
|
|
|
1247
1248
|
await mkdir(plan.dataDir, { recursive: true });
|
|
1248
1249
|
await run('docker', plan.args, {
|
|
1249
1250
|
errorName: 'docker run',
|
|
1251
|
+
stdio: options?.stdio ?? 'ignore',
|
|
1250
1252
|
});
|
|
1251
1253
|
}
|
|
1252
1254
|
async startBuiltinDb(params) {
|
|
@@ -1278,7 +1280,9 @@ export default class Install extends Command {
|
|
|
1278
1280
|
throw new Error(`Built-in ${plan.dbDialect} needs host port ${plan.dbPort}, but ${portError}`);
|
|
1279
1281
|
}
|
|
1280
1282
|
}
|
|
1281
|
-
await this.ensureBuiltinDbContainer(plan
|
|
1283
|
+
await this.ensureBuiltinDbContainer(plan, {
|
|
1284
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
1285
|
+
});
|
|
1282
1286
|
p.log.info(`Built-in ${plan.dbDialect} database is ready at ${plan.dbHost}:${plan.dbPort}`);
|
|
1283
1287
|
return plan;
|
|
1284
1288
|
}
|
|
@@ -1332,7 +1336,7 @@ export default class Install extends Command {
|
|
|
1332
1336
|
args,
|
|
1333
1337
|
};
|
|
1334
1338
|
}
|
|
1335
|
-
async ensureDockerAppContainer(plan) {
|
|
1339
|
+
async ensureDockerAppContainer(plan, options) {
|
|
1336
1340
|
const exists = await this.dockerContainerExists(plan.containerName);
|
|
1337
1341
|
if (exists) {
|
|
1338
1342
|
p.log.info(`App container already exists: ${plan.containerName}`);
|
|
@@ -1341,6 +1345,7 @@ export default class Install extends Command {
|
|
|
1341
1345
|
await mkdir(plan.storagePath, { recursive: true });
|
|
1342
1346
|
await run('docker', plan.args, {
|
|
1343
1347
|
errorName: 'docker run',
|
|
1348
|
+
stdio: options?.stdio ?? 'ignore',
|
|
1344
1349
|
});
|
|
1345
1350
|
return 'created';
|
|
1346
1351
|
}
|
|
@@ -1363,7 +1368,9 @@ export default class Install extends Command {
|
|
|
1363
1368
|
displayName: 'app container',
|
|
1364
1369
|
force: params.force,
|
|
1365
1370
|
});
|
|
1366
|
-
const containerState = await this.ensureDockerAppContainer(plan
|
|
1371
|
+
const containerState = await this.ensureDockerAppContainer(plan, {
|
|
1372
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
1373
|
+
});
|
|
1367
1374
|
if (containerState === 'existing') {
|
|
1368
1375
|
const env = await this.inspectDockerContainerEnv(plan.containerName);
|
|
1369
1376
|
plan.appKey = env.APP_KEY || plan.appKey;
|
|
@@ -1417,12 +1424,24 @@ export default class Install extends Command {
|
|
|
1417
1424
|
|| defaultInstallAppRootPath(params.envName);
|
|
1418
1425
|
return path.resolve(process.cwd(), outputDir);
|
|
1419
1426
|
}
|
|
1420
|
-
|
|
1427
|
+
commandStdio(verbose) {
|
|
1428
|
+
return verbose ? 'inherit' : 'ignore';
|
|
1429
|
+
}
|
|
1430
|
+
async downloadManagedSource(params) {
|
|
1421
1431
|
const argv = Install.buildDownloadArgvFromResults(params.downloadResults, {
|
|
1422
1432
|
verbose: params.verbose,
|
|
1423
1433
|
});
|
|
1424
|
-
|
|
1425
|
-
|
|
1434
|
+
const source = String(params.downloadResults.source ?? '').trim();
|
|
1435
|
+
p.log.step(source === 'docker'
|
|
1436
|
+
? 'Downloading Docker image'
|
|
1437
|
+
: 'Downloading local NocoBase app files');
|
|
1438
|
+
return await this.config.runCommand('download', argv);
|
|
1439
|
+
}
|
|
1440
|
+
async downloadLocalApp(params) {
|
|
1441
|
+
const result = await this.downloadManagedSource({
|
|
1442
|
+
downloadResults: params.downloadResults,
|
|
1443
|
+
verbose: params.verbose,
|
|
1444
|
+
});
|
|
1426
1445
|
const projectRoot = Install.resolveLocalProjectRoot({
|
|
1427
1446
|
envName: params.envName,
|
|
1428
1447
|
appResults: params.appResults,
|
|
@@ -1476,6 +1495,7 @@ export default class Install extends Command {
|
|
|
1476
1495
|
await runNocoBaseCommand(['pm2', 'kill'], {
|
|
1477
1496
|
cwd: params.projectRoot,
|
|
1478
1497
|
env,
|
|
1498
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
1479
1499
|
});
|
|
1480
1500
|
}
|
|
1481
1501
|
catch (error) {
|
|
@@ -1486,6 +1506,7 @@ export default class Install extends Command {
|
|
|
1486
1506
|
await runNocoBaseCommand(args, {
|
|
1487
1507
|
cwd: params.projectRoot,
|
|
1488
1508
|
env,
|
|
1509
|
+
stdio: params.commandStdio ?? 'ignore',
|
|
1489
1510
|
});
|
|
1490
1511
|
p.log.info(`Local app is starting at http://127.0.0.1:${env.APP_PORT}`);
|
|
1491
1512
|
return {
|
|
@@ -1761,6 +1782,7 @@ export default class Install extends Command {
|
|
|
1761
1782
|
const parsed = {
|
|
1762
1783
|
...flags,
|
|
1763
1784
|
};
|
|
1785
|
+
const commandStdio = this.commandStdio(parsed.verbose);
|
|
1764
1786
|
if (!parsed['no-intro']) {
|
|
1765
1787
|
p.intro('Set Up NocoBase');
|
|
1766
1788
|
}
|
|
@@ -1787,6 +1809,7 @@ export default class Install extends Command {
|
|
|
1787
1809
|
downloadResults,
|
|
1788
1810
|
dbResults,
|
|
1789
1811
|
force: parsed.force,
|
|
1812
|
+
commandStdio,
|
|
1790
1813
|
});
|
|
1791
1814
|
dbResults.dbHost = builtinDbPlan.dbHost;
|
|
1792
1815
|
dbResults.dbPort = builtinDbPlan.dbPort;
|
|
@@ -1799,6 +1822,10 @@ export default class Install extends Command {
|
|
|
1799
1822
|
let localAppPlan;
|
|
1800
1823
|
if (Boolean(appResults.fetchSource)) {
|
|
1801
1824
|
if (source === 'docker') {
|
|
1825
|
+
await this.downloadManagedSource({
|
|
1826
|
+
downloadResults,
|
|
1827
|
+
verbose: parsed.verbose,
|
|
1828
|
+
});
|
|
1802
1829
|
dockerAppPlan = await this.installDockerApp({
|
|
1803
1830
|
envName,
|
|
1804
1831
|
workspaceName,
|
|
@@ -1808,6 +1835,7 @@ export default class Install extends Command {
|
|
|
1808
1835
|
rootResults,
|
|
1809
1836
|
builtinDbPlan,
|
|
1810
1837
|
force: parsed.force,
|
|
1838
|
+
commandStdio,
|
|
1811
1839
|
});
|
|
1812
1840
|
appResults.appKey = dockerAppPlan.appKey;
|
|
1813
1841
|
appResults.timeZone = dockerAppPlan.timeZone;
|
|
@@ -1826,6 +1854,7 @@ export default class Install extends Command {
|
|
|
1826
1854
|
appResults,
|
|
1827
1855
|
dbResults,
|
|
1828
1856
|
rootResults,
|
|
1857
|
+
commandStdio,
|
|
1829
1858
|
});
|
|
1830
1859
|
appResults.appKey = localAppPlan.appKey;
|
|
1831
1860
|
appResults.timeZone = localAppPlan.timeZone;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, Flags } from '@oclif/core';
|
|
10
|
+
import { getRecommendedSelfUpdateCommand, inspectSelfStatus, } from '../../lib/self-manager.js';
|
|
11
|
+
import { printInfo, renderTable } from '../../lib/ui.js';
|
|
12
|
+
export default class SelfCheck extends Command {
|
|
13
|
+
static summary = 'Check the installed NocoBase CLI version and self-update support';
|
|
14
|
+
static description = 'Inspect the current NocoBase CLI install, resolve the latest version for the selected channel, and report whether automatic self-update is supported.';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> <%= command.id %>',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> --channel beta',
|
|
18
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
19
|
+
];
|
|
20
|
+
static flags = {
|
|
21
|
+
channel: Flags.string({
|
|
22
|
+
description: 'Release channel to compare against. Defaults to the current CLI channel.',
|
|
23
|
+
options: ['auto', 'latest', 'beta', 'alpha'],
|
|
24
|
+
default: 'auto',
|
|
25
|
+
}),
|
|
26
|
+
json: Flags.boolean({
|
|
27
|
+
description: 'Output the result as JSON',
|
|
28
|
+
default: false,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const { flags } = await this.parse(SelfCheck);
|
|
33
|
+
const status = await inspectSelfStatus({
|
|
34
|
+
channel: flags.channel,
|
|
35
|
+
});
|
|
36
|
+
if (flags.json) {
|
|
37
|
+
this.log(JSON.stringify({
|
|
38
|
+
ok: true,
|
|
39
|
+
kind: 'self',
|
|
40
|
+
packageName: status.packageName,
|
|
41
|
+
currentVersion: status.currentVersion,
|
|
42
|
+
latestVersion: status.latestVersion,
|
|
43
|
+
channel: status.channel,
|
|
44
|
+
updateAvailable: status.updateAvailable,
|
|
45
|
+
installMethod: status.installMethod,
|
|
46
|
+
updatable: status.updatable,
|
|
47
|
+
updateBlockedReason: status.updateBlockedReason,
|
|
48
|
+
recommendedCommand: getRecommendedSelfUpdateCommand(status),
|
|
49
|
+
registryError: status.registryError,
|
|
50
|
+
}, null, 2));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this.log(renderTable(['Field', 'Value'], [
|
|
54
|
+
['Current version', status.currentVersion || 'unknown'],
|
|
55
|
+
['Latest version', status.latestVersion || 'unknown'],
|
|
56
|
+
['Channel', status.channel],
|
|
57
|
+
['Install method', status.installMethod],
|
|
58
|
+
['Auto-update', status.updatable ? 'supported' : 'not supported'],
|
|
59
|
+
['Update available', status.updateAvailable ? 'yes' : 'no'],
|
|
60
|
+
]));
|
|
61
|
+
if (status.updateAvailable && status.updatable) {
|
|
62
|
+
printInfo('Run `nb self update` to update the CLI.');
|
|
63
|
+
}
|
|
64
|
+
else if (status.updateAvailable && status.updateBlockedReason) {
|
|
65
|
+
printInfo(status.updateBlockedReason);
|
|
66
|
+
}
|
|
67
|
+
if (status.registryError) {
|
|
68
|
+
printInfo(`Version check warning: ${status.registryError}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, loadHelpClass } from '@oclif/core';
|
|
10
|
+
export default class Self extends Command {
|
|
11
|
+
static summary = 'Inspect or update the NocoBase CLI itself';
|
|
12
|
+
async run() {
|
|
13
|
+
await this.parse(Self);
|
|
14
|
+
const Help = await loadHelpClass(this.config);
|
|
15
|
+
await new Help(this.config, this.config.pjson.oclif.helpOptions ?? this.config.pjson.helpOptions).showHelp([
|
|
16
|
+
this.id ?? 'self',
|
|
17
|
+
...this.argv,
|
|
18
|
+
]);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, Flags } from '@oclif/core';
|
|
10
|
+
import { confirmAction } from '../../lib/ui.js';
|
|
11
|
+
import { formatSelfUpdateUnavailableMessage, formatUnsupportedSelfUpdateMessage, inspectSelfStatus, updateSelf, } from '../../lib/self-manager.js';
|
|
12
|
+
export default class SelfUpdate extends Command {
|
|
13
|
+
static summary = 'Update the globally installed NocoBase CLI';
|
|
14
|
+
static description = 'Update the current NocoBase CLI install when it is managed by a standard global npm install.';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> <%= command.id %>',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> --yes',
|
|
18
|
+
'<%= config.bin %> <%= command.id %> --channel alpha --json',
|
|
19
|
+
];
|
|
20
|
+
static flags = {
|
|
21
|
+
channel: Flags.string({
|
|
22
|
+
description: 'Release channel to update to. Defaults to the current CLI channel.',
|
|
23
|
+
options: ['auto', 'latest', 'beta', 'alpha'],
|
|
24
|
+
default: 'auto',
|
|
25
|
+
}),
|
|
26
|
+
yes: Flags.boolean({
|
|
27
|
+
char: 'y',
|
|
28
|
+
description: 'Skip the update confirmation prompt',
|
|
29
|
+
default: false,
|
|
30
|
+
}),
|
|
31
|
+
json: Flags.boolean({
|
|
32
|
+
description: 'Output the result as JSON',
|
|
33
|
+
default: false,
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
async run() {
|
|
37
|
+
const { flags } = await this.parse(SelfUpdate);
|
|
38
|
+
const status = await inspectSelfStatus({
|
|
39
|
+
channel: flags.channel,
|
|
40
|
+
});
|
|
41
|
+
if (!status.updatable) {
|
|
42
|
+
this.error(formatUnsupportedSelfUpdateMessage(status));
|
|
43
|
+
}
|
|
44
|
+
if (!status.latestVersion && status.registryError) {
|
|
45
|
+
this.error(formatSelfUpdateUnavailableMessage(status));
|
|
46
|
+
}
|
|
47
|
+
if (!flags.yes && status.updateAvailable) {
|
|
48
|
+
const confirmed = await confirmAction(`Update ${status.packageName} from ${status.currentVersion} to ${status.latestVersion}?`, { defaultValue: false });
|
|
49
|
+
if (!confirmed) {
|
|
50
|
+
this.log('Skipped CLI update.');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const result = await updateSelf({
|
|
55
|
+
channel: flags.channel,
|
|
56
|
+
});
|
|
57
|
+
if (flags.json) {
|
|
58
|
+
this.log(JSON.stringify({
|
|
59
|
+
ok: true,
|
|
60
|
+
kind: 'self',
|
|
61
|
+
action: result.action,
|
|
62
|
+
packageName: result.status.packageName,
|
|
63
|
+
packageSpec: result.packageSpec,
|
|
64
|
+
channel: result.status.channel,
|
|
65
|
+
fromVersion: result.status.currentVersion,
|
|
66
|
+
toVersion: result.targetVersion,
|
|
67
|
+
}, null, 2));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (result.action === 'noop') {
|
|
71
|
+
this.log(`NocoBase CLI is already up to date at ${result.status.currentVersion}.`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.log(`Updated NocoBase CLI from ${result.status.currentVersion} using ${result.packageSpec}${result.targetVersion ? ` (latest ${result.status.channel} resolves to ${result.targetVersion})` : ''}.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, Flags } from '@oclif/core';
|
|
10
|
+
import { inspectSkillsStatus } from '../../lib/skills-manager.js';
|
|
11
|
+
import { printInfo, renderTable } from '../../lib/ui.js';
|
|
12
|
+
export default class SkillsCheck extends Command {
|
|
13
|
+
static summary = 'Check the NocoBase AI coding skills installed for this workspace';
|
|
14
|
+
static description = 'Inspect the current workspace for NocoBase AI coding skills and report whether they are managed by the CLI and whether an update is available.';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> <%= command.id %>',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
18
|
+
];
|
|
19
|
+
static flags = {
|
|
20
|
+
json: Flags.boolean({
|
|
21
|
+
description: 'Output the result as JSON',
|
|
22
|
+
default: false,
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
async run() {
|
|
26
|
+
const { flags } = await this.parse(SkillsCheck);
|
|
27
|
+
const status = await inspectSkillsStatus();
|
|
28
|
+
if (flags.json) {
|
|
29
|
+
this.log(JSON.stringify({
|
|
30
|
+
ok: true,
|
|
31
|
+
kind: 'skills',
|
|
32
|
+
workspaceRoot: status.workspaceRoot,
|
|
33
|
+
installed: status.installed,
|
|
34
|
+
managedByNb: status.managedByNb,
|
|
35
|
+
sourcePackage: status.sourcePackage,
|
|
36
|
+
installedSkillNames: status.installedSkillNames,
|
|
37
|
+
installedRef: status.installedRef,
|
|
38
|
+
latestRef: status.latestRef,
|
|
39
|
+
updateAvailable: status.updateAvailable,
|
|
40
|
+
recommendedCommand: status.installed ? 'nb skills update --yes' : 'nb skills install --yes',
|
|
41
|
+
registryError: status.registryError,
|
|
42
|
+
}, null, 2));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.log(renderTable(['Field', 'Value'], [
|
|
46
|
+
['Workspace', status.workspaceRoot],
|
|
47
|
+
['Installed', status.installed ? 'yes' : 'no'],
|
|
48
|
+
['Managed by nb', status.managedByNb ? 'yes' : 'no'],
|
|
49
|
+
['Installed skills', status.installedSkillNames.length ? status.installedSkillNames.join(', ') : '(none)'],
|
|
50
|
+
['Update available', status.updateAvailable === null ? 'unknown' : status.updateAvailable ? 'yes' : 'no'],
|
|
51
|
+
]));
|
|
52
|
+
if (!status.installed) {
|
|
53
|
+
printInfo('Run `nb skills install` to install the NocoBase AI coding skills for this workspace.');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (status.updateAvailable) {
|
|
57
|
+
printInfo('Run `nb skills update` to refresh the NocoBase AI coding skills for this workspace.');
|
|
58
|
+
}
|
|
59
|
+
if (status.registryError) {
|
|
60
|
+
printInfo(`Update check warning: ${status.registryError}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, loadHelpClass } from '@oclif/core';
|
|
10
|
+
export default class Skills extends Command {
|
|
11
|
+
static summary = 'Inspect or synchronize NocoBase AI coding skills for this workspace';
|
|
12
|
+
async run() {
|
|
13
|
+
await this.parse(Skills);
|
|
14
|
+
const Help = await loadHelpClass(this.config);
|
|
15
|
+
await new Help(this.config, this.config.pjson.oclif.helpOptions ?? this.config.pjson.helpOptions).showHelp([
|
|
16
|
+
this.id ?? 'skills',
|
|
17
|
+
...this.argv,
|
|
18
|
+
]);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, Flags } from '@oclif/core';
|
|
10
|
+
import { confirmAction } from '../../lib/ui.js';
|
|
11
|
+
import { installNocoBaseSkills } from '../../lib/skills-manager.js';
|
|
12
|
+
export default class SkillsInstall extends Command {
|
|
13
|
+
static summary = 'Install the NocoBase AI coding skills for this workspace';
|
|
14
|
+
static description = 'Install the NocoBase AI coding skills for the current workspace. If they are already installed, this command does not update them.';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> <%= command.id %>',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> --yes',
|
|
18
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
19
|
+
];
|
|
20
|
+
static flags = {
|
|
21
|
+
yes: Flags.boolean({
|
|
22
|
+
char: 'y',
|
|
23
|
+
description: 'Skip the install confirmation prompt',
|
|
24
|
+
default: false,
|
|
25
|
+
}),
|
|
26
|
+
json: Flags.boolean({
|
|
27
|
+
description: 'Output the result as JSON',
|
|
28
|
+
default: false,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const { flags } = await this.parse(SkillsInstall);
|
|
33
|
+
if (!flags.yes) {
|
|
34
|
+
const confirmed = await confirmAction('Install the NocoBase AI coding skills for this workspace?', { defaultValue: true });
|
|
35
|
+
if (!confirmed) {
|
|
36
|
+
this.log('Skipped skills install.');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const result = await installNocoBaseSkills();
|
|
41
|
+
if (flags.json) {
|
|
42
|
+
this.log(JSON.stringify({
|
|
43
|
+
ok: true,
|
|
44
|
+
kind: 'skills',
|
|
45
|
+
action: result.action,
|
|
46
|
+
workspaceRoot: result.status.workspaceRoot,
|
|
47
|
+
installedSkillNames: result.status.installedSkillNames,
|
|
48
|
+
installedRef: result.status.installedRef,
|
|
49
|
+
}, null, 2));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (result.action === 'noop') {
|
|
53
|
+
this.log('NocoBase AI coding skills are already installed for this workspace. Run `nb skills update` to refresh them.');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this.log('Installed the NocoBase AI coding skills for this workspace.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Command, Flags } from '@oclif/core';
|
|
10
|
+
import { confirmAction } from '../../lib/ui.js';
|
|
11
|
+
import { updateNocoBaseSkills } from '../../lib/skills-manager.js';
|
|
12
|
+
export default class SkillsUpdate extends Command {
|
|
13
|
+
static summary = 'Update the NocoBase AI coding skills for this workspace';
|
|
14
|
+
static description = 'Refresh the NocoBase AI coding skills for the current workspace. This command only updates an existing nocobase/skills install.';
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> <%= command.id %>',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> --yes',
|
|
18
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
19
|
+
];
|
|
20
|
+
static flags = {
|
|
21
|
+
yes: Flags.boolean({
|
|
22
|
+
char: 'y',
|
|
23
|
+
description: 'Skip the update confirmation prompt',
|
|
24
|
+
default: false,
|
|
25
|
+
}),
|
|
26
|
+
json: Flags.boolean({
|
|
27
|
+
description: 'Output the result as JSON',
|
|
28
|
+
default: false,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const { flags } = await this.parse(SkillsUpdate);
|
|
33
|
+
if (!flags.yes) {
|
|
34
|
+
const confirmed = await confirmAction('Update the NocoBase AI coding skills for this workspace?', { defaultValue: true });
|
|
35
|
+
if (!confirmed) {
|
|
36
|
+
this.log('Skipped skills update.');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const result = await updateNocoBaseSkills();
|
|
41
|
+
if (flags.json) {
|
|
42
|
+
this.log(JSON.stringify({
|
|
43
|
+
ok: true,
|
|
44
|
+
kind: 'skills',
|
|
45
|
+
action: result.action,
|
|
46
|
+
workspaceRoot: result.status.workspaceRoot,
|
|
47
|
+
installedSkillNames: result.status.installedSkillNames,
|
|
48
|
+
installedRef: result.status.installedRef,
|
|
49
|
+
}, null, 2));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (result.action === 'noop') {
|
|
53
|
+
this.log('NocoBase AI coding skills are already up to date for this workspace.');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this.log('Updated the NocoBase AI coding skills for this workspace.');
|
|
57
|
+
}
|
|
58
|
+
}
|