@nocobase/ctl 0.1.5

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 (38) hide show
  1. package/README.md +164 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +14 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +20 -0
  6. package/dist/commands/env/add.js +51 -0
  7. package/dist/commands/env/index.js +27 -0
  8. package/dist/commands/env/list.js +31 -0
  9. package/dist/commands/env/remove.js +54 -0
  10. package/dist/commands/env/update.js +54 -0
  11. package/dist/commands/env/use.js +26 -0
  12. package/dist/commands/resource/create.js +15 -0
  13. package/dist/commands/resource/destroy.js +15 -0
  14. package/dist/commands/resource/get.js +15 -0
  15. package/dist/commands/resource/index.js +7 -0
  16. package/dist/commands/resource/list.js +16 -0
  17. package/dist/commands/resource/query.js +15 -0
  18. package/dist/commands/resource/update.js +15 -0
  19. package/dist/generated/command-registry.js +81 -0
  20. package/dist/lib/api-client.js +196 -0
  21. package/dist/lib/auth-store.js +92 -0
  22. package/dist/lib/bootstrap.js +263 -0
  23. package/dist/lib/build-config.js +10 -0
  24. package/dist/lib/cli-home.js +30 -0
  25. package/dist/lib/generated-command.js +113 -0
  26. package/dist/lib/naming.js +70 -0
  27. package/dist/lib/openapi.js +254 -0
  28. package/dist/lib/post-processors.js +23 -0
  29. package/dist/lib/resource-command.js +331 -0
  30. package/dist/lib/resource-request.js +103 -0
  31. package/dist/lib/runtime-generator.js +383 -0
  32. package/dist/lib/runtime-store.js +56 -0
  33. package/dist/lib/ui.js +154 -0
  34. package/dist/post-processors/data-modeling.js +66 -0
  35. package/dist/post-processors/data-source-manager.js +114 -0
  36. package/dist/post-processors/index.js +19 -0
  37. package/nocobase-ctl.config.json +327 -0
  38. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # NocoBase CLI
2
+
3
+ NocoBase CLI combines:
4
+
5
+ - built-in commands for environment management and generic resource access
6
+ - runtime-generated commands loaded from your NocoBase application's Swagger schema
7
+
8
+ This allows the CLI to stay aligned with the target application instead of relying on a fixed command list.
9
+
10
+ ## Install
11
+
12
+ Install dependencies for local development:
13
+
14
+ ```bash
15
+ pnpm install
16
+ ```
17
+
18
+ Run in development mode:
19
+
20
+ ```bash
21
+ node ./bin/dev.js --help
22
+ ```
23
+
24
+ Build the CLI:
25
+
26
+ ```bash
27
+ pnpm build
28
+ ```
29
+
30
+ Run the built CLI:
31
+
32
+ ```bash
33
+ node ./bin/run.js --help
34
+ ```
35
+
36
+ After packaging or linking, the executable name is:
37
+
38
+ ```bash
39
+ nocobase
40
+ ```
41
+
42
+ ## Quick Start
43
+
44
+ Add an environment:
45
+
46
+ ```bash
47
+ nocobase env add --name local --base-url http://localhost:13000/api --token <token>
48
+ ```
49
+
50
+ Show the current environment:
51
+
52
+ ```bash
53
+ nocobase env
54
+ ```
55
+
56
+ List configured environments:
57
+
58
+ ```bash
59
+ nocobase env list
60
+ ```
61
+
62
+ Switch the current environment:
63
+
64
+ ```bash
65
+ nocobase env use local
66
+ ```
67
+
68
+ Update the runtime command cache from `swagger:get`:
69
+
70
+ ```bash
71
+ nocobase env update
72
+ nocobase env update -e local
73
+ ```
74
+
75
+ Use the generic resource commands:
76
+
77
+ ```bash
78
+ nocobase resource list --resource users
79
+ nocobase resource get --resource users --filter-by-tk 1
80
+ nocobase resource create --resource users --values '{"nickname":"Ada"}'
81
+ ```
82
+
83
+ ## Runtime Commands
84
+
85
+ When you execute a runtime command, the CLI will:
86
+
87
+ 1. resolve the target environment
88
+ 2. read the application's Swagger schema from `swagger:get`
89
+ 3. generate or reuse a cached runtime command set for that application version
90
+ 4. execute the requested command
91
+
92
+ If the `API documentation plugin` is disabled, the CLI will prompt to enable it.
93
+
94
+ ## Environment Selection
95
+
96
+ Use `-e, --env` to temporarily select an environment:
97
+
98
+ ```bash
99
+ nocobase env update -e prod
100
+ nocobase resource list --resource users -e prod
101
+ ```
102
+
103
+ This does not change the current environment unless you explicitly run:
104
+
105
+ ```bash
106
+ nocobase env use <name>
107
+ ```
108
+
109
+ ## Config Scope
110
+
111
+ The `env` command supports two config scopes:
112
+
113
+ - `project`: use `./.nocobase-cli` in the current working directory
114
+ - `global`: use the global `.nocobase-cli` directory
115
+
116
+ Use `-s, --scope` to select one explicitly:
117
+
118
+ ```bash
119
+ nocobase env list -s project
120
+ nocobase env add -s global --name prod --base-url http://example.com/api --token <token>
121
+ nocobase env use local -s project
122
+ ```
123
+
124
+ If you do not pass `--scope`, the CLI uses automatic resolution:
125
+
126
+ 1. current working directory if `./.nocobase-cli` exists
127
+ 2. `NOCOBASE_HOME_CLI`
128
+ 3. your home directory
129
+
130
+ ## Built-in Commands
131
+
132
+ Current built-in topics:
133
+
134
+ - `env`
135
+ - `resource`
136
+
137
+ Check available commands at any time:
138
+
139
+ ```bash
140
+ nocobase --help
141
+ nocobase env --help
142
+ nocobase resource --help
143
+ ```
144
+
145
+ ## Common Flags
146
+
147
+ - `-e, --env`: temporary environment selection
148
+ - `-s, --scope`: config scope for `env` commands
149
+ - `-t, --token`: token override
150
+ - `-j, --json-output`: print raw JSON response
151
+
152
+ Example:
153
+
154
+ ```bash
155
+ nocobase env update -e prod -s global
156
+ nocobase resource list --resource users -e prod -j
157
+ ```
158
+
159
+ ## Local Data
160
+
161
+ The CLI stores its local state in `.nocobase-cli`, including:
162
+
163
+ - `config.json`: environment definitions and current selection
164
+ - `versions/<version>/commands.json`: cached runtime commands for a generated version
package/bin/dev.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node --import tsx --no-warnings=ExperimentalWarning "%~dp0\dev" %*
package/bin/dev.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env -S node --import tsx --disable-warning=ExperimentalWarning
2
+
3
+ import { ensureRuntimeFromArgv } from '../src/lib/bootstrap.ts';
4
+ import { execute } from '@oclif/core';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ await ensureRuntimeFromArgv(process.argv.slice(2), {
11
+ configFile: path.join(path.dirname(__dirname), 'nocobase-cli.config.json'),
12
+ });
13
+
14
+ await execute({ development: true, dir: import.meta.url });
package/bin/run.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node "%~dp0\run" %*
package/bin/run.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { ensureRuntimeFromArgv } from '../dist/lib/bootstrap.js';
4
+ import { execute } from '@oclif/core';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ try {
11
+ await ensureRuntimeFromArgv(process.argv.slice(2), {
12
+ configFile: path.join(path.dirname(__dirname), 'nocobase-cli.config.json'),
13
+ });
14
+
15
+ await execute({ dir: import.meta.url });
16
+ } catch (error) {
17
+ const message = error instanceof Error ? error.message : String(error);
18
+ console.error(message);
19
+ process.exitCode = 1;
20
+ }
@@ -0,0 +1,51 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { upsertEnv } from "../../lib/auth-store.js";
3
+ import { formatCliHomeScope } from "../../lib/cli-home.js";
4
+ import { isInteractiveTerminal, printVerbose, setVerboseMode, promptText } from "../../lib/ui.js";
5
+ export default class EnvAdd extends Command {
6
+ static summary = 'Add or update a NocoBase environment';
7
+ static id = 'env add';
8
+ static flags = {
9
+ verbose: Flags.boolean({
10
+ description: 'Show detailed progress output',
11
+ default: false,
12
+ }),
13
+ name: Flags.string({
14
+ description: 'Environment name',
15
+ default: 'default',
16
+ }),
17
+ scope: Flags.string({
18
+ char: 's',
19
+ description: 'Config scope',
20
+ options: ['project', 'global'],
21
+ }),
22
+ 'base-url': Flags.string({
23
+ description: 'NocoBase API base URL, for example http://localhost:13000/api',
24
+ }),
25
+ token: Flags.string({
26
+ char: 't',
27
+ description: 'Bearer token',
28
+ }),
29
+ };
30
+ async run() {
31
+ const { flags } = await this.parse(EnvAdd);
32
+ setVerboseMode(flags.verbose);
33
+ const name = flags.name || 'default';
34
+ const scope = flags.scope;
35
+ const baseUrl = flags['base-url'] ||
36
+ (isInteractiveTerminal()
37
+ ? await promptText('Base URL', { defaultValue: 'http://localhost:13000/api' })
38
+ : '');
39
+ const token = flags.token ||
40
+ (isInteractiveTerminal() ? await promptText('Bearer token', { secret: true }) : '');
41
+ if (!baseUrl) {
42
+ this.error('Missing base URL. Pass `--base-url <url>` or run in a TTY to enter it interactively.');
43
+ }
44
+ if (!token) {
45
+ this.error('Missing token. Pass `--token <token>` or run in a TTY to enter it interactively.');
46
+ }
47
+ printVerbose(`Saving env "${name}" with base URL ${baseUrl}`);
48
+ await upsertEnv(name, baseUrl, token, { scope });
49
+ this.log(`Saved env "${name}" and set it as current${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
50
+ }
51
+ }
@@ -0,0 +1,27 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getCurrentEnvName, getEnv } from "../../lib/auth-store.js";
3
+ import { formatCliHomeScope } from "../../lib/cli-home.js";
4
+ import { renderTable } from "../../lib/ui.js";
5
+ export default class Env extends Command {
6
+ static summary = 'Show the current environment';
7
+ static id = 'env';
8
+ static flags = {
9
+ scope: Flags.string({
10
+ char: 's',
11
+ description: 'Config scope',
12
+ options: ['project', 'global'],
13
+ }),
14
+ };
15
+ async run() {
16
+ const { flags } = await this.parse(Env);
17
+ const scope = flags.scope;
18
+ const envName = await getCurrentEnvName({ scope });
19
+ const env = await getEnv(envName, { scope });
20
+ if (!env?.baseUrl) {
21
+ this.log(`No current env is configured${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
22
+ this.log('Run `nocobase env add --name <name> --base-url <url> --token <token>` to add one.');
23
+ return;
24
+ }
25
+ this.log(renderTable(['Name', 'Base URL', 'Runtime'], [[envName, env?.baseUrl ?? '', env?.runtime?.version ?? '']]));
26
+ }
27
+ }
@@ -0,0 +1,31 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { listEnvs } from "../../lib/auth-store.js";
3
+ import { formatCliHomeScope } from "../../lib/cli-home.js";
4
+ import { renderTable } from "../../lib/ui.js";
5
+ export default class EnvList extends Command {
6
+ static summary = 'List configured environments';
7
+ static id = 'env list';
8
+ static flags = {
9
+ scope: Flags.string({
10
+ char: 's',
11
+ description: 'Config scope',
12
+ options: ['project', 'global'],
13
+ }),
14
+ };
15
+ async run() {
16
+ const { flags } = await this.parse(EnvList);
17
+ const scope = flags.scope;
18
+ const { currentEnv, envs } = await listEnvs({ scope });
19
+ const names = Object.keys(envs).sort();
20
+ if (!names.length) {
21
+ this.log(`No envs configured${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
22
+ this.log('Run `nocobase env add --name <name> --base-url <url> --token <token>` to add one.');
23
+ return;
24
+ }
25
+ const rows = names.map((name) => {
26
+ const env = envs[name];
27
+ return [name === currentEnv ? '*' : '', name, env.baseUrl ?? '', env.runtime?.version ?? ''];
28
+ });
29
+ this.log(renderTable(['Current', 'Name', 'Base URL', 'Runtime'], rows));
30
+ }
31
+ }
@@ -0,0 +1,54 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { getCurrentEnvName, removeEnv } from "../../lib/auth-store.js";
3
+ import { formatCliHomeScope } from "../../lib/cli-home.js";
4
+ import { confirmAction, isInteractiveTerminal, printVerbose, setVerboseMode } from "../../lib/ui.js";
5
+ export default class EnvRemove extends Command {
6
+ static id = 'env remove';
7
+ static summary = 'Remove a configured environment';
8
+ static flags = {
9
+ force: Flags.boolean({
10
+ char: 'f',
11
+ description: 'Remove without confirmation',
12
+ default: false,
13
+ }),
14
+ verbose: Flags.boolean({
15
+ description: 'Show detailed progress output',
16
+ default: false,
17
+ }),
18
+ scope: Flags.string({
19
+ char: 's',
20
+ description: 'Config scope',
21
+ options: ['project', 'global'],
22
+ }),
23
+ };
24
+ static args = {
25
+ name: Args.string({
26
+ description: 'Configured environment name',
27
+ required: true,
28
+ }),
29
+ };
30
+ async run() {
31
+ const { args, flags } = await this.parse(EnvRemove);
32
+ setVerboseMode(flags.verbose);
33
+ const scope = flags.scope;
34
+ const currentEnv = await getCurrentEnvName({ scope });
35
+ if (args.name === currentEnv && !flags.force) {
36
+ if (!isInteractiveTerminal()) {
37
+ this.error('Refusing to remove the current env without confirmation. Re-run with `--force`.');
38
+ }
39
+ const confirmed = await confirmAction(`Remove current env "${args.name}"?`, { defaultValue: false });
40
+ if (!confirmed) {
41
+ this.log('Canceled.');
42
+ return;
43
+ }
44
+ }
45
+ printVerbose(`Removing env "${args.name}"`);
46
+ const result = await removeEnv(args.name, { scope });
47
+ this.log(`Removed env "${result.removed}"${scope ? ` from ${formatCliHomeScope(scope)} scope` : ''}.`);
48
+ if (result.hasEnvs) {
49
+ this.log(`Current env: ${result.currentEnv}`);
50
+ return;
51
+ }
52
+ this.log('No envs configured.');
53
+ }
54
+ }
@@ -0,0 +1,54 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { Command, Flags } from '@oclif/core';
4
+ import { updateEnvRuntime } from "../../lib/bootstrap.js";
5
+ import { formatCliHomeScope } from "../../lib/cli-home.js";
6
+ import { failTask, startTask, succeedTask } from "../../lib/ui.js";
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+ export default class EnvUpdate extends Command {
9
+ static summary = 'Update commands for an environment from swagger:get';
10
+ static id = 'env update';
11
+ static flags = {
12
+ verbose: Flags.boolean({
13
+ description: 'Show detailed progress output',
14
+ default: false,
15
+ }),
16
+ env: Flags.string({
17
+ char: 'e',
18
+ description: 'Environment name',
19
+ }),
20
+ scope: Flags.string({
21
+ char: 's',
22
+ description: 'Config scope',
23
+ options: ['project', 'global'],
24
+ }),
25
+ 'base-url': Flags.string({
26
+ description: 'NocoBase API base URL override',
27
+ }),
28
+ token: Flags.string({
29
+ char: 't',
30
+ description: 'Bearer token override',
31
+ }),
32
+ };
33
+ async run() {
34
+ const { flags } = await this.parse(EnvUpdate);
35
+ const scope = flags.scope;
36
+ const envLabel = flags.env ?? 'current';
37
+ startTask(`Updating env runtime: ${envLabel}${scope ? ` (${formatCliHomeScope(scope)})` : ''}`);
38
+ try {
39
+ const runtime = await updateEnvRuntime({
40
+ envName: flags.env,
41
+ scope,
42
+ baseUrl: flags['base-url'],
43
+ token: flags.token,
44
+ configFile: path.join(path.dirname(path.dirname(path.dirname(__dirname))), 'nocobase-ctl.config.json'),
45
+ verbose: flags.verbose,
46
+ });
47
+ succeedTask(`Updated env "${envLabel}" to runtime "${runtime.version}"${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
48
+ }
49
+ catch (error) {
50
+ failTask(`Failed to update env "${envLabel}".`);
51
+ throw error;
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,26 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { setCurrentEnv } from "../../lib/auth-store.js";
3
+ import { formatCliHomeScope } from "../../lib/cli-home.js";
4
+ export default class EnvUse extends Command {
5
+ static summary = 'Switch the current environment';
6
+ static id = 'env use';
7
+ static flags = {
8
+ scope: Flags.string({
9
+ char: 's',
10
+ description: 'Config scope',
11
+ options: ['project', 'global'],
12
+ }),
13
+ };
14
+ static args = {
15
+ name: Args.string({
16
+ description: 'Configured environment name',
17
+ required: true,
18
+ }),
19
+ };
20
+ async run() {
21
+ const { args, flags } = await this.parse(EnvUse);
22
+ const scope = flags.scope;
23
+ await setCurrentEnv(args.name, { scope });
24
+ this.log(`Current env: ${args.name}${scope ? ` (${formatCliHomeScope(scope)} scope)` : ''}`);
25
+ }
26
+ }
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+ import { buildCreateArgs, createFlags, runResourceCommand } from "../../lib/resource-command.js";
3
+ export default class ResourceCreate extends Command {
4
+ static summary = 'Create a record in a resource';
5
+ static description = 'Create a record in a generic resource. Pass record content through --values as a JSON object.';
6
+ static examples = [
7
+ `<%= config.bin %> <%= command.id %> --resource users --values '{"nickname":"Ada"}'`,
8
+ `<%= config.bin %> <%= command.id %> --resource posts.comments --source-id 1 --values '{"content":"Hello"}'`,
9
+ ];
10
+ static flags = createFlags;
11
+ async run() {
12
+ const { flags } = await this.parse(ResourceCreate);
13
+ await runResourceCommand(this, 'create', flags, buildCreateArgs(flags));
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+ import { buildDestroyArgs, destroyFlags, runResourceCommand } from "../../lib/resource-command.js";
3
+ export default class ResourceDestroy extends Command {
4
+ static summary = 'Delete records from a resource';
5
+ static description = 'Delete records from a generic resource. Target records with --filter-by-tk or --filter.';
6
+ static examples = [
7
+ '<%= config.bin %> <%= command.id %> --resource users --filter-by-tk 1',
8
+ `<%= config.bin %> <%= command.id %> --resource posts --filter '{"status":"archived"}'`,
9
+ ];
10
+ static flags = destroyFlags;
11
+ async run() {
12
+ const { flags } = await this.parse(ResourceDestroy);
13
+ await runResourceCommand(this, 'destroy', flags, buildDestroyArgs(flags));
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+ import { buildGetArgs, getFlags, runResourceCommand } from "../../lib/resource-command.js";
3
+ export default class ResourceGet extends Command {
4
+ static summary = 'Get a record from a resource';
5
+ static description = 'Get a record from a generic resource. Use --filter-by-tk for the primary key and association resource names with --source-id when needed.';
6
+ static examples = [
7
+ '<%= config.bin %> <%= command.id %> --resource users --filter-by-tk 1',
8
+ '<%= config.bin %> <%= command.id %> --resource posts.comments --source-id 1 --filter-by-tk 2',
9
+ ];
10
+ static flags = getFlags;
11
+ async run() {
12
+ const { flags } = await this.parse(ResourceGet);
13
+ await runResourceCommand(this, 'get', flags, buildGetArgs(flags));
14
+ }
15
+ }
@@ -0,0 +1,7 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Resource extends Command {
3
+ static summary = 'Work with generic collection resources';
4
+ async run() {
5
+ this.log('Use `nocobase resource --help` to view available subcommands.');
6
+ }
7
+ }
@@ -0,0 +1,16 @@
1
+ import { Command } from '@oclif/core';
2
+ import { buildListArgs, listFlags, runResourceCommand } from "../../lib/resource-command.js";
3
+ export default class ResourceList extends Command {
4
+ static summary = 'List records from a resource';
5
+ static description = 'List records from a generic resource. Use association resource names like posts.comments with --source-id when needed.';
6
+ static examples = [
7
+ '<%= config.bin %> <%= command.id %> --resource users',
8
+ '<%= config.bin %> <%= command.id %> --resource posts.comments --source-id 1 --fields id --fields content',
9
+ `<%= config.bin %> <%= command.id %> --resource users --filter '{"status":"active"}' --sort=-createdAt`,
10
+ ];
11
+ static flags = listFlags;
12
+ async run() {
13
+ const { flags } = await this.parse(ResourceList);
14
+ await runResourceCommand(this, 'list', flags, buildListArgs(flags));
15
+ }
16
+ }
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+ import { buildQueryArgs, queryFlags, runResourceCommand } from "../../lib/resource-command.js";
3
+ export default class ResourceQuery extends Command {
4
+ static summary = 'Run an aggregate query on a resource';
5
+ static description = 'Run an aggregate query on a generic resource. Pass measures, dimensions, and orders as JSON arrays.';
6
+ static examples = [
7
+ `<%= config.bin %> <%= command.id %> --resource orders --measures '[{"field":["id"],"aggregation":"count","alias":"count"}]'`,
8
+ `<%= config.bin %> <%= command.id %> --resource orders --dimensions '[{"field":["status"],"alias":"status"}]' --orders '[{"field":["createdAt"],"order":"desc"}]'`,
9
+ ];
10
+ static flags = queryFlags;
11
+ async run() {
12
+ const { flags } = await this.parse(ResourceQuery);
13
+ await runResourceCommand(this, 'query', flags, buildQueryArgs(flags));
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+ import { buildUpdateArgs, runResourceCommand, updateFlags } from "../../lib/resource-command.js";
3
+ export default class ResourceUpdate extends Command {
4
+ static summary = 'Update records in a resource';
5
+ static description = 'Update records in a generic resource. Target records with --filter-by-tk or --filter, and pass updated values through --values.';
6
+ static examples = [
7
+ `<%= config.bin %> <%= command.id %> --resource users --filter-by-tk 1 --values '{"nickname":"Grace"}'`,
8
+ `<%= config.bin %> <%= command.id %> --resource posts --filter '{"status":"draft"}' --values '{"status":"published"}'`,
9
+ ];
10
+ static flags = updateFlags;
11
+ async run() {
12
+ const { flags } = await this.parse(ResourceUpdate);
13
+ await runResourceCommand(this, 'update', flags, buildUpdateArgs(flags));
14
+ }
15
+ }
@@ -0,0 +1,81 @@
1
+ import { Command } from '@oclif/core';
2
+ import EnvAdd from "../commands/env/add.js";
3
+ import Env from "../commands/env/index.js";
4
+ import EnvList from "../commands/env/list.js";
5
+ import EnvRemove from "../commands/env/remove.js";
6
+ import EnvUpdate from "../commands/env/update.js";
7
+ import EnvUse from "../commands/env/use.js";
8
+ import ResourceCreate from "../commands/resource/create.js";
9
+ import ResourceDestroy from "../commands/resource/destroy.js";
10
+ import ResourceGet from "../commands/resource/get.js";
11
+ import Resource from "../commands/resource/index.js";
12
+ import ResourceList from "../commands/resource/list.js";
13
+ import ResourceQuery from "../commands/resource/query.js";
14
+ import ResourceUpdate from "../commands/resource/update.js";
15
+ import { getCurrentEnvName, getEnv } from "../lib/auth-store.js";
16
+ import { createGeneratedFlags, GeneratedApiCommand } from "../lib/generated-command.js";
17
+ import { toKebabCase } from "../lib/naming.js";
18
+ import { loadRuntimeSync } from "../lib/runtime-store.js";
19
+ function readEnvName(argv) {
20
+ for (let index = 0; index < argv.length; index += 1) {
21
+ const token = argv[index];
22
+ if (token === '--env') {
23
+ return argv[index + 1];
24
+ }
25
+ if (token === '-e') {
26
+ return argv[index + 1];
27
+ }
28
+ if (token.startsWith('--env=')) {
29
+ return token.slice('--env='.length);
30
+ }
31
+ }
32
+ return undefined;
33
+ }
34
+ function createRuntimeCommand(operation) {
35
+ return class RuntimeCommand extends GeneratedApiCommand {
36
+ static summary = operation.summary;
37
+ static description = operation.description;
38
+ static examples = operation.examples;
39
+ static flags = createGeneratedFlags(operation);
40
+ static operation = operation;
41
+ };
42
+ }
43
+ function createRuntimeIndexCommand(commandId, operation) {
44
+ return class RuntimeIndexCommand extends Command {
45
+ static summary = operation.resourceDescription || operation.resourceDisplayName || `Work with ${commandId}`;
46
+ static description = operation.resourceDescription;
47
+ async run() {
48
+ this.log(`Use \`nocobase ${commandId} --help\` to view available subcommands.`);
49
+ }
50
+ };
51
+ }
52
+ const registry = {
53
+ env: Env,
54
+ 'env:add': EnvAdd,
55
+ 'env:list': EnvList,
56
+ 'env:remove': EnvRemove,
57
+ 'env:update': EnvUpdate,
58
+ 'env:use': EnvUse,
59
+ resource: Resource,
60
+ 'resource:create': ResourceCreate,
61
+ 'resource:destroy': ResourceDestroy,
62
+ 'resource:get': ResourceGet,
63
+ 'resource:list': ResourceList,
64
+ 'resource:query': ResourceQuery,
65
+ 'resource:update': ResourceUpdate,
66
+ };
67
+ const envName = readEnvName(process.argv.slice(2)) ?? (await getCurrentEnvName());
68
+ const env = await getEnv(envName);
69
+ const runtime = loadRuntimeSync(env?.runtime?.version);
70
+ for (const operation of runtime?.commands ?? []) {
71
+ const commandSegments = operation.commandId.split(' ');
72
+ const commandKey = commandSegments.join(':');
73
+ registry[commandKey] = createRuntimeCommand(operation);
74
+ const topLevelCommandId = commandSegments[0];
75
+ const modulePrefix = toKebabCase(operation.moduleDisplayName || operation.moduleName || '');
76
+ const isTopLevelResource = Boolean(topLevelCommandId && modulePrefix && topLevelCommandId !== modulePrefix);
77
+ if (isTopLevelResource && !registry[topLevelCommandId]) {
78
+ registry[topLevelCommandId] = createRuntimeIndexCommand(topLevelCommandId, operation);
79
+ }
80
+ }
81
+ export default registry;