fix(npm): show timeout hint on first retry (#1538)

Co-Authored-By: jieshu666 <jieshu666@users.noreply.github.com>
This commit is contained in:
Hunter Bown
2026-05-12 12:10:29 -05:00
parent c535f85a4d
commit 9ca759bd11
4 changed files with 82 additions and 1 deletions
+35
View File
@@ -439,6 +439,41 @@ target/debug/build/libsqlite3-sys-*/build-script-build
# fine — the AV is blocking Cargo's process-spawning path specifically.
```
### npm binary download times out
If `deepseek` waits several seconds and prints `connect ETIMEDOUT` or
`EAI_AGAIN` while fetching from `github.com`, the npm wrapper installed
successfully but the prebuilt binary download from GitHub Releases is blocked
or unreliable on your network. This download is separate from the npm registry
package download.
Use one of these paths:
1. Set a proxy and retry:
```bash
export HTTPS_PROXY=http://your-proxy:port
deepseek
```
2. Mirror the release assets internally and set `DEEPSEEK_TUI_RELEASE_BASE_URL`:
```bash
export DEEPSEEK_TUI_RELEASE_BASE_URL=https://your-mirror.example.com/DeepSeek-TUI/
deepseek
```
The directory must contain `deepseek-artifacts-sha256.txt` and the platform
binaries from the GitHub release.
3. Install via Cargo, which builds locally and does not download GitHub release
assets. See [Section 3](#3-install-via-cargo-any-tier-1-rust-target).
4. Download both `deepseek` and `deepseek-tui` manually from the
[Releases page](https://github.com/Hmbown/DeepSeek-TUI/releases), place them
in a directory on `PATH`, and make them executable. See
[Section 4](#4-manual-download-from-github-releases).
---
## 7. Verifying your install
+7 -1
View File
@@ -195,7 +195,7 @@ function installFailureHint(error) {
" If GitHub is unavailable on this network, mirror the release assets and set:",
" DEEPSEEK_TUI_RELEASE_BASE_URL=https://<mirror>/<release-asset-directory>/",
" The directory must contain deepseek-artifacts-sha256.txt and the platform binaries.",
" See docs/INSTALL.md#npm-download-is-slow-or-times-out-from-mainland-china.",
" See docs/INSTALL.md#npm-binary-download-times-out.",
].join("\n");
}
@@ -790,6 +790,12 @@ async function withRetry(label, fn, context = "runtime") {
logInfo(
`${label} failed (attempt ${attempt}/${attemptLimit}): ${err.message}; retrying in ${wait} ms`,
);
if (attempt === 1) {
const hint = installFailureHint(err);
if (hint) {
process.stderr.write(`${hint}\n`);
}
}
await sleep(wait);
}
}
+1
View File
@@ -39,6 +39,7 @@ test("install failure hint explains release base override for blocked GitHub dow
assert.match(hint, /DEEPSEEK_TUI_RELEASE_BASE_URL/);
assert.match(hint, /deepseek-artifacts-sha256\.txt/);
assert.match(hint, /platform binaries/);
assert.match(hint, /#npm-binary-download-times-out/);
} finally {
if (previous === undefined) {
delete process.env.DEEPSEEK_TUI_RELEASE_BASE_URL;
+39
View File
@@ -89,3 +89,42 @@ test("optional install still swallows wrapped http 5xx failures", async () => {
}
}
});
test("withRetry prints install hint on first retryable failure", async () => {
const previousWrite = process.stderr.write;
const previousSetTimeout = global.setTimeout;
let stderr = "";
let attempts = 0;
process.stderr.write = (chunk) => {
stderr += String(chunk);
return true;
};
global.setTimeout = (callback) => {
callback();
return 0;
};
try {
const result = await _internal.withRetry(
"fetch https://github.com/example",
async () => {
attempts += 1;
if (attempts === 1) {
const err = new Error("connect ETIMEDOUT 20.205.243.166:443");
err.code = "ETIMEDOUT";
throw err;
}
return "ok";
},
"runtime",
);
assert.equal(result, "ok");
assert.equal(attempts, 2);
assert.match(stderr, /deepseek-tui install hint:/);
assert.match(stderr, /#npm-binary-download-times-out/);
} finally {
process.stderr.write = previousWrite;
global.setTimeout = previousSetTimeout;
}
});