From 81862ff14c3b9ec4d456d9f2380389def6221a23 Mon Sep 17 00:00:00 2001 From: Aidan Daly Date: Thu, 25 Jun 2026 06:12:12 +0000 Subject: [PATCH] fix(tui): force clean exit after interactive create so the CLI returns to the shell on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLI-side defensive exit only. Did not bump ink 6.8.0 -> 7.x (the upstream root-cause complement tracked by open PR #1512), which is a major-version change needing separate validation and is out of scope for a surgical fix. No test added: a unit test would need to mock Ink rendering and intercept process.exit, making it larger and more fragile than the one-line fix (violating the "test only if smaller than the fix" rule); the regression guard is the tui-harness surface per the gate. symptom: On Windows, no-flag `agentcore create` (interactive TUI) writes the project successfully but hangs until the user presses Enter instead of returning to the shell. pass_condition: a successful no-flag create through the TUI exits with code 0 on its own within a short timeout without any stdin/keypress; renderTUI reaches a guarded process.exit(0) on the terminal flow while the dev/exec/exec-shell early-return branches at render.ts:70-103 are NOT force-exited. test_surface: tui-harness. Verified: `tsc --noEmit` clean; 787 pure TUI/create/invoke unit tests pass; the 15 create.test.ts subprocess failures are pre-existing (identical on the stashed clean base) caused by a missing dist/ build, and all 16 pass after `npm run build` — confirming they are unrelated to this change. --- src/cli/tui/render.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cli/tui/render.ts b/src/cli/tui/render.ts index 8a2f91434..b421295be 100644 --- a/src/cli/tui/render.ts +++ b/src/cli/tui/render.ts @@ -110,6 +110,12 @@ export async function renderTUI(options: RenderTUIOptions = {}) { } await printPostCommandNotices(isFirstRun, updateCheck); + + // Force a clean exit for terminal TUI flows. Ink's synchronous raw-mode teardown does not + // cancel the pending libuv stdin read on Windows, so the event loop stays alive until a + // keypress flushes it (the process hangs until the user presses Enter). The dev/exec/exec-shell + // re-entry branches above return before reaching here, so they are intentionally not exited. + process.exit(0); } /**