@geoly-ai/skills-hub 0.3.1 → 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.
- package/bin/skills-hub.mjs +39 -0
- package/package.json +1 -1
- package/src/download.mjs +29 -1
package/bin/skills-hub.mjs
CHANGED
|
@@ -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,6 +21,43 @@ 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
|
}
|
|
24
|
+
// 🔴 认 HTTP_PROXY / HTTPS_PROXY / NO_PROXY —— 只能靠**启动前**就带上变量。
|
|
25
|
+
//
|
|
26
|
+
// Node 的内建 fetch(undici)默认**不认**代理环境变量,而 npm / git / curl 都认。
|
|
27
|
+
// 后果不是「慢一点」:在企业代理后面 `install` 报 `UND_ERR_CONNECT_TIMEOUT`,
|
|
28
|
+
// 而同一台机器上 `curl` 同一个地址是通的 —— 看起来像我们的 registry 挂了。
|
|
29
|
+
//
|
|
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
|
+
// **在一个本来就会过的窗口里验证一道闸,等于没验。**
|
|
38
|
+
//
|
|
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);
|
|
59
|
+
}
|
|
60
|
+
|
|
22
61
|
const { lockdown } = await import('../src/fault-inject.mjs');
|
|
23
62
|
lockdown();
|
|
24
63
|
|
package/package.json
CHANGED
package/src/download.mjs
CHANGED
|
@@ -171,7 +171,35 @@ export async function download(url, {
|
|
|
171
171
|
});
|
|
172
172
|
} catch (e) {
|
|
173
173
|
if (ac.signal.aborted) throw new NetworkError(`${what} 下载超时(${timeoutMs} ms)`);
|
|
174
|
-
|
|
174
|
+
// 🔴 **必须带上 `e.cause`。** undici 抛的永远是 `TypeError: fetch failed`,
|
|
175
|
+
// 真因(ETIMEDOUT / UND_ERR_CONNECT_TIMEOUT / ENOTFOUND / 证书错误…)
|
|
176
|
+
// 全在 `cause` 里。只报 message 的话用户看到的就是一句
|
|
177
|
+
// 「fetch failed」—— 什么都定位不了。
|
|
178
|
+
// 2026-09-03 我自己被这句话挡了两轮,最后是手写探针才挖出
|
|
179
|
+
// UND_ERR_CONNECT_TIMEOUT,进而发现是代理没被认。
|
|
180
|
+
const why = e.cause?.code ?? e.cause?.message ?? e.code ?? '';
|
|
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
|
+
}
|
|
202
|
+
throw new NetworkError(`${what} 下载失败:${e.message}${why ? `(${why})` : ''}${hint}`);
|
|
175
203
|
}
|
|
176
204
|
|
|
177
205
|
if (res.status >= 300 && res.status < 400) {
|