@nocobase/cli 2.1.0-alpha.30 → 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.
- package/README.md +14 -0
- package/README.zh-CN.md +14 -0
- package/dist/commands/app/down.js +47 -9
- package/dist/commands/app/logs.js +17 -0
- package/dist/commands/app/restart.js +23 -1
- package/dist/commands/app/start.js +17 -0
- package/dist/commands/app/stop.js +17 -0
- package/dist/commands/app/upgrade.js +17 -0
- package/dist/commands/env/add.js +2 -1
- package/dist/commands/env/current.js +21 -0
- package/dist/commands/env/list.js +8 -14
- package/dist/commands/env/remove.js +1 -1
- package/dist/commands/env/status.js +90 -0
- package/dist/commands/env/use.js +10 -0
- package/dist/commands/install.js +2 -1
- package/dist/commands/license/activate.js +18 -19
- package/dist/commands/license/id.js +18 -0
- package/dist/commands/license/plugins/clean.js +18 -0
- package/dist/commands/license/plugins/list.js +19 -1
- package/dist/commands/license/plugins/sync.js +18 -0
- package/dist/commands/license/status.js +18 -0
- package/dist/commands/plugin/disable.js +24 -3
- package/dist/commands/plugin/enable.js +24 -3
- package/dist/commands/plugin/list.js +24 -3
- package/dist/commands/session/id.js +24 -0
- package/dist/commands/session/remove.js +57 -0
- package/dist/commands/session/setup.js +62 -0
- package/dist/commands/source/test.js +11 -1
- package/dist/lib/app-runtime.js +1 -1
- package/dist/lib/auth-store.js +28 -11
- package/dist/lib/env-guard.js +61 -0
- package/dist/lib/generated-command.js +16 -0
- package/dist/lib/resource-command.js +15 -0
- package/dist/lib/runtime-generator.js +1 -1
- package/dist/lib/session-id.js +17 -0
- package/dist/lib/session-integration.js +719 -0
- package/dist/lib/session-store.js +118 -0
- 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: '
|
|
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,
|
|
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(
|
|
58
|
+
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
40
59
|
if (!runtime) {
|
|
41
|
-
this.error(formatMissingManagedAppEnvMessage(
|
|
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',
|
|
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(
|
|
58
|
+
const runtime = await resolveManagedAppRuntime(requestedEnv);
|
|
40
59
|
if (!runtime) {
|
|
41
|
-
this.error(formatMissingManagedAppEnvMessage(
|
|
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',
|
|
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
|
|
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(
|
|
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',
|
|
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
|
+
}
|
|
@@ -12,6 +12,7 @@ import fsp from 'node:fs/promises';
|
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import Install from '../install.js';
|
|
14
14
|
import { defaultWorkspaceName } from '../../lib/app-runtime.js';
|
|
15
|
+
import { resolveCliLocale } from '../../lib/cli-locale.js';
|
|
15
16
|
import { findAvailableTcpPort, validateAvailableTcpPort } from '../../lib/prompt-validators.js';
|
|
16
17
|
import { commandSucceeds, resolveProjectCwd, run, runNocoBaseCommand } from '../../lib/run-npm.js';
|
|
17
18
|
import { failTask, printInfo, setVerboseMode, startTask, succeedTask } from '../../lib/ui.js';
|
|
@@ -27,6 +28,12 @@ const DEFAULT_TEST_DB_IMAGES = {
|
|
|
27
28
|
mariadb: 'mariadb:11',
|
|
28
29
|
kingbase: 'registry.cn-shanghai.aliyuncs.com/nocobase/kingbase:v009r001c001b0030_single_x86',
|
|
29
30
|
};
|
|
31
|
+
const DEFAULT_TEST_DB_IMAGES_ZH_CN = {
|
|
32
|
+
postgres: 'registry.cn-shanghai.aliyuncs.com/nocobase/postgres:16',
|
|
33
|
+
mysql: 'registry.cn-shanghai.aliyuncs.com/nocobase/mysql:8',
|
|
34
|
+
mariadb: 'registry.cn-shanghai.aliyuncs.com/nocobase/mariadb:11',
|
|
35
|
+
kingbase: 'registry.cn-shanghai.aliyuncs.com/nocobase/kingbase:v009r001c001b0030_single_x86',
|
|
36
|
+
};
|
|
30
37
|
const DEFAULT_TEST_DB_DISTRIBUTOR_PORT = '23450';
|
|
31
38
|
const DEFAULT_TEST_DB_DISTRIBUTOR_PREFIX = {
|
|
32
39
|
postgres: 'test',
|
|
@@ -70,7 +77,10 @@ function defaultTestDbPort(dbDialect) {
|
|
|
70
77
|
return String(DEFAULT_DB_PORTS[dbDialect] ?? DEFAULT_DB_PORTS.postgres);
|
|
71
78
|
}
|
|
72
79
|
function defaultTestDbImage(dbDialect) {
|
|
73
|
-
|
|
80
|
+
const defaults = resolveCliLocale(process.env.NB_LOCALE) === 'zh-CN'
|
|
81
|
+
? DEFAULT_TEST_DB_IMAGES_ZH_CN
|
|
82
|
+
: DEFAULT_TEST_DB_IMAGES;
|
|
83
|
+
return defaults[dbDialect] ?? defaults.postgres;
|
|
74
84
|
}
|
|
75
85
|
function delay(ms) {
|
|
76
86
|
return new Promise((resolve) => {
|
package/dist/lib/app-runtime.js
CHANGED
|
@@ -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.
|
|
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());
|