From 8ae3645b78228a5bdaee239bd7e4370c7e4ad15a Mon Sep 17 00:00:00 2001 From: Kailigithub Date: Sat, 23 May 2026 03:46:20 +0000 Subject: [PATCH] fix: prevent TUI crash when /rewind picker triggers session remount When /rewind is invoked via the picker, the callback (_do_rewind) truncates session messages and calls _remount_current_session(), which removes all widgets from the container. Back in _collapse_choice(), the anchor widget reference still exists but is now detached, causing a crash on mount(after=anchor). Add a guard that checks is_mounted on the anchor widget after the on_select callback. If the callback already rebuilt the UI, return early to avoid operating on detached widgets. Closes #421 --- frontends/tuiapp_v2.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontends/tuiapp_v2.py b/frontends/tuiapp_v2.py index 2c7244d40..f017f03e7 100644 --- a/frontends/tuiapp_v2.py +++ b/frontends/tuiapp_v2.py @@ -2750,6 +2750,11 @@ def _collapse_choice(self, msg: ChatMessage, idx: int) -> None: result_text = msg.on_select(value) except Exception as e: result_text = f"❌ 失败: {type(e).__name__}: {e}" + # If on_select rebuilt the message container (e.g. /rewind), + # the old anchor widgets are now detached — skip collapse. + anchor = msg._hint_widget or msg._body_widget + if anchor is not None and hasattr(anchor, 'is_mounted') and not anchor.is_mounted: + return display = (result_text or label).strip() or label msg.selected_label = display msg.content = display @@ -2759,7 +2764,6 @@ def _collapse_choice(self, msg: ChatMessage, idx: int) -> None: body.append("✓ ", style=C_GREEN) body.append(display, style=C_FG) new_widget = SelectableStatic(body, classes="msg") - anchor = msg._hint_widget or msg._body_widget if anchor is not None: container.mount(new_widget, after=anchor) else: