@nocobase/cli 2.1.0-alpha.31 → 2.1.0-alpha.32

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 (37) hide show
  1. package/README.md +14 -0
  2. package/README.zh-CN.md +14 -0
  3. package/dist/commands/app/down.js +47 -9
  4. package/dist/commands/app/logs.js +17 -0
  5. package/dist/commands/app/restart.js +23 -1
  6. package/dist/commands/app/start.js +17 -0
  7. package/dist/commands/app/stop.js +17 -0
  8. package/dist/commands/app/upgrade.js +17 -0
  9. package/dist/commands/env/add.js +2 -1
  10. package/dist/commands/env/current.js +21 -0
  11. package/dist/commands/env/list.js +8 -14
  12. package/dist/commands/env/remove.js +1 -1
  13. package/dist/commands/env/status.js +90 -0
  14. package/dist/commands/env/use.js +10 -0
  15. package/dist/commands/install.js +2 -1
  16. package/dist/commands/license/activate.js +18 -19
  17. package/dist/commands/license/id.js +18 -0
  18. package/dist/commands/license/plugins/clean.js +18 -0
  19. package/dist/commands/license/plugins/list.js +19 -1
  20. package/dist/commands/license/plugins/sync.js +18 -0
  21. package/dist/commands/license/status.js +18 -0
  22. package/dist/commands/plugin/disable.js +24 -3
  23. package/dist/commands/plugin/enable.js +24 -3
  24. package/dist/commands/plugin/list.js +24 -3
  25. package/dist/commands/session/id.js +24 -0
  26. package/dist/commands/session/remove.js +57 -0
  27. package/dist/commands/session/setup.js +62 -0
  28. package/dist/lib/app-runtime.js +1 -1
  29. package/dist/lib/auth-store.js +28 -11
  30. package/dist/lib/env-guard.js +61 -0
  31. package/dist/lib/generated-command.js +16 -0
  32. package/dist/lib/resource-command.js +15 -0
  33. package/dist/lib/runtime-generator.js +1 -1
  34. package/dist/lib/session-id.js +17 -0
  35. package/dist/lib/session-integration.js +719 -0
  36. package/dist/lib/session-store.js +118 -0
  37. package/package.json +3 -3
@@ -9,6 +9,7 @@
9
9
  import * as p from '@clack/prompts';
10
10
  import { Command, Flags } from '@oclif/core';
11
11
  import { readFile } from 'node:fs/promises';
12
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
12
13
  import { ensureInstanceId, licenseEnvFlag, licenseJsonFlag, licensePkgUrlFlag, redactLicenseKey, requireLicenseRuntime, resolveLicenseKeyFile, resolveLicenseServiceUrl, saveLicenseKey, sanitizeLicenseOutput, validateLicenseKey, } from './shared.js';
13
14
  import { announceTargetEnv, isInteractiveTerminal } from '../../lib/ui.js';
14
15
  import { appUrl } from '../env/shared.js';
@@ -114,21 +115,10 @@ async function promptOnlineActivationInput(initial) {
114
115
  p.cancel('License activation cancelled.');
115
116
  return;
116
117
  }
117
- const confirmedAnswer = typeof initial.confirmed === 'boolean'
118
- ? initial.confirmed
119
- : await p.confirm({
120
- message: 'Confirm that the submitted license information is true and accurate?',
121
- initialValue: false,
122
- });
123
- if (p.isCancel(confirmedAnswer)) {
124
- p.cancel('License activation cancelled.');
125
- return;
126
- }
127
118
  return {
128
119
  account,
129
120
  password,
130
121
  appName,
131
- confirmed: Boolean(confirmedAnswer),
132
122
  serviceUrl: await resolveLicenseServiceUrl(initial.serviceUrl),
133
123
  };
134
124
  }
@@ -176,6 +166,7 @@ export default class LicenseActivate extends Command {
176
166
  '<%= config.bin %> <%= command.id %> --env app1 --key <licenseKey>',
177
167
  '<%= config.bin %> <%= command.id %> --env app1 --key-file ./license.txt',
178
168
  '<%= config.bin %> <%= command.id %> --env app1 --online',
169
+ '<%= config.bin %> <%= command.id %> --env app1 --online --account aa --password bb --desc test24',
179
170
  '<%= config.bin %> <%= command.id %> --env app1 --online --account aa --password bb --desc test24 --yes',
180
171
  '<%= config.bin %> <%= command.id %> --env app1 --json --key-file ./license.txt',
181
172
  ];
@@ -203,12 +194,25 @@ export default class LicenseActivate extends Command {
203
194
  }),
204
195
  'pkg-url': licensePkgUrlFlag,
205
196
  yes: Flags.boolean({
206
- description: 'Confirm that the submitted application information is true and accurate',
197
+ description: 'Skip the interactive cross-env confirmation prompt',
207
198
  default: false,
208
199
  }),
209
200
  };
210
201
  async run() {
211
202
  const { flags } = await this.parse(LicenseActivate);
203
+ const requestedEnv = flags.env?.trim() || undefined;
204
+ const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
205
+ if (explicitEnvSelection) {
206
+ const confirmed = await ensureCrossEnvConfirmed({
207
+ command: this,
208
+ requestedEnv,
209
+ yes: flags.yes,
210
+ });
211
+ if (!confirmed) {
212
+ this.log('Canceled.');
213
+ return;
214
+ }
215
+ }
212
216
  const runtime = await requireLicenseRuntime(flags.env);
213
217
  if (!flags.json) {
214
218
  announceTargetEnv(runtime.envName);
@@ -246,16 +250,14 @@ export default class LicenseActivate extends Command {
246
250
  account: resolveOnlineInputValue(flags.account),
247
251
  password: resolveOnlineInputValue(flags.password),
248
252
  appName: resolveOnlineInputValue(flags.desc),
249
- confirmed: flags.yes ? true : undefined,
250
253
  serviceUrl: resolvedServiceUrl,
251
254
  };
252
255
  let onlineInput = initialOnline;
253
256
  if (!onlineInput.account
254
257
  || !onlineInput.password
255
- || !onlineInput.appName
256
- || !onlineInput.confirmed) {
258
+ || !onlineInput.appName) {
257
259
  if (!isInteractiveTerminal()) {
258
- this.error('Online activation requires --account, --password, --desc, and --yes when not using a TTY.');
260
+ this.error('Online activation requires --account, --password, and --desc when not using a TTY.');
259
261
  }
260
262
  const prompted = await promptOnlineActivationInput(initialOnline);
261
263
  if (!prompted) {
@@ -264,9 +266,6 @@ export default class LicenseActivate extends Command {
264
266
  }
265
267
  onlineInput = prompted;
266
268
  }
267
- if (!onlineInput.confirmed) {
268
- this.error('Online activation requires confirmation that the submitted application information is true and accurate.');
269
- }
270
269
  const instanceId = await ensureInstanceId(runtime);
271
270
  const resolvedAppUrl = resolveAppUrlOrThrow(runtime);
272
271
  const resolvedKey = await requestOnlineLicenseKey(onlineInput.serviceUrl, onlineInput.account, onlineInput.password, {
@@ -7,6 +7,7 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
  import { Command, Flags } from '@oclif/core';
10
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
10
11
  import { generateAndSaveInstanceId, licenseEnvFlag, licenseJsonFlag, readSavedInstanceId, requireLicenseRuntime, resolveInstanceIdFile, } from './shared.js';
11
12
  import { announceTargetEnv } from '../../lib/ui.js';
12
13
  export default class LicenseId extends Command {
@@ -21,6 +22,10 @@ export default class LicenseId extends Command {
21
22
  static flags = {
22
23
  env: licenseEnvFlag,
23
24
  json: licenseJsonFlag,
25
+ yes: Flags.boolean({
26
+ description: 'Skip the interactive cross-env confirmation prompt',
27
+ default: false,
28
+ }),
24
29
  force: Flags.boolean({
25
30
  description: 'Force regenerate the instance ID even if one is already saved',
26
31
  default: false,
@@ -28,6 +33,19 @@ export default class LicenseId extends Command {
28
33
  };
29
34
  async run() {
30
35
  const { flags } = await this.parse(LicenseId);
36
+ const requestedEnv = flags.env?.trim() || undefined;
37
+ const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
38
+ if (explicitEnvSelection) {
39
+ const confirmed = await ensureCrossEnvConfirmed({
40
+ command: this,
41
+ requestedEnv,
42
+ yes: flags.yes,
43
+ });
44
+ if (!confirmed) {
45
+ this.log('Canceled.');
46
+ return;
47
+ }
48
+ }
31
49
  const runtime = await requireLicenseRuntime(flags.env);
32
50
  if (!flags.json) {
33
51
  announceTargetEnv(runtime.envName);
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { Command, Flags } from '@oclif/core';
10
10
  import pc from 'picocolors';
11
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../../lib/env-guard.js';
11
12
  import { licenseEnvFlag, licenseJsonFlag, licensePkgUrlFlag, requireLicenseRuntime } from '../shared.js';
12
13
  import { cleanLicensedPlugins } from './shared.js';
13
14
  import { resolvePluginStoragePath } from '../../../lib/plugin-storage.js';
@@ -42,9 +43,26 @@ export default class LicensePluginsClean extends Command {
42
43
  description: 'Show detailed per-plugin clean logs',
43
44
  default: false,
44
45
  }),
46
+ yes: Flags.boolean({
47
+ description: 'Skip the interactive cross-env confirmation prompt',
48
+ default: false,
49
+ }),
45
50
  };
46
51
  async run() {
47
52
  const { flags } = await this.parse(LicensePluginsClean);
53
+ const requestedEnv = flags.env?.trim() || undefined;
54
+ const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
55
+ if (explicitEnvSelection) {
56
+ const confirmed = await ensureCrossEnvConfirmed({
57
+ command: this,
58
+ requestedEnv,
59
+ yes: flags.yes,
60
+ });
61
+ if (!confirmed) {
62
+ this.log('Canceled.');
63
+ return;
64
+ }
65
+ }
48
66
  const runtime = await requireLicenseRuntime(flags.env);
49
67
  if (!flags.json) {
50
68
  announceTargetEnv(runtime.envName);
@@ -6,7 +6,8 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
- import { Command } from '@oclif/core';
9
+ import { Command, Flags } from '@oclif/core';
10
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../../lib/env-guard.js';
10
11
  import { licenseEnvFlag, licenseJsonFlag, licensePkgUrlFlag, requireLicenseRuntime } from '../shared.js';
11
12
  import { fetchLicensedPluginPackages } from './shared.js';
12
13
  import { renderTable } from '../../../lib/ui.js';
@@ -22,9 +23,26 @@ export default class LicensePluginsList extends Command {
22
23
  env: licenseEnvFlag,
23
24
  json: licenseJsonFlag,
24
25
  'pkg-url': licensePkgUrlFlag,
26
+ yes: Flags.boolean({
27
+ description: 'Skip the interactive cross-env confirmation prompt',
28
+ default: false,
29
+ }),
25
30
  };
26
31
  async run() {
27
32
  const { flags } = await this.parse(LicensePluginsList);
33
+ const requestedEnv = flags.env?.trim() || undefined;
34
+ const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
35
+ if (explicitEnvSelection) {
36
+ const confirmed = await ensureCrossEnvConfirmed({
37
+ command: this,
38
+ requestedEnv,
39
+ yes: flags.yes,
40
+ });
41
+ if (!confirmed) {
42
+ this.log('Canceled.');
43
+ return;
44
+ }
45
+ }
28
46
  const runtime = await requireLicenseRuntime(flags.env);
29
47
  const { commercialPlugins, licensedPlugins } = await fetchLicensedPluginPackages(runtime, {
30
48
  pkgUrl: flags['pkg-url'],
@@ -10,6 +10,7 @@ import { Command, Flags } from '@oclif/core';
10
10
  import pc from 'picocolors';
11
11
  import { readFile } from 'node:fs/promises';
12
12
  import path from 'node:path';
13
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../../lib/env-guard.js';
13
14
  import { licenseEnvFlag, licenseJsonFlag, licensePkgUrlFlag, requireLicenseRuntime } from '../shared.js';
14
15
  import { syncLicensedPlugins } from './shared.js';
15
16
  import { resolvePluginStoragePath } from '../../../lib/plugin-storage.js';
@@ -151,9 +152,26 @@ export default class LicensePluginsSync extends Command {
151
152
  description: 'Show detailed per-plugin sync logs',
152
153
  default: false,
153
154
  }),
155
+ yes: Flags.boolean({
156
+ description: 'Skip the interactive cross-env confirmation prompt',
157
+ default: false,
158
+ }),
154
159
  };
155
160
  async run() {
156
161
  const { flags } = await this.parse(LicensePluginsSync);
162
+ const requestedEnv = flags.env?.trim() || undefined;
163
+ const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
164
+ if (explicitEnvSelection) {
165
+ const confirmed = await ensureCrossEnvConfirmed({
166
+ command: this,
167
+ requestedEnv,
168
+ yes: flags.yes,
169
+ });
170
+ if (!confirmed) {
171
+ this.log('Canceled.');
172
+ return;
173
+ }
174
+ }
157
175
  const runtime = await requireLicenseRuntime(flags.env);
158
176
  if (!flags.json) {
159
177
  announceTargetEnv(runtime.envName);
@@ -7,6 +7,7 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
  import { Command, Flags } from '@oclif/core';
10
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
10
11
  import { ensureInstanceId, licenseEnvFlag, licenseJsonFlag, requireLicenseRuntime } from './shared.js';
11
12
  export default class LicenseStatus extends Command {
12
13
  static summary = 'Show commercial license status for the selected env';
@@ -20,6 +21,10 @@ export default class LicenseStatus extends Command {
20
21
  static flags = {
21
22
  env: licenseEnvFlag,
22
23
  json: licenseJsonFlag,
24
+ yes: Flags.boolean({
25
+ description: 'Skip the interactive cross-env confirmation prompt',
26
+ default: false,
27
+ }),
23
28
  doctor: Flags.boolean({
24
29
  description: 'Run extra diagnostic checks and suggestions',
25
30
  default: false,
@@ -27,6 +32,19 @@ export default class LicenseStatus extends Command {
27
32
  };
28
33
  async run() {
29
34
  const { flags } = await this.parse(LicenseStatus);
35
+ const requestedEnv = flags.env?.trim() || undefined;
36
+ const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv ?? []));
37
+ if (explicitEnvSelection) {
38
+ const confirmed = await ensureCrossEnvConfirmed({
39
+ command: this,
40
+ requestedEnv,
41
+ yes: flags.yes,
42
+ });
43
+ if (!confirmed) {
44
+ this.log('Canceled.');
45
+ return;
46
+ }
47
+ }
30
48
  const runtime = await requireLicenseRuntime(flags.env);
31
49
  const payload = {
32
50
  ok: true,
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { Args, Command, Flags } from '@oclif/core';
10
10
  import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, runDockerNocoBaseCommand, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
11
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
11
12
  import { announceTargetEnv } from '../../lib/ui.js';
12
13
  export default class PluginDisable extends Command {
13
14
  static hidden = false;
@@ -29,16 +30,34 @@ export default class PluginDisable extends Command {
29
30
  char: 'e',
30
31
  description: 'CLI env name (from `nb env` / `nb init`). Defaults to the current env when omitted',
31
32
  }),
33
+ yes: Flags.boolean({
34
+ char: 'y',
35
+ description: 'Confirm using --env when it targets a different env than the current env',
36
+ default: false,
37
+ }),
32
38
  };
33
39
  async run() {
34
40
  const { args, flags } = await this.parse(PluginDisable);
41
+ const requestedEnv = flags.env?.trim() || undefined;
42
+ const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv));
43
+ if (explicitEnvSelection) {
44
+ const confirmed = await ensureCrossEnvConfirmed({
45
+ command: this,
46
+ requestedEnv,
47
+ yes: flags.yes,
48
+ });
49
+ if (!confirmed) {
50
+ this.log('Canceled.');
51
+ return;
52
+ }
53
+ }
35
54
  const packages = args.packages;
36
55
  if (!Array.isArray(packages) || packages.length === 0) {
37
56
  this.error('Pass at least one plugin package name.');
38
57
  }
39
- const runtime = await resolveManagedAppRuntime(flags.env);
58
+ const runtime = await resolveManagedAppRuntime(requestedEnv);
40
59
  if (!runtime) {
41
- this.error(formatMissingManagedAppEnvMessage(flags.env));
60
+ this.error(formatMissingManagedAppEnvMessage(requestedEnv));
42
61
  }
43
62
  announceTargetEnv(runtime.envName);
44
63
  if (runtime.kind === 'local') {
@@ -61,6 +80,8 @@ export default class PluginDisable extends Command {
61
80
  }
62
81
  return;
63
82
  }
64
- await this.config.runCommand('api:pm:disable', ['--await-response', '--filter-by-tk', packages.join(',')]);
83
+ await this.config.runCommand('api:pm:disable', explicitEnvSelection
84
+ ? ['--await-response', '--filter-by-tk', packages.join(','), '--env', runtime.envName, '--yes']
85
+ : ['--await-response', '--filter-by-tk', packages.join(',')]);
65
86
  }
66
87
  }
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { Args, Command, Flags } from '@oclif/core';
10
10
  import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, runDockerNocoBaseCommand, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
11
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
11
12
  import { announceTargetEnv } from '../../lib/ui.js';
12
13
  export default class PluginEnable extends Command {
13
14
  static hidden = false;
@@ -29,16 +30,34 @@ export default class PluginEnable extends Command {
29
30
  char: 'e',
30
31
  description: 'CLI env name (from `nb env` / `nb init`). Defaults to the current env when omitted',
31
32
  }),
33
+ yes: Flags.boolean({
34
+ char: 'y',
35
+ description: 'Confirm using --env when it targets a different env than the current env',
36
+ default: false,
37
+ }),
32
38
  };
33
39
  async run() {
34
40
  const { args, flags } = await this.parse(PluginEnable);
41
+ const requestedEnv = flags.env?.trim() || undefined;
42
+ const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv));
43
+ if (explicitEnvSelection) {
44
+ const confirmed = await ensureCrossEnvConfirmed({
45
+ command: this,
46
+ requestedEnv,
47
+ yes: flags.yes,
48
+ });
49
+ if (!confirmed) {
50
+ this.log('Canceled.');
51
+ return;
52
+ }
53
+ }
35
54
  const packages = args.packages;
36
55
  if (!Array.isArray(packages) || packages.length === 0) {
37
56
  this.error('Pass at least one plugin package name.');
38
57
  }
39
- const runtime = await resolveManagedAppRuntime(flags.env);
58
+ const runtime = await resolveManagedAppRuntime(requestedEnv);
40
59
  if (!runtime) {
41
- this.error(formatMissingManagedAppEnvMessage(flags.env));
60
+ this.error(formatMissingManagedAppEnvMessage(requestedEnv));
42
61
  }
43
62
  announceTargetEnv(runtime.envName);
44
63
  if (runtime.kind === 'local') {
@@ -61,6 +80,8 @@ export default class PluginEnable extends Command {
61
80
  }
62
81
  return;
63
82
  }
64
- await this.config.runCommand('api:pm:enable', ['--await-response', '--filter-by-tk', packages.join(',')]);
83
+ await this.config.runCommand('api:pm:enable', explicitEnvSelection
84
+ ? ['--await-response', '--filter-by-tk', packages.join(','), '--env', runtime.envName, '--yes']
85
+ : ['--await-response', '--filter-by-tk', packages.join(',')]);
65
86
  }
66
87
  }
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { Command, Flags } from '@oclif/core';
10
10
  import { formatMissingManagedAppEnvMessage, resolveManagedAppRuntime, runDockerNocoBaseCommand, runLocalNocoBaseCommand, } from '../../lib/app-runtime.js';
11
+ import { ensureCrossEnvConfirmed, hasExplicitEnvSelection } from '../../lib/env-guard.js';
11
12
  export default class PluginList extends Command {
12
13
  static hidden = false;
13
14
  static args = {};
@@ -23,12 +24,30 @@ export default class PluginList extends Command {
23
24
  char: 'e',
24
25
  description: 'CLI env name (from `nb env` / `nb init`). Defaults to the current env when omitted',
25
26
  }),
27
+ yes: Flags.boolean({
28
+ char: 'y',
29
+ description: 'Confirm using --env when it targets a different env than the current env',
30
+ default: false,
31
+ }),
26
32
  };
27
33
  async run() {
28
34
  const { flags } = await this.parse(PluginList);
29
- const runtime = await resolveManagedAppRuntime(flags.env);
35
+ const requestedEnv = flags.env?.trim() || undefined;
36
+ const explicitEnvSelection = Boolean(requestedEnv && hasExplicitEnvSelection(this.argv));
37
+ if (explicitEnvSelection) {
38
+ const confirmed = await ensureCrossEnvConfirmed({
39
+ command: this,
40
+ requestedEnv,
41
+ yes: flags.yes,
42
+ });
43
+ if (!confirmed) {
44
+ this.log('Canceled.');
45
+ return;
46
+ }
47
+ }
48
+ const runtime = await resolveManagedAppRuntime(requestedEnv);
30
49
  if (!runtime) {
31
- this.error(formatMissingManagedAppEnvMessage(flags.env));
50
+ this.error(formatMissingManagedAppEnvMessage(requestedEnv));
32
51
  }
33
52
  if (runtime.kind === 'local') {
34
53
  try {
@@ -57,6 +76,8 @@ export default class PluginList extends Command {
57
76
  'Use a local, Docker, or HTTP env for plugin inspection right now.',
58
77
  ].join('\n'));
59
78
  }
60
- await this.config.runCommand('api:pm:list', ['--mode=summary']);
79
+ await this.config.runCommand('api:pm:list', explicitEnvSelection
80
+ ? ['--mode=summary', '--env', runtime.envName, '--yes']
81
+ : ['--mode=summary']);
61
82
  }
62
83
  }
@@ -0,0 +1,24 @@
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 { resolveSessionIdentity } from '../../lib/session-id.js';
11
+ export default class SessionId extends Command {
12
+ static summary = 'Show the current effective session id';
13
+ static examples = [
14
+ '<%= config.bin %> <%= command.id %>',
15
+ ];
16
+ async run() {
17
+ await this.parse(SessionId);
18
+ const identity = resolveSessionIdentity();
19
+ if (!identity) {
20
+ this.error('No effective session id is available. Run `nb session setup`, then open a new shell session or runtime.');
21
+ }
22
+ this.log(identity.id);
23
+ }
24
+ }
@@ -0,0 +1,57 @@
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
+ /**
10
+ * This file is part of the NocoBase (R) project.
11
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
12
+ * Authors: NocoBase Team.
13
+ *
14
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
15
+ * For more information, please refer to: https://www.nocobase.com/agreement.
16
+ */
17
+ import { Command, Flags } from '@oclif/core';
18
+ import { detectSessionShell, removeSessionIntegration } from '../../lib/session-integration.js';
19
+ export default class SessionRemove extends Command {
20
+ static summary = 'Remove shell session integration for NB_SESSION_ID';
21
+ static examples = [
22
+ '<%= config.bin %> <%= command.id %>',
23
+ '<%= config.bin %> <%= command.id %> --shell zsh',
24
+ ];
25
+ static flags = {
26
+ shell: Flags.string({
27
+ description: 'Target shell to remove configuration from',
28
+ options: ['bash', 'zsh', 'fish', 'powershell', 'cmd'],
29
+ }),
30
+ };
31
+ async run() {
32
+ const { flags } = await this.parse(SessionRemove);
33
+ const shell = flags.shell ?? detectSessionShell();
34
+ if (!shell) {
35
+ this.error('Could not detect the current shell. Re-run with `--shell bash|zsh|fish|powershell|cmd`.');
36
+ }
37
+ const result = await removeSessionIntegration(shell);
38
+ this.log(`Session integration removed for ${result.shell}.`);
39
+ if (result.profileUpdated) {
40
+ for (const profileFile of result.profileFiles) {
41
+ this.log(`Profile updated: ${profileFile}`);
42
+ }
43
+ }
44
+ if (result.managedFileRemoved) {
45
+ this.log(`Managed file removed: ${result.managedFile}`);
46
+ }
47
+ if (result.cmdAutoRunRemoved) {
48
+ this.log(`cmd AutoRun updated: ${result.cmdAutoRunLocation}`);
49
+ }
50
+ if (result.agentConfigUpdated) {
51
+ this.log(`Opencode config updated: ${result.agentConfigFile}`);
52
+ }
53
+ if (result.agentPluginRemoved) {
54
+ this.log(`Opencode agent plugin removed: ${result.agentPluginFile}`);
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,62 @@
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
+ /**
10
+ * This file is part of the NocoBase (R) project.
11
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
12
+ * Authors: NocoBase Team.
13
+ *
14
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
15
+ * For more information, please refer to: https://www.nocobase.com/agreement.
16
+ */
17
+ import { Command, Flags } from '@oclif/core';
18
+ import { detectSessionShell, setupSessionIntegration } from '../../lib/session-integration.js';
19
+ export default class SessionSetup extends Command {
20
+ static summary = 'Set up shell session integration for NB_SESSION_ID';
21
+ static examples = [
22
+ '<%= config.bin %> <%= command.id %>',
23
+ '<%= config.bin %> <%= command.id %> --shell zsh',
24
+ '<%= config.bin %> <%= command.id %> --shell powershell',
25
+ ];
26
+ static flags = {
27
+ shell: Flags.string({
28
+ description: 'Target shell to configure',
29
+ options: ['bash', 'zsh', 'fish', 'powershell', 'cmd'],
30
+ }),
31
+ };
32
+ async run() {
33
+ const { flags } = await this.parse(SessionSetup);
34
+ const shell = flags.shell ?? detectSessionShell();
35
+ if (!shell) {
36
+ this.error('Could not detect the current shell. Re-run with `--shell bash|zsh|fish|powershell|cmd`.');
37
+ }
38
+ const result = await setupSessionIntegration(shell);
39
+ this.log(`Session integration configured for ${result.shell}.`);
40
+ this.log(`Managed file: ${result.managedFile}`);
41
+ if (result.cmdAutoRunConfigured) {
42
+ this.log(`cmd AutoRun updated: ${result.cmdAutoRunLocation}`);
43
+ this.log('Open a new cmd session to initialize NB_SESSION_ID automatically.');
44
+ }
45
+ if (result.agentConfigured) {
46
+ this.log(`Opencode agent plugin installed: ${result.agentPluginFile}`);
47
+ this.log(`Opencode config updated: ${result.agentConfigFile}`);
48
+ }
49
+ else if (result.agentSkippedReason === 'opencode_dir_not_found') {
50
+ this.log('Opencode config directory not found. Skipped agent session integration.');
51
+ }
52
+ if (result.profileFiles.length > 0) {
53
+ for (const profileFile of result.profileFiles) {
54
+ this.log(`Profile updated: ${profileFile}`);
55
+ }
56
+ this.log('Open a new shell session or reload your profile to initialize NB_SESSION_ID automatically.');
57
+ }
58
+ if (result.manualStep) {
59
+ this.log(result.manualStep);
60
+ }
61
+ }
62
+ }
@@ -61,7 +61,7 @@ export async function resolveManagedAppRuntime(envName) {
61
61
  if (!env) {
62
62
  return undefined;
63
63
  }
64
- const resolvedName = env.name || envName?.trim() || config.currentEnv || 'default';
64
+ const resolvedName = env.name || envName?.trim() || config.lastEnv || 'default';
65
65
  const source = normalizeEnvSource(env);
66
66
  const dockerNetworkName = sanitizeDockerResourceName(getEffectiveCliConfigValue(config, 'docker.network') || defaultDockerNetworkName());
67
67
  const dockerContainerPrefix = sanitizeDockerResourceName(getEffectiveCliConfigValue(config, 'docker.container-prefix') || defaultDockerContainerPrefix());