@nocobase/cli 2.1.0-alpha.16 → 2.1.0-alpha.18

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 (105) hide show
  1. package/LICENSE.txt +107 -0
  2. package/README.md +134 -63
  3. package/bin/run.cmd +3 -0
  4. package/bin/run.js +87 -0
  5. package/dist/commands/api/index.js +8 -0
  6. package/dist/commands/env/add.js +53 -0
  7. package/dist/commands/env/auth.js +36 -0
  8. package/dist/commands/env/index.js +27 -0
  9. package/dist/commands/env/list.js +31 -0
  10. package/dist/commands/env/remove.js +54 -0
  11. package/dist/commands/env/update.js +58 -0
  12. package/dist/commands/env/use.js +26 -0
  13. package/dist/commands/resource/create.js +15 -0
  14. package/dist/commands/resource/destroy.js +15 -0
  15. package/dist/commands/resource/get.js +15 -0
  16. package/dist/commands/resource/index.js +7 -0
  17. package/dist/commands/resource/list.js +16 -0
  18. package/dist/commands/resource/query.js +15 -0
  19. package/dist/commands/resource/update.js +15 -0
  20. package/dist/generated/command-registry.js +88 -0
  21. package/dist/lib/api-client.js +199 -0
  22. package/dist/lib/auth-store.js +155 -0
  23. package/dist/lib/bootstrap.js +349 -0
  24. package/dist/lib/build-config.js +10 -0
  25. package/dist/lib/cli-home.js +30 -0
  26. package/dist/lib/env-auth.js +405 -0
  27. package/dist/lib/generated-command.js +142 -0
  28. package/dist/lib/naming.js +70 -0
  29. package/dist/lib/openapi.js +254 -0
  30. package/dist/lib/post-processors.js +23 -0
  31. package/dist/lib/resource-command.js +335 -0
  32. package/dist/lib/resource-request.js +104 -0
  33. package/dist/lib/runtime-generator.js +408 -0
  34. package/dist/lib/runtime-store.js +56 -0
  35. package/dist/lib/ui.js +169 -0
  36. package/dist/post-processors/data-modeling.js +66 -0
  37. package/dist/post-processors/data-source-manager.js +114 -0
  38. package/dist/post-processors/index.js +19 -0
  39. package/nocobase-ctl.config.json +327 -0
  40. package/package.json +50 -25
  41. package/LICENSE +0 -201
  42. package/bin/index.js +0 -39
  43. package/nocobase.conf.tpl +0 -184
  44. package/src/cli.js +0 -28
  45. package/src/commands/benchmark.js +0 -73
  46. package/src/commands/build.js +0 -81
  47. package/src/commands/clean.js +0 -30
  48. package/src/commands/client.js +0 -168
  49. package/src/commands/create-nginx-conf.js +0 -53
  50. package/src/commands/create-plugin.js +0 -33
  51. package/src/commands/dev.js +0 -290
  52. package/src/commands/doc.js +0 -76
  53. package/src/commands/e2e.js +0 -265
  54. package/src/commands/global.js +0 -43
  55. package/src/commands/index.js +0 -45
  56. package/src/commands/instance-id.js +0 -47
  57. package/src/commands/locale/cronstrue.js +0 -122
  58. package/src/commands/locale/react-js-cron/en-US.json +0 -75
  59. package/src/commands/locale/react-js-cron/index.js +0 -17
  60. package/src/commands/locale/react-js-cron/zh-CN.json +0 -33
  61. package/src/commands/locale/react-js-cron/zh-TW.json +0 -33
  62. package/src/commands/locale.js +0 -81
  63. package/src/commands/p-test.js +0 -88
  64. package/src/commands/perf.js +0 -63
  65. package/src/commands/pkg.js +0 -321
  66. package/src/commands/pm2.js +0 -37
  67. package/src/commands/postinstall.js +0 -88
  68. package/src/commands/start.js +0 -148
  69. package/src/commands/tar.js +0 -36
  70. package/src/commands/test-coverage.js +0 -55
  71. package/src/commands/test.js +0 -107
  72. package/src/commands/umi.js +0 -33
  73. package/src/commands/update-deps.js +0 -72
  74. package/src/commands/upgrade.js +0 -47
  75. package/src/commands/view-license-key.js +0 -44
  76. package/src/index.js +0 -14
  77. package/src/license.js +0 -76
  78. package/src/logger.js +0 -75
  79. package/src/plugin-generator.js +0 -80
  80. package/src/util.js +0 -607
  81. package/templates/bundle-status.html +0 -338
  82. package/templates/create-app-package.json +0 -39
  83. package/templates/plugin/.npmignore.tpl +0 -2
  84. package/templates/plugin/README.md.tpl +0 -1
  85. package/templates/plugin/client-v2.d.ts +0 -2
  86. package/templates/plugin/client-v2.js +0 -1
  87. package/templates/plugin/client.d.ts +0 -2
  88. package/templates/plugin/client.js +0 -1
  89. package/templates/plugin/package.json.tpl +0 -12
  90. package/templates/plugin/server.d.ts +0 -2
  91. package/templates/plugin/server.js +0 -1
  92. package/templates/plugin/src/client/client.d.ts +0 -249
  93. package/templates/plugin/src/client/index.tsx.tpl +0 -1
  94. package/templates/plugin/src/client/locale.ts +0 -21
  95. package/templates/plugin/src/client/models/index.ts +0 -12
  96. package/templates/plugin/src/client/plugin.tsx.tpl +0 -10
  97. package/templates/plugin/src/client-v2/client.d.ts +0 -103
  98. package/templates/plugin/src/client-v2/index.tsx.tpl +0 -1
  99. package/templates/plugin/src/client-v2/plugin.tsx.tpl +0 -7
  100. package/templates/plugin/src/index.ts +0 -2
  101. package/templates/plugin/src/locale/en-US.json +0 -1
  102. package/templates/plugin/src/locale/zh-CN.json +0 -1
  103. package/templates/plugin/src/server/collections/.gitkeep +0 -0
  104. package/templates/plugin/src/server/index.ts.tpl +0 -1
  105. package/templates/plugin/src/server/plugin.ts.tpl +0 -19
package/LICENSE.txt ADDED
@@ -0,0 +1,107 @@
1
+ Updated Date: February 24, 2026
2
+
3
+ NocoBase License Agreement
4
+
5
+ NOCOBASE PTE. LTD.,a Singaporean Exempt Private Company Limited by Shares with its principal place of business located at 112 ROBINSON ROAD, #03-01, SINGAPORE ("The Company") https://www.nocobase.com/ issues this License Agreement ("Agreement") to you. You, as an individual or a company ("The User"), will be deemed to voluntarily accept all terms of this Agreement by using NocoBase (including but not limited to obtaining NocoBase source code or installation package in any form, installing and using NocoBase, purchasing NocoBase commercial license and services, purchasing NocoBase commercial plugins). If the User does not agree to any term of this Agreement, or cannot accurately understand our interpretation of the relevant terms, please stop using it immediately.
6
+
7
+ This Agreement applies to any use, quotation, contract, invoice, and all software delivered by the Company. The User and the Company or NocoBase's agents can no longer sign a separate license agreement for the sale and delivery of the software.
8
+
9
+ The Company reserves the right to formulate and modify this Agreement from time to time as needed. If there are changes, the Company will announce them in the form of website announcements, without further individual notification. The changed Agreement will automatically take effect once it is announced, becoming part of this Agreement.
10
+
11
+ ==============
12
+ 1. Definitions
13
+ ==============
14
+
15
+ 1.1 "Software" refers to the NocoBase kernel and plugins placed in the same code repository as the kernel, including their source code, installation packages, images, and all their modifications, updates, and upgrades.
16
+
17
+ 1.2 "Community Edition" refers to the free version of the Software provided to the User through public channels.
18
+
19
+ 1.3 "Commercial Edition" refers to the paid version of the Software purchased by the User from the Company or its agents, downloaded through exclusive channels, and includes additional benefits. It consists of three versions: Standard Edition, Professional Edition, and Enterprise Edition.
20
+
21
+ 1.4 "Upper Layer Application" refers to a specific business use case application serving internal or external customers of the User, developed based on Software and Commercial Plugins, such as ERP/CRM.
22
+
23
+ 1.5 "Customer" refers to the clients who purchase the User's Upper Layer Application.
24
+
25
+ 1.6 "Third-Party Open Source Software" refers to open source software provided with Software and Commercial Plugins. They are licensed through various published open source software licenses or copyright notices accompanying such software.
26
+
27
+ ===================================
28
+ 2. Intellectual Property Protection
29
+ ===================================
30
+
31
+ Except for Third-Party Open Source Software, the Company owns all copyrights, trademark rights, patent rights, trade secrets, and other intellectual property rights of the Software, and has registered and protected them in relevant countries and regions according to the "Paris Convention" or "TRIPS Agreement", ensuring that the intellectual property rights of the Software and Commercial Plugins are internationally recognized and protected.
32
+
33
+ =============
34
+ 3. Disclaimer
35
+ =============
36
+
37
+ 3.1 The User shall not use the Software and Commercial Plugins to engage in activities that contravene applicable laws and regulations or offend against public order or religious prohibitions. All legal liabilities and consequences arising from the User’s use shall be borne by the User.
38
+
39
+ 3.2 The Company shall not be liable for any direct, indirect, special, incidental, or consequential damages (including but not limited to loss of profits, business interruption, data loss, or business information disclosure) caused by the User's use of the Software and Commercial Plugins, even if it has been previously informed of the possibility of such damages.
40
+
41
+ ===============
42
+ 4. License Type
43
+ ===============
44
+
45
+ 4.1 This Agreement serves as the unified license agreement for NocoBase Software, applying to both the Community Edition and the Commercial Editions.
46
+
47
+ 4.2 This Agreement incorporates and references the full text of the Apache License, Version 2.0 ("Apache-2.0", available at: https://www.apache.org/licenses/LICENSE-2.0 ). Users must comply with the Apache-2.0 License as well as the supplementary terms set forth in this Agreement. In case of any inconsistency between Apache-2.0 and this Agreement, the supplementary terms of this Agreement shall prevail.
48
+
49
+ ================================================
50
+ 5. Rights and Obligations of Open Source License
51
+ ================================================
52
+
53
+ 5.1 The Software can be used for commercial purposes.
54
+
55
+ 5.2 It is not allowed to remove or change the brand, name, link, version number, license, and other information about NocoBase on the Software interface, except for the main LOGO in the upper left corner of the page.
56
+
57
+ 5.3 It is not allowed to remove or change all intellectual property statements about NocoBase in the code.
58
+
59
+ 5.4 It is not allowed to provide to the public any form of no-code, zero-code, low-code, AI platform SaaS/PaaS products using the original or modified Software.
60
+
61
+ ===============================
62
+ 6. Rights of Commercial License
63
+ ===============================
64
+
65
+ 6.1 Obtain a permanent commercial license of the Software.
66
+
67
+ 6.2 Get software upgrades and exclusive technical support during the upgrade validity period.
68
+
69
+ 6.3 The licensed Software can be used for commercial purposes with no restrictions on the number of applications and users.
70
+
71
+ 6.4 Can remove or change the brand, name, link, version number, license, and other information about NocoBase on the Software interface.
72
+
73
+ 6.5 The User holding a Professional or Enterprise Edition License can sell Upper Layer Application to its Customers.
74
+
75
+ 6.6 If there are other agreements in the contract for the above rights, the contract agreement shall prevail.
76
+
77
+ ====================================
78
+ 7. Obligations of Commercial License
79
+ ====================================
80
+
81
+ 7.1 It is not allowed to remove or change all intellectual property statements about NocoBase in the code.
82
+
83
+ 7.2 It is not allowed to sell, transfer, lease, share, gift, or distribute the Commercial License.
84
+
85
+ 7.3 It is not allowed to sell, transfer, lease, share, or distribute any form of no-code, zero-code, low-code, AI platform, or developer tools developed based on Software.
86
+
87
+ 7.4 It is not allowed to provide any form of no-code, zero-code, low-code, AI platform SaaS/PaaS products to the public using the original or modified Software.
88
+
89
+ 7.5 It is not allowed for the User holding a Standard Edition license to sell Upper Layer Application to Customers without a Commercial license.
90
+
91
+ 7.6 It is not allowed for the User holding a Professional or Enterprise Edition license to sell Upper Layer Application to Customers without a Commercial license with access to further development and configuration.
92
+
93
+ 7.7 If there is a violation of the above obligations or the terms of this Agreement, the rights owned by the User will be immediately terminated, the paid fees will not be refunded, and the Company reserves the right to pursue the User's legal responsibility.
94
+
95
+ 7.8 If there are other agreements in the contract for the above obligations, the contract agreement shall prevail.
96
+
97
+ =============================================================
98
+ 8. Legal Jurisdiction, Interpretation, and Dispute Resolution
99
+ =============================================================
100
+
101
+ 8.1 Except for Mainland China, the interpretation, application, and all matters related to this agreement are subject to the jurisdiction of Singapore law.
102
+
103
+ 8.2 Any dispute related to this Agreement should first be resolved through friendly negotiation. If the negotiation fails to resolve the dispute, the dispute should be submitted to the International Chamber of Commerce (ICC) for arbitration. The arbitration venue should be Singapore, conducted in English.
104
+
105
+ 8.3 All terms and conditions of this Agreement shall be deemed enforceable to the maximum extent permitted by applicable law. If any term of this Agreement is deemed invalid by any applicable law, the invalidity of that term does not affect the validity of any other term of this Agreement, and it should be deemed that the invalid term has been modified as much as possible to make it valid and enforceable, or if the term cannot be modified, it should be deemed to have been deleted from this Agreement.
106
+
107
+ 8.4 The arbitration award is final, binding on both parties, and can be enforced in any court with jurisdiction.
package/README.md CHANGED
@@ -1,99 +1,170 @@
1
- # NocoBase
1
+ # NocoBase CTL
2
2
 
3
- <video width="100%" controls>
4
- <source src="https://github.com/user-attachments/assets/4d11a87b-00e2-48f3-9bf7-389d21072d13" type="video/mp4">
5
- </video>
3
+ NocoBase CTL is a command-line tool for managing and controlling NocoBase applications. Its relationship with multiple NocoBase App instances is shown below:
6
4
 
7
- <p align="center">
8
- <a href="https://trendshift.io/repositories/4112" target="_blank"><img src="https://trendshift.io/api/badge/repositories/4112" alt="nocobase%2Fnocobase | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
9
- <a href="https://www.producthunt.com/posts/nocobase?embed=true&utm_source=badge-top-post-topic-badge&utm_medium=badge&utm_souce=badge-nocobase" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-topic-badge.svg?post_id=456520&theme=light&period=weekly&topic_id=267" alt="NocoBase - Scalability&#0045;first&#0044;&#0032;open&#0045;source&#0032;no&#0045;code&#0032;platform | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
10
- </p>
5
+ ```
6
+ +----------------------+
7
+ | NocoBase CTL |
8
+ | Controller |
9
+ +----------------------+
10
+ |
11
+ +----------------+----------------+
12
+ | | |
13
+ v v v
14
+ +----------------+ +----------------+ +----------------+
15
+ | NocoBase App | | NocoBase App | | NocoBase App |
16
+ | Dev | | Test | | Prod |
17
+ +----------------+ +----------------+ +----------------+
18
+ ```
11
19
 
12
- ## What is NocoBase
20
+ NocoBase CTL combines:
13
21
 
14
- NocoBase is the most extensible AI-powered no-code platform.
15
- Total control. Infinite extensibility. AI collaboration.
16
- Enable your team to adapt quickly and cut costs dramatically.
17
- No years of development. No millions wasted.
18
- Deploy NocoBase in minutes — and take control of everything.
22
+ - built-in commands for environment management and generic resource access
23
+ - runtime-generated commands loaded from your NocoBase application's Swagger schema
19
24
 
20
- Homepage:
21
- https://www.nocobase.com/
25
+ This allows the CLI to stay aligned with the target application instead of relying on a fixed command list.
22
26
 
23
- Online Demo:
24
- https://demo.nocobase.com/new
27
+ ## Quick Start
25
28
 
26
- Documents:
27
- https://docs.nocobase.com/
29
+ Install NocoBase CTL globally:
28
30
 
29
- Forum:
30
- https://forum.nocobase.com/
31
+ ```bash
32
+ npm install -g @nocobase/ctl@latest
33
+ ```
31
34
 
32
- Use Cases:
33
- https://www.nocobase.com/en/blog/tags/customer-stories
35
+ Add an environment:
34
36
 
35
- ## Release Notes
37
+ ```bash
38
+ nb env add --name local --base-url http://localhost:13000/api
39
+ ```
36
40
 
37
- Our [blog](https://www.nocobase.com/en/blog/timeline) is regularly updated with release notes and provides a weekly summary.
41
+ Add an environment with an API key:
38
42
 
39
- ## Distinctive features
43
+ ```bash
44
+ nb env add --name local --base-url http://localhost:13000/api --token <api-key>
45
+ ```
40
46
 
41
- ### 1. Data model-driven, not form/table–driven
47
+ Authenticate an environment with OAuth:
42
48
 
43
- Instead of being constrained by forms or tables, NocoBase adopts a data model–driven approach, separating data structure from user interface to unlock unlimited possibilities.
49
+ ```bash
50
+ nb env auth -e local
51
+ ```
44
52
 
45
- - UI and data structure are fully decoupled
46
- - Multiple blocks and actions can be created for the same table or record in any quantity or form
47
- - Supports the main database, external databases, and third-party APIs as data sources
53
+ Show the current environment:
48
54
 
49
- ![model](https://static-docs.nocobase.com/model.png)
55
+ ```bash
56
+ nb env
57
+ ```
50
58
 
51
- ### 2. AI employees, integrated into your business systems
52
- Unlike standalone AI demos, NocoBase allows you to embed AI capabilities seamlessly into your interfaces, workflows, and data context, making AI truly useful in real business scenarios.
59
+ List configured environments:
53
60
 
54
- - Define AI employees for roles such as translator, analyst, researcher, or assistant
55
- - Seamless AI–human collaboration in interfaces and workflows
56
- - Ensure AI usage is secure, transparent, and customizable for your business needs
61
+ ```bash
62
+ nb env list
63
+ ```
57
64
 
58
- ![AI-employee](https://static-docs.nocobase.com/ai-employee-home.png)
65
+ Switch the current environment:
59
66
 
60
- ### 3. What you see is what you get, incredibly easy to use
67
+ ```bash
68
+ nb env use local
69
+ ```
61
70
 
62
- While enabling the development of complex business systems, NocoBase keeps the experience simple and intuitive.
71
+ Update the runtime command cache from `swagger:get`:
63
72
 
64
- - One-click switch between usage mode and configuration mode
65
- - Pages serve as a canvas to arrange blocks and actions, similar to Notion
66
- - Configuration mode is designed for ordinary users, not just programmers
73
+ ```bash
74
+ nb env update
75
+ nb env update -e local
76
+ ```
67
77
 
68
- ![wysiwyg](https://static-docs.nocobase.com/wysiwyg.gif)
78
+ Use the generic resource commands:
69
79
 
70
- ### 4. Everything is a plugin, designed for extension
71
- Adding more no-code features will never cover every business case. NocoBase is built for extension through its plugin-based microkernel architecture.
80
+ ```bash
81
+ nb api resource list --resource users
82
+ nb api resource get --resource users --filter-by-tk 1
83
+ nb api resource create --resource users --values '{"nickname":"Ada"}'
84
+ ```
72
85
 
73
- - All functionalities are plugins, similar to WordPress
74
- - Plugins are ready to use upon installation
75
- - Pages, blocks, actions, APIs, and data sources can all be extended through custom plugins
86
+ ## Runtime Commands
76
87
 
77
- ![plugins](https://static-docs.nocobase.com/plugins.png)
88
+ When you execute a runtime command, the CLI will:
78
89
 
79
- ## Installation
90
+ 1. resolve the target environment
91
+ 2. read the application's Swagger schema from `swagger:get`
92
+ 3. generate or reuse a cached runtime command set for that application version
93
+ 4. execute the requested command
80
94
 
81
- NocoBase supports three installation methods:
95
+ If the `API documentation plugin` is disabled, the CLI will prompt to enable it.
82
96
 
83
- - <a target="_blank" href="https://docs.nocobase.com/welcome/getting-started/installation/docker-compose">Installing With Docker (👍Recommended)</a>
97
+ ## Environment Selection
84
98
 
85
- Suitable for no-code scenarios, no code to write. When upgrading, just download the latest image and reboot.
99
+ Use `-e, --env` to temporarily select an environment:
86
100
 
87
- - <a target="_blank" href="https://docs.nocobase.com/welcome/getting-started/installation/create-nocobase-app">Installing from create-nocobase-app CLI</a>
101
+ ```bash
102
+ nb env update -e prod
103
+ nb api resource list --resource users -e prod
104
+ ```
88
105
 
89
- The business code of the project is completely independent and supports low-code development.
106
+ This does not change the current environment unless you explicitly run:
90
107
 
91
- - <a target="_blank" href="https://docs.nocobase.com/welcome/getting-started/installation/git-clone">Installing from Git source code</a>
108
+ ```bash
109
+ nb env use <name>
110
+ ```
92
111
 
93
- If you want to experience the latest unreleased version, or want to participate in the contribution, you need to make changes and debug on the source code, it is recommended to choose this installation method, which requires a high level of development skills, and if the code has been updated, you can git pull the latest code.
112
+ ## Config Scope
94
113
 
95
- ## How NocoBase works
114
+ The `env` command supports two config scopes:
96
115
 
97
- <video width="100%" controls>
98
- <source src="https://github.com/user-attachments/assets/8d183b44-9bb5-4792-b08f-bc08fe8dfaaf" type="video/mp4">
99
- </video>
116
+ - `project`: use `./.nocobase-ctl` in the current working directory
117
+ - `global`: use the global `.nocobase-ctl` directory
118
+
119
+ Use `-s, --scope` to select one explicitly:
120
+
121
+ ```bash
122
+ nb env list -s project
123
+ nb env add -s global --name prod --base-url http://example.com/api --token <api-key>
124
+ nb env auth -e prod -s global
125
+ nb env use local -s project
126
+ ```
127
+
128
+ If you do not pass `--scope`, the CLI uses automatic resolution:
129
+
130
+ 1. current working directory if `./.nocobase-ctl` exists
131
+ 2. `NOCOBASE_HOME_CLI`
132
+ 3. your home directory
133
+
134
+ ## Built-in Commands
135
+
136
+ Current built-in topics:
137
+
138
+ - `env`
139
+ - `api`
140
+
141
+ Check available commands at any time:
142
+
143
+ ```bash
144
+ nb --help
145
+ nb env --help
146
+ nb api resource --help
147
+ ```
148
+
149
+ ## Common Flags
150
+
151
+ - `-e, --env`: temporary environment selection
152
+ - `-s, --scope`: config scope for `env` commands
153
+ - `--role`: role override, sent as `X-Role`
154
+ - `-t, --token`: API key override
155
+ - `-j, --json-output`: print raw JSON response
156
+
157
+ Example:
158
+
159
+ ```bash
160
+ nb env update -e prod -s global
161
+ nb api resource list --resource users -e prod -j
162
+ nb api resource list --resource users -e prod --role admin
163
+ ```
164
+
165
+ ## Local Data
166
+
167
+ The CLI stores its local state in `.nocobase-ctl`, including:
168
+
169
+ - `config.json`: environment definitions and current selection
170
+ - `versions/<version>/commands.json`: cached runtime commands for a generated version
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,87 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from 'node:child_process';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { fileURLToPath, pathToFileURL } from 'node:url';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const root = path.resolve(__dirname, '..');
10
+ const realRoot = fs.realpathSync(root);
11
+ const isSourcePackage = realRoot.split(path.sep).join('/').endsWith('/packages/core/cli');
12
+
13
+ /**
14
+ * In the monorepo, plain `node` cannot load `.ts`. Re-exec once with `--import tsx`
15
+ * (same effect as a dedicated dev entry with `#!/usr/bin/env -S node --import tsx`).
16
+ */
17
+ function reexecWithTsx() {
18
+ const result = spawnSync(
19
+ process.execPath,
20
+ ['--import', 'tsx', '--disable-warning=ExperimentalWarning', ...process.argv.slice(1)],
21
+ {
22
+ stdio: 'inherit',
23
+ env: {
24
+ ...process.env,
25
+ _NOCO_CLI_TSX_CHILD: '1',
26
+ NODE_ENV: 'development',
27
+ },
28
+ },
29
+ );
30
+ process.exit(result.status === null ? 1 : result.status);
31
+ }
32
+
33
+ if (isSourcePackage && !process.env._NOCO_CLI_TSX_CHILD) {
34
+ reexecWithTsx();
35
+ }
36
+
37
+ const bootstrapPath = isSourcePackage
38
+ ? path.join(root, 'src/lib/bootstrap.ts')
39
+ : path.join(root, 'dist/lib/bootstrap.js');
40
+ const { ensureRuntimeFromArgv } = await import(pathToFileURL(bootstrapPath).href);
41
+ const { flush, run, settings } = await import('@oclif/core');
42
+
43
+ if (isSourcePackage) {
44
+ settings.debug = true;
45
+ }
46
+
47
+ function getCommandToken(argv) {
48
+ for (const token of argv) {
49
+ if (!token || token.startsWith('-')) {
50
+ continue;
51
+ }
52
+
53
+ return token;
54
+ }
55
+
56
+ return undefined;
57
+ }
58
+
59
+ function formatCliEntryError(error, argv) {
60
+ const message = error instanceof Error ? error.message : String(error);
61
+ const missingCommandMatch = message.match(/^Command (.+) not found\.$/);
62
+ if (missingCommandMatch) {
63
+ const commandToken = getCommandToken(argv) ?? missingCommandMatch[1];
64
+ return [
65
+ `Unknown command: \`${commandToken}\`.`,
66
+ 'If this is a built-in command or a typo, run `nb --help` to inspect available commands.',
67
+ `If \`${commandToken}\` should be a runtime command from your NocoBase app, run \`nb env update\` and try again.`,
68
+ ].join('\n');
69
+ }
70
+
71
+ return message;
72
+ }
73
+
74
+ try {
75
+ const argv = process.argv.slice(2);
76
+ if (argv[0] === 'api') {
77
+ await ensureRuntimeFromArgv(argv, {
78
+ configFile: path.join(root, 'nocobase-ctl.config.json'),
79
+ });
80
+ }
81
+ await run(argv, import.meta.url);
82
+ flush();
83
+ } catch (error) {
84
+ const message = formatCliEntryError(error, process.argv.slice(2));
85
+ console.error(message);
86
+ process.exitCode = 1;
87
+ }
@@ -0,0 +1,8 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Api extends Command {
3
+ static summary = 'Work with NocoBase APIs, environments, resources, and runtime commands';
4
+ static id = 'api';
5
+ async run() {
6
+ this.log('Use `nb api --help` to view available subcommands.');
7
+ }
8
+ }
@@ -0,0 +1,53 @@
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, promptText, setVerboseMode } 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: 'API key',
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
+ if (Object.keys(flags).includes('token') && !flags.token) {
40
+ flags.token = isInteractiveTerminal() ? await promptText('API key (optional)', { secret: true }) : '';
41
+ if (!flags.token) {
42
+ this.error('API key cannot be empty if --token flag is provided without a value.');
43
+ }
44
+ }
45
+ const token = flags.token;
46
+ if (!baseUrl) {
47
+ this.error('Missing base URL. Pass `--base-url <url>` or run in a TTY to enter it interactively.');
48
+ }
49
+ printVerbose(`Saving env "${name}" with base URL ${baseUrl}`);
50
+ await upsertEnv(name, baseUrl, token, { scope });
51
+ this.log(`Saved env "${name}" and set it as current${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
52
+ }
53
+ }
@@ -0,0 +1,36 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { formatCliHomeScope } from '../../lib/cli-home.js';
3
+ import { authenticateEnvWithOauth } from '../../lib/env-auth.js';
4
+ import { failTask, startTask, succeedTask } from '../../lib/ui.js';
5
+ export default class EnvAuth extends Command {
6
+ static summary = 'Authenticate an environment with OAuth';
7
+ static id = 'env auth';
8
+ static flags = {
9
+ env: Flags.string({
10
+ char: 'e',
11
+ description: 'Environment name',
12
+ }),
13
+ scope: Flags.string({
14
+ char: 's',
15
+ description: 'Config scope',
16
+ options: ['project', 'global'],
17
+ }),
18
+ };
19
+ async run() {
20
+ const { flags } = await this.parse(EnvAuth);
21
+ const scope = flags.scope;
22
+ const envLabel = flags.env ?? 'current';
23
+ startTask(`Authenticating env: ${envLabel}${scope ? ` (${formatCliHomeScope(scope)})` : ''}`);
24
+ try {
25
+ await authenticateEnvWithOauth({
26
+ envName: flags.env,
27
+ scope,
28
+ });
29
+ succeedTask(`Authenticated env "${envLabel}" with OAuth${scope ? ` in ${formatCliHomeScope(scope)} scope` : ''}.`);
30
+ }
31
+ catch (error) {
32
+ failTask(`Failed to authenticate env "${envLabel}".`);
33
+ throw error;
34
+ }
35
+ }
36
+ }
@@ -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 `nb env add --name <name> --base-url <url>` to add one.');
23
+ return;
24
+ }
25
+ this.log(renderTable(['Name', 'Base URL', 'Auth', 'Runtime'], [[envName, env?.baseUrl ?? '', env?.auth?.type ?? '', 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 `nb env add --name <name> --base-url <url>` 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.auth?.type ?? '', env.runtime?.version ?? ''];
28
+ });
29
+ this.log(renderTable(['Current', 'Name', 'Base URL', 'Auth', '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
+ }