@nocobase/cli 2.1.0-beta.2 → 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.
Files changed (145) hide show
  1. package/LICENSE.txt +107 -0
  2. package/README.md +367 -19
  3. package/README.zh-CN.md +336 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +131 -0
  6. package/dist/commands/api/resource/create.js +15 -0
  7. package/dist/commands/api/resource/destroy.js +15 -0
  8. package/dist/commands/api/resource/get.js +15 -0
  9. package/dist/commands/api/resource/index.js +20 -0
  10. package/dist/commands/api/resource/list.js +16 -0
  11. package/dist/commands/api/resource/query.js +15 -0
  12. package/dist/commands/api/resource/update.js +15 -0
  13. package/dist/commands/build.js +57 -0
  14. package/dist/commands/db/logs.js +85 -0
  15. package/dist/commands/db/ps.js +60 -0
  16. package/dist/commands/db/shared.js +95 -0
  17. package/dist/commands/db/start.js +70 -0
  18. package/dist/commands/db/stop.js +70 -0
  19. package/dist/commands/dev.js +156 -0
  20. package/dist/commands/down.js +197 -0
  21. package/dist/commands/download.js +865 -0
  22. package/dist/commands/env/add.js +307 -0
  23. package/dist/commands/env/auth.js +55 -0
  24. package/dist/commands/env/list.js +36 -0
  25. package/dist/commands/env/remove.js +59 -0
  26. package/dist/commands/env/update.js +67 -0
  27. package/dist/commands/env/use.js +28 -0
  28. package/dist/commands/init.js +950 -0
  29. package/dist/commands/install.js +1927 -0
  30. package/dist/commands/logs.js +97 -0
  31. package/dist/commands/pm/disable.js +63 -0
  32. package/dist/commands/pm/enable.js +63 -0
  33. package/dist/commands/pm/list.js +61 -0
  34. package/dist/commands/prompts-stages.js +150 -0
  35. package/dist/commands/prompts-test.js +181 -0
  36. package/dist/commands/ps.js +119 -0
  37. package/dist/commands/restart.js +74 -0
  38. package/dist/commands/scaffold/migration.js +38 -0
  39. package/dist/commands/scaffold/plugin.js +37 -0
  40. package/dist/commands/self/check.js +71 -0
  41. package/dist/commands/self/index.js +20 -0
  42. package/dist/commands/self/update.js +86 -0
  43. package/dist/commands/skills/check.js +69 -0
  44. package/dist/commands/skills/index.js +20 -0
  45. package/dist/commands/skills/install.js +71 -0
  46. package/dist/commands/skills/update.js +71 -0
  47. package/dist/commands/start.js +218 -0
  48. package/dist/commands/stop.js +97 -0
  49. package/dist/commands/test.js +466 -0
  50. package/dist/commands/upgrade.js +594 -0
  51. package/dist/generated/command-registry.js +133 -0
  52. package/dist/help/runtime-help.js +20 -0
  53. package/dist/lib/api-client.js +244 -0
  54. package/dist/lib/app-runtime.js +153 -0
  55. package/dist/lib/auth-store.js +357 -0
  56. package/dist/lib/bootstrap.js +388 -0
  57. package/dist/lib/build-config.js +10 -0
  58. package/dist/lib/cli-home.js +61 -0
  59. package/dist/lib/cli-locale.js +115 -0
  60. package/dist/lib/command-discovery.js +39 -0
  61. package/dist/lib/env-auth.js +872 -0
  62. package/dist/lib/generated-command.js +150 -0
  63. package/dist/lib/http-request.js +49 -0
  64. package/dist/lib/naming.js +70 -0
  65. package/dist/lib/openapi.js +62 -0
  66. package/dist/lib/post-processors.js +23 -0
  67. package/dist/lib/prompt-catalog.js +581 -0
  68. package/dist/lib/prompt-validators.js +185 -0
  69. package/dist/lib/prompt-web-ui.js +2096 -0
  70. package/dist/lib/resource-command.js +343 -0
  71. package/dist/lib/resource-request.js +104 -0
  72. package/dist/lib/run-npm.js +197 -0
  73. package/dist/lib/runtime-generator.js +419 -0
  74. package/dist/lib/runtime-store.js +56 -0
  75. package/dist/lib/self-manager.js +246 -0
  76. package/dist/lib/skills-manager.js +269 -0
  77. package/dist/lib/startup-update.js +203 -0
  78. package/dist/lib/ui.js +175 -0
  79. package/dist/locale/en-US.json +336 -0
  80. package/dist/locale/zh-CN.json +336 -0
  81. package/dist/post-processors/data-modeling.js +66 -0
  82. package/dist/post-processors/data-source-manager.js +114 -0
  83. package/dist/post-processors/index.js +19 -0
  84. package/nocobase-ctl.config.json +287 -0
  85. package/package.json +60 -26
  86. package/LICENSE +0 -661
  87. package/bin/index.js +0 -39
  88. package/nocobase.conf.tpl +0 -95
  89. package/src/cli.js +0 -19
  90. package/src/commands/benchmark.js +0 -73
  91. package/src/commands/build.js +0 -49
  92. package/src/commands/clean.js +0 -30
  93. package/src/commands/client.js +0 -166
  94. package/src/commands/create-nginx-conf.js +0 -37
  95. package/src/commands/create-plugin.js +0 -33
  96. package/src/commands/dev.js +0 -200
  97. package/src/commands/doc.js +0 -76
  98. package/src/commands/e2e.js +0 -265
  99. package/src/commands/global.js +0 -43
  100. package/src/commands/index.js +0 -45
  101. package/src/commands/instance-id.js +0 -47
  102. package/src/commands/locale/cronstrue.js +0 -122
  103. package/src/commands/locale/react-js-cron/en-US.json +0 -75
  104. package/src/commands/locale/react-js-cron/index.js +0 -17
  105. package/src/commands/locale/react-js-cron/zh-CN.json +0 -33
  106. package/src/commands/locale/react-js-cron/zh-TW.json +0 -33
  107. package/src/commands/locale.js +0 -81
  108. package/src/commands/p-test.js +0 -88
  109. package/src/commands/perf.js +0 -63
  110. package/src/commands/pkg.js +0 -321
  111. package/src/commands/pm2.js +0 -37
  112. package/src/commands/postinstall.js +0 -88
  113. package/src/commands/start.js +0 -148
  114. package/src/commands/tar.js +0 -36
  115. package/src/commands/test-coverage.js +0 -55
  116. package/src/commands/test.js +0 -107
  117. package/src/commands/umi.js +0 -33
  118. package/src/commands/update-deps.js +0 -72
  119. package/src/commands/upgrade.js +0 -47
  120. package/src/commands/view-license-key.js +0 -44
  121. package/src/index.js +0 -14
  122. package/src/license.js +0 -76
  123. package/src/logger.js +0 -75
  124. package/src/plugin-generator.js +0 -80
  125. package/src/util.js +0 -517
  126. package/templates/bundle-status.html +0 -338
  127. package/templates/create-app-package.json +0 -39
  128. package/templates/plugin/.npmignore.tpl +0 -2
  129. package/templates/plugin/README.md.tpl +0 -1
  130. package/templates/plugin/client.d.ts +0 -2
  131. package/templates/plugin/client.js +0 -1
  132. package/templates/plugin/package.json.tpl +0 -11
  133. package/templates/plugin/server.d.ts +0 -2
  134. package/templates/plugin/server.js +0 -1
  135. package/templates/plugin/src/client/client.d.ts +0 -249
  136. package/templates/plugin/src/client/index.tsx.tpl +0 -1
  137. package/templates/plugin/src/client/locale.ts +0 -21
  138. package/templates/plugin/src/client/models/index.ts +0 -12
  139. package/templates/plugin/src/client/plugin.tsx.tpl +0 -10
  140. package/templates/plugin/src/index.ts +0 -2
  141. package/templates/plugin/src/locale/en-US.json +0 -1
  142. package/templates/plugin/src/locale/zh-CN.json +0 -1
  143. package/templates/plugin/src/server/collections/.gitkeep +0 -0
  144. package/templates/plugin/src/server/index.ts.tpl +0 -1
  145. package/templates/plugin/src/server/plugin.ts.tpl +0 -19
@@ -0,0 +1,119 @@
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 { buildDockerDbContainerName, dockerContainerExists, dockerContainerIsRunning, formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, } from '../lib/app-runtime.js';
11
+ import { listEnvs } from '../lib/auth-store.js';
12
+ import { renderTable } from '../lib/ui.js';
13
+ function resolveApiBaseUrl(config) {
14
+ return String(config.apiBaseUrl ?? config.baseUrl ?? config.apibaseUrl ?? '').trim();
15
+ }
16
+ function appUrl(runtime) {
17
+ const port = String(runtime.env.config.appPort ?? '').trim();
18
+ if (port) {
19
+ return `http://127.0.0.1:${port}`;
20
+ }
21
+ const baseUrl = resolveApiBaseUrl(runtime.env.config);
22
+ return baseUrl.replace(/\/api\/?$/, '');
23
+ }
24
+ async function isLocalAppHealthy(runtime) {
25
+ const port = String(runtime.env.config.appPort ?? '').trim();
26
+ if (!port) {
27
+ return false;
28
+ }
29
+ const controller = new AbortController();
30
+ const timeout = setTimeout(() => controller.abort(), 1500);
31
+ try {
32
+ const response = await fetch(`http://127.0.0.1:${port}/api/__health_check`, {
33
+ signal: controller.signal,
34
+ });
35
+ const text = await response.text();
36
+ return response.ok && text.trim().toLowerCase() === 'ok';
37
+ }
38
+ catch (_error) {
39
+ return false;
40
+ }
41
+ finally {
42
+ clearTimeout(timeout);
43
+ }
44
+ }
45
+ async function dockerStatus(containerName) {
46
+ if (!(await dockerContainerExists(containerName))) {
47
+ return 'missing';
48
+ }
49
+ return await dockerContainerIsRunning(containerName) ? 'running' : 'stopped';
50
+ }
51
+ async function dbStatus(runtime) {
52
+ if (!runtime.env.config.builtinDb) {
53
+ return runtime.kind === 'http' ? 'external' : '-';
54
+ }
55
+ if (runtime.kind === 'http') {
56
+ return 'external';
57
+ }
58
+ if (runtime.kind === 'ssh') {
59
+ return '-';
60
+ }
61
+ const dbDialect = String(runtime.env.config.dbDialect ?? 'postgres').trim() || 'postgres';
62
+ const containerName = buildDockerDbContainerName(runtime.envName, dbDialect, runtime.workspaceName);
63
+ return await dockerStatus(containerName);
64
+ }
65
+ async function runtimeStatus(runtime) {
66
+ if (runtime.kind === 'http') {
67
+ return 'http';
68
+ }
69
+ if (runtime.kind === 'ssh') {
70
+ return 'ssh';
71
+ }
72
+ if (runtime.kind === 'docker') {
73
+ return await dockerStatus(runtime.containerName);
74
+ }
75
+ return await isLocalAppHealthy(runtime) ? 'running' : 'stopped';
76
+ }
77
+ export default class Ps extends Command {
78
+ static description = 'Show NocoBase runtime status for configured envs without starting or stopping anything.';
79
+ static examples = [
80
+ '<%= config.bin %> <%= command.id %>',
81
+ '<%= config.bin %> <%= command.id %> --env app1',
82
+ ];
83
+ static flags = {
84
+ env: Flags.string({
85
+ char: 'e',
86
+ description: 'CLI env name to inspect. Omit to show all configured envs',
87
+ }),
88
+ };
89
+ async run() {
90
+ const { flags } = await this.parse(Ps);
91
+ const requestedEnv = flags.env?.trim() || undefined;
92
+ const envNames = requestedEnv
93
+ ? [requestedEnv]
94
+ : Object.keys((await listEnvs()).envs).sort();
95
+ if (!envNames.length) {
96
+ this.log('No NocoBase env is configured yet. Run `nb init` to create one first.');
97
+ return;
98
+ }
99
+ const rows = [];
100
+ for (const envName of envNames) {
101
+ const runtime = await resolveManagedAppRuntime(envName);
102
+ if (!runtime) {
103
+ if (requestedEnv) {
104
+ this.error(formatMissingManagedAppEnvMessage(envName));
105
+ }
106
+ rows.push([envName, '-', 'missing', '-', '']);
107
+ continue;
108
+ }
109
+ rows.push([
110
+ runtime.envName,
111
+ runtime.kind,
112
+ await runtimeStatus(runtime),
113
+ await dbStatus(runtime),
114
+ appUrl(runtime),
115
+ ]);
116
+ }
117
+ this.log(renderTable(['Env', 'Kind', 'Status', 'Database', 'URL'], rows));
118
+ }
119
+ }
@@ -0,0 +1,74 @@
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
+ function argvHasToken(argv, tokens) {
11
+ return tokens.some((token) => argv.includes(token));
12
+ }
13
+ function pushFlag(argv, flag, value) {
14
+ if (value !== undefined) {
15
+ argv.push(flag, String(value));
16
+ }
17
+ }
18
+ export default class Restart extends Command {
19
+ static description = 'Restart NocoBase for the selected env by stopping it first, then starting it again.';
20
+ static examples = [
21
+ '<%= config.bin %> <%= command.id %>',
22
+ '<%= config.bin %> <%= command.id %> --env local',
23
+ '<%= config.bin %> <%= command.id %> --env local --quickstart',
24
+ '<%= config.bin %> <%= command.id %> --env local --port 12000',
25
+ '<%= config.bin %> <%= command.id %> --env local --daemon',
26
+ '<%= config.bin %> <%= command.id %> --env local --no-daemon',
27
+ '<%= config.bin %> <%= command.id %> --env local --instances 2',
28
+ '<%= config.bin %> <%= command.id %> --env local --launch-mode pm2',
29
+ '<%= config.bin %> <%= command.id %> --env local --verbose',
30
+ '<%= config.bin %> <%= command.id %> --env local-docker',
31
+ ];
32
+ static flags = {
33
+ env: Flags.string({
34
+ char: 'e',
35
+ description: 'CLI env name to restart. Defaults to the current env when omitted',
36
+ }),
37
+ quickstart: Flags.boolean({ description: 'Quickstart the application after stopping it', required: false }),
38
+ port: Flags.string({ description: 'Port (overrides appPort from env config when set)', char: 'p', required: false }),
39
+ daemon: Flags.boolean({
40
+ description: 'Run the application as a daemon after stopping it (default: true; use --no-daemon to stay in the foreground)',
41
+ char: 'd',
42
+ required: false,
43
+ default: true,
44
+ allowNo: true,
45
+ }),
46
+ instances: Flags.integer({ description: 'Number of instances to run after stopping it', char: 'i', required: false }),
47
+ 'launch-mode': Flags.string({ description: 'Launch Mode', required: false, options: ['pm2', 'node'] }),
48
+ verbose: Flags.boolean({
49
+ description: 'Show raw shutdown/startup output from the underlying local or Docker command',
50
+ default: false,
51
+ }),
52
+ };
53
+ async run() {
54
+ const { flags } = await this.parse(Restart);
55
+ const stopArgv = [];
56
+ const daemonFlagWasProvided = argvHasToken(this.argv, ['--daemon', '--no-daemon']);
57
+ pushFlag(stopArgv, '--env', flags.env?.trim() || undefined);
58
+ if (flags.verbose) {
59
+ stopArgv.push('--verbose');
60
+ }
61
+ await this.config.runCommand('stop', stopArgv);
62
+ const startArgv = [...stopArgv];
63
+ if (flags.quickstart) {
64
+ startArgv.push('--quickstart');
65
+ }
66
+ pushFlag(startArgv, '--port', flags.port);
67
+ if (daemonFlagWasProvided) {
68
+ startArgv.push(flags.daemon === false ? '--no-daemon' : '--daemon');
69
+ }
70
+ pushFlag(startArgv, '--instances', flags.instances);
71
+ pushFlag(startArgv, '--launch-mode', flags['launch-mode']);
72
+ await this.config.runCommand('start', startArgv);
73
+ }
74
+ }
@@ -0,0 +1,38 @@
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 { Args, Command, Flags } from '@oclif/core';
10
+ import { runNocoBaseCommand } from "../../lib/run-npm.js";
11
+ export default class ScaffoldMigration extends Command {
12
+ static args = {
13
+ name: Args.string({ description: 'migration name', required: true }),
14
+ };
15
+ static description = 'Run the legacy NocoBase scaffold migration (forwards to `npm run scaffold:migration` in the repo root)';
16
+ static examples = [
17
+ '<%= config.bin %> <%= command.id %> migration-name --pkg @nocobase/plugin-acl',
18
+ '<%= config.bin %> <%= command.id %> migration-name --pkg @nocobase/plugin-acl --on afterLoad',
19
+ ];
20
+ static flags = {
21
+ pkg: Flags.string({ description: 'plugin package name', required: true }),
22
+ on: Flags.string({ description: 'on', required: false, options: ['beforeLoad', 'afterSync', 'afterLoad'] }),
23
+ };
24
+ async run() {
25
+ const { args, flags } = await this.parse(ScaffoldMigration);
26
+ const npmArgs = ['create-migration', args.name, '--pkg', flags.pkg];
27
+ if (flags.on) {
28
+ npmArgs.push('--on', flags.on);
29
+ }
30
+ try {
31
+ await runNocoBaseCommand(npmArgs, { env: { LOGGER_SILENT: 'true' } });
32
+ }
33
+ catch (error) {
34
+ const message = error instanceof Error ? error.message : String(error);
35
+ this.error(message);
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,37 @@
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 { Args, Command, Flags } from '@oclif/core';
10
+ import { runNocoBaseCommand } from "../../lib/run-npm.js";
11
+ export default class ScaffoldPlugin extends Command {
12
+ static args = {
13
+ pkg: Args.string({ description: 'plugin package name', required: true }),
14
+ };
15
+ static description = 'Run the legacy NocoBase scaffold plugin (forwards to `npm run scaffold:plugin` in the repo root)';
16
+ static examples = [
17
+ '<%= config.bin %> <%= command.id %> @nocobase-example/plugin-hello',
18
+ '<%= config.bin %> <%= command.id %> @nocobase-example/plugin-hello --force-recreate',
19
+ ];
20
+ static flags = {
21
+ 'force-recreate': Flags.boolean({ description: 'Force recreate the plugin', char: 'f', required: false }),
22
+ };
23
+ async run() {
24
+ const { args, flags } = await this.parse(ScaffoldPlugin);
25
+ const npmArgs = ['pm', 'create', args.pkg];
26
+ if (flags['force-recreate']) {
27
+ npmArgs.push('--force-recreate');
28
+ }
29
+ try {
30
+ await runNocoBaseCommand(npmArgs, { env: { LOGGER_SILENT: 'true' } });
31
+ }
32
+ catch (error) {
33
+ const message = error instanceof Error ? error.message : String(error);
34
+ this.error(message);
35
+ }
36
+ }
37
+ }
@@ -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`.');
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,86 @@
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, setVerboseMode } 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
+ verbose: Flags.boolean({
36
+ description: 'Show detailed update output',
37
+ default: false,
38
+ }),
39
+ };
40
+ async run() {
41
+ const { flags } = await this.parse(SelfUpdate);
42
+ setVerboseMode(flags.verbose);
43
+ const status = await inspectSelfStatus({
44
+ channel: flags.channel,
45
+ });
46
+ if (!status.updatable) {
47
+ this.error(formatUnsupportedSelfUpdateMessage(status));
48
+ }
49
+ if (!status.latestVersion && status.registryError) {
50
+ this.error(formatSelfUpdateUnavailableMessage(status));
51
+ }
52
+ if (!flags.yes && status.updateAvailable) {
53
+ const confirmed = await confirmAction(`Update ${status.packageName} from ${status.currentVersion} to ${status.latestVersion}?`, { defaultValue: false });
54
+ if (!confirmed) {
55
+ this.log('Skipped CLI update.');
56
+ return;
57
+ }
58
+ }
59
+ const result = await updateSelf({
60
+ channel: flags.channel,
61
+ verbose: flags.verbose,
62
+ });
63
+ if (flags.json) {
64
+ this.log(JSON.stringify({
65
+ ok: true,
66
+ kind: 'self',
67
+ action: result.action,
68
+ packageName: result.status.packageName,
69
+ packageSpec: result.packageSpec,
70
+ channel: result.status.channel,
71
+ fromVersion: result.status.currentVersion,
72
+ toVersion: result.targetVersion,
73
+ }, null, 2));
74
+ return;
75
+ }
76
+ if (result.action === 'noop') {
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}.`);
80
+ return;
81
+ }
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}.`);
85
+ }
86
+ }
@@ -0,0 +1,69 @@
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 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
+ 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
+ globalRoot: status.globalRoot,
33
+ workspaceRoot: status.workspaceRoot,
34
+ installed: status.installed,
35
+ managedByNb: status.managedByNb,
36
+ sourcePackage: status.sourcePackage,
37
+ npmPackageName: status.npmPackageName,
38
+ installedSkillNames: status.installedSkillNames,
39
+ installedVersion: status.installedVersion,
40
+ latestVersion: status.latestVersion,
41
+ installedRef: status.installedRef,
42
+ latestRef: status.latestRef,
43
+ updateAvailable: status.updateAvailable,
44
+ recommendedCommand: status.installed ? 'nb skills update --yes' : 'nb skills install --yes',
45
+ registryError: status.registryError,
46
+ }, null, 2));
47
+ return;
48
+ }
49
+ this.log(renderTable(['Field', 'Value'], [
50
+ ['Skills home', status.globalRoot],
51
+ ['Installed', status.installed ? 'yes' : 'no'],
52
+ ['Managed by nb', status.managedByNb ? 'yes' : 'no'],
53
+ ['Installed skills', status.installedSkillNames.length ? status.installedSkillNames.join(', ') : '(none)'],
54
+ ['Installed version', status.installedVersion ?? '(unknown)'],
55
+ ['Latest version', status.latestVersion ?? '(unknown)'],
56
+ ['Update available', status.updateAvailable === null ? 'unknown' : status.updateAvailable ? 'yes' : 'no'],
57
+ ]));
58
+ if (!status.installed) {
59
+ printInfo('Run `nb skills install` to install the NocoBase AI coding skills globally.');
60
+ return;
61
+ }
62
+ if (status.updateAvailable) {
63
+ printInfo('Run `nb skills update` to refresh the global NocoBase AI coding skills.');
64
+ }
65
+ if (status.registryError) {
66
+ printInfo(`Update check warning: ${status.registryError}`);
67
+ }
68
+ }
69
+ }
@@ -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 global NocoBase AI coding skills';
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,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 { confirmAction, setVerboseMode } 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 globally';
14
+ static description = 'Install the NocoBase AI coding skills globally. 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
+ verbose: Flags.boolean({
31
+ description: 'Show detailed install output',
32
+ default: false,
33
+ }),
34
+ };
35
+ async run() {
36
+ const { flags } = await this.parse(SkillsInstall);
37
+ setVerboseMode(flags.verbose);
38
+ if (!flags.yes) {
39
+ const confirmed = await confirmAction('Install the NocoBase AI coding skills globally?', { defaultValue: true });
40
+ if (!confirmed) {
41
+ this.log('Skipped skills install.');
42
+ return;
43
+ }
44
+ }
45
+ const result = await installNocoBaseSkills({
46
+ verbose: flags.verbose,
47
+ });
48
+ if (flags.json) {
49
+ this.log(JSON.stringify({
50
+ ok: true,
51
+ kind: 'skills',
52
+ action: result.action,
53
+ globalRoot: result.status.globalRoot,
54
+ workspaceRoot: result.status.workspaceRoot,
55
+ installedSkillNames: result.status.installedSkillNames,
56
+ installedVersion: result.status.installedVersion,
57
+ installedRef: result.status.installedRef,
58
+ }, null, 2));
59
+ return;
60
+ }
61
+ if (result.action === 'noop') {
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.');
65
+ return;
66
+ }
67
+ this.log(flags.verbose
68
+ ? 'Installed the NocoBase AI coding skills globally.'
69
+ : 'Installed NocoBase AI coding skills globally.');
70
+ }
71
+ }