@flun/nodejs-mobile-gyp 1.1.4 → 1.2.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # 变更日志
2
2
 
3
+ ## [1.2.0] - 2026-11-02 16:05
4
+ ### 新增
5
+ - 帮助文本重写为中文三层结构:`用法:` 为 0 级,`命令:`/`选项:` 缩进 2,各条目缩进 4;
6
+ 命令含别名 `ls`/`rm`,选项简写在前、完整写法置于行尾注释;末尾仅输出版本号行;
7
+ - 无参数、`help`、`-h`、`--help` 均打印完整帮助并以 exit 0 退出;
8
+ - 帮助文本按语义着色:`用法:` 用 `chalk.blueBright`,分组名用 `chalk.cyan`,命令与选项名用 `chalk.cyanBright`,
9
+ 说明文字用 `chalk.gray`,末尾版本号用 `chalk.hex('#B8860B')`;非 TTY 下自动关闭颜色,不向管道泄漏 ANSI;
10
+ - 未知命令提示着色:错误标记用 `chalk.red`,命令名用 `chalk.yellow`;
11
+
12
+ ### 修复
13
+ - 未知命令改为输出 `✗ 未知命令: xxx` + 一个空行 + 完整帮助,并以 exit 1 退出;
14
+ 此前未知参数不报错,静默继续;
15
+ - `-h` 此前被忽略,现作为帮助入口;该行为变更可能影响依赖旧行为的脚本;
16
+ - 帮助文本命令区与选项区说明列错位:命令区原补到显示列 17,选项区 23,现统一补到 23;
17
+ 补白改为按显示宽度计算,中日韩全角字符按 2 列计,此前按码元计导致含中文的选项名整体左移;
18
+ - `package.json` 的 `dependencies` 补声明 `chalk`;`lib/node-gyp.js` 已引用该模块,
19
+ 此前未声明,从 npm 安装后缺少依赖会导致 `--help` 直接报错;
20
+
21
+ ### 文档
22
+ - `lib/` 下 12 个 js 去除 BOM;`维护.md`、`package.json`、`lib/util.js` 换行符由 CRLF 改为 LF;
23
+
3
24
  ## [1.1.4] - 2026-10-24 09:20
4
25
  ### 优化
5
26
  - 项目标点已改为以英文标点为主;
@@ -7,10 +28,4 @@
7
28
 
8
29
  ## [1.1.3] - 2026-10-20 13:55
9
30
  ### 修复
10
- - 一些细节优化
11
-
12
- ## [1.1.2] - 2026-09-28 21:49
13
- ### 修复
14
-
15
- - **action 目标的路径分隔符**:`make.py` 中 `self.output` 由 `ComputeOutput` 产出,Windows 上带反斜杠(如
16
- `$(obj).target\../node-addon-api\foo.stamp`),导致 `sh` 把 `\.` 当转义、目录不存在;现统一转正斜杠;非 Windows 平台为 no-op;
31
+ - 一些细节优化
package/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # @flun/nodejs-mobile-gyp
2
2
 
3
+ ## 简介
4
+
3
5
  移动端 Node.js 原生模块(Native Addon)的交叉编译工具;
4
6
 
5
7
  用于为 nodejs-mobile 环境编译 C/C++ 原生模块,支持 Android 与 iOS 的交叉编译;
6
8
  适用于官方 [nodejs-mobile](https://github.com/nodejs-mobile/nodejs-mobile) 及兼容的社区发行版
7
9
  (如 [OpenFlun/nodejs-mobile](https://github.com/OpenFlun/nodejs-mobile));
8
10
 
9
- 宿主平台支持 **Windows** / **macOS** / **Linux**,各平台所需的环境与工具见"[支持的系统与配置要求](#支持的系统与配置要求)";
11
+ 宿主平台支持 **Windows** / **macOS** / **Linux**,各平台所需的环境与工具见 [安装前准备](#安装前准备);
10
12
 
11
13
  [`@flun/nodejs-mobile-react-native`](https://www.npmjs.com/package/@flun/nodejs-mobile-react-native)
12
14
  在构建时会自动调用本包,无需手动安装;
@@ -18,7 +20,39 @@
18
20
  - gitee: https://gitee.com/OpenFlun/nodejs-mobile-gyp
19
21
  - npm:https://www.npmjs.com/package/@flun/nodejs-mobile-gyp
20
22
 
21
- ## 项目结构
23
+ ### 与原版的差异
24
+
25
+ #### 代码风格
26
+
27
+ | 项 | 原版 | 本 fork |
28
+ | -------- | ----------------------- | --------------------------------------------- |
29
+ | 模块系统 | CommonJS | **ESM**(`package.json` 的 `type: "module"`) |
30
+ | 导出方式 | 文件内 `module.exports` | **末尾统一 `export { ... }`** |
31
+ | 函数声明 | `async function xxx` | `const xxx = async () =>`(`class` 保留) |
32
+ | 注释 | 英文 | 中文 |
33
+
34
+ #### 依赖升级
35
+
36
+ | 包 | 原版 | 本 fork | 原因 |
37
+ | ------------------- | ---------- | --------- | -------------------------------------------- |
38
+ | `tar` | `^6.1.2` | `^7.5.22` | 上游 v6 停更,有安全公告 |
39
+ | `glob` | `^10.3.10` | `^13.0.6` | 上游 v10 停更 |
40
+ | `make-fetch-happen` | `^13.0.0` | `^16.0.1` | 连带升级 `cacache`,去掉 `tar@6` / `glob@10` |
41
+
42
+ 升级后依赖树干净,`npm audit` 0 vulnerabilities;
43
+
44
+ ## 特性
45
+
46
+ - 为 nodejs-mobile 环境交叉编译 C/C++ 原生模块
47
+ - 支持 Android 与 iOS 目标,宿主可为 Windows / macOS / Linux
48
+ - 自动探测 Windows 下的 Python、Visual Studio、Git for Windows(MSYS2 POSIX 工具集)
49
+ - 跨平台路径处理统一转正斜杠,兼容 Windows 下的 gyp 生成器
50
+ - 依赖链升级至较新版本(make-fetch-happen、nopt、proc-log、which 等)
51
+ - 由 `@flun/nodejs-mobile-react-native` 自动调用,通常无需手动安装
52
+
53
+ ---
54
+
55
+ ## 包目录结构
22
56
 
23
57
  ```txt
24
58
  @flun/nodejs-mobile-gyp/
@@ -77,138 +111,15 @@
77
111
  └── macOS_Catalina_acid_test.sh # macOS Catalina 兼容性验证脚本(仅本地开发,不随包发布)
78
112
  ```
79
113
 
80
- ## 本 fork 的改动
81
-
82
- 本 fork 在功能上与原版 `nodejs-mobile-gyp` 一致,做了以下改造;
83
-
84
- ### 代码风格
85
-
86
- | 项 | 原版 | 本 fork |
87
- | -------- | ----------------------- | --------------------------------------------- |
88
- | 模块系统 | CommonJS | **ESM**(`package.json` 的 `type: "module"`) |
89
- | 导出方式 | 文件内 `module.exports` | **末尾统一 `export { ... }`** |
90
- | 函数声明 | `async function xxx` | `const xxx = async () =>`(`class` 保留) |
91
- | 注释 | 英文 | 中文 |
92
-
93
- ### 依赖升级
94
-
95
- | 包 | 原版 | 本 fork | 原因 |
96
- | ------------------- | ---------- | --------- | -------------------------------------------- |
97
- | `tar` | `^6.1.2` | `^7.5.22` | 上游 v6 停更,有安全公告 |
98
- | `glob` | `^10.3.10` | `^13.0.6` | 上游 v10 停更 |
99
- | `make-fetch-happen` | `^13.0.0` | `^16.0.1` | 连带升级 `cacache`,去掉 `tar@6` / `glob@10` |
100
-
101
- 升级后依赖树干净,`npm audit` 0 vulnerabilities;
102
-
103
- ### Windows 构建适配
104
-
105
- 原版 `nodejs-mobile-gyp` 在 Windows 上有若干问题,本 fork 逐一解决,涉及三方面;
106
-
107
- #### 1. 工具集与 LTO
108
-
109
- 原版默认走 ClangCL 工具集,且继承 Node 官方二进制的 LTO 配置;Node.js 24+ 官方二进制由 ClangCL + ThinLTO 编译,其
110
- `common.gypi` 会在 `clang==1` 时把 MSBuild 工具集设为 `ClangCL`,并在 `enable_lto==true` / `enable_thin_lto==true`
111
- 时向链接器传入 `-flto=thin`、`/opt:lldltojobs` 等 Clang 专用参数;若用户本机没装 ClangCL,或用的是传统 MSVC 工具链,会报:
112
-
113
- - `MSB8020: 无法找到 ClangCL 的生成工具`
114
- - `LNK1117: 选项"opt:lldltojobs=2"中的语法错误`
115
-
116
- 本 fork 强制走 MSVC 工具集并关闭 LTO,避免上述报错;工具集版本从 `find-visualstudio` 的探测结果**动态获取**(`v140` / `v141`
117
- / `v142` / `v143` / `v145`...),不写死;
118
-
119
- #### 2. GNU make 的 POSIX 环境
120
-
121
- Android 原生模块通过 GNU make 构建,其 Makefile 会调用 `printf`、`xargs`、`sed` 等 Unix 命令;GNU make 需要一个 POSIX
122
- shell(`sh.exe`)来执行它们;Windows 上若无,会直接报 `CreateProcess(NULL, printf ...) failed`;Git for Windows 自带整套 POSIX
123
- 工具集;本 fork 会自动定位其 `usr/bin` 并前置到 PATH,详见"[支持的系统与配置要求](#支持的系统与配置要求) → 自动探测";
124
-
125
- #### 3. 路径分隔符
126
-
127
- gyp 生成的 Makefile 中,路径原本会带上 Windows 的反斜杠(如 `src\bufferutil.o`),导致 `sh` / `sed` / `make` 解析失败;本 fork
128
- 在 gyp 的路径生成环节统一转成正斜杠;该改动在非 Windows 平台上是 no-op;
129
-
130
- ### 具体改动清单
131
-
132
- #### 构建工具链
133
-
134
- - `lib/create-config-gypi.js`
135
- - 改动:生成 `config.gypi` 时把 `clang` 置 0、`enable_lto` / `enable_thin_lto` 置 `'false'`、
136
- `lto_jobs` 置空,避免 `common.gypi` 切到 ClangCL 并向 MSVC 传 LTO 参数
137
- - `lib/configure.js`
138
- - 改动:调用 gyp 时追加 `-Gmsvs_toolset=<探测到的 toolset>`,不再写死 `v145`
139
- - `lib/find-visualstudio.js`
140
- - 改动:支持 VS2013+,含最新 VS2026(版本号 18,`versionYear=2026`,toolset `v145`)
141
- - `gyp/pylib/gyp/MSVSSettings.py`
142
- - 改动:注册 `ExternalWarningLevel`(MSBuild 属性),供 `addon.gypi` 使用
143
- - `addon.gypi`
144
- - 改动:Windows 下追加 `/external:anglebrackets` +
145
- `ExternalWarningLevel: TurnOffAllWarnings`,只静音外部头(Node / V8)的警告
146
-
147
- #### 跨平台路径
148
-
149
- | 文件 | 改动
150
- |
151
- | --------------------------------- |
152
- ----------------------------------------------------------------------------------------------------------- |
153
- | `gyp/pylib/gyp/common.py` | `RelativePath` 返回值统一转正斜杠
154
- |
155
- | `gyp/pylib/gyp/generator/make.py` | `Absolutify` 返回正斜杠;新增 `slashpath` 供 `mkdir` 使用;Windows 下跳过
156
- `node_modules` 中的超长 gypi 依赖 |
157
-
158
- #### Windows 运行时探测
159
-
160
- | 文件 | 改动
161
- |
162
- | -------------------- |
163
- -------------------------------------------------------------------------------------------------------------- |
164
- | `lib/find-python.js` | 重写:移除硬编码版本列表,改为 `py.exe` 候选 + `py -0p` 枚举 + 目录扫描;`run()` 显式检查 `execFile`
165
- 的 err |
166
- | `lib/build.js` | 区分"宿主 Windows"与"Android 交叉编译";自动探测 `sh.exe` 并前置到 PATH;为 Python 创建
167
- `python3.cmd` shim |
168
-
169
- #### 兼容性与健壮性
170
-
171
- - **`proc-log` 新版本兼容**:新版把日志级别函数与 `pause` / `resume` 挂在默认导出的 `log` 对象下;本 fork 已按此调整
172
- `lib/log.js`,否则 `configure` 阶段会抛 `TypeError`;
173
- - **弃用 API 清理**:`lib/process-release.js` 不再用 `url.resolve()` / `url.parse()`,改用 WHATWG `URL`,消除 `DEP0169` 警告;
174
- - **依赖脚本放行**:`package.json` 显式声明 `allowScripts`,适配新版 npm 默认禁止依赖执行安装脚本的行为;
175
-
176
-
177
- ### 迁移踩过的坑
178
-
179
- 1. **`graceful-fs` 是 CJS,命名导入会失败**
180
- 写成 `import gracefulFs from 'graceful-fs'`,再从 default 解构 `const { openSync, closeSync } = gracefulFs`;
181
-
182
- 2. **`tar@7` 没有 default export**
183
- 写成 `import * as tar from 'tar'`;
184
-
185
- 3. **`proc-log` 的解构**
186
- `import procLog from 'proc-log'`,再把需要的函数从 default 里解构后统一导出;
187
-
188
- 4. **PowerShell 写文件会加 BOM**
189
- `Set-Content -Encoding UTF8` 会写入 `\uFEFF`,导致 gyp 的 `eval()` 报
190
- `SyntaxError: invalid non-printable character U+FEFF`;写 `binding.gyp` 等交给 Python eval 的文件时,用
191
- `[System.IO.File]::WriteAllText` + `New-Object System.Text.UTF8Encoding $false`;
192
-
193
- 5. **ESM 不支持动态 `require('./' + command)`**
194
- `lib/node-gyp.js` 原本用 `require('./' + command)` 动态加载命令模块,ESM 下改为在顶部静态 import 所有命令,
195
- 再用静态映射表组装 `this.commands`;
196
-
197
- 6. **`__dirname` / `__filename` 在 ESM 中不存在**
198
- 用 `fileURLToPath(import.meta.url)` 重建;
199
-
200
- 7. **非 Windows 平台不引入 `find-visualstudio.js`**
201
- 该模块依赖 Windows 专属的 `path.win32` 和注册表操作,保持原版的"仅在 Windows 上条件加载"逻辑;
202
-
203
- ## 支持的系统与配置要求
114
+ ## 安装前准备
204
115
 
205
116
  本包面向 **Android / iOS 交叉编译**,宿主平台支持情况:
206
117
 
207
118
  | 宿主平台 | 目标:Android | 目标:iOS |
208
119
  | -------- | ------------- | ---------- |
209
- | Windows | ✅ 完整支持 | ❌ 需 macOS |
210
- | macOS | ✅ 完整支持 | ✅ 完整支持 |
211
- | Linux | ✅ 完整支持 | ❌ 需 macOS |
120
+ | Windows | 完整支持 | 需 macOS |
121
+ | macOS | 完整支持 | 完整支持 |
122
+ | Linux | 完整支持 | 需 macOS |
212
123
 
213
124
  各平台所需的构建环境如下;
214
125
 
@@ -222,16 +133,14 @@ gyp 生成的 Makefile 中,路径原本会带上 Windows 的反斜杠(如 `src\b
222
133
 
223
134
  ### Windows
224
135
 
225
- | 组件 | 要求 | 说明 |
226
- | --------------- | --------------------------------------- | ----------------------------------------------------------- |
227
- | Node.js | 见 `engines.node` | |
228
- | Python | 3.6+ | 支持任意安装位置,见下方"自动探测" |
229
- | Visual Studio | **VS2019 / VS2022 / VS2026**(2026 已验证) | 需勾选"使用 C++ 的桌面开发"工作负载,含 Windows SDK;VS2017
230
- 及更早受 Node 版本上限限制 |
231
- | Android NDK | **23–27**(已验证) | 由 `@flun/nodejs-mobile-react-native` 自动定位
232
- |
233
- | Git for Windows | 任意近期版本 | 自带**整套 MSYS2 POSIX 工具集**(`sh.exe`、`printf`、`xargs`、
234
- `sed`、`rm`、`mkdir` 等数十个命令),GNU make 执行 Makefile 所依赖的 Unix 命令均由它提供;位置自动探测(见下方) |
136
+ - `Node.js`:见 `engines.node`
137
+ - `Python`:3.6+,支持任意安装位置,见下方"自动探测"
138
+ - `Visual Studio`:**VS2019 / VS2022 / VS2026**(2026 已验证);需勾选"使用 C++ 的桌面开发"工作负载,
139
+ 含 Windows SDK;VS2017 及更早受 Node 版本上限限制
140
+ - `Android NDK`:**23–27**(已验证);由 `@flun/nodejs-mobile-react-native` 自动定位
141
+ - `Git for Windows`:任意近期版本;自带**整套 MSYS2 POSIX 工具集**
142
+ (`sh.exe`、`printf`、`xargs`、`sed`、`rm`、`mkdir` 等数十个命令),
143
+ GNU make 执行 Makefile 所依赖的 Unix 命令均由它提供;位置自动探测(见下方)
235
144
 
236
145
  > **为什么需要 Git for Windows?** Android 原生模块通过 GNU make 构建,Makefile 中会调用 `printf`、`xargs`、`sed` 等 Unix
237
146
  命令;这些命令并非 Windows 自带,GNU make 需要一个 POSIX 环境来执行它们;Git for Windows
@@ -289,16 +198,28 @@ gyp 生成的 Makefile 中,路径原本会带上 Windows 的反斜杠(如 `src\b
289
198
  npm i @flun/nodejs-mobile-gyp
290
199
  ```
291
200
 
292
- 通常你不需要手动安装本包--它由 [`@flun/nodejs-mobile-react-native`](https://www.npmjs.
293
- com/package/@flun/nodejs-mobile-react-native) 在编译原生模块时自动调用;
201
+ 通常你不需要手动安装本包--它由 [`@flun/nodejs-mobile-react-native`][rn-pkg] 在编译原生模块时自动调用;
202
+
203
+ [rn-pkg]: https://www.npmjs.com/package/@flun/nodejs-mobile-react-native
294
204
 
295
205
  > **Node 版本要求**:本 fork 的依赖链(`make-fetch-happen`、`nopt`、`proc-log`、`which` 等)已升级到较新版本,要求比原版
296
206
  `nodejs-mobile-gyp` 更高的 Node;具体最低版本见 `package.json` 的 `engines.node` 字段;若你的项目仍在使用较旧的 Node,
297
207
  请改用原版 `nodejs-mobile-gyp`;
298
208
 
299
- ## 使用
209
+ ## 命令行
210
+
211
+ ### 快速开始
212
+
213
+ 在需要编译原生模块的项目目录下执行:
214
+
215
+ ```bash
216
+ npx @flun/nodejs-mobile-gyp rebuild --target=v18.20.4 --arch=arm64
217
+ ```
218
+
219
+ `rebuild` 依次执行 `clean` → `configure` → `build`;`--target` 指定目标 Node.js 版本,
220
+ `--arch` 指定目标架构;Android 与 iOS 的构建环境要求见 [安装前准备](#安装前准备);
300
221
 
301
- ### 命令行
222
+ ### 调用方式
302
223
 
303
224
  ```bash
304
225
  npx @flun/nodejs-mobile-gyp <command> [options]
@@ -314,84 +235,60 @@ npx @flun/nodejs-mobile-gyp <command> [options]
314
235
  }
315
236
  ```
316
237
 
317
- ### 从 Node.js 代码调用
318
-
319
- 本包主要作为 CLI 工具使用,推荐通过 spawn / execFile 调用其命令行入口;包本身也导出了 Gyp 类,但属于内部实现,
320
- 接口可能随版本变化,不建议直接在代码中依赖;
321
-
322
- ## 命令
323
-
324
- | 命令 | 说明 |
325
- | ----------- | ---------------------------------------- |
326
- | `help` | 显示帮助 |
327
- | `build` | 调用 `make` / `msbuild.exe` 编译原生模块 |
328
- | `clean` | 删除 `build` 目录(若存在) |
329
- | `configure` | 为当前平台生成工程构建文件 |
330
- | `rebuild` | 依次执行 `clean` → `configure` → `build` |
331
- | `install` | 为指定版本安装 Node.js 头文件 |
332
- | `list` | 列出已安装的 Node.js 头文件版本 |
333
- | `remove` | 删除指定版本的 Node.js 头文件 |
334
-
335
- ## 命令选项
336
-
337
- | 选项 | 说明
338
- |
339
- | --------------------------------- |
340
- -------------------------------------------------------------------------------------------- |
341
- | `-v`, `--version` | 打印本包版本号
342
- |
343
- | `-j n`, `--jobs n` | 并行运行 `make`;`max` 表示使用所有 CPU 核心
344
- |
345
- | `--target=v6.2.1` | 目标 Node.js 版本(默认 `process.version`)
346
- |
347
- | `--silly`, `--loglevel=silly` | 输出全部进度日志
348
- |
349
- | `--verbose`, `--loglevel=verbose` | 输出大部分进度日志
350
- |
351
- | `--silent`, `--loglevel=silent` | 不输出任何日志
352
- |
353
- | `debug`, `--debug` | 生成 Debug 构建(默认 Release)
354
- |
355
- | `--release`, `--no-debug` | 生成 Release 构建
356
- |
357
- | `-C $dir`, `--directory=$dir` | 在指定目录运行命令
358
- |
359
- | `--make=$make` | 覆盖 `make` 命令(如 `gmake`)
360
- |
361
- | `--thin=yes` | 启用 thin 静态库
362
- |
363
- | `--arch=$arch` | 目标架构(如 `ia32`)
364
- |
365
- | `--tarball=$path` | 从本地 tarball 获取头文件
366
- |
367
- | `--devdir=$path` | SDK 下载目录(默认为系统缓存目录)
368
- |
369
- | `--ensure` | 已存在的头文件不重装
370
- |
371
- | `--dist-url=$url` | 从自定义 URL 下载头文件 tarball
372
- |
373
- | `--proxy=$url` | 下载时使用 HTTP(S) 代理
374
- |
375
- | `--noproxy=$urls` | 下载时忽略代理的 URL 列表
376
- |
377
- | `--cafile=$cafile` | 覆盖默认 CA 链(用于下载 tarball)
378
- |
379
- | `--nodedir=$path` | 指定 Node 源码路径
380
- |
381
- | `--python=$path` | 指定 Python 二进制路径
382
- |
383
- | `--msvs_version=$version` | 指定 Visual Studio 版本或安装路径(仅 Windows;可填 `2022` / `2026` 或
384
- `C:\...\BuildTools`) |
385
- | `--solution=$solution` | 指定 Visual Studio Solution 版本(仅 Windows)
386
- |
387
- | `--force-process-config` | 强制用运行时的 `process.config` 生成 `config.gypi`
388
- |
389
-
390
- ## 配置
238
+ ### 命令
239
+
240
+ | 命令 | 说明 |
241
+ |---|---|
242
+ | `help` | 显示帮助 |
243
+ | `build` | 调用 `make` / `msbuild.exe` 编译原生模块 |
244
+ | `clean` | 删除 `build` 目录(若存在) |
245
+ | `configure` | 为当前平台生成工程构建文件 |
246
+ | `rebuild` | 依次执行 `clean` → `configure` → `build` |
247
+ | `install` | 为指定版本安装 Node.js 头文件 |
248
+ | `list` | 列出已安装的 Node.js 头文件版本 |
249
+ | `remove` | 删除指定版本的 Node.js 头文件 |
250
+
251
+ ### 参数
252
+
253
+ - `-v`, `--version`:打印本包版本号
254
+ - `-j n`, `--jobs n`:并行运行 `make`;`max` 表示使用所有 CPU 核心
255
+ - `--target=v6.2.1`:目标 Node.js 版本(默认 `process.version`)
256
+ - `--silly`, `--loglevel=silly`:输出全部进度日志
257
+ - `--verbose`, `--loglevel=verbose`:输出大部分进度日志
258
+ - `--silent`, `--loglevel=silent`:不输出任何日志
259
+ - `debug`, `--debug`:生成 Debug 构建(默认 Release)
260
+ - `--release`, `--no-debug`:生成 Release 构建
261
+ - `-C $dir`, `--directory=$dir`:在指定目录运行命令
262
+ - `--make=$make`:覆盖 `make` 命令(如 `gmake`)
263
+ - `--thin=yes`:启用 thin 静态库
264
+ - `--arch=$arch`:目标架构(如 `ia32`)
265
+ - `--tarball=$path`:从本地 tarball 获取头文件
266
+ - `--devdir=$path`:SDK 下载目录(默认为系统缓存目录)
267
+ - `--ensure`:已存在的头文件不重装
268
+ - `--dist-url=$url`:从自定义 URL 下载头文件 tarball
269
+ - `--proxy=$url`:下载时使用 HTTP(S) 代理
270
+ - `--noproxy=$urls`:下载时忽略代理的 URL 列表
271
+ - `--cafile=$cafile`:覆盖默认 CA 链(用于下载 tarball)
272
+ - `--nodedir=$path`:指定 Node 源码路径
273
+ - `--python=$path`:指定 Python 二进制路径
274
+ - `--msvs-version=$version`:指定 Visual Studio 版本或安装路径(仅 Windows;可填 `2022` / `2026` 或 `C:\...\BuildTools`)
275
+ - `--solution=$solution`:指定 Visual Studio Solution 版本(仅 Windows)
276
+ - `--force-process-config`:强制用运行时的 `process.config` 生成 `config.gypi`
277
+
278
+ ## 函数方式
279
+
280
+ 本包主要作为 CLI 工具使用,推荐通过 spawn / execFile 调用其命令行入口;
281
+ 包本身也导出了 Gyp 类,但属于内部实现,接口可能随版本变化,不建议直接在代码中依赖;
282
+
283
+ ---
284
+
285
+
286
+ ## 参考配置
391
287
 
392
288
  ### 环境变量
393
289
 
394
- 上表中的所有命令选项,都可以用 `npm_config_OPTION_NAME` 形式的**环境变量**来设置(选项名中的 `-` 替换为 `_`);
290
+ 上表中的命令选项(除 `-v`/`--version` 外),都可以用 `npm_config_OPTION_NAME` 形式的**环境变量**来设置;
291
+ 选项名中的 `-` 替换为 `_`;
395
292
 
396
293
  例如,把 `devdir` 设为 `/tmp/.gyp`:
397
294
 
@@ -415,14 +312,113 @@ npm config set [--global] devdir /tmp/.gyp
415
312
 
416
313
  **注意**:通过 `npm config` 设置的配置,只在本包 **由 npm 调用时**生效,直接运行 `nodejs-mobile-gyp` 不生效;
417
314
 
418
- ## 上游参考
315
+ ## 开发者参考
419
316
 
420
- 本包是 `node-gyp` 的 fork;上游完整文档(含更多高级用法、`binding.gyp` 语法、跨平台细节)请见:
317
+ ### Windows 构建适配
421
318
 
422
- - [nodejs/node-gyp README](https://github.com/nodejs/node-gyp#readme)
423
- - [gyp 用户文档](https://gyp.gsrc.io/docs/UserDocumentation.md)
424
- - [gyp 输入格式参考](https://gyp.gsrc.io/docs/InputFormatReference.md)
319
+ 原版 `nodejs-mobile-gyp` 在 Windows 上有若干问题,本 fork 逐一解决,涉及三方面;
425
320
 
426
- ## 许可
321
+ #### 1. 工具集与 LTO
427
322
 
428
- ISC
323
+ 原版默认走 ClangCL 工具集,且继承 Node 官方二进制的 LTO 配置;Node.js 24+ 官方二进制由 ClangCL + ThinLTO 编译,其
324
+ `common.gypi` 会在 `clang==1` 时把 MSBuild 工具集设为 `ClangCL`,并在 `enable_lto==true` / `enable_thin_lto==true`
325
+ 时向链接器传入 `-flto=thin`、`/opt:lldltojobs` 等 Clang 专用参数;若用户本机没装 ClangCL,或用的是传统 MSVC 工具链,会报:
326
+
327
+ - `MSB8020: 无法找到 ClangCL 的生成工具`
328
+ - `LNK1117: 选项"opt:lldltojobs=2"中的语法错误`
329
+
330
+ 本 fork 强制走 MSVC 工具集并关闭 LTO,避免上述报错;工具集版本从 `find-visualstudio` 的探测结果**动态获取**(`v140` / `v141`
331
+ / `v142` / `v143` / `v145`...),不写死;
332
+
333
+ #### 2. GNU make 的 POSIX 环境
334
+
335
+ Android 原生模块通过 GNU make 构建,其 Makefile 会调用 `printf`、`xargs`、`sed` 等 Unix 命令;GNU make 需要一个 POSIX
336
+ shell(`sh.exe`)来执行它们;Windows 上若无,会直接报 `CreateProcess(NULL, printf ...) failed`;Git for Windows 自带整套 POSIX
337
+ 工具集;本 fork 会自动定位其 `usr/bin` 并前置到 PATH,详见 [安装前准备](#安装前准备) 的"自动探测(Windows)";
338
+
339
+ #### 3. 路径分隔符
340
+
341
+ gyp 生成的 Makefile 中,路径原本会带上 Windows 的反斜杠(如 `src\bufferutil.o`),导致 `sh` / `sed` / `make` 解析失败;本 fork
342
+ 在 gyp 的路径生成环节统一转成正斜杠;该改动在非 Windows 平台上是 no-op;
343
+
344
+ ### 具体改动清单
345
+
346
+ #### 构建工具链
347
+
348
+ - `lib/create-config-gypi.js`
349
+ - 改动:生成 `config.gypi` 时把 `clang` 置 0、`enable_lto` / `enable_thin_lto` 置 `'false'`、
350
+ `lto_jobs` 置空,避免 `common.gypi` 切到 ClangCL 并向 MSVC 传 LTO 参数
351
+ - `lib/configure.js`
352
+ - 改动:调用 gyp 时追加 `-Gmsvs_toolset=<探测到的 toolset>`,不再写死 `v145`
353
+ - `lib/find-visualstudio.js`
354
+ - 改动:支持 VS2013+,含最新 VS2026(版本号 18,`versionYear=2026`,toolset `v145`)
355
+ - `gyp/pylib/gyp/MSVSSettings.py`
356
+ - 改动:注册 `ExternalWarningLevel`(MSBuild 属性),供 `addon.gypi` 使用
357
+ - `addon.gypi`
358
+ - 改动:Windows 下追加 `/external:anglebrackets` +
359
+ `ExternalWarningLevel: TurnOffAllWarnings`,只静音外部头(Node / V8)的警告
360
+
361
+ #### 跨平台路径
362
+
363
+ - `gyp/pylib/gyp/common.py`:`RelativePath` 返回值统一转正斜杠
364
+ - `gyp/pylib/gyp/generator/make.py`:`Absolutify` 返回正斜杠;新增 `slashpath` 供 `mkdir` 使用;
365
+ Windows 下跳过 `node_modules` 中的超长 gypi 依赖
366
+
367
+ #### Windows 运行时探测
368
+
369
+ - `lib/find-python.js`:重写:移除硬编码版本列表,改为 `py.exe` 候选 + `py -0p` 枚举 + 目录扫描;
370
+ `run()` 显式检查 `execFile` 的 err
371
+ - `lib/build.js`:区分"宿主 Windows"与"Android 交叉编译";自动探测 `sh.exe` 并前置到 PATH;
372
+ 为 Python 创建 `python3.cmd` shim
373
+
374
+ #### 兼容性与健壮性
375
+
376
+ - **`proc-log` 新版本兼容**:新版把日志级别函数与 `pause` / `resume` 挂在默认导出的 `log` 对象下;本 fork 已按此调整
377
+ `lib/log.js`,否则 `configure` 阶段会抛 `TypeError`;
378
+ - **弃用 API 清理**:`lib/process-release.js` 不再用 `url.resolve()` / `url.parse()`,改用 WHATWG `URL`,消除 `DEP0169` 警告;
379
+ - **依赖脚本放行**:`package.json` 显式声明 `allowScripts`,适配新版 npm 默认禁止依赖执行安装脚本的行为;
380
+
381
+ ## 常见问题
382
+
383
+ 1. **`graceful-fs` 是 CJS,命名导入会失败**
384
+ 写成 `import gracefulFs from 'graceful-fs'`,再从 default 解构 `const { openSync, closeSync } = gracefulFs`;
385
+
386
+ 2. **`tar@7` 没有 default export**
387
+ 写成 `import * as tar from 'tar'`;
388
+
389
+ 3. **`proc-log` 的解构**
390
+ `import procLog from 'proc-log'`,再把需要的函数从 default 里解构后统一导出;
391
+
392
+ 4. **PowerShell 写文件会加 BOM**
393
+ `Set-Content -Encoding UTF8` 会写入 `\uFEFF`,导致 gyp 的 `eval()` 报
394
+ `SyntaxError: invalid non-printable character U+FEFF`;写 `binding.gyp` 等交给 Python eval 的文件时,用
395
+ `[System.IO.File]::WriteAllText` + `New-Object System.Text.UTF8Encoding $false`;
396
+
397
+ 5. **ESM 不支持动态 `require('./' + command)`**
398
+ `lib/node-gyp.js` 原本用 `require('./' + command)` 动态加载命令模块,ESM 下改为在顶部静态 import 所有命令,
399
+ 再用静态映射表组装 `this.commands`;
400
+
401
+ 6. **`__dirname` / `__filename` 在 ESM 中不存在**
402
+ 用 `fileURLToPath(import.meta.url)` 重建;
403
+
404
+ 7. **非 Windows 平台不引入 `find-visualstudio.js`**
405
+ 该模块依赖 Windows 专属的 `path.win32` 和注册表操作,保持原版的"仅在 Windows 上条件加载"逻辑;
406
+
407
+ ## 许可证
408
+
409
+ ISC
410
+
411
+ ---
412
+
413
+ ## 贡献
414
+
415
+ - 源码:[GitHub](https://github.com/OpenFlun/nodejs-mobile-gyp)
416
+ - 镜像:[gitee](https://gitee.com/OpenFlun/nodejs-mobile-gyp)
417
+ - 问题反馈:[Issues](https://github.com/OpenFlun/nodejs-mobile-gyp/issues)
418
+ - 上游:`nodejs-mobile-gyp` 与 `node-gyp`
419
+
420
+ 上游文档:
421
+
422
+ - [nodejs/node-gyp README](https://github.com/nodejs/node-gyp#readme)
423
+ - [gyp 用户文档](https://gyp.gsrc.io/docs/UserDocumentation.md)
424
+ - [gyp 输入格式参考](https://gyp.gsrc.io/docs/InputFormatReference.md)
package/bin/node-gyp.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import envPaths from 'env-paths';
4
4
  import os from 'os';
5
5
  import fs from 'fs';
6
+ import chalk from 'chalk';
6
7
  import { Gyp } from '../lib/node-gyp.js';
7
8
  import * as log from '../lib/log.js';
8
9
 
@@ -26,8 +27,15 @@ else {
26
27
  }
27
28
 
28
29
  if (prog.todo.length === 0) {
30
+ const helpArgs = ['help', '-h', '--help'],
31
+ hasHelp = process.argv.some(a => helpArgs.includes(a)),
32
+ unknown = prog.argv.filter(a => !helpArgs.includes(a));
29
33
  if (~process.argv.indexOf('-v') || ~process.argv.indexOf('--version')) log.stdout('v%s', prog.version);
30
- else log.stdout('%s', prog.usage());
34
+ else if (hasHelp || unknown.length === 0) log.stdout('%s', prog.usage());
35
+ else {
36
+ console.error(`${chalk.red('✗ 未知命令: ')}${chalk.yellow(unknown[0])}`), console.error(''), console.log(prog.usage());
37
+ process.exit(1);
38
+ }
31
39
  process.exit(0);
32
40
  }
33
41
 
package/lib/build.js CHANGED
@@ -1,4 +1,4 @@
1
- import gracefulFs from 'graceful-fs';
1
+ import gracefulFs from 'graceful-fs';
2
2
  import path from 'path';
3
3
  import { glob } from 'glob';
4
4
  import * as log from './log.js';
package/lib/clean.js CHANGED
@@ -1,4 +1,4 @@
1
- import gracefulFs from 'graceful-fs';
1
+ import gracefulFs from 'graceful-fs';
2
2
  import * as log from './log.js';
3
3
 
4
4
  const fs = gracefulFs.promises,
package/lib/configure.js CHANGED
@@ -1,4 +1,4 @@
1
- import gracefulFs from 'graceful-fs';
1
+ import gracefulFs from 'graceful-fs';
2
2
  import path from 'path';
3
3
  import * as log from './log.js';
4
4
  import os from 'os';
@@ -1,4 +1,4 @@
1
- import gracefulFs from 'graceful-fs';
1
+ import gracefulFs from 'graceful-fs';
2
2
  import * as log from './log.js';
3
3
  import path from 'path';
4
4
 
package/lib/download.js CHANGED
@@ -1,4 +1,4 @@
1
- import fetch from 'make-fetch-happen';
1
+ import fetch from 'make-fetch-happen';
2
2
  import gracefulFs from 'graceful-fs';
3
3
  import * as log from './log.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import path from 'path';
1
+ import path from 'path';
2
2
  import { fileURLToPath } from 'url';
3
3
  import * as log from './log.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import * as log from './log.js';
1
+ import * as log from './log.js';
2
2
  import { existsSync } from 'fs';
3
3
  import nodePath from 'path';
4
4
  import { fileURLToPath } from 'url';
package/lib/install.js CHANGED
@@ -1,4 +1,4 @@
1
- import gracefulFs from 'graceful-fs';
1
+ import gracefulFs from 'graceful-fs';
2
2
  import os from 'os';
3
3
  import { backOff } from 'exponential-backoff';
4
4
  import * as tar from 'tar';
package/lib/list.js CHANGED
@@ -1,4 +1,4 @@
1
- import gracefulFs from 'graceful-fs';
1
+ import gracefulFs from 'graceful-fs';
2
2
  import * as log from './log.js';
3
3
 
4
4
  const fs = gracefulFs.promises,
package/lib/node-gyp.js CHANGED
@@ -1,5 +1,6 @@
1
- import path from 'path';
1
+ import path from 'path';
2
2
  import nopt from 'nopt';
3
+ import chalk from 'chalk';
3
4
  import * as log from './log.js';
4
5
  import childProcess from 'child_process';
5
6
  import { EventEmitter } from 'events';
@@ -50,6 +51,7 @@ class Gyp extends EventEmitter {
50
51
  tarball: String, // 'install'
51
52
  jobs: String, // 'build'
52
53
  thin: String, // 'configure'
54
+ target: String, // 'rebuild'、'remove'、'install' 等处
53
55
  'force-process-config': Boolean // 'configure'
54
56
  }
55
57
 
@@ -143,10 +145,34 @@ class Gyp extends EventEmitter {
143
145
  * 返回 node-gyp 的用法说明
144
146
  */
145
147
  usage() {
148
+ const gold = chalk.hex('#B8860B'),
149
+ wide = cp => (cp >= 0x1100 && cp <= 0x115F) || (cp >= 0x2E80 && cp <= 0xA4CF) ||
150
+ (cp >= 0xAC00 && cp <= 0xD7A3) || (cp >= 0xF900 && cp <= 0xFAFF) ||
151
+ (cp >= 0xFE30 && cp <= 0xFE4F) || (cp >= 0xFF00 && cp <= 0xFF60) || (cp >= 0xFFE0 && cp <= 0xFFE6),
152
+ width = s => [...s].reduce((n, ch) => n + (wide(ch.codePointAt(0)) ? 2 : 1), 0),
153
+ pad = (s, n) => s + ' '.repeat(Math.max(0, n - width(s))),
154
+ cmd = (name, desc) => ` ${chalk.cyanBright(pad(name, 19))}${chalk.gray(desc)}`,
155
+ opt = (flag, desc) => ` ${chalk.cyanBright(pad(flag, 19))}${chalk.gray(desc)}`;
146
156
  return [
147
- '', ' Usage: node-gyp <command> [options]', '', ' where <command> is one of:',
148
- commands.map((c) => ' - ' + c + ' - ' + commandModules[c].usage).join('\n'), '',
149
- 'node-gyp@' + this.version + ' ' + path.resolve(__dirname, '..'), 'node@' + process.versions.node
157
+ `${chalk.blueBright('用法:')} nodejs-mobile-gyp <命令> [选项]`, '',
158
+ ` ${chalk.cyan('命令:')}`,
159
+ cmd('build', '构建模块(Windows 调 msbuild,其它平台调 make)'),
160
+ cmd('clean', '清理生成文件与 out 目录'),
161
+ cmd('configure', '为当前模块生成项目文件(Windows 为 MSVC 项目,其它平台为 Makefile)'),
162
+ cmd('rebuild', '依次执行 clean、configure、build'),
163
+ cmd('install', '安装指定 Node 版本的开发文件'),
164
+ cmd('list', '列出已安装的 Node 开发文件;别名 ls'),
165
+ cmd('remove', '移除指定版本的 Node 开发文件;别名 rm'), '',
166
+ ` ${chalk.cyan('选项:')}`,
167
+ opt('-C <路径>', '切换到该目录后执行;完整写法 --directory'),
168
+ opt('--devdir <路径>', '指定开发文件缓存目录,默认取系统缓存目录'),
169
+ opt('-j <数量>', '并行构建任务数,仅 build;完整写法 --jobs'),
170
+ opt('--target <版本>', '目标 Node.js 版本,默认当前主机版本'),
171
+ opt('--arch <架构>', '目标架构,如 arm64、ia32'),
172
+ opt('--debug', '输出详细日志'),
173
+ opt('-v', '输出版本号;完整写法 --version'), '',
174
+ ` ${chalk.gray('无参数、help、-h、--help 输出本帮助。')}`, '',
175
+ `${gold('nodejs-mobile-gyp@' + this.version)} ${gold('node@' + process.versions.node)}`
150
176
  ].join('\n');
151
177
  }
152
178
  }
package/lib/rebuild.js CHANGED
@@ -1,4 +1,4 @@
1
- /**
1
+ /**
2
2
  * 依次执行 clean、configure、build
3
3
  */
4
4
  const rebuild = async (gyp, argv) => {
package/lib/remove.js CHANGED
@@ -1,4 +1,4 @@
1
- import gracefulFs from 'graceful-fs';
1
+ import gracefulFs from 'graceful-fs';
2
2
  import path from 'path';
3
3
  import * as log from './log.js';
4
4
  import semver from 'semver';
package/lib/util.js CHANGED
@@ -1,73 +1,73 @@
1
- import cp from 'child_process';
2
- import path from 'path';
3
- import gracefulFs from 'graceful-fs';
4
- import * as log from './log.js';
5
-
6
- const { openSync, closeSync } = gracefulFs,
7
- /**
8
- * 执行外部命令并返回 [err, stdout, stderr]
9
- */
10
- execFile = async (...args) => new Promise(resolve => {
11
- const child = cp.execFile(...args, (...a) => resolve(a));
12
- child.stdin.end();
13
- }),
14
- /**
15
- * 读取 Windows 注册表指定键的值
16
- */
17
- regGetValue = async (key, value, addOpts) => {
18
- const outReValue = value.replace(/\W/g, '.'), outRe = new RegExp(`^\\s+${outReValue}\\s+REG_\\w+\\s+(\\S.*)$`, 'im'),
19
- reg = path.join(process.env.SystemRoot, 'System32', 'reg.exe'),
20
- regArgs = ['query', key, '/v', value].concat(addOpts);
21
-
22
- log.silly('reg', 'running', reg, regArgs);
23
- const [err, stdout, stderr] = await execFile(reg, regArgs, { encoding: 'utf8' });
24
-
25
- log.silly('reg', 'reg.exe stdout = %j', stdout);
26
- if (err || stderr.trim() !== '') {
27
- log.silly('reg', 'reg.exe err = %j', err && (err.stack || err));
28
- log.silly('reg', 'reg.exe stderr = %j', stderr);
29
- if (err) throw err;
30
- throw new Error(stderr);
31
- }
32
-
33
- const result = outRe.exec(stdout)
34
- if (!result) {
35
- log.silly('reg', 'error parsing stdout');
36
- throw new Error('无法解析 reg.exe 的输出');
37
- }
38
-
39
- log.silly('reg', 'found: %j', result[1]);
40
- return result[1];
41
- },
42
- /**
43
- * 依次搜索多个注册表键,返回第一个可读的值
44
- */
45
- regSearchKeys = async (keys, value, addOpts) => {
46
- for (const key of keys) {
47
- try {
48
- return await regGetValue(key, value, addOpts);
49
- } catch { continue }
50
- }
51
- },
52
- /**
53
- * 返回候选列表中第一个当前用户可读的文件或目录,都不存在则返回 undefined
54
- */
55
- findAccessibleSync = (logprefix, dir, candidates) => {
56
- for (let next = 0; next < candidates.length; next++) {
57
- const candidate = path.resolve(dir, candidates[next]);
58
- let fd;
59
- try {
60
- fd = openSync(candidate, 'r');
61
- } catch (e) {
62
- // 该候选文件不存在或不可读,继续检查下一个
63
- log.silly(logprefix, 'Could not open %s: %s', candidate, e.message);
64
- continue;
65
- }
66
- closeSync(fd), log.silly(logprefix, 'Found readable %s', candidate);
67
- return candidate;
68
- }
69
-
70
- return undefined;
71
- }
72
-
1
+ import cp from 'child_process';
2
+ import path from 'path';
3
+ import gracefulFs from 'graceful-fs';
4
+ import * as log from './log.js';
5
+
6
+ const { openSync, closeSync } = gracefulFs,
7
+ /**
8
+ * 执行外部命令并返回 [err, stdout, stderr]
9
+ */
10
+ execFile = async (...args) => new Promise(resolve => {
11
+ const child = cp.execFile(...args, (...a) => resolve(a));
12
+ child.stdin.end();
13
+ }),
14
+ /**
15
+ * 读取 Windows 注册表指定键的值
16
+ */
17
+ regGetValue = async (key, value, addOpts) => {
18
+ const outReValue = value.replace(/\W/g, '.'), outRe = new RegExp(`^\\s+${outReValue}\\s+REG_\\w+\\s+(\\S.*)$`, 'im'),
19
+ reg = path.join(process.env.SystemRoot, 'System32', 'reg.exe'),
20
+ regArgs = ['query', key, '/v', value].concat(addOpts);
21
+
22
+ log.silly('reg', 'running', reg, regArgs);
23
+ const [err, stdout, stderr] = await execFile(reg, regArgs, { encoding: 'utf8' });
24
+
25
+ log.silly('reg', 'reg.exe stdout = %j', stdout);
26
+ if (err || stderr.trim() !== '') {
27
+ log.silly('reg', 'reg.exe err = %j', err && (err.stack || err));
28
+ log.silly('reg', 'reg.exe stderr = %j', stderr);
29
+ if (err) throw err;
30
+ throw new Error(stderr);
31
+ }
32
+
33
+ const result = outRe.exec(stdout)
34
+ if (!result) {
35
+ log.silly('reg', 'error parsing stdout');
36
+ throw new Error('无法解析 reg.exe 的输出');
37
+ }
38
+
39
+ log.silly('reg', 'found: %j', result[1]);
40
+ return result[1];
41
+ },
42
+ /**
43
+ * 依次搜索多个注册表键,返回第一个可读的值
44
+ */
45
+ regSearchKeys = async (keys, value, addOpts) => {
46
+ for (const key of keys) {
47
+ try {
48
+ return await regGetValue(key, value, addOpts);
49
+ } catch { continue }
50
+ }
51
+ },
52
+ /**
53
+ * 返回候选列表中第一个当前用户可读的文件或目录,都不存在则返回 undefined
54
+ */
55
+ findAccessibleSync = (logprefix, dir, candidates) => {
56
+ for (let next = 0; next < candidates.length; next++) {
57
+ const candidate = path.resolve(dir, candidates[next]);
58
+ let fd;
59
+ try {
60
+ fd = openSync(candidate, 'r');
61
+ } catch (e) {
62
+ // 该候选文件不存在或不可读,继续检查下一个
63
+ log.silly(logprefix, 'Could not open %s: %s', candidate, e.message);
64
+ continue;
65
+ }
66
+ closeSync(fd), log.silly(logprefix, 'Found readable %s', candidate);
67
+ return candidate;
68
+ }
69
+
70
+ return undefined;
71
+ }
72
+
73
73
  export { execFile, regGetValue, regSearchKeys, findAccessibleSync }
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "bindings",
12
12
  "gyp"
13
13
  ],
14
- "version": "1.1.4",
14
+ "version": "1.2.0",
15
15
  "installVersion": 11,
16
16
  "author": "flun <open@flun.top>",
17
17
  "bin": {
@@ -39,9 +39,10 @@
39
39
  "LICENSE"
40
40
  ],
41
41
  "dependencies": {
42
+ "chalk": "^6.0.1",
42
43
  "env-paths": "^4.0.0",
43
44
  "exponential-backoff": "^3.1.3",
44
- "glob": "^13.0.6",
45
+ "glob": "^14.0.3",
45
46
  "graceful-fs": "^4.2.11",
46
47
  "make-fetch-happen": "^16.0.1",
47
48
  "nopt": "^10.0.1",