# Agent Note: Source dsh HTTP proxy overlay Status: implemented English | [中文](2026-08-19-source-dsh-http-proxy-overlay.zh.md) ## Problem Machines whose ambient proxy is SOCKS can reach OpenRouter with curl and still fail `pnpm dsh` HTTPS fetches: Node, undici, and pi-ai accept `http://` / `https://` proxy URLs and reject `socks5` / `socks5h`. Setting `HTTPS_PROXY` in the calling PowerShell or bash session also routes later shell commands through that HTTP proxy. Product `.env` files cannot supply `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, or `NO_PROXY` because those names are bootstrap-only. Assigning those names on `process.env` after Node has started does not rebind `fetch`: undici reads `NODE_USE_ENV_PROXY` and `HTTPS_PROXY` at process start. Node `--env-file-if-exists` also leaves inherited names in place, so a user-level `HTTPS_PROXY=socks5h://…` still wins. ## Decision The root `dsh` script runs [`scripts/run-source-dsh.ts`](../../../../scripts/run-source-dsh.ts) as `node --import tsx/esm scripts/run-source-dsh.ts`. [`applySourceDshHttpProxy`](../../../../scripts/apply-source-dsh-http-proxy.ts) writes HTTP proxy variables onto a copy of `process.env`. When gitignored [`.dsh-http-proxy.env`](../../../../.gitignore) or `DSH_HTTP_PROXY` supplies an overlay and `DSH_SOURCE_HTTP_PROXY_APPLIED` is unset, the wrapper respawns the same Node argv with that environment so `NODE_USE_ENV_PROXY=1` and the HTTP proxy URLs exist before `fetch` initializes. The marker prevents a second respawn. The calling shell is unchanged. `DSH_HTTP_PROXY`, when set to a non-empty HTTP(S) URL, overwrites `HTTP_PROXY` / `HTTPS_PROXY` / `ALL_PROXY` (both cases) and sets `NODE_USE_ENV_PROXY=1`. When `NO_PROXY` and `no_proxy` are both unset, it sets them to `localhost,127.0.0.1,::1`. Otherwise the overlay file's parsed assignments are applied, then any remaining SOCKS value on those six names is replaced by the file's HTTP URL so an omitted `ALL_PROXY` cannot keep `socks5h://`. A `socks5` or `socks5h` winning overlay fails before the CLI boots. Absent both sources, the inherited environment is unchanged and there is no respawn. The wrapper prints the applied HTTP URL once to stderr before respawn. The installed `apps/cli/lib/bin.js` path is unchanged: it has no checkout overlay file. ## Alternatives considered **Tell the user to export `HTTPS_PROXY` in the shell before `pnpm dsh`.** That reaches OpenRouter, but the same variables remain on later commands in that session, including tools that should keep a SOCKS proxy. **Put proxy names in the invoking `.env` or `$DSH_HOME/.env`.** Rejected by the [configuration-source-ownership decision](../architecture/2026-08-04-configuration-source-ownership.md): bootstrap network variables may come only from the inherited process environment. **Assign `NODE_USE_ENV_PROXY` only inside the wrapper after Node has started.** OpenRouter traffic uses `fetch`; Node binds the env-proxy dispatcher at process start, so a later `process.env` write does not change it. **Use Node `--env-file-if-exists` without respawning.** That file does not replace names the parent already set, so an inherited `socks5h://` `HTTPS_PROXY` still reaches `fetch`. ## Consequences Source `pnpm dsh` can use an HTTP overlay without mutating the calling shell. An inherited SOCKS `HTTPS_PROXY` is replaced in the respawned Node process, not in the shell. Contributors without `DSH_HTTP_PROXY` or `.dsh-http-proxy.env` see the previous inheritance behavior and no extra process. A SOCKS-only overlay fails loud instead of timing out against OpenRouter. The published bin still requires the caller to pass HTTP proxy variables when the host needs a proxy. `--use-env-proxy` is not on the command: Node 22.19 in CI rejects the flag. ## Testing `scripts/apply-source-dsh-http-proxy.spec.ts` covers no-overlay, `DSH_HTTP_PROXY` overwrite of SOCKS, file parse, file-versus-`DSH_HTTP_PROXY` precedence, SOCKS leftover on omitted names, SOCKS rejection, and the one-shot respawn marker. `apps/cli/tests/source-launch.compat.spec.ts` pins the root `dsh` command to `scripts/run-source-dsh.ts` and smokes that vector.