From 7cd72d58f513552ea8439b557547f3e58f14cb2e Mon Sep 17 00:00:00 2001 From: LeaFluorine <3377422475@qq.com> Date: Mon, 14 Sep 2026 15:20:36 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E4=BC=9A=E8=AF=9D=E5=BB=BA=E7=AB=8B?= =?UTF-8?q?=E6=97=B6=E6=8A=8A=E7=BB=88=E7=AB=AF=E5=AE=9E=E9=99=85=E5=B0=BA?= =?UTF-8?q?=E5=AF=B8=E5=90=8C=E6=AD=A5=E7=BB=99=20PTY?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/src/components/app/TerminalPanel.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/renderer/src/components/app/TerminalPanel.tsx b/src/renderer/src/components/app/TerminalPanel.tsx index 0b98b8f..92e9551 100644 --- a/src/renderer/src/components/app/TerminalPanel.tsx +++ b/src/renderer/src/components/app/TerminalPanel.tsx @@ -611,6 +611,20 @@ export function TerminalPanel({ sessionsRef.current.set(snapshot.id, snapshot); upsertUserTerminal(snapshot); void loadSessionBuffer(snapshot.id); + + // PTY 由主进程按固定尺寸创建(service-manager 的 SERVICE_TERMINAL_COLS/ROWS)。 + // 此时 xterm 通常已按面板尺寸 fit 完毕,尺寸不会再变化,terminal.onResize + // 也就不会触发,PTY 会长期停留在主进程的默认尺寸上:子进程按错误宽度排版, + // 依赖行数的相对光标移动(tqdm/rich 等进度条重绘)会算错行,画面被覆盖。 + // 快照是在 spawn 之后、子进程尚未输出时发出的,在这里同步一次真实尺寸最干净。 + const snapshotInstance = terminalsRef.current.get(snapshot.id); + if (snapshotInstance?.opened) { + const { cols, rows } = snapshotInstance.terminal; + if (cols > 0 && rows > 0 && (snapshot.cols !== cols || snapshot.rows !== rows)) { + void bridge.pty.resize({ sessionId: snapshot.id, cols, rows }).catch(() => undefined); + } + } + notifySessionsChanged(); }), bridge.logs.onEntry((entry) => { From 7a95cd73148c8e7af66999d8641a058dd43febc6 Mon Sep 17 00:00:00 2001 From: LeaFluorine <3377422475@qq.com> Date: Mon, 14 Sep 2026 15:21:37 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E4=B8=BA=20xterm=20=E5=A3=B0?= =?UTF-8?q?=E6=98=8E=20ConPTY=20=E5=90=8E=E7=AB=AF=E4=BB=A5=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E8=A1=8C=E5=A2=9E=E9=95=BF=E8=AF=AD=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/src/components/app/TerminalPanel.tsx | 3 +++ src/renderer/src/lib/platform.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/components/app/TerminalPanel.tsx b/src/renderer/src/components/app/TerminalPanel.tsx index 92e9551..b204405 100644 --- a/src/renderer/src/components/app/TerminalPanel.tsx +++ b/src/renderer/src/components/app/TerminalPanel.tsx @@ -8,6 +8,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import "@xterm/xterm/css/xterm.css"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; +import { detectPlatformSync } from "@/lib/platform"; import { useShortcut } from "@/lib/use-shortcut"; import { cn } from "@/lib/utils"; @@ -41,6 +42,7 @@ const serviceTerminals: Array<{ serviceId: ServiceId; sessionId: string; title: ]; const USER_TERMINAL_SESSION_PREFIX = "user-terminal:"; +const IS_WINDOWS_PLATFORM = detectPlatformSync() === "win32"; const MIN_VISIBLE_TERMINAL_WIDTH = 240; const MIN_VISIBLE_TERMINAL_HEIGHT = 120; const TERMINAL_LINK_PATTERN = /\b(?:https?:\/\/[^\s<>"',。;)\])]+|logs\/[^\s<>"',。;)\])]+\.(?:html|txt|json|log))/giu; @@ -382,6 +384,7 @@ export function TerminalPanel({ rescaleOverlappingGlyphs: true, scrollback: 100_000, tabStopWidth: 8, + ...(IS_WINDOWS_PLATFORM ? { windowsPty: { backend: "conpty" as const } } : {}), theme: XTERM_THEME, }); const fitAddon = new FitAddon(); diff --git a/src/renderer/src/lib/platform.ts b/src/renderer/src/lib/platform.ts index 88ea6c1..62d9604 100644 --- a/src/renderer/src/lib/platform.ts +++ b/src/renderer/src/lib/platform.ts @@ -6,7 +6,7 @@ export type Platform = "darwin" | "win32" | "linux"; let cachedPlatform: Platform | null = null; const subscribers = new Set<(p: Platform) => void>(); -function detectPlatformSync(): Platform { +export function detectPlatformSync(): Platform { if (typeof navigator === "undefined") return "linux"; const ua = `${navigator.platform || ""} ${navigator.userAgent || ""}`; if (/Mac|iPhone|iPad|iPod/i.test(ua)) return "darwin";