@nocobase/cli 2.1.0-beta.8 → 2.2.0-alpha.1

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 (263) hide show
  1. package/assets/env-proxy/nginx/app.conf.tpl +23 -0
  2. package/assets/env-proxy/nginx/nocobase.conf.tpl +5 -0
  3. package/assets/env-proxy/nginx/snippets/dist-location.conf +5 -0
  4. package/assets/env-proxy/nginx/snippets/gzip.conf +17 -0
  5. package/assets/env-proxy/nginx/snippets/log-format-http.conf +13 -0
  6. package/assets/env-proxy/nginx/snippets/maps-http.conf +14 -0
  7. package/assets/env-proxy/nginx/snippets/mime-types.conf +98 -0
  8. package/assets/env-proxy/nginx/snippets/proxy-location.conf +17 -0
  9. package/assets/env-proxy/nginx/snippets/spa-location.conf +6 -0
  10. package/assets/env-proxy/nginx/snippets/uploads-location.conf +21 -0
  11. package/bin/run.cmd +3 -0
  12. package/bin/run.js +145 -0
  13. package/bin/session-env.js +39 -0
  14. package/dist/commands/api/resource/create.js +15 -0
  15. package/dist/commands/api/resource/destroy.js +15 -0
  16. package/dist/commands/api/resource/get.js +15 -0
  17. package/dist/commands/api/resource/index.js +20 -0
  18. package/dist/commands/api/resource/list.js +16 -0
  19. package/dist/commands/api/resource/query.js +15 -0
  20. package/dist/commands/api/resource/update.js +15 -0
  21. package/dist/commands/app/autostart/disable.js +55 -0
  22. package/dist/commands/app/autostart/enable.js +55 -0
  23. package/dist/commands/app/autostart/list.js +37 -0
  24. package/dist/commands/app/autostart/run.js +84 -0
  25. package/dist/commands/app/autostart/shared.js +49 -0
  26. package/dist/commands/app/destroy.js +234 -0
  27. package/dist/commands/app/down.js +71 -0
  28. package/dist/commands/app/logs.js +115 -0
  29. package/dist/commands/app/restart.js +229 -0
  30. package/dist/commands/app/shared.js +123 -0
  31. package/dist/commands/app/start.js +416 -0
  32. package/dist/commands/app/stop.js +183 -0
  33. package/dist/commands/app/upgrade.js +523 -0
  34. package/dist/commands/backup/create.js +147 -0
  35. package/dist/commands/backup/index.js +20 -0
  36. package/dist/commands/backup/restore.js +105 -0
  37. package/{src/cli.js → dist/commands/build.js} +4 -11
  38. package/dist/commands/config/delete.js +42 -0
  39. package/dist/commands/config/get.js +39 -0
  40. package/dist/commands/config/index.js +20 -0
  41. package/dist/commands/config/list.js +29 -0
  42. package/dist/commands/config/set.js +49 -0
  43. package/dist/commands/db/check.js +240 -0
  44. package/dist/commands/db/logs.js +85 -0
  45. package/dist/commands/db/ps.js +47 -0
  46. package/dist/commands/db/shared.js +96 -0
  47. package/dist/commands/db/start.js +86 -0
  48. package/dist/commands/db/stop.js +71 -0
  49. package/{templates/plugin/src/client/models/index.ts → dist/commands/dev.js} +4 -4
  50. package/{src/commands/locale/react-js-cron/index.js → dist/commands/down.js} +3 -8
  51. package/dist/commands/download.js +13 -0
  52. package/dist/commands/env/add.js +406 -0
  53. package/dist/commands/env/auth.js +189 -0
  54. package/dist/commands/env/current.js +21 -0
  55. package/dist/commands/env/info.js +202 -0
  56. package/dist/commands/env/list.js +43 -0
  57. package/dist/commands/env/remove.js +174 -0
  58. package/dist/commands/env/shared.js +204 -0
  59. package/dist/commands/env/status.js +93 -0
  60. package/dist/commands/env/update.js +448 -0
  61. package/dist/commands/env/use.js +38 -0
  62. package/dist/commands/examples/prompts-stages.js +150 -0
  63. package/dist/commands/examples/prompts-test.js +181 -0
  64. package/dist/commands/init.js +1390 -0
  65. package/dist/commands/install.js +2609 -0
  66. package/dist/commands/license/activate.js +179 -0
  67. package/dist/commands/license/env.js +94 -0
  68. package/dist/commands/license/generate-id.js +108 -0
  69. package/dist/commands/license/id.js +70 -0
  70. package/dist/commands/license/index.js +20 -0
  71. package/dist/commands/license/plugins/clean.js +115 -0
  72. package/dist/commands/license/plugins/index.js +20 -0
  73. package/dist/commands/license/plugins/list.js +64 -0
  74. package/dist/commands/license/plugins/shared.js +382 -0
  75. package/dist/commands/license/plugins/sync.js +314 -0
  76. package/dist/commands/license/shared.js +423 -0
  77. package/dist/commands/license/status.js +64 -0
  78. package/dist/commands/logs.js +12 -0
  79. package/dist/commands/plugin/disable.js +86 -0
  80. package/dist/commands/plugin/enable.js +86 -0
  81. package/dist/commands/plugin/import.js +108 -0
  82. package/dist/commands/plugin/list.js +82 -0
  83. package/dist/commands/pm/disable.js +12 -0
  84. package/dist/commands/pm/enable.js +12 -0
  85. package/dist/commands/pm/list.js +12 -0
  86. package/dist/commands/proxy/caddy/current.js +17 -0
  87. package/dist/commands/proxy/caddy/generate.js +69 -0
  88. package/dist/commands/proxy/caddy/index.js +28 -0
  89. package/dist/commands/proxy/caddy/info.js +31 -0
  90. package/dist/commands/proxy/caddy/reload.js +30 -0
  91. package/dist/commands/proxy/caddy/restart.js +28 -0
  92. package/dist/commands/proxy/caddy/start.js +30 -0
  93. package/dist/commands/proxy/caddy/status.js +19 -0
  94. package/dist/commands/proxy/caddy/stop.js +30 -0
  95. package/dist/commands/proxy/caddy/use.js +26 -0
  96. package/dist/commands/proxy/index.js +28 -0
  97. package/dist/commands/proxy/nginx/current.js +18 -0
  98. package/dist/commands/proxy/nginx/generate.js +68 -0
  99. package/dist/commands/proxy/nginx/index.js +28 -0
  100. package/dist/commands/proxy/nginx/info.js +34 -0
  101. package/dist/commands/proxy/nginx/reload.js +30 -0
  102. package/dist/commands/proxy/nginx/restart.js +28 -0
  103. package/dist/commands/proxy/nginx/start.js +30 -0
  104. package/dist/commands/proxy/nginx/status.js +19 -0
  105. package/dist/commands/proxy/nginx/stop.js +30 -0
  106. package/dist/commands/proxy/nginx/use.js +31 -0
  107. package/dist/commands/restart.js +12 -0
  108. package/dist/commands/revision/create.js +118 -0
  109. package/dist/commands/scaffold/migration.js +38 -0
  110. package/dist/commands/scaffold/plugin.js +37 -0
  111. package/dist/commands/self/check.js +71 -0
  112. package/dist/commands/self/index.js +20 -0
  113. package/dist/commands/self/update.js +152 -0
  114. package/dist/commands/session/id.js +24 -0
  115. package/dist/commands/session/remove.js +57 -0
  116. package/dist/commands/session/setup.js +62 -0
  117. package/dist/commands/skills/check.js +69 -0
  118. package/dist/commands/skills/index.js +20 -0
  119. package/dist/commands/skills/install.js +80 -0
  120. package/dist/commands/skills/remove.js +80 -0
  121. package/dist/commands/skills/update.js +87 -0
  122. package/dist/commands/source/build.js +58 -0
  123. package/dist/commands/source/dev.js +182 -0
  124. package/dist/commands/source/download.js +884 -0
  125. package/dist/commands/source/publish.js +109 -0
  126. package/dist/commands/source/registry/logs.js +70 -0
  127. package/dist/commands/source/registry/start.js +57 -0
  128. package/dist/commands/source/registry/status.js +33 -0
  129. package/dist/commands/source/registry/stop.js +48 -0
  130. package/dist/commands/source/test.js +476 -0
  131. package/dist/commands/start.js +12 -0
  132. package/dist/commands/stop.js +12 -0
  133. package/dist/commands/test.js +12 -0
  134. package/dist/commands/upgrade.js +12 -0
  135. package/dist/commands/v1.js +210 -0
  136. package/dist/generated/command-registry.js +134 -0
  137. package/dist/help/runtime-help.js +23 -0
  138. package/dist/lib/api-client.js +335 -0
  139. package/dist/lib/api-command-compat.js +641 -0
  140. package/dist/lib/app-health.js +139 -0
  141. package/dist/lib/app-managed-resources.js +337 -0
  142. package/dist/lib/app-public-path.js +80 -0
  143. package/dist/lib/app-runtime.js +189 -0
  144. package/dist/lib/auth-store.js +528 -0
  145. package/dist/lib/backup.js +171 -0
  146. package/dist/lib/bootstrap.js +409 -0
  147. package/dist/lib/build-config.js +18 -0
  148. package/dist/lib/builtin-db.js +86 -0
  149. package/dist/lib/cli-config.js +569 -0
  150. package/dist/lib/cli-entry-error.js +52 -0
  151. package/dist/lib/cli-home.js +47 -0
  152. package/dist/lib/cli-locale.js +141 -0
  153. package/dist/lib/command-discovery.js +39 -0
  154. package/dist/lib/command-log.js +284 -0
  155. package/dist/lib/db-connection-check.js +219 -0
  156. package/dist/lib/docker-env-file.js +60 -0
  157. package/dist/lib/docker-image.js +37 -0
  158. package/dist/lib/docker-log-stream.js +45 -0
  159. package/dist/lib/env-auth.js +963 -0
  160. package/dist/lib/env-command-config.js +45 -0
  161. package/dist/lib/env-config.js +108 -0
  162. package/dist/lib/env-guard.js +61 -0
  163. package/dist/lib/env-paths.js +101 -0
  164. package/dist/lib/env-proxy.js +1325 -0
  165. package/dist/lib/generated-command.js +203 -0
  166. package/dist/lib/http-request.js +49 -0
  167. package/dist/lib/inquirer-theme.js +17 -0
  168. package/dist/lib/inquirer.js +243 -0
  169. package/dist/lib/managed-env-file.js +101 -0
  170. package/dist/lib/managed-init-env.js +32 -0
  171. package/dist/lib/naming.js +70 -0
  172. package/dist/lib/object-utils.js +76 -0
  173. package/dist/lib/openapi.js +62 -0
  174. package/dist/lib/plugin-import.js +279 -0
  175. package/dist/lib/plugin-storage.js +64 -0
  176. package/dist/lib/post-processors.js +23 -0
  177. package/dist/lib/prompt-catalog-core.js +186 -0
  178. package/dist/lib/prompt-catalog-terminal.js +374 -0
  179. package/{src/index.js → dist/lib/prompt-catalog.js} +2 -6
  180. package/dist/lib/prompt-validators.js +278 -0
  181. package/dist/lib/prompt-web-ui.js +2234 -0
  182. package/dist/lib/proxy-caddy.js +274 -0
  183. package/dist/lib/proxy-nginx.js +330 -0
  184. package/dist/lib/resource-command.js +357 -0
  185. package/dist/lib/resource-request.js +104 -0
  186. package/dist/lib/run-npm.js +429 -0
  187. package/dist/lib/runtime-env-vars.js +32 -0
  188. package/dist/lib/runtime-generator.js +498 -0
  189. package/dist/lib/runtime-store.js +56 -0
  190. package/dist/lib/self-manager.js +301 -0
  191. package/dist/lib/session-id.js +17 -0
  192. package/dist/lib/session-integration.js +703 -0
  193. package/dist/lib/session-store.js +118 -0
  194. package/dist/lib/skills-manager.js +438 -0
  195. package/dist/lib/source-publish.js +326 -0
  196. package/dist/lib/source-registry.js +188 -0
  197. package/dist/lib/startup-update.js +309 -0
  198. package/dist/lib/ui.js +159 -0
  199. package/dist/locale/en-US.json +526 -0
  200. package/dist/locale/zh-CN.json +526 -0
  201. package/dist/post-processors/data-modeling.js +84 -0
  202. package/dist/post-processors/data-source-manager.js +138 -0
  203. package/dist/post-processors/index.js +19 -0
  204. package/nocobase-ctl.config.json +388 -0
  205. package/package.json +128 -24
  206. package/scripts/build.mjs +34 -0
  207. package/scripts/clean.mjs +9 -0
  208. package/tsconfig.json +19 -0
  209. package/bin/index.js +0 -39
  210. package/nocobase.conf.tpl +0 -95
  211. package/src/commands/benchmark.js +0 -73
  212. package/src/commands/build.js +0 -49
  213. package/src/commands/clean.js +0 -30
  214. package/src/commands/client.js +0 -166
  215. package/src/commands/create-nginx-conf.js +0 -37
  216. package/src/commands/create-plugin.js +0 -33
  217. package/src/commands/dev.js +0 -200
  218. package/src/commands/doc.js +0 -76
  219. package/src/commands/e2e.js +0 -265
  220. package/src/commands/global.js +0 -43
  221. package/src/commands/index.js +0 -45
  222. package/src/commands/instance-id.js +0 -47
  223. package/src/commands/locale/cronstrue.js +0 -122
  224. package/src/commands/locale/react-js-cron/en-US.json +0 -75
  225. package/src/commands/locale/react-js-cron/zh-CN.json +0 -33
  226. package/src/commands/locale/react-js-cron/zh-TW.json +0 -33
  227. package/src/commands/locale.js +0 -81
  228. package/src/commands/p-test.js +0 -88
  229. package/src/commands/perf.js +0 -63
  230. package/src/commands/pkg.js +0 -321
  231. package/src/commands/pm2.js +0 -37
  232. package/src/commands/postinstall.js +0 -88
  233. package/src/commands/start.js +0 -148
  234. package/src/commands/tar.js +0 -36
  235. package/src/commands/test-coverage.js +0 -55
  236. package/src/commands/test.js +0 -107
  237. package/src/commands/umi.js +0 -33
  238. package/src/commands/update-deps.js +0 -72
  239. package/src/commands/upgrade.js +0 -47
  240. package/src/commands/view-license-key.js +0 -44
  241. package/src/license.js +0 -76
  242. package/src/logger.js +0 -75
  243. package/src/plugin-generator.js +0 -80
  244. package/src/util.js +0 -517
  245. package/templates/bundle-status.html +0 -338
  246. package/templates/create-app-package.json +0 -39
  247. package/templates/plugin/.npmignore.tpl +0 -2
  248. package/templates/plugin/README.md.tpl +0 -1
  249. package/templates/plugin/client.d.ts +0 -2
  250. package/templates/plugin/client.js +0 -1
  251. package/templates/plugin/package.json.tpl +0 -11
  252. package/templates/plugin/server.d.ts +0 -2
  253. package/templates/plugin/server.js +0 -1
  254. package/templates/plugin/src/client/client.d.ts +0 -249
  255. package/templates/plugin/src/client/index.tsx.tpl +0 -1
  256. package/templates/plugin/src/client/locale.ts +0 -21
  257. package/templates/plugin/src/client/plugin.tsx.tpl +0 -10
  258. package/templates/plugin/src/index.ts +0 -2
  259. package/templates/plugin/src/locale/en-US.json +0 -1
  260. package/templates/plugin/src/locale/zh-CN.json +0 -1
  261. package/templates/plugin/src/server/collections/.gitkeep +0 -0
  262. package/templates/plugin/src/server/index.ts.tpl +0 -1
  263. package/templates/plugin/src/server/plugin.ts.tpl +0 -19
@@ -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 { Command } from '@oclif/core';
10
+ import { getCurrentEnvName, listEnvs } from '../../../lib/auth-store.js';
11
+ import { renderTable } from '../../../lib/ui.js';
12
+ import { isAutostartEnabled } from './shared.js';
13
+ export default class AppAutostartList extends Command {
14
+ static description = 'List app autostart status for configured envs.';
15
+ static examples = ['<%= config.bin %> <%= command.id %>'];
16
+ async run() {
17
+ await this.parse(AppAutostartList);
18
+ const { envs } = await listEnvs();
19
+ const currentEnv = await getCurrentEnvName();
20
+ const names = Object.keys(envs).sort();
21
+ if (!names.length) {
22
+ this.log('No environments are configured.');
23
+ return;
24
+ }
25
+ const rows = names.map((name) => {
26
+ const env = envs[name];
27
+ return [
28
+ name === currentEnv ? '*' : '',
29
+ name,
30
+ env.kind ?? '-',
31
+ env.source ? String(env.source) : '-',
32
+ isAutostartEnabled(env) ? 'yes' : 'no',
33
+ ];
34
+ });
35
+ this.log(renderTable(['Current', 'Env', 'Kind', 'Source', 'Autostart'], rows));
36
+ }
37
+ }
@@ -0,0 +1,84 @@
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 { listEnvs } from '../../../lib/auth-store.js';
11
+ import { resolveManagedAppRuntime } from '../../../lib/app-runtime.js';
12
+ import { renderTable } from '../../../lib/ui.js';
13
+ import { ensureManagedAutostartRuntime, isAutostartEnabled } from './shared.js';
14
+ function formatSummary(results) {
15
+ return renderTable(['Env', 'Status', 'Detail'], results.map((result) => [result.env, result.status, result.detail]));
16
+ }
17
+ export default class AppAutostartRun extends Command {
18
+ static description = 'Start every env that has app autostart enabled.';
19
+ static examples = ['<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --verbose'];
20
+ static flags = {
21
+ verbose: Flags.boolean({
22
+ description: 'Show raw startup output from the underlying local or Docker command',
23
+ default: false,
24
+ }),
25
+ };
26
+ async run() {
27
+ const { flags } = await this.parse(AppAutostartRun);
28
+ const { envs } = await listEnvs();
29
+ const enabledNames = Object.keys(envs)
30
+ .filter((name) => isAutostartEnabled(envs[name]))
31
+ .sort((left, right) => left.localeCompare(right));
32
+ if (!enabledNames.length) {
33
+ this.log('No environments have app autostart enabled.');
34
+ return;
35
+ }
36
+ const results = [];
37
+ for (const envName of enabledNames) {
38
+ const env = envs[envName];
39
+ try {
40
+ ensureManagedAutostartRuntime({ ...env, name: envName });
41
+ }
42
+ catch (error) {
43
+ results.push({
44
+ env: envName,
45
+ status: 'skipped',
46
+ detail: error instanceof Error ? error.message : String(error),
47
+ });
48
+ continue;
49
+ }
50
+ const runtime = await resolveManagedAppRuntime(envName);
51
+ if (!runtime) {
52
+ results.push({
53
+ env: envName,
54
+ status: 'failed',
55
+ detail: 'Env configuration could not be resolved.',
56
+ });
57
+ continue;
58
+ }
59
+ try {
60
+ const argv = ['--env', envName, '--yes'];
61
+ if (flags.verbose) {
62
+ argv.push('--verbose');
63
+ }
64
+ await this.config.runCommand('app:start', argv);
65
+ results.push({
66
+ env: envName,
67
+ status: 'started',
68
+ detail: `Started ${runtime.kind} app runtime.`,
69
+ });
70
+ }
71
+ catch (error) {
72
+ results.push({
73
+ env: envName,
74
+ status: 'failed',
75
+ detail: error instanceof Error ? error.message : String(error),
76
+ });
77
+ }
78
+ }
79
+ this.log(formatSummary(results));
80
+ if (results.some((result) => result.status === 'failed')) {
81
+ this.error('Some app autostart envs failed to start.');
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,49 @@
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 { loadExactAuthConfig, saveAuthConfig } from '../../../lib/auth-store.js';
10
+ export function isAutostartEnabled(config) {
11
+ return config?.autostart?.enabled === true;
12
+ }
13
+ export function ensureManagedAutostartRuntime(config) {
14
+ const kind = String(config.kind ?? '').trim();
15
+ const source = String(config.source ?? '').trim();
16
+ const inferredLocal = source === 'npm' || source === 'git' || source === 'local';
17
+ if (kind === 'local' || kind === 'docker' || (!kind && (source === 'docker' || inferredLocal))) {
18
+ return;
19
+ }
20
+ const envName = String(config.name ?? '').trim() || 'unknown';
21
+ throw new Error([
22
+ `Env "${envName}" cannot be added to app autostart.`,
23
+ 'Only local and Docker envs with CLI-managed app runtimes can be started automatically on this machine.',
24
+ ].join('\n'));
25
+ }
26
+ export async function updateAutostartSetting(envName, enabled) {
27
+ const config = await loadExactAuthConfig();
28
+ const previous = config.envs[envName];
29
+ if (!previous) {
30
+ throw new Error(`Env "${envName}" is not configured`);
31
+ }
32
+ ensureManagedAutostartRuntime({ ...previous, name: envName });
33
+ const next = { ...previous };
34
+ const wasEnabled = isAutostartEnabled(previous);
35
+ if (enabled) {
36
+ next.autostart = { enabled: true };
37
+ }
38
+ else {
39
+ delete next.autostart;
40
+ }
41
+ config.envs[envName] = next;
42
+ if (wasEnabled !== enabled) {
43
+ await saveAuthConfig(config);
44
+ }
45
+ return {
46
+ config,
47
+ changed: wasEnabled !== enabled,
48
+ };
49
+ }
@@ -0,0 +1,234 @@
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 { removeEnv } from '../../lib/auth-store.js';
11
+ import { formatMissingManagedAppEnvMessage, managedAppLifecycleEnvVars, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
12
+ import { hasExplicitEnvSelection } from '../../lib/env-guard.js';
13
+ import { resolveEnvProxyEntryDir, resolveLegacyNginxEnvProxyAppOutputPath } from "../../lib/env-proxy.js";
14
+ import { resolveConfiguredStoragePath } from '../../lib/env-paths.js';
15
+ import { input } from "../../lib/inquirer.js";
16
+ import { announceTargetEnv, failTask, isInteractiveTerminal, printInfo, startTask, succeedTask } from '../../lib/ui.js';
17
+ import path from 'node:path';
18
+ import { builtinDbContainerName, managedDockerNetworkName, removeDockerContainerIfExists, removeDockerNetworkIfUnused, removePathIfExists, resolveManagedLocalAppPath, shouldRemoveManagedLocalAppFiles, } from './shared.js';
19
+ function formatDestroyFailure(envName, message) {
20
+ return [
21
+ `Couldn't destroy env "${envName}".`,
22
+ 'Some managed local resources may still exist. Check Docker, local app files, and storage data, then try again.',
23
+ `Details: ${message}`,
24
+ ].join('\n');
25
+ }
26
+ function formatDestroyForceRequiredMessage(envName, explicitEnv) {
27
+ if (!explicitEnv) {
28
+ return [
29
+ `Refusing to destroy current env "${envName}" without explicit selection in non-interactive mode.`,
30
+ `Re-run with \`--env ${envName} --force\` to destroy this env.`,
31
+ ].join('\n');
32
+ }
33
+ return [
34
+ `Refusing to destroy env "${envName}" without confirmation in non-interactive mode.`,
35
+ `Re-run with \`--env ${envName} --force\` to destroy this env.`,
36
+ ].join('\n');
37
+ }
38
+ function buildDestroyPrompt(runtime, options) {
39
+ const subject = options.explicitEnv ? `env "${runtime.envName}"` : `current env "${runtime.envName}"`;
40
+ const lines = [`Destroy ${subject}?`];
41
+ if (runtime.kind === 'http' || runtime.kind === 'ssh') {
42
+ lines.push('This env has no CLI-managed local app or database runtime on this machine.');
43
+ lines.push('Only the saved CLI env config will be removed. External services are not touched.');
44
+ }
45
+ else {
46
+ lines.push('This removes managed app runtime resources.');
47
+ if (runtime.env.config.builtinDb) {
48
+ lines.push('CLI-managed built-in database runtime will also be removed.');
49
+ }
50
+ else {
51
+ lines.push('External database resources are not managed by the CLI and will be left untouched.');
52
+ }
53
+ if (options.removesManagedLocalAppFiles) {
54
+ lines.push('CLI-managed local app files will also be removed.');
55
+ }
56
+ lines.push('Env-specific proxy entry files generated by `nb proxy` will also be removed when present.');
57
+ if (options.removesStorageData) {
58
+ lines.push('Storage data will be removed.');
59
+ }
60
+ else {
61
+ lines.push('No saved storage path was found for this env.');
62
+ }
63
+ lines.push('The saved CLI env config will be removed.');
64
+ }
65
+ lines.push(`Type "${runtime.envName}" to confirm:`);
66
+ return lines.join('\n');
67
+ }
68
+ async function confirmDestroy(runtime, options) {
69
+ if (!isInteractiveTerminal()) {
70
+ if (!options.explicitEnv) {
71
+ throw new Error(formatDestroyForceRequiredMessage(runtime.envName, false));
72
+ }
73
+ if (options.force) {
74
+ return true;
75
+ }
76
+ throw new Error(formatDestroyForceRequiredMessage(runtime.envName, options.explicitEnv));
77
+ }
78
+ if (options.force) {
79
+ return true;
80
+ }
81
+ try {
82
+ await input({
83
+ message: buildDestroyPrompt(runtime, options),
84
+ required: true,
85
+ validate: (value) => (value.trim() === runtime.envName ? true : `Type "${runtime.envName}" to confirm.`),
86
+ placeholder: runtime.envName,
87
+ });
88
+ return true;
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ export default class AppDestroy extends Command {
95
+ static hidden = true;
96
+ static description = 'Deprecated compatibility alias for `nb env remove <name> --purge`.';
97
+ static examples = [
98
+ '<%= config.bin %> <%= command.id %> --env app1',
99
+ '<%= config.bin %> <%= command.id %> --env app1 --force',
100
+ ];
101
+ static flags = {
102
+ env: Flags.string({
103
+ char: 'e',
104
+ description: 'CLI env name to destroy. Defaults to the current env when omitted in interactive mode',
105
+ }),
106
+ force: Flags.boolean({
107
+ char: 'f',
108
+ description: 'Skip confirmation and destroy the selected env immediately',
109
+ default: false,
110
+ }),
111
+ verbose: Flags.boolean({
112
+ description: 'Show raw output from destruction commands',
113
+ default: false,
114
+ }),
115
+ };
116
+ async run() {
117
+ const { flags } = await this.parse(AppDestroy);
118
+ const requestedEnv = flags.env?.trim() || undefined;
119
+ const explicitEnv = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv));
120
+ const runtime = await resolveManagedAppRuntime(requestedEnv);
121
+ if (!runtime) {
122
+ this.error(formatMissingManagedAppEnvMessage(requestedEnv));
123
+ }
124
+ const removesManagedLocalAppFiles = runtime.kind === 'local' &&
125
+ Boolean(resolveManagedLocalAppPath(runtime)) &&
126
+ shouldRemoveManagedLocalAppFiles(runtime);
127
+ const removesStorageData = (runtime.kind === 'local' || runtime.kind === 'docker') &&
128
+ Boolean(resolveConfiguredStoragePath(runtime.env.config));
129
+ let confirmed = false;
130
+ try {
131
+ confirmed = await confirmDestroy(runtime, {
132
+ explicitEnv,
133
+ force: flags.force,
134
+ removesManagedLocalAppFiles,
135
+ removesStorageData,
136
+ });
137
+ }
138
+ catch (error) {
139
+ this.error(error instanceof Error ? error.message : String(error));
140
+ }
141
+ if (!confirmed) {
142
+ return;
143
+ }
144
+ announceTargetEnv(runtime.envName);
145
+ try {
146
+ if (runtime.kind === 'docker') {
147
+ startTask(`Removing Docker app container for "${runtime.envName}"...`);
148
+ const state = await removeDockerContainerIfExists(runtime.containerName, {
149
+ stdio: flags.verbose ? 'inherit' : 'ignore',
150
+ });
151
+ succeedTask(state === 'removed'
152
+ ? `Docker app container removed for "${runtime.envName}".`
153
+ : `No Docker app container found for "${runtime.envName}".`);
154
+ }
155
+ else if (runtime.kind === 'local') {
156
+ startTask(`Stopping local NocoBase app for "${runtime.envName}"...`);
157
+ await runLocalNocoBaseCommand(runtime, ['pm2', 'kill'], {
158
+ env: managedAppLifecycleEnvVars(),
159
+ stdio: flags.verbose ? 'inherit' : 'ignore',
160
+ });
161
+ succeedTask(`Local NocoBase app stopped for "${runtime.envName}".`);
162
+ }
163
+ if (runtime.kind === 'local' || runtime.kind === 'docker') {
164
+ const dbContainer = builtinDbContainerName(runtime);
165
+ if (dbContainer) {
166
+ startTask(`Removing built-in database container for "${runtime.envName}"...`);
167
+ const state = await removeDockerContainerIfExists(dbContainer, {
168
+ stdio: flags.verbose ? 'inherit' : 'ignore',
169
+ });
170
+ succeedTask(state === 'removed'
171
+ ? `Built-in database container removed for "${runtime.envName}".`
172
+ : `No built-in database container found for "${runtime.envName}".`);
173
+ }
174
+ else {
175
+ printInfo(`External database resources for "${runtime.envName}" were left untouched.`);
176
+ }
177
+ const networkName = managedDockerNetworkName(runtime);
178
+ if (networkName) {
179
+ startTask(`Removing Docker network for "${runtime.envName}" if unused...`);
180
+ const state = await removeDockerNetworkIfUnused(networkName);
181
+ if (state === 'removed') {
182
+ succeedTask(`Docker network removed for "${runtime.envName}".`);
183
+ }
184
+ else if (state === 'missing') {
185
+ succeedTask(`No Docker network found for "${runtime.envName}".`);
186
+ }
187
+ else {
188
+ succeedTask(`Docker network is still in use for "${runtime.envName}". Keeping it.`);
189
+ }
190
+ }
191
+ if (runtime.kind === 'local') {
192
+ const localAppPath = resolveManagedLocalAppPath(runtime);
193
+ if (localAppPath && removesManagedLocalAppFiles) {
194
+ startTask(`Removing managed local app files for "${runtime.envName}"...`);
195
+ await removePathIfExists(localAppPath, `managed app files for "${runtime.envName}"`);
196
+ succeedTask(`Managed local app files removed for "${runtime.envName}".`);
197
+ }
198
+ else {
199
+ printInfo(`No saved local app path found for "${runtime.envName}".`);
200
+ }
201
+ }
202
+ const proxyEntryDirs = [
203
+ resolveEnvProxyEntryDir(runtime.envName, { provider: 'nginx' }),
204
+ resolveEnvProxyEntryDir(runtime.envName, { provider: 'caddy' }),
205
+ path.dirname(resolveLegacyNginxEnvProxyAppOutputPath(runtime.envName)),
206
+ ];
207
+ startTask(`Removing proxy entry files for "${runtime.envName}"...`);
208
+ for (const proxyEntryDir of proxyEntryDirs) {
209
+ await removePathIfExists(proxyEntryDir, `proxy entry files for "${runtime.envName}"`);
210
+ }
211
+ succeedTask(`Proxy entry files removed for "${runtime.envName}".`);
212
+ const configuredStoragePath = resolveConfiguredStoragePath(runtime.env.config);
213
+ if (configuredStoragePath) {
214
+ startTask(`Removing storage data for "${runtime.envName}"...`);
215
+ await removePathIfExists(configuredStoragePath, `storage data for "${runtime.envName}"`);
216
+ succeedTask(`Storage data removed for "${runtime.envName}".`);
217
+ }
218
+ else {
219
+ printInfo(`No saved storage path found for "${runtime.envName}".`);
220
+ }
221
+ }
222
+ else {
223
+ printInfo(`No CLI-managed local app or database runtime exists for "${runtime.envName}" on this machine.`);
224
+ }
225
+ startTask(`Removing saved CLI env config for "${runtime.envName}"...`);
226
+ const result = await removeEnv(runtime.envName);
227
+ succeedTask(`Saved CLI env config removed for "${runtime.envName}"${result.lastEnv ? ` (last env: ${result.lastEnv})` : ''}.`);
228
+ }
229
+ catch (error) {
230
+ failTask(`Failed to destroy env "${runtime.envName}".`);
231
+ this.error(formatDestroyFailure(runtime.envName, error instanceof Error ? error.message : String(error)));
232
+ }
233
+ }
234
+ }
@@ -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 { printWarning } from '../../lib/ui.js';
11
+ export default class AppDown extends Command {
12
+ static hidden = true;
13
+ static description = 'Deprecated compatibility alias for `nb app stop --with-db` and `nb env remove <name> --purge`.';
14
+ static examples = [
15
+ '<%= config.bin %> <%= command.id %> --env app1',
16
+ '<%= config.bin %> <%= command.id %> --env app1 --all --force',
17
+ ];
18
+ static flags = {
19
+ env: Flags.string({
20
+ char: 'e',
21
+ description: 'CLI env name to bring down. Defaults to the current env when omitted',
22
+ }),
23
+ all: Flags.boolean({
24
+ description: 'Delete everything for this env, including storage data and the saved env config',
25
+ default: false,
26
+ }),
27
+ yes: Flags.boolean({
28
+ char: 'y',
29
+ description: 'Compatibility alias for confirmation flags on the replacement command',
30
+ default: false,
31
+ }),
32
+ force: Flags.boolean({
33
+ char: 'f',
34
+ description: 'Compatibility alias for confirmation flags on the replacement command',
35
+ default: false,
36
+ }),
37
+ verbose: Flags.boolean({
38
+ description: 'Show raw output from shutdown commands',
39
+ default: false,
40
+ }),
41
+ };
42
+ async run() {
43
+ const { flags } = await this.parse(AppDown);
44
+ const runCommand = this.config.runCommand.bind(this.config);
45
+ const envName = flags.env?.trim();
46
+ const argv = [];
47
+ if (envName) {
48
+ argv.push('--env', envName);
49
+ }
50
+ if (flags.verbose) {
51
+ argv.push('--verbose');
52
+ }
53
+ if (flags.all) {
54
+ printWarning('`nb app down --all` is deprecated. Use `nb env remove <name> --purge` instead.');
55
+ if (flags.force || flags.yes) {
56
+ argv.push('--force');
57
+ }
58
+ await runCommand('app:destroy', argv);
59
+ return;
60
+ }
61
+ printWarning('`nb app down` is deprecated. Use `nb app stop --with-db` instead.');
62
+ argv.push('--with-db');
63
+ if (flags.yes) {
64
+ argv.push('--yes');
65
+ }
66
+ if (flags.force) {
67
+ argv.push('--force');
68
+ }
69
+ await runCommand('app:stop', argv);
70
+ }
71
+ }
@@ -0,0 +1,115 @@
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 { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
11
+ import { formatMissingManagedAppEnvMessage, managedAppLifecycleEnvVars, resolveManagedAppRuntime, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
12
+ import { run } from '../../lib/run-npm.js';
13
+ import { printInfo } from '../../lib/ui.js';
14
+ function formatLogsFailure(envName, message) {
15
+ return [
16
+ `Couldn't show logs for "${envName}".`,
17
+ 'Check that the saved local app or Docker container still exists on this machine, then try again.',
18
+ `Details: ${message}`,
19
+ ].join('\n');
20
+ }
21
+ export default class AppLogs extends Command {
22
+ static hidden = false;
23
+ static description = 'Show NocoBase logs for the selected env. Local npm/git installs use pm2 logs, and Docker installs use docker logs.';
24
+ static examples = [
25
+ '<%= config.bin %> <%= command.id %>',
26
+ '<%= config.bin %> <%= command.id %> --env app1',
27
+ '<%= config.bin %> <%= command.id %> --env app1 --tail 200',
28
+ '<%= config.bin %> <%= command.id %> --env app1 --no-follow',
29
+ ];
30
+ static flags = {
31
+ env: Flags.string({
32
+ char: 'e',
33
+ description: 'CLI env name to inspect logs for. Defaults to the current env when omitted',
34
+ }),
35
+ yes: Flags.boolean({
36
+ char: 'y',
37
+ description: 'Confirm using --env when it targets a different env than the current env',
38
+ default: false,
39
+ }),
40
+ tail: Flags.integer({
41
+ description: 'Number of recent log lines to show before following',
42
+ default: 100,
43
+ min: 0,
44
+ }),
45
+ follow: Flags.boolean({
46
+ char: 'f',
47
+ description: 'Keep streaming new log lines',
48
+ default: false,
49
+ allowNo: true,
50
+ }),
51
+ };
52
+ async run() {
53
+ const { flags } = await this.parse(AppLogs);
54
+ const requestedEnv = flags.env?.trim() || undefined;
55
+ if (requestedEnv && hasExplicitEnvSelection(this.argv)) {
56
+ const confirmed = await ensureCrossEnvConfirmed({
57
+ command: this,
58
+ requestedEnv,
59
+ yes: flags.yes,
60
+ });
61
+ if (!confirmed) {
62
+ return;
63
+ }
64
+ }
65
+ const runtime = await resolveManagedAppRuntime(requestedEnv);
66
+ if (!runtime) {
67
+ this.error(formatMissingManagedAppEnvMessage(requestedEnv));
68
+ }
69
+ if (runtime.kind === 'http') {
70
+ this.error([
71
+ `Can't show runtime logs for "${runtime.envName}" from this machine.`,
72
+ 'This env only has an API connection, so there is no saved local app or Docker container to read logs from.',
73
+ 'Connect it to a local checkout or reinstall it with npm, git, or Docker if you want CLI-managed logs.',
74
+ ].join('\n'));
75
+ }
76
+ if (runtime.kind === 'ssh') {
77
+ this.error([
78
+ `Can't show runtime logs for "${runtime.envName}" yet.`,
79
+ 'SSH env support is reserved but not implemented yet.',
80
+ 'Use a local or Docker env for CLI-managed logs for now.',
81
+ ].join('\n'));
82
+ }
83
+ const tail = String(flags.tail ?? 100);
84
+ const follow = flags.follow === true;
85
+ printInfo(follow
86
+ ? `Showing logs for "${runtime.envName}" (press Ctrl+C to stop).`
87
+ : `Showing recent logs for "${runtime.envName}".`);
88
+ try {
89
+ if (runtime.kind === 'docker') {
90
+ const dockerArgs = ['logs', '--tail', tail];
91
+ if (follow) {
92
+ dockerArgs.push('--follow');
93
+ }
94
+ dockerArgs.push(runtime.containerName);
95
+ await run('docker', dockerArgs, {
96
+ errorName: 'docker logs',
97
+ stdio: 'inherit',
98
+ });
99
+ return;
100
+ }
101
+ const localArgs = ['pm2', 'logs', '--lines', tail];
102
+ if (!follow) {
103
+ localArgs.push('--nostream');
104
+ }
105
+ await runLocalNocoBaseCommand(runtime, localArgs, {
106
+ env: managedAppLifecycleEnvVars(),
107
+ stdio: 'inherit',
108
+ });
109
+ }
110
+ catch (error) {
111
+ const message = error instanceof Error ? error.message : String(error);
112
+ this.error(formatLogsFailure(runtime.envName, message));
113
+ }
114
+ }
115
+ }