From e90d7dba769f55f265fed766f01bf2338a928774 Mon Sep 17 00:00:00 2001 From: didericis Date: Tue, 26 May 2026 15:01:56 -0400 Subject: [PATCH] fix(dashboard): repaint stdscr immediately after modal closes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the operator pressed `y` on the preflight modal (or picked an agent in the picker), the modal's curses sub-window stayed on screen until the dashboard's main loop ticked again — which during a 5-10s launch made it look like the confirmation never registered. Add `_erase_modal` (touchwin + refresh on stdscr) and call it at every exit from `_preflight_modal` and `_picker_modal`. The pre-modal frame buffered on stdscr immediately overwrites the sub-window's area; the launch proceeds with a clean dashboard underneath. --- claude_bottle/cli/dashboard.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/claude_bottle/cli/dashboard.py b/claude_bottle/cli/dashboard.py index d2962b0..8aae861 100644 --- a/claude_bottle/cli/dashboard.py +++ b/claude_bottle/cli/dashboard.py @@ -445,6 +445,7 @@ def _picker_modal( try: key = stdscr.getch() except KeyboardInterrupt: + _erase_modal(stdscr) return None if key == 27: # Esc @@ -452,9 +453,11 @@ def _picker_modal( query = "" selected = 0 continue + _erase_modal(stdscr) return None if key in (curses.KEY_ENTER, 10, 13): if filtered: + _erase_modal(stdscr) return filtered[selected] continue if key in (curses.KEY_DOWN, ord("\x0e")): # KEY_DOWN, Ctrl-N @@ -578,13 +581,28 @@ def _preflight_modal( try: key = stdscr.getch() except KeyboardInterrupt: + _erase_modal(stdscr) return False if key in (ord("y"), ord("Y")): + _erase_modal(stdscr) return True if key in (ord("n"), ord("N"), 27, curses.KEY_ENTER, 10, 13): + _erase_modal(stdscr) return False +def _erase_modal(stdscr: "curses._CursesWindow") -> None: + """Force-redraw the dashboard's pre-modal frame so a modal + sub-window's content stops showing. Curses tracks the modal + via the newwin sub-window we created; touchwin + refresh + on stdscr repaints stdscr's last buffered frame over the + sub-window's area. Without this, the modal stays on screen + until the dashboard's main loop ticks again — which during + a long-running launch is several seconds away.""" + stdscr.touchwin() + stdscr.refresh() + + def _capture_preflight_text(plan) -> str: """Capture `plan.print` output by temporarily redirecting stderr. Plan rendering is stderr-bound (existing behavior the