From 1809df9609ffa29a23246ba62b08a1a67dff4f0b Mon Sep 17 00:00:00 2001 From: CleverThis Date: Fri, 10 Apr 2026 19:39:16 +0000 Subject: [PATCH] fix(tui): clear reference token on escape ISSUES CLOSED: #6450 --- features/steps/tui_input_modes_steps.py | 17 ++++++++++++ features/tui_input_modes.feature | 5 ++++ src/cleveragents/tui/app.py | 36 +++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/features/steps/tui_input_modes_steps.py b/features/steps/tui_input_modes_steps.py index 38f8ae327..380919f1e 100644 --- a/features/steps/tui_input_modes_steps.py +++ b/features/steps/tui_input_modes_steps.py @@ -143,3 +143,20 @@ def step_run_fallback_tui_app(context: Context) -> None: def step_fallback_tui_fails(context: Context, message: str) -> None: assert context.tui_fallback_error is not None assert message in str(context.tui_fallback_error) + + +@given('a TUI prompt value "{value}"') +def step_set_tui_prompt_value(context: Context, value: str) -> None: + context.tui_prompt_value = value + + +@when("I clear pending TUI reference token via escape") +def step_clear_pending_reference(context: Context) -> None: + cleanup = getattr(tui_app_module, "_strip_pending_reference_token") + assert callable(cleanup) + context.tui_prompt_value = cleanup(context.tui_prompt_value) + + +@then('the TUI prompt value should be "{expected}"') +def step_assert_tui_prompt_value(context: Context, expected: str) -> None: + assert context.tui_prompt_value == expected diff --git a/features/tui_input_modes.feature b/features/tui_input_modes.feature index 954e7cc12..63a4f72c6 100644 --- a/features/tui_input_modes.feature +++ b/features/tui_input_modes.feature @@ -37,3 +37,8 @@ Feature: TUI input modes Then TUI textual availability should be boolean When I run fallback TUI app Then fallback TUI app should fail with "Textual dependency missing." + + Scenario: Escape removes pending reference trigger from prompt + Given a TUI prompt value "inspect @reso" + When I clear pending TUI reference token via escape + Then the TUI prompt value should be "inspect" diff --git a/src/cleveragents/tui/app.py b/src/cleveragents/tui/app.py index 4de84e2e1..742345c91 100644 --- a/src/cleveragents/tui/app.py +++ b/src/cleveragents/tui/app.py @@ -189,6 +189,35 @@ class SessionView: transcript: list[str] = field(default_factory=list) +def _strip_pending_reference_token(value: str) -> str: + """Remove the trailing @ reference trigger (if any). + + This trims whitespace and drops the last token that begins with ``@`` when the + token does not contain any embedded whitespace. Escaped triggers (``\\@``) + remain untouched. + """ + + if not isinstance(value, str): + return "" + + candidate = value.rstrip() + if "@" not in candidate: + return candidate + + last_at = candidate.rfind("@") + if last_at == -1: + return candidate + + if last_at > 0 and candidate[last_at - 1] == "\\": + return candidate + + suffix = candidate[last_at:] + if any(ch.isspace() for ch in suffix): + return candidate + + return candidate[:last_at].rstrip() + + class _CommandRouter(Protocol): """Router protocol used by the TUI input-mode command handler.""" @@ -331,6 +360,13 @@ if _TEXTUAL_AVAILABLE: if getattr(ref_picker, "visible", False): self._remove_reference_trigger(prompt) ref_picker.hide() + prompt = self.query_one("#prompt", PromptInput) + prompt_value = getattr(prompt, "value", "") + if isinstance(prompt_value, str): + prompt.value = _strip_pending_reference_token(prompt_value) + focus_method = getattr(prompt, "focus", None) + if callable(focus_method): + focus_method() return focus_method = getattr(prompt, "focus", None)