229f02ea2c
A community user from China reported `npm install deepseek-tui` took 18 minutes through a CN npm mirror. The bottleneck is the GitHub Releases binary fetch (~46 MB across two binaries), not the npm tarball (which is 6.9 kB). The CN mirror does NOT proxy GitHub release downloads, so any user behind a slow or lossy connection is hitting the GitHub fetch directly with no resilience. Four behaviors added to `npm/deepseek-tui/scripts/install.js`: 1. **Retry with exponential backoff.** Up to 5 attempts on network errors (ECONNRESET, ECONNREFUSED, ETIMEDOUT, EAI_AGAIN, network/host unreachable, EPIPE, ECONNABORTED) and 5xx upstream responses. Backoff `1s, 2s, 4s, 8s, 16s` with ±20% jitter. 4xx and checksum-mismatch are flagged non-retryable so we don't thrash on permanent failures. Final error includes the underlying message and the attempt count. 2. **Per-attempt total timeout + stall detector.** Total timeout defaults to 5 minutes per attempt (`DEEPSEEK_TUI_DOWNLOAD_TIMEOUT_MS`, alias `DEEPSEEK_DOWNLOAD_TIMEOUT_MS`). A stall detector aborts the request when no bytes arrive for 30 s (`DEEPSEEK_TUI_DOWNLOAD_STALL_MS`, alias `DEEPSEEK_DOWNLOAD_STALL_MS`) so a hung connection doesn't waste the whole timeout. Both budgets are surfaced in the error so the user can dial them up if they're on a slow pipe. 3. **HTTPS_PROXY / HTTP_PROXY support — pure Node, no new dependencies.** Detects `HTTPS_PROXY` / `HTTP_PROXY` (and the lowercase variants) and routes through the proxy via CONNECT tunneling. `NO_PROXY` exclusion list honored, with `*` and dotted- suffix matching. Proxy auth via standard `user:pass@` URL form is passed through as `Proxy-Authorization: Basic ...`. Pure-Node implementation using `net` + `tls` + `http` + `https` builtins — no `https-proxy-agent` dependency added. 4. **Download progress indicator.** Writes to stderr every ~1 MB or every 2 s in TTY mode using `\r` to overwrite a single line. Non-TTY mode (CI, piped) emits one line per 5 MB so logs stay reasonable. Suppressed when `DEEPSEEK_TUI_QUIET_INSTALL=1` or when `npm_config_loglevel` is `silent` or `error`. Falls back to `N MB downloaded` when the response has no `Content-Length`. Public API unchanged: existing callers of `getBinaryPath` and `run` keep working identically when no new env vars are set. The escape hatch `DEEPSEEK_TUI_DISABLE_INSTALL=1` still exits cleanly. Verified locally: * `node -c install.js` and module-load syntax checks. * `DEEPSEEK_TUI_FORCE_DOWNLOAD=1 DEEPSEEK_TUI_VERSION=0.8.10 node install.js` — real GitHub Releases download succeeded with visible progress, both binaries landed. * `HTTPS_PROXY=http://invalid.proxy.local:9999 ... node install.js` — proxy path exercised, fails cleanly with the bad host named in the error message after retries exhausted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>