From 255209931eeb73bddce541c7eeb20e78fd8afbbf Mon Sep 17 00:00:00 2001 From: Letta Integration <300689746+letta-integration[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 05:47:57 +0000 Subject: [PATCH] test(integration): wait for the CLI child to exit before the lazy-recovery test resolves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test resolved its promise as soon as the final result frame arrived and killed the spawned CLI 500 ms later. The test-home preload removes the temp HOME in afterAll right after the test resolves, while the child still holds files there; on Windows that rm fails with EBUSY (API / windows-latest / 4 on four main pushes 2026-09-13/14). Resolve from the "close" handler instead. Co-Authored-By: Charles Packer <5475622+cpacker@users.noreply.github.com> 👾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta Code --- .../lazy-approval-recovery.test.ts | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/integration-tests/lazy-approval-recovery.test.ts b/src/integration-tests/lazy-approval-recovery.test.ts index 2d4b468a7b..83b369bec2 100644 --- a/src/integration-tests/lazy-approval-recovery.test.ts +++ b/src/integration-tests/lazy-approval-recovery.test.ts @@ -124,9 +124,19 @@ async function runLazyRecoveryTest(timeoutMs = 300000): Promise<{ } }, timeoutMs); - const cleanup = () => { + // The promise resolves from the "close" handler, after the CLI's stdio has + // closed, so the test-home preload never removes the temp home while the + // child still holds files in it (Windows reports EBUSY). + let finalResult: { + messages: StreamMessage[]; + success: boolean; + errorSeen: boolean; + } | null = null; + const finish = (success: boolean) => { + if (closing) return; closing = true; clearTimeout(timeout); + finalResult = { messages, success, errorSeen }; setTimeout(() => { proc.stdin?.end(); proc.kill(); @@ -255,8 +265,7 @@ async function runLazyRecoveryTest(timeoutMs = 300000): Promise<{ return; } if (resultCount >= 1 && !approvalSeen) { - cleanup(); - resolve({ messages, success: false, errorSeen }); + finish(false); return; } @@ -267,8 +276,7 @@ async function runLazyRecoveryTest(timeoutMs = 300000): Promise<{ approvalSeen && (interruptSent || errorSeen) ) { - cleanup(); - resolve({ messages, success: true, errorSeen }); + finish(true); } } } catch { @@ -298,14 +306,8 @@ async function runLazyRecoveryTest(timeoutMs = 300000): Promise<{ processLine(buffer); } - if (!closing) { - // If we got here without resolving, check what we have - resolve({ - messages, - success: resultCount > 0, - errorSeen, - }); - } + // A child that exited on its own is judged by what it produced. + resolve(finalResult ?? { messages, success: resultCount > 0, errorSeen }); }); proc.on("error", (err) => {