@geoly-ai/skills-hub 0.3.2 → 0.3.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.
@@ -2,6 +2,8 @@
2
2
  // 🔴 必须在任何 import 之前抑制 node:sqlite 的 ExperimentalWarning。
3
3
  // 依据:04-install.md §5.1「代价」第 2 条 —— 警告在模块导入时发出,
4
4
  // 放在适配层里抑制来不及。此处是进程内最早的可执行位置。
5
+ import os from 'node:os';
6
+
5
7
  const origEmit = process.emit;
6
8
  process.emit = function (name, data, ...rest) {
7
9
  if (
@@ -19,22 +21,41 @@ process.emit = function (name, data, ...rest) {
19
21
  for (const k of Object.keys(process.env)) {
20
22
  if (k.startsWith('GEOLY_FAULT')) delete process.env[k];
21
23
  }
22
- // 🔴 认 HTTP_PROXY / HTTPS_PROXY / NO_PROXY —— **必须在第一次 fetch 之前**。
23
- //
24
- // Node 的内建 fetch(undici)**默认不认代理环境变量**,而 curl / npm / git 都认。
25
- // 后果不是「慢一点」:在企业代理后面,`install` 会以 `UND_ERR_CONNECT_TIMEOUT`
26
- // 直接失败,而同一台机器上 `curl` 同一个地址是通的 —— 于是看起来像我们的
27
- // registry 挂了。2026-09-03 在开发机上实测到,绕了两圈才找到。
24
+ // 🔴 认 HTTP_PROXY / HTTPS_PROXY / NO_PROXY —— 只能靠**启动前**就带上变量。
28
25
  //
29
- // ⚠️ `NODE_USE_ENV_PROXY` Node **24** 引入的;22.x 上这一行**无效**,
30
- // 代理后面的 22.x 用户仍然连不上。这是已知缺口,不要写成已解决。
26
+ // Node 的内建 fetch(undici)默认**不认**代理环境变量,而 npm / git / curl 都认。
27
+ // 后果不是「慢一点」:在企业代理后面 `install` 报 `UND_ERR_CONNECT_TIMEOUT`,
28
+ // 而同一台机器上 `curl` 同一个地址是通的 —— 看起来像我们的 registry 挂了。
31
29
  //
32
- // 📌 代理不削弱安全性:HTTPS CONNECT 隧道,TLS 仍是端到端;
33
- // 而且我们对取回的字节做的是**签名验证**,一个恶意代理改了字节只会验签失败。
30
+ // ⚠️ **`process.env.NODE_USE_ENV_PROXY = '1'` 在进程内设置是无效的**(实测)。
31
+ // Node 在**启动时**读它,之后再改不算数。
32
+ // 📌 我第一版正是那么写的,而且「验证」过它有效 —— 那是**假阳性**:
33
+ // 当时网络恰好能直连,设不设都通。三个对照才把它钉死:
34
+ // ① 什么都不设 → UND_ERR_CONNECT_TIMEOUT
35
+ // ② 进程内设置 → UND_ERR_CONNECT_TIMEOUT ← 无效
36
+ // ③ 启动前外部设置 → 302
37
+ // **在一个本来就会过的窗口里验证一道闸,等于没验。**
34
38
  //
35
- // 🔴 只在**用户没有显式表态**时设置:已经设过(哪怕设成 '0')就尊重用户的选择。
36
- if (process.env.NODE_USE_ENV_PROXY === undefined) {
37
- process.env.NODE_USE_ENV_PROXY = '1';
39
+ // 所以:检测到代理配置但变量没带上时,**带着变量把自己重启一次**。
40
+ // 🔴 三个前提缺一不可,否则不重启:
41
+ // · 用户没有显式表态(`NODE_USE_ENV_PROXY` 未设 —— 设成 '0' 也是表态)
42
+ // · 环境里确实配了代理(没配就重启纯属白费一个进程)
43
+ // · 不是已经重启过的那一次(防无限自我重启)
44
+ if (
45
+ process.env.NODE_USE_ENV_PROXY === undefined &&
46
+ process.env.GEOLY_PROXY_REEXEC === undefined &&
47
+ ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy'].some((k) => process.env[k])
48
+ ) {
49
+ const { spawnSync } = await import('node:child_process');
50
+ const r = spawnSync(process.execPath, [...process.execArgv, ...process.argv.slice(1)], {
51
+ // 🔴 `inherit`:stdin 必须原样传下去 —— `install --all` 的数量确认
52
+ // 要读 TTY,管道化会让它变成非交互而**静默走另一条分支**。
53
+ stdio: 'inherit',
54
+ env: { ...process.env, NODE_USE_ENV_PROXY: '1', GEOLY_PROXY_REEXEC: '1' },
55
+ });
56
+ // 被信号杀掉时用 128+signo 表示,别把它压成 0
57
+ if (r.signal) process.exit(128 + (os.constants.signals[r.signal] ?? 0));
58
+ process.exit(r.status ?? 1);
38
59
  }
39
60
 
40
61
  const { lockdown } = await import('../src/fault-inject.mjs');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geoly-ai/skills-hub",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "geoly-ai 的 skill 分发中心 —— 安装、校验、审计",
5
5
  "type": "module",
6
6
  "bin": {
package/src/download.mjs CHANGED
@@ -178,10 +178,27 @@ export async function download(url, {
178
178
  // 2026-09-03 我自己被这句话挡了两轮,最后是手写探针才挖出
179
179
  // UND_ERR_CONNECT_TIMEOUT,进而发现是代理没被认。
180
180
  const why = e.cause?.code ?? e.cause?.message ?? e.code ?? '';
181
- const hint = /TIMEOUT|ETIMEDOUT|ECONNREFUSED/.test(String(why))
182
- ? '\n 连不上。若你在代理后面:本 CLI HTTPS_PROXY / NO_PROXY,'
183
- + '但那需要 Node ≥ 24(当前 ' + process.version + ')。'
184
- : '';
181
+ // 🔴 提示要**按当前环境分情形**,不能一句话套所有人。
182
+ // 我第一版无论如何都说「需要 Node 24」,而在 Node 25 上读者会
183
+ // 合理地认为「我满足了,那问题在别处」—— 一句正确但不适用的话,
184
+ // 比不说更能把人带偏。
185
+ let hint = '';
186
+ if (/TIMEOUT|ETIMEDOUT|ECONNREFUSED|ENOTFOUND|EAI_AGAIN/.test(String(why))) {
187
+ const major = Number(process.versions.node.split('.')[0]);
188
+ const hasProxyEnv = ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy']
189
+ .some((k) => process.env[k]);
190
+ if (hasProxyEnv && major < 24) {
191
+ hint = `\n 你配了代理,但代理支持需要 Node ≥ 24(当前 ${process.version})。`
192
+ + '\n 可以先在能直连的网络里跑一次把缓存热起来,之后 --offline 可用。';
193
+ } else if (hasProxyEnv && process.env.NODE_USE_ENV_PROXY === '0') {
194
+ hint = '\n 你配了代理,但显式设了 NODE_USE_ENV_PROXY=0 —— CLI 因此没走代理。';
195
+ } else if (!hasProxyEnv) {
196
+ hint = '\n 连不上。若你的网络需要代理,设置 HTTPS_PROXY 后重试'
197
+ + '(NO_PROXY 也会被尊重)。';
198
+ } else {
199
+ hint = '\n 代理已配置且已启用,但仍然连不上 —— 请检查代理本身是否可达。';
200
+ }
201
+ }
185
202
  throw new NetworkError(`${what} 下载失败:${e.message}${why ? `(${why})` : ''}${hint}`);
186
203
  }
187
204