@nocobase/cli 2.1.4-test.2 → 2.1.4-test.3

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.
@@ -0,0 +1,89 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ export function normalizeEarlyCliLocale(value) {
7
+ const normalized = String(value ?? '')
8
+ .trim()
9
+ .replace(/\..*$/, '')
10
+ .replace(/_/g, '-')
11
+ .toLowerCase();
12
+
13
+ if (normalized === 'zh' || normalized.startsWith('zh-')) {
14
+ return 'zh-CN';
15
+ }
16
+
17
+ if (normalized === 'en' || normalized.startsWith('en-')) {
18
+ return 'en-US';
19
+ }
20
+
21
+ return undefined;
22
+ }
23
+
24
+ function readConfiguredEarlyCliLocale() {
25
+ try {
26
+ const cliHomeRoot = String(process.env.NB_CLI_ROOT ?? '').trim() || os.homedir();
27
+ const configPath = path.join(cliHomeRoot, '.nocobase', 'config.json');
28
+ const content = fs.readFileSync(configPath, 'utf8');
29
+ const parsed = JSON.parse(content);
30
+ return normalizeEarlyCliLocale(parsed?.settings?.locale);
31
+ } catch {
32
+ return undefined;
33
+ }
34
+ }
35
+
36
+ export function detectEarlyCliLocale() {
37
+ const candidates = [
38
+ process.env.NB_LOCALE,
39
+ readConfiguredEarlyCliLocale(),
40
+ process.env.LC_ALL,
41
+ process.env.LC_MESSAGES,
42
+ process.env.LANG,
43
+ Intl.DateTimeFormat().resolvedOptions().locale,
44
+ ];
45
+
46
+ for (const candidate of candidates) {
47
+ const locale = normalizeEarlyCliLocale(candidate);
48
+ if (locale) {
49
+ return locale;
50
+ }
51
+ }
52
+
53
+ return 'en-US';
54
+ }
55
+
56
+ function getEarlyLocalePathValue(input, key) {
57
+ let current = input;
58
+ for (const part of key.split('.')) {
59
+ if (!current || typeof current !== 'object' || !Object.prototype.hasOwnProperty.call(current, part)) {
60
+ return undefined;
61
+ }
62
+ current = current[part];
63
+ }
64
+ return typeof current === 'string' ? current : undefined;
65
+ }
66
+
67
+ function readEarlyLocaleMessages(locale) {
68
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
69
+ const packageRoot = path.resolve(moduleDir, '..');
70
+ const localePaths = [
71
+ path.join(packageRoot, 'src', 'locale', `${locale}.json`),
72
+ path.join(packageRoot, 'dist', 'locale', `${locale}.json`),
73
+ ];
74
+
75
+ for (const localePath of localePaths) {
76
+ try {
77
+ return JSON.parse(fs.readFileSync(localePath, 'utf8'));
78
+ } catch {
79
+ // Try the next runtime layout.
80
+ }
81
+ }
82
+
83
+ return undefined;
84
+ }
85
+
86
+ export function translateEarlyCli(key, fallback, locale = detectEarlyCliLocale()) {
87
+ const messages = readEarlyLocaleMessages(locale);
88
+ return getEarlyLocalePathValue(messages, key) ?? fallback;
89
+ }
package/bin/run.js CHANGED
@@ -8,6 +8,7 @@ import pc from 'picocolors';
8
8
  import { fileURLToPath, pathToFileURL } from 'node:url';
9
9
  import { formatUnsupportedNodeVersionMessage, isSupportedNodeVersion } from './node-version.js';
10
10
  import { normalizeNodeOptions, normalizeSessionEnv } from './session-env.js';
11
+ import { ensureWindowsAdministrator } from './windows-admin.js';
11
12
 
12
13
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
14
  const requireFromCli = createRequire(import.meta.url);
@@ -27,54 +28,6 @@ if (!isSupportedNodeVersion()) {
27
28
  normalizeSessionEnv();
28
29
  normalizeNodeOptions();
29
30
 
30
- const windowsAdministratorCheckScript = [
31
- '$identity = [Security.Principal.WindowsIdentity]::GetCurrent();',
32
- '$principal = New-Object Security.Principal.WindowsPrincipal($identity);',
33
- 'if ($principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { exit 0 }',
34
- 'exit 1',
35
- ].join(' ');
36
-
37
- function isWindowsAdministrator() {
38
- for (const command of ['pwsh.exe', 'powershell.exe']) {
39
- const result = spawnSync(
40
- command,
41
- ['-NoLogo', '-NoProfile', '-NonInteractive', '-Command', windowsAdministratorCheckScript],
42
- {
43
- stdio: 'ignore',
44
- windowsHide: true,
45
- },
46
- );
47
-
48
- if (result.error?.code === 'ENOENT') {
49
- continue;
50
- }
51
-
52
- return result.status === 0;
53
- }
54
-
55
- return false;
56
- }
57
-
58
- function ensureWindowsAdministrator() {
59
- if (process.platform !== 'win32' || process.env.NB_CLI_WINDOWS_ADMIN_CHECKED === '1') {
60
- return;
61
- }
62
-
63
- if (!isWindowsAdministrator()) {
64
- console.error(
65
- pc.red(
66
- [
67
- 'NocoBase CLI must be run as Administrator on Windows.',
68
- 'Open PowerShell 5 or PowerShell 7 with "Run as administrator", then run the command again.',
69
- ].join('\n'),
70
- ),
71
- );
72
- process.exit(1);
73
- }
74
-
75
- process.env.NB_CLI_WINDOWS_ADMIN_CHECKED = '1';
76
- }
77
-
78
31
  ensureWindowsAdministrator();
79
32
 
80
33
  /**
@@ -0,0 +1,60 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import pc from 'picocolors';
3
+ import { detectEarlyCliLocale, translateEarlyCli } from './early-locale.js';
4
+
5
+ const windowsAdministratorCheckScript = [
6
+ '$identity = [Security.Principal.WindowsIdentity]::GetCurrent();',
7
+ '$principal = New-Object Security.Principal.WindowsPrincipal($identity);',
8
+ 'if ($principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { exit 0 }',
9
+ 'exit 1',
10
+ ].join(' ');
11
+
12
+ export function formatWindowsAdministratorRequiredMessage() {
13
+ const locale = detectEarlyCliLocale();
14
+ const message = translateEarlyCli(
15
+ 'entry.windowsAdministratorRequired.message',
16
+ 'NocoBase CLI must be run as Administrator on Windows.',
17
+ locale,
18
+ );
19
+ const hint = translateEarlyCli(
20
+ 'entry.windowsAdministratorRequired.hint',
21
+ 'Open your terminal as Administrator, then run the command again.',
22
+ locale,
23
+ );
24
+
25
+ return [message, hint].join('\n');
26
+ }
27
+
28
+ function isWindowsAdministrator() {
29
+ for (const command of ['pwsh.exe', 'powershell.exe']) {
30
+ const result = spawnSync(
31
+ command,
32
+ ['-NoLogo', '-NoProfile', '-NonInteractive', '-Command', windowsAdministratorCheckScript],
33
+ {
34
+ stdio: 'ignore',
35
+ windowsHide: true,
36
+ },
37
+ );
38
+
39
+ if (result.error?.code === 'ENOENT') {
40
+ continue;
41
+ }
42
+
43
+ return result.status === 0;
44
+ }
45
+
46
+ return false;
47
+ }
48
+
49
+ export function ensureWindowsAdministrator() {
50
+ if (process.platform !== 'win32' || process.env.NB_CLI_WINDOWS_ADMIN_CHECKED === '1') {
51
+ return;
52
+ }
53
+
54
+ if (!isWindowsAdministrator()) {
55
+ console.error(pc.red(formatWindowsAdministratorRequiredMessage()));
56
+ process.exit(1);
57
+ }
58
+
59
+ process.env.NB_CLI_WINDOWS_ADMIN_CHECKED = '1';
60
+ }
@@ -1,4 +1,10 @@
1
1
  {
2
+ "entry": {
3
+ "windowsAdministratorRequired": {
4
+ "message": "NocoBase CLI must be run as Administrator on Windows.",
5
+ "hint": "Open your terminal as Administrator, then run the command again."
6
+ }
7
+ },
2
8
  "promptCatalog": {
3
9
  "common": {
4
10
  "cancelled": "Cancelled.",
@@ -1,4 +1,10 @@
1
1
  {
2
+ "entry": {
3
+ "windowsAdministratorRequired": {
4
+ "message": "Windows 上运行 NocoBase CLI 必须使用管理员模式。",
5
+ "hint": "请以管理员身份打开终端,然后重新执行命令。"
6
+ }
7
+ },
2
8
  "promptCatalog": {
3
9
  "common": {
4
10
  "cancelled": "已取消。",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/cli",
3
- "version": "2.1.4-test.2",
3
+ "version": "2.1.4-test.3",
4
4
  "description": "NocoBase Command Line Tool",
5
5
  "type": "module",
6
6
  "main": "dist/generated/command-registry.js",