From 4129092fda8b53af00b9ca6d611602944ba0569a Mon Sep 17 00:00:00 2001 From: Robert Ban Date: Mon, 25 May 2026 22:55:36 +0200 Subject: [PATCH] fix(cli): strip OSC 8 hyperlink sequences in ChatConsole output prompt_toolkit's ANSI parser does not handle OSC escape sequences (\x1b]...\x07 / \x1b]...\x1b\), which caused Rich's [link=...] markup to leak raw OSC 8 payload into the banner title after /clear. Added _OSC_ESCAPE_RE to strip OSC sequences in ChatConsole.print() before routing through _cprint(). CSI/SGR color sequences are preserved. Visible text between OSC sequences is kept intact. --- cli.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cli.py b/cli.py index 5f42e7639..2bc6e1f81 100644 --- a/cli.py +++ b/cli.py @@ -2801,6 +2801,12 @@ def _collect_query_images(query: str | None, image_arg: str | None = None) -> tu return message, deduped +# Strip OSC escape sequences (e.g. OSC-8 hyperlinks) that prompt_toolkit's +# ANSI parser can't handle — it strips \x1b but passes the payload through +# as literal text, garbling the TUI output. +_OSC_ESCAPE_RE = re.compile(r"\x1b\][\s\S]*?(?:\x07|\x1b\\)") + + class ChatConsole: """Rich Console adapter for prompt_toolkit's patch_stdout context. @@ -2827,6 +2833,10 @@ class ChatConsole: self._inner.width = shutil.get_terminal_size((80, 24)).columns self._inner.print(*args, **kwargs) output = self._buffer.getvalue() + # Strip OSC escape sequences (e.g. OSC-8 hyperlinks) before + # routing through prompt_toolkit's ANSI parser, which only + # handles CSI/SGR and passes OSC payload through as literal text. + output = _OSC_ESCAPE_RE.sub("", output) for line in output.rstrip("\n").split("\n"): _cprint(line)