4.1 KiB
Agent Note: Source dsh HTTP proxy overlay
Status: implemented
English | 中文
问题
环境中只有 SOCKS 代理的机器可以用 curl 访问 OpenRouter,但 pnpm dsh 的 HTTPS fetch 仍会失败:Node、undici 和 pi-ai 接受 http:// / https:// 代理 URL,并拒绝 socks5 / socks5h。在调用方的 PowerShell 或 bash 会话里设置 HTTPS_PROXY 也会让该会话中后续命令走这个 HTTP 代理。产品 .env 文件不能提供 HTTP_PROXY、HTTPS_PROXY、ALL_PROXY 或 NO_PROXY,因为这些名称只能来自进程启动环境。在 Node 启动之后再往 process.env 写入这些名称不会重新绑定 fetch:undici 在进程启动时读取 NODE_USE_ENV_PROXY 和 HTTPS_PROXY。Node --env-file-if-exists 同样不会替换已继承的名称,因此用户级的 HTTPS_PROXY=socks5h://… 仍然生效。
决策
根目录的 dsh 脚本以 node --import tsx/esm scripts/run-source-dsh.ts 运行 scripts/run-source-dsh.ts。applySourceDshHttpProxy 把 HTTP 代理变量写入 process.env 的副本。当被 gitignore 的 .dsh-http-proxy.env 或 DSH_HTTP_PROXY 提供覆盖层且未设置 DSH_SOURCE_HTTP_PROXY_APPLIED 时,包装层用该环境按相同的 Node argv 再拉起一次进程,以便在 fetch 初始化之前就存在 NODE_USE_ENV_PROXY=1 和 HTTP 代理 URL。该标记防止第二次再拉起。调用方 shell 不变。
当 DSH_HTTP_PROXY 设为非空的 HTTP(S) URL 时,它会覆盖 HTTP_PROXY / HTTPS_PROXY / ALL_PROXY(两种大小写)并设置 NODE_USE_ENV_PROXY=1。当 NO_PROXY 与 no_proxy 都未设置时,它将它们设为 localhost,127.0.0.1,::1。否则先应用覆盖文件中解析出的赋值,再把这六个名称上残留的 SOCKS 值换成文件中的 HTTP URL,以免漏写的 ALL_PROXY 仍指向 socks5h://。最终生效的覆盖层若为 socks5 或 socks5h,会在 CLI 启动前失败。两种来源都不存在时,继承的环境保持不变,也不会再拉起进程。包装层在再拉起之前会把生效的 HTTP URL 打印到 stderr 一次。
已安装的 apps/cli/lib/bin.js 路径不变:它没有检出级覆盖文件。
考虑过的备选方案
**让用户在运行 pnpm dsh 之前于 shell 中导出 HTTPS_PROXY。**这样可以访问 OpenRouter,但这些变量会留在该会话的后续命令上,包括本应继续使用 SOCKS 代理的工具。
**把代理名称放进调用目录的 .env 或 $DSH_HOME/.env。**被配置来源归属决策拒绝:网络启动变量只能来自继承的进程环境。
仅在包装层内、Node 启动之后赋值 NODE_USE_ENV_PROXY。 OpenRouter 流量走 fetch;Node 在进程启动时绑定 env-proxy dispatcher,随后再写 process.env 不会改变它。
**使用 Node --env-file-if-exists 且不再拉起进程。**该文件不会替换父进程已经设置的名称,因此继承来的 socks5h:// HTTPS_PROXY 仍会到达 fetch。
影响
源码路径的 pnpm dsh 可以使用 HTTP 覆盖层,而不修改调用方 shell。继承来的 SOCKS HTTPS_PROXY 会在再拉起的 Node 进程中被替换,而不是在 shell 中。没有 DSH_HTTP_PROXY 或 .dsh-http-proxy.env 的贡献者仍看到原来的继承行为,也不会多一个进程。仅有 SOCKS 的覆盖层会立即失败,而不是在访问 OpenRouter 时超时。已发布的 bin 在宿主需要代理时,仍要求调用方传入 HTTP 代理变量。命令行不加 --use-env-proxy:CI 中的 Node 22.19 会拒绝该 flag。
测试
scripts/apply-source-dsh-http-proxy.spec.ts 覆盖无覆盖层、DSH_HTTP_PROXY 覆盖 SOCKS、文件解析、文件与 DSH_HTTP_PROXY 的优先级、文件未写出的名称上残留的 SOCKS、SOCKS 拒绝,以及一次性再拉起标记。apps/cli/tests/source-launch.compat.spec.ts 将根目录 dsh 命令钉在 scripts/run-source-dsh.ts 上,并对该启动向量做冒烟测试。