From 5c9ce47c53e0a60f7450add52f30b58915beb960 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Sat, 14 Mar 2026 03:57:59 +0100 Subject: [PATCH] fix(coding-agent): fix startup crash when downloading fd/ripgrep on first run Use pipeline() instead of finished(readable.pipe(writable)) so stream errors from abort signals are caught as promise rejections. Increase download timeout from 10s to 120s for multi-MB archives. closes #2066 --- packages/coding-agent/CHANGELOG.md | 4 ++++ packages/coding-agent/src/utils/tools-manager.ts | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index d7d9d5d5..3f8228c8 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed startup crash when downloading `fd`/`ripgrep` on first run by using `pipeline()` instead of `finished(readable.pipe(writable))` so stream errors from timeouts are caught properly, and increased the download timeout from 10s to 120s ([#2066](https://github.com/badlogic/pi-mono/issues/2066)) + ## [0.58.0] - 2026-03-14 ### New Features diff --git a/packages/coding-agent/src/utils/tools-manager.ts b/packages/coding-agent/src/utils/tools-manager.ts index f51e042b..b24c43a3 100644 --- a/packages/coding-agent/src/utils/tools-manager.ts +++ b/packages/coding-agent/src/utils/tools-manager.ts @@ -5,11 +5,12 @@ import { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renam import { arch, platform } from "os"; import { join } from "path"; import { Readable } from "stream"; -import { finished } from "stream/promises"; +import { pipeline } from "stream/promises"; import { APP_NAME, getBinDir } from "../config.js"; const TOOLS_DIR = getBinDir(); -const NETWORK_TIMEOUT_MS = 10000; +const NETWORK_TIMEOUT_MS = 10_000; +const DOWNLOAD_TIMEOUT_MS = 120_000; function isOfflineModeEnabled(): boolean { const value = process.env.PI_OFFLINE; @@ -116,7 +117,7 @@ async function getLatestVersion(repo: string): Promise { // Download a file from URL async function downloadFile(url: string, dest: string): Promise { const response = await fetch(url, { - signal: AbortSignal.timeout(NETWORK_TIMEOUT_MS), + signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS), }); if (!response.ok) { @@ -128,7 +129,7 @@ async function downloadFile(url: string, dest: string): Promise { } const fileStream = createWriteStream(dest); - await finished(Readable.fromWeb(response.body as any).pipe(fileStream)); + await pipeline(Readable.fromWeb(response.body as any), fileStream); } function findBinaryRecursively(rootDir: string, binaryFileName: string): string | null {