From c81914ab87c0eeb1b83b028d9aa93af12f3605a9 Mon Sep 17 00:00:00 2001 From: shuiyu67 Date: Fri, 7 Aug 2026 19:29:50 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8A=A0=E8=BD=BD=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=E5=9C=A8=E9=9D=9E=20TTY=20=E7=8E=AF=E5=A2=83=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E6=B1=A1=E6=9F=93=E8=BE=93=E5=87=BA=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _generate_response_with_animation 的 show_animation 用 print("\r...") 逐帧输出情话+spinner,仅真终端能原地覆盖;被聊天前端/管道/ 日志镜像捕获时每帧(10/s)变成一行垃圾混进对话显示。 - 加 sys.stdout.isatty() 守卫:非 TTY 只输出一行静态 "AI 正在思考中…",不跑逐帧 \r 动画 - 两处清行动画行的 print("\r" + " "*80 + "\r") 也加 is_tty 守卫 - TUI 模式(tui_output_callback)本就跳过动画,不受影响 已验证:非 TTY 输出单行静态提示、TTY 仍正常逐帧动画。 --- xcli_core/cli_core.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/xcli_core/cli_core.py b/xcli_core/cli_core.py index 124eb26..7ebac15 100644 --- a/xcli_core/cli_core.py +++ b/xcli_core/cli_core.py @@ -963,6 +963,10 @@ multi 操作支持一次修改多处: response_ready = threading.Event() response_result = [None] # 用列表存储,方便线程内修改 + # 是否真实交互终端:非 TTY(管道 / 日志镜像 / 聊天前端捕获 stdout)时, + # \r 无法原地覆盖,逐帧动画会污染输出流,必须禁用。 + is_tty = sys.stdout.isatty() + love_sentences = [] love_file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), LOVE_FILE_PATH) if os.path.exists(love_file_path): @@ -1015,6 +1019,13 @@ multi 操作支持一次修改多处: # ── 动画线程 ── def show_animation(): + # 非 TTY:只输出一行静态提示,不跑逐帧 \r 动画(避免残帧进入捕获流) + if not is_tty: + try: + print("⏳ AI 正在思考中…", flush=True) + except Exception: + pass + return last_change_time = time.time() current_sentence = random.choice(love_sentences) while animation_running.is_set(): @@ -1058,7 +1069,8 @@ multi 操作支持一次修改多处: # ESC 被按下 → 取消 if esc_pressed.is_set(): # 清除动画行 - print("\r" + " " * 80 + "\r", end="", flush=True) + if is_tty: + print("\r" + " " * 80 + "\r", end="", flush=True) print(f"\n{Fore.YELLOW}⚡ AI 请求已取消 (ESC){Style.RESET_ALL}") return "[AI请求已取消]" @@ -1066,7 +1078,8 @@ multi 操作支持一次修改多处: response = response_result[0] if response: # 清除动画行后再输出 - print("\r" + " " * 80 + "\r", end="", flush=True) + if is_tty: + print("\r" + " " * 80 + "\r", end="", flush=True) self._typeprint(response, Fore.CYAN) if response and self.shared_conversation_history is not None: