From 10874d98d17417f395cc15d93127c0f997e72f43 Mon Sep 17 00:00:00 2001 From: pedrofrxncx Date: Thu, 30 Jul 2026 02:59:56 -0300 Subject: [PATCH] fix(sandbox): make the daemon URL-transfer routes async write_from_url and upload_to_url ran fs.mkdirSync/rmSync/statSync directly in the request handler, blocking the daemon's single-threaded event loop on every call (mkdirSync/statSync on every request, rmSync on failure). This mirrors the read/rename route fixes (#5403, #5406) using the already-imported mkdir/rm/stat promises. --- packages/sandbox/daemon/routes/fs.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/sandbox/daemon/routes/fs.ts b/packages/sandbox/daemon/routes/fs.ts index 4e6a14eaf1..804b69b28f 100644 --- a/packages/sandbox/daemon/routes/fs.ts +++ b/packages/sandbox/daemon/routes/fs.ts @@ -715,7 +715,7 @@ export function makeWriteFromUrlHandler(deps: FsDeps) { ); } - fs.mkdirSync(path.dirname(filePath), { recursive: true }); + await mkdir(path.dirname(filePath), { recursive: true }); // pipeline() guarantees: backpressure honored, errors propagate // through the chain, all streams destroyed on failure. The Transform @@ -739,7 +739,7 @@ export function makeWriteFromUrlHandler(deps: FsDeps) { // Any failure (network RST, TLS error, size cap, write fault) // leaves a partial file. Remove it so a later skill step can't // read a half-baked artifact. - fs.rmSync(filePath, { force: true }); + await rm(filePath, { force: true }); return jsonResponse( { error: abortController.signal.aborted @@ -782,24 +782,26 @@ export function makeUploadToUrlHandler(deps: FsDeps) { return jsonResponse({ error: "Path escapes project root" }, 400); } - let stat: fs.Stats; + let fileStat: fs.Stats; try { - stat = fs.statSync(filePath); + fileStat = await stat(filePath); } catch { return jsonResponse({ error: `File not found: ${body.path}` }, 400); } - if (stat.isDirectory()) { + if (fileStat.isDirectory()) { return jsonResponse({ error: "Path is a directory" }, 400); } - if (stat.size > MAX_TRANSFER_BYTES) { + if (fileStat.size > MAX_TRANSFER_BYTES) { return jsonResponse( - { error: `File too large (${stat.size} > ${MAX_TRANSFER_BYTES})` }, + { + error: `File too large (${fileStat.size} > ${MAX_TRANSFER_BYTES})`, + }, 413, ); } const headers: Record = { - "Content-Length": String(stat.size), + "Content-Length": String(fileStat.size), }; if (body.contentType) headers["Content-Type"] = body.contentType; @@ -844,7 +846,7 @@ export function makeUploadToUrlHandler(deps: FsDeps) { 502, ); } - return jsonResponse({ ok: true, size: stat.size }); + return jsonResponse({ ok: true, size: fileStat.size }); }; }