@nocobase/cli 2.1.0-beta.2 → 2.1.0-beta.20

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 (143) 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 +116 -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 +81 -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 +149 -0
  20. package/dist/commands/down.js +193 -0
  21. package/dist/commands/download.js +865 -0
  22. package/dist/commands/env/add.js +327 -0
  23. package/dist/commands/env/auth.js +62 -0
  24. package/dist/commands/env/list.js +41 -0
  25. package/dist/commands/env/remove.js +65 -0
  26. package/dist/commands/env/update.js +73 -0
  27. package/dist/commands/env/use.js +36 -0
  28. package/dist/commands/init.js +822 -0
  29. package/dist/commands/install.js +1888 -0
  30. package/dist/commands/logs.js +90 -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 +54 -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 +116 -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 +76 -0
  43. package/dist/commands/skills/check.js +63 -0
  44. package/dist/commands/skills/index.js +20 -0
  45. package/dist/commands/skills/install.js +58 -0
  46. package/dist/commands/skills/update.js +58 -0
  47. package/dist/commands/start.js +211 -0
  48. package/dist/commands/stop.js +90 -0
  49. package/dist/commands/test.js +466 -0
  50. package/dist/commands/upgrade.js +583 -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 +243 -0
  54. package/dist/lib/app-runtime.js +142 -0
  55. package/dist/lib/auth-store.js +241 -0
  56. package/dist/lib/bootstrap.js +387 -0
  57. package/dist/lib/build-config.js +10 -0
  58. package/dist/lib/cli-home.js +30 -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 +142 -0
  63. package/dist/lib/naming.js +70 -0
  64. package/dist/lib/openapi.js +62 -0
  65. package/dist/lib/post-processors.js +23 -0
  66. package/dist/lib/prompt-catalog.js +581 -0
  67. package/dist/lib/prompt-validators.js +185 -0
  68. package/dist/lib/prompt-web-ui.js +2096 -0
  69. package/dist/lib/resource-command.js +335 -0
  70. package/dist/lib/resource-request.js +104 -0
  71. package/dist/lib/run-npm.js +197 -0
  72. package/dist/lib/runtime-generator.js +419 -0
  73. package/dist/lib/runtime-store.js +56 -0
  74. package/dist/lib/self-manager.js +246 -0
  75. package/dist/lib/skills-manager.js +202 -0
  76. package/dist/lib/ui.js +175 -0
  77. package/dist/locale/en-US.json +333 -0
  78. package/dist/locale/zh-CN.json +333 -0
  79. package/dist/post-processors/data-modeling.js +66 -0
  80. package/dist/post-processors/data-source-manager.js +114 -0
  81. package/dist/post-processors/index.js +19 -0
  82. package/nocobase-ctl.config.json +287 -0
  83. package/package.json +60 -26
  84. package/LICENSE +0 -661
  85. package/bin/index.js +0 -39
  86. package/nocobase.conf.tpl +0 -95
  87. package/src/cli.js +0 -19
  88. package/src/commands/benchmark.js +0 -73
  89. package/src/commands/build.js +0 -49
  90. package/src/commands/clean.js +0 -30
  91. package/src/commands/client.js +0 -166
  92. package/src/commands/create-nginx-conf.js +0 -37
  93. package/src/commands/create-plugin.js +0 -33
  94. package/src/commands/dev.js +0 -200
  95. package/src/commands/doc.js +0 -76
  96. package/src/commands/e2e.js +0 -265
  97. package/src/commands/global.js +0 -43
  98. package/src/commands/index.js +0 -45
  99. package/src/commands/instance-id.js +0 -47
  100. package/src/commands/locale/cronstrue.js +0 -122
  101. package/src/commands/locale/react-js-cron/en-US.json +0 -75
  102. package/src/commands/locale/react-js-cron/index.js +0 -17
  103. package/src/commands/locale/react-js-cron/zh-CN.json +0 -33
  104. package/src/commands/locale/react-js-cron/zh-TW.json +0 -33
  105. package/src/commands/locale.js +0 -81
  106. package/src/commands/p-test.js +0 -88
  107. package/src/commands/perf.js +0 -63
  108. package/src/commands/pkg.js +0 -321
  109. package/src/commands/pm2.js +0 -37
  110. package/src/commands/postinstall.js +0 -88
  111. package/src/commands/start.js +0 -148
  112. package/src/commands/tar.js +0 -36
  113. package/src/commands/test-coverage.js +0 -55
  114. package/src/commands/test.js +0 -107
  115. package/src/commands/umi.js +0 -33
  116. package/src/commands/update-deps.js +0 -72
  117. package/src/commands/upgrade.js +0 -47
  118. package/src/commands/view-license-key.js +0 -44
  119. package/src/index.js +0 -14
  120. package/src/license.js +0 -76
  121. package/src/logger.js +0 -75
  122. package/src/plugin-generator.js +0 -80
  123. package/src/util.js +0 -517
  124. package/templates/bundle-status.html +0 -338
  125. package/templates/create-app-package.json +0 -39
  126. package/templates/plugin/.npmignore.tpl +0 -2
  127. package/templates/plugin/README.md.tpl +0 -1
  128. package/templates/plugin/client.d.ts +0 -2
  129. package/templates/plugin/client.js +0 -1
  130. package/templates/plugin/package.json.tpl +0 -11
  131. package/templates/plugin/server.d.ts +0 -2
  132. package/templates/plugin/server.js +0 -1
  133. package/templates/plugin/src/client/client.d.ts +0 -249
  134. package/templates/plugin/src/client/index.tsx.tpl +0 -1
  135. package/templates/plugin/src/client/locale.ts +0 -21
  136. package/templates/plugin/src/client/models/index.ts +0 -12
  137. package/templates/plugin/src/client/plugin.tsx.tpl +0 -10
  138. package/templates/plugin/src/index.ts +0 -2
  139. package/templates/plugin/src/locale/en-US.json +0 -1
  140. package/templates/plugin/src/locale/zh-CN.json +0 -1
  141. package/templates/plugin/src/server/collections/.gitkeep +0 -0
  142. package/templates/plugin/src/server/index.ts.tpl +0 -1
  143. package/templates/plugin/src/server/plugin.ts.tpl +0 -19
@@ -0,0 +1,90 @@
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 { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../lib/app-runtime.js';
11
+ import { run } from '../lib/run-npm.js';
12
+ import { printInfo } from '../lib/ui.js';
13
+ function formatLogsFailure(envName, message) {
14
+ return [
15
+ `Couldn't show logs for "${envName}".`,
16
+ 'Check that the saved local app or Docker container still exists on this machine, then try again.',
17
+ `Details: ${message}`,
18
+ ].join('\n');
19
+ }
20
+ export default class Logs extends Command {
21
+ static description = 'Show NocoBase logs for the selected env. Local npm/git installs use pm2 logs, and Docker installs use docker logs.';
22
+ static examples = [
23
+ '<%= config.bin %> <%= command.id %>',
24
+ '<%= config.bin %> <%= command.id %> --env app1',
25
+ '<%= config.bin %> <%= command.id %> --env app1 --tail 200',
26
+ '<%= config.bin %> <%= command.id %> --env app1 --no-follow',
27
+ ];
28
+ static flags = {
29
+ env: Flags.string({
30
+ char: 'e',
31
+ description: 'CLI env name to inspect logs for. Defaults to the current env when omitted',
32
+ }),
33
+ tail: Flags.integer({
34
+ description: 'Number of recent log lines to show before following',
35
+ default: 100,
36
+ min: 0,
37
+ }),
38
+ follow: Flags.boolean({
39
+ char: 'f',
40
+ description: 'Keep streaming new log lines',
41
+ default: true,
42
+ allowNo: true,
43
+ }),
44
+ };
45
+ async run() {
46
+ const { flags } = await this.parse(Logs);
47
+ const requestedEnv = flags.env?.trim() || undefined;
48
+ const runtime = await resolveManagedAppRuntime(requestedEnv);
49
+ if (!runtime) {
50
+ this.error(formatMissingManagedAppEnvMessage(requestedEnv));
51
+ }
52
+ if (runtime.kind === 'remote') {
53
+ this.error([
54
+ `Can't show runtime logs for "${runtime.envName}" from this machine.`,
55
+ 'This env only has an API connection, so there is no saved local app or Docker container to read logs from.',
56
+ 'Connect it to a local checkout or reinstall it with npm, git, or Docker if you want CLI-managed logs.',
57
+ ].join('\n'));
58
+ }
59
+ const tail = String(flags.tail ?? 100);
60
+ const follow = flags.follow !== false;
61
+ printInfo(follow
62
+ ? `Showing logs for "${runtime.envName}" (press Ctrl+C to stop).`
63
+ : `Showing recent logs for "${runtime.envName}".`);
64
+ try {
65
+ if (runtime.kind === 'docker') {
66
+ const dockerArgs = ['logs', '--tail', tail];
67
+ if (follow) {
68
+ dockerArgs.push('--follow');
69
+ }
70
+ dockerArgs.push(runtime.containerName);
71
+ await run('docker', dockerArgs, {
72
+ errorName: 'docker logs',
73
+ stdio: 'inherit',
74
+ });
75
+ return;
76
+ }
77
+ const localArgs = ['pm2', 'logs', '--lines', tail];
78
+ if (!follow) {
79
+ localArgs.push('--nostream');
80
+ }
81
+ await runLocalNocoBaseCommand(runtime, localArgs, {
82
+ stdio: 'inherit',
83
+ });
84
+ }
85
+ catch (error) {
86
+ const message = error instanceof Error ? error.message : String(error);
87
+ this.error(formatLogsFailure(runtime.envName, message));
88
+ }
89
+ }
90
+ }
@@ -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 { Args, Command, Flags } from '@oclif/core';
10
+ import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, runDockerNocoBaseCommand, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
11
+ export default class PmDisable extends Command {
12
+ static args = {
13
+ packages: Args.string({
14
+ required: true,
15
+ multiple: true,
16
+ description: 'Plugin package name(s) to disable (e.g. `@nocobase/plugin-sample`). Pass one or more names as separate arguments.',
17
+ }),
18
+ };
19
+ static description = 'Disable one or more plugins in the selected env (npm/git runs locally, Docker runs inside the saved app container)';
20
+ static examples = [
21
+ '<%= config.bin %> <%= command.id %> @nocobase/plugin-sample',
22
+ '<%= config.bin %> <%= command.id %> @nocobase/plugin-a @nocobase/plugin-b',
23
+ '<%= config.bin %> <%= command.id %> -e local @nocobase/plugin-sample',
24
+ ];
25
+ static flags = {
26
+ env: Flags.string({
27
+ char: 'e',
28
+ description: 'CLI env name (from `nb env` / `nb install`). Defaults to the current env when omitted',
29
+ }),
30
+ };
31
+ async run() {
32
+ const { args, flags } = await this.parse(PmDisable);
33
+ const packages = args.packages;
34
+ if (!Array.isArray(packages) || packages.length === 0) {
35
+ this.error('Pass at least one plugin package name.');
36
+ }
37
+ const runtime = await resolveManagedAppRuntime(flags.env);
38
+ if (!runtime) {
39
+ this.error(formatMissingManagedAppEnvMessage(flags.env));
40
+ }
41
+ if (runtime.kind === 'local') {
42
+ try {
43
+ await runLocalNocoBaseCommand(runtime, ['pm', 'disable', ...packages]);
44
+ }
45
+ catch (error) {
46
+ const message = error instanceof Error ? error.message : String(error);
47
+ this.error(message);
48
+ }
49
+ return;
50
+ }
51
+ if (runtime.kind === 'docker') {
52
+ try {
53
+ await runDockerNocoBaseCommand(runtime.containerName, ['pm', 'disable', ...packages]);
54
+ }
55
+ catch (error) {
56
+ const message = error instanceof Error ? error.message : String(error);
57
+ this.error(message);
58
+ }
59
+ return;
60
+ }
61
+ await this.config.runCommand('api:pm:disable', ['--await-response', '--filter-by-tk', packages.join(',')]);
62
+ }
63
+ }
@@ -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 { Args, Command, Flags } from '@oclif/core';
10
+ import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, runDockerNocoBaseCommand, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
11
+ export default class PmEnable extends Command {
12
+ static args = {
13
+ packages: Args.string({
14
+ required: true,
15
+ multiple: true,
16
+ description: 'Plugin package name(s) to enable (e.g. `@nocobase/plugin-sample`). Pass one or more names as separate arguments.',
17
+ }),
18
+ };
19
+ static description = 'Enable one or more plugins in the selected env (npm/git runs locally, Docker runs inside the saved app container)';
20
+ static examples = [
21
+ '<%= config.bin %> <%= command.id %> @nocobase/plugin-sample',
22
+ '<%= config.bin %> <%= command.id %> @nocobase/plugin-a @nocobase/plugin-b',
23
+ '<%= config.bin %> <%= command.id %> -e local @nocobase/plugin-sample',
24
+ ];
25
+ static flags = {
26
+ env: Flags.string({
27
+ char: 'e',
28
+ description: 'CLI env name (from `nb env` / `nb install`). Defaults to the current env when omitted',
29
+ }),
30
+ };
31
+ async run() {
32
+ const { args, flags } = await this.parse(PmEnable);
33
+ const packages = args.packages;
34
+ if (!Array.isArray(packages) || packages.length === 0) {
35
+ this.error('Pass at least one plugin package name.');
36
+ }
37
+ const runtime = await resolveManagedAppRuntime(flags.env);
38
+ if (!runtime) {
39
+ this.error(formatMissingManagedAppEnvMessage(flags.env));
40
+ }
41
+ if (runtime.kind === 'local') {
42
+ try {
43
+ await runLocalNocoBaseCommand(runtime, ['pm', 'enable', ...packages]);
44
+ }
45
+ catch (error) {
46
+ const message = error instanceof Error ? error.message : String(error);
47
+ this.error(message);
48
+ }
49
+ return;
50
+ }
51
+ if (runtime.kind === 'docker') {
52
+ try {
53
+ await runDockerNocoBaseCommand(runtime.containerName, ['pm', 'enable', ...packages]);
54
+ }
55
+ catch (error) {
56
+ const message = error instanceof Error ? error.message : String(error);
57
+ this.error(message);
58
+ }
59
+ return;
60
+ }
61
+ await this.config.runCommand('api:pm:enable', ['--await-response', '--filter-by-tk', packages.join(',')]);
62
+ }
63
+ }
@@ -0,0 +1,54 @@
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 { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, runDockerNocoBaseCommand, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
11
+ export default class PmList extends Command {
12
+ static args = {};
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, remote envs fall back to the API)';
15
+ static examples = [
16
+ '<%= config.bin %> <%= command.id %>',
17
+ '<%= config.bin %> <%= command.id %> -e local',
18
+ '<%= config.bin %> <%= command.id %> -e local-docker',
19
+ ];
20
+ static flags = {
21
+ env: Flags.string({
22
+ char: 'e',
23
+ description: 'CLI env name (from `nb env` / `nb install`). Defaults to the current env when omitted',
24
+ }),
25
+ };
26
+ async run() {
27
+ const { flags } = await this.parse(PmList);
28
+ const runtime = await resolveManagedAppRuntime(flags.env);
29
+ if (!runtime) {
30
+ this.error(formatMissingManagedAppEnvMessage(flags.env));
31
+ }
32
+ if (runtime.kind === 'local') {
33
+ try {
34
+ await runLocalNocoBaseCommand(runtime, ['pm', 'list']);
35
+ }
36
+ catch (error) {
37
+ const message = error instanceof Error ? error.message : String(error);
38
+ this.error(message);
39
+ }
40
+ return;
41
+ }
42
+ if (runtime.kind === 'docker') {
43
+ try {
44
+ await runDockerNocoBaseCommand(runtime.containerName, ['pm', 'list']);
45
+ }
46
+ catch (error) {
47
+ const message = error instanceof Error ? error.message : String(error);
48
+ this.error(message);
49
+ }
50
+ return;
51
+ }
52
+ await this.config.runCommand('api:pm:list', ['--mode=summary']);
53
+ }
54
+ }
@@ -0,0 +1,150 @@
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 { runPromptCatalog, } from "../lib/prompt-catalog.js";
11
+ import { applyCliLocale, CLI_LOCALE_FLAG_DESCRIPTION, CLI_LOCALE_FLAG_OPTIONS, } from "../lib/cli-locale.js";
12
+ import { runPromptCatalogWebUI } from "../lib/prompt-web-ui.js";
13
+ import PromptsTest from "./prompts-test.js";
14
+ function buildWebUiStagesFromTestPrompts(c) {
15
+ return [
16
+ {
17
+ sectionTitle: 'Step 1',
18
+ sectionDescription: 'intro, file, name, and boolean',
19
+ catalog: {
20
+ intro1: c.intro1,
21
+ file: c.file,
22
+ text: c.text,
23
+ boolean: c.boolean,
24
+ },
25
+ },
26
+ {
27
+ sectionTitle: 'Step 2',
28
+ sectionDescription: 'select, then the option1 run hook',
29
+ catalog: {
30
+ select: c.select,
31
+ onOption1: c.onOption1,
32
+ },
33
+ },
34
+ {
35
+ sectionTitle: 'Step 3',
36
+ sectionDescription: 'password, integer, and outro',
37
+ catalog: {
38
+ password: c.password,
39
+ integer: c.integer,
40
+ outro1: c.outro1,
41
+ },
42
+ },
43
+ ];
44
+ }
45
+ /**
46
+ * With `--ui`: `runPromptCatalogWebUI` using `stages` + `sectionTitle`, then
47
+ * `runPromptCatalog` on the same catalog as `prompts-test`. Without `--ui`, same terminal behavior
48
+ * as `prompts-test` (handy for comparing).
49
+ */
50
+ export default class PromptsStages extends Command {
51
+ static hidden = true;
52
+ static args = {
53
+ file: Args.string({ description: 'file to read', required: false }),
54
+ };
55
+ static description = 'Demo: with --ui, `runPromptCatalogWebUI` with `stages` (section headings in the form); without --ui, same as `prompts-test`. The submitted preset runs through the same `PromptsTest.prompts` catalog as `prompts-test`.';
56
+ static examples = [
57
+ '<%= config.bin %> <%= command.id %> # same terminal flow as `prompts-test`',
58
+ '<%= config.bin %> <%= command.id %> --ui # `runPromptCatalogWebUI` with `stages` + `sectionTitle`',
59
+ '<%= config.bin %> <%= command.id %> -y ./README.md -p secret --ui',
60
+ ];
61
+ static flags = {
62
+ ui: Flags.boolean({
63
+ description: 'Open the localhost form: `runPromptCatalogWebUI` with `stages` and `sectionTitle` (vs `prompts-test --ui`, which uses one `catalog`). Without --ui, behavior matches `prompts-test` (Clack in TTY / presets).',
64
+ default: false,
65
+ }),
66
+ yes: Flags.boolean({
67
+ char: 'y',
68
+ description: 'Accept defaults only in the terminal (no Clack after submit); same semantics as `prompts-test` when used with the submitted or default preset.',
69
+ default: false,
70
+ }),
71
+ locale: Flags.string({
72
+ description: CLI_LOCALE_FLAG_DESCRIPTION,
73
+ options: CLI_LOCALE_FLAG_OPTIONS,
74
+ }),
75
+ file: Flags.string({
76
+ char: 'f',
77
+ description: 'Merged into initialValues.file (default for the text prompt when set)',
78
+ }),
79
+ text: Flags.string({
80
+ char: 't',
81
+ description: 'Merged into initialValues.text (default for the text prompt when set)',
82
+ }),
83
+ boolean: Flags.boolean({
84
+ char: 'b',
85
+ description: 'Merged into initialValues.boolean (default for confirm when set)',
86
+ allowNo: true,
87
+ }),
88
+ select: Flags.string({
89
+ char: 's',
90
+ description: 'Merged into initialValues.select (default for select when set)',
91
+ options: ['option1', 'option2', 'option3'],
92
+ }),
93
+ password: Flags.string({
94
+ char: 'p',
95
+ description: 'Merged into initialValues.password (required when -y / non-TTY if password is required)',
96
+ }),
97
+ integer: Flags.integer({
98
+ char: 'i',
99
+ description: 'Merged into initialValues.integer (default for integer prompt when set)',
100
+ }),
101
+ };
102
+ async run() {
103
+ const { args, flags } = await this.parse(PromptsStages);
104
+ applyCliLocale(flags.locale);
105
+ let presetValues = this.buildPresetValuesFromParsed(args, flags);
106
+ if (flags.ui) {
107
+ presetValues = await runPromptCatalogWebUI({
108
+ stages: buildWebUiStagesFromTestPrompts(PromptsTest.prompts),
109
+ values: presetValues,
110
+ pageTitle: 'nb prompts-stages — Web UI',
111
+ documentHeading: 'nb prompts-stages — `stages` demo',
112
+ onServerStart: ({ host, port, url }) => {
113
+ this.log(`Local Web UI (multi-stage) ready — ${url} (listening on ${host}:${port}). Submit the form in the browser to continue.`);
114
+ },
115
+ onOpenBrowserError: (url, err) => {
116
+ this.log(`Open this URL in a browser: ${url} (${err instanceof Error ? err.message : String(err)})`);
117
+ },
118
+ });
119
+ }
120
+ const results = await runPromptCatalog(PromptsTest.prompts, {
121
+ initialValues: {},
122
+ values: presetValues,
123
+ yes: flags.yes || flags.ui,
124
+ });
125
+ this.log(JSON.stringify(results, null, 2));
126
+ }
127
+ buildPresetValuesFromParsed(args, flags) {
128
+ const preset = {};
129
+ const file = args.file ?? flags.file;
130
+ if (file !== undefined) {
131
+ preset.file = file;
132
+ }
133
+ if (flags.text !== undefined) {
134
+ preset.text = flags.text;
135
+ }
136
+ if (flags.boolean !== undefined) {
137
+ preset.boolean = flags.boolean;
138
+ }
139
+ if (flags.select !== undefined) {
140
+ preset.select = flags.select;
141
+ }
142
+ if (flags.password !== undefined) {
143
+ preset.password = flags.password;
144
+ }
145
+ if (flags.integer !== undefined) {
146
+ preset.integer = flags.integer;
147
+ }
148
+ return preset;
149
+ }
150
+ }
@@ -0,0 +1,181 @@
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 * as p from '@clack/prompts';
10
+ import { Args, Command, Flags } from '@oclif/core';
11
+ import { runPromptCatalog, } from "../lib/prompt-catalog.js";
12
+ import { applyCliLocale, CLI_LOCALE_FLAG_DESCRIPTION, CLI_LOCALE_FLAG_OPTIONS, } from "../lib/cli-locale.js";
13
+ import { runPromptCatalogWebUI, } from "../lib/prompt-web-ui.js";
14
+ export default class PromptsTest extends Command {
15
+ static hidden = true;
16
+ static args = {
17
+ file: Args.string({ description: 'file to read', required: false }),
18
+ };
19
+ static description = 'Demo: declarative `prompts` catalog + `initialValues` + `yesInitialValues` / per-block `yesInitialValue`; runner is `runPromptCatalog`.';
20
+ static examples = [
21
+ '<%= config.bin %> <%= command.id %>',
22
+ '<%= config.bin %> <%= command.id %> -t Ada --boolean',
23
+ '<%= config.bin %> <%= command.id %> -y',
24
+ '<%= config.bin %> <%= command.id %> -y ./README.md -p secret',
25
+ '<%= config.bin %> <%= command.id %> --ui',
26
+ ];
27
+ static flags = {
28
+ ui: Flags.boolean({
29
+ description: 'Open a browser to configure the same parameters in a form (served only on 127.0.0.1). Uses `runPromptCatalogWebUI` with this command’s `prompts` catalog. Submit to continue; then `runPromptCatalog` runs in this terminal with the submitted preset.',
30
+ default: false,
31
+ }),
32
+ yes: Flags.boolean({
33
+ char: 'y',
34
+ description: 'Accept defaults only (no prompts); uses `yesInitialValues` merged over `initialValues`, then per-block `yesInitialValue`. Same as non-TTY.',
35
+ default: false,
36
+ }),
37
+ locale: Flags.string({
38
+ description: CLI_LOCALE_FLAG_DESCRIPTION,
39
+ options: CLI_LOCALE_FLAG_OPTIONS,
40
+ }),
41
+ file: Flags.string({
42
+ char: 'f',
43
+ description: 'Merged into initialValues.file (default for the text prompt when set)',
44
+ }),
45
+ text: Flags.string({
46
+ char: 't',
47
+ description: 'Merged into initialValues.text (default for the text prompt when set)',
48
+ }),
49
+ boolean: Flags.boolean({
50
+ char: 'b',
51
+ description: 'Merged into initialValues.boolean (default for confirm when set)',
52
+ allowNo: true,
53
+ }),
54
+ select: Flags.string({
55
+ char: 's',
56
+ description: 'Merged into initialValues.select (default for select when set)',
57
+ options: ['option1', 'option2', 'option3'],
58
+ }),
59
+ password: Flags.string({
60
+ char: 'p',
61
+ description: 'Merged into initialValues.password (required when -y / non-TTY if password is required)',
62
+ }),
63
+ integer: Flags.integer({
64
+ char: 'i',
65
+ description: 'Merged into initialValues.integer (default for integer prompt when set)',
66
+ }),
67
+ };
68
+ static prompts = {
69
+ intro1: {
70
+ type: 'intro',
71
+ title: 'Welcome to the prompts test!',
72
+ },
73
+ file: {
74
+ type: 'text',
75
+ message: 'File to read',
76
+ initialValue: '',
77
+ placeholder: 'Enter the file to read',
78
+ yesInitialValue: 'package.json',
79
+ required: true,
80
+ },
81
+ text: {
82
+ type: 'text',
83
+ message: 'What is your name?',
84
+ initialValue: 'world',
85
+ placeholder: 'Your name',
86
+ /**
87
+ * Example: async validation (Clack re-prompts; Web UI returns 400 on submit with this message).
88
+ */
89
+ validate: async (v) => {
90
+ if (String(v).trim().length < 2) {
91
+ return 'Name must be at least 2 characters';
92
+ }
93
+ return undefined;
94
+ },
95
+ },
96
+ boolean: {
97
+ type: 'boolean',
98
+ message: 'Do you want to continue?',
99
+ initialValue: true,
100
+ },
101
+ select: {
102
+ type: 'select',
103
+ message: 'Select an option',
104
+ options: ['option1', 'option2', 'option3'],
105
+ initialValue: 'option1',
106
+ yesInitialValue: 'option2',
107
+ },
108
+ onOption1: {
109
+ type: 'run',
110
+ when: (values) => values.select === 'option1',
111
+ run: (values) => {
112
+ p.log.info(`run block: select is option1 (current keys: ${Object.keys(values).join(', ')})`);
113
+ },
114
+ },
115
+ password: {
116
+ type: 'password',
117
+ message: 'Enter your password',
118
+ yesInitialValue: 'demo-secret',
119
+ required: true,
120
+ },
121
+ integer: {
122
+ type: 'integer',
123
+ message: 'Enter an integer',
124
+ initialValue: 0,
125
+ placeholder: 'e.g. 42',
126
+ hidden: (values) => values.select === 'option1',
127
+ },
128
+ outro1: {
129
+ type: 'outro',
130
+ message: 'Done.',
131
+ },
132
+ };
133
+ async run() {
134
+ const { args, flags } = await this.parse(PromptsTest);
135
+ applyCliLocale(flags.locale);
136
+ let presetValues = this.buildPresetValuesFromParsed(args, flags);
137
+ if (flags.ui) {
138
+ presetValues = await runPromptCatalogWebUI(PromptsTest.prompts, {
139
+ values: presetValues,
140
+ pageTitle: 'nb prompts-test — UI',
141
+ documentHeading: 'nb prompts-test',
142
+ onServerStart: ({ host, port, url }) => {
143
+ this.log(`Local Web UI ready — ${url} (listening on ${host}:${port}). Submit the form in the browser to continue.`);
144
+ },
145
+ onOpenBrowserError: (url, err) => {
146
+ this.log(`Open this URL in a browser: ${url} (${err instanceof Error ? err.message : String(err)})`);
147
+ },
148
+ });
149
+ }
150
+ const results = await runPromptCatalog(PromptsTest.prompts, {
151
+ initialValues: {},
152
+ values: presetValues,
153
+ yes: flags.yes || flags.ui,
154
+ });
155
+ this.log(JSON.stringify(results, null, 2));
156
+ }
157
+ /** Map oclif parse result into `values` presets: each key here skips that prompt (no Clack UI). */
158
+ buildPresetValuesFromParsed(args, flags) {
159
+ const preset = {};
160
+ const file = args.file ?? flags.file;
161
+ if (file !== undefined) {
162
+ preset.file = file;
163
+ }
164
+ if (flags.text !== undefined) {
165
+ preset.text = flags.text;
166
+ }
167
+ if (flags.boolean !== undefined) {
168
+ preset.boolean = flags.boolean;
169
+ }
170
+ if (flags.select !== undefined) {
171
+ preset.select = flags.select;
172
+ }
173
+ if (flags.password !== undefined) {
174
+ preset.password = flags.password;
175
+ }
176
+ if (flags.integer !== undefined) {
177
+ preset.integer = flags.integer;
178
+ }
179
+ return preset;
180
+ }
181
+ }