diff --git a/frontend/src/components/panels/TerminalPanel.tsx b/frontend/src/components/panels/TerminalPanel.tsx index 43106bdd..c3f73f7e 100644 --- a/frontend/src/components/panels/TerminalPanel.tsx +++ b/frontend/src/components/panels/TerminalPanel.tsx @@ -122,6 +122,7 @@ export const TerminalPanel: React.FC = React.memo(({ panel, const isCliPanel = !!terminalState?.isCliPanel; const [isCliReady, setIsCliReady] = useState(!!terminalState?.isCliReady); const isRemoteMode = useConfigStore((state) => state.config?.remoteDaemon?.client.mode === 'remote'); + const isCliPanelRef = useRef(isCliPanel); // ptyId for the current PTY behind this panel, delivered via // `terminal:ptyReady` when spawned through the ptyHost UtilityProcess. @@ -148,6 +149,10 @@ export const TerminalPanel: React.FC = React.memo(({ panel, // Sync isCliReady from panel prop when it changes (e.g. backend persisted isCliReady // before this component subscribed to the IPC event, or panel state was updated externally) + useEffect(() => { + isCliPanelRef.current = isCliPanel; + }, [isCliPanel]); + useEffect(() => { if (terminalState?.isCliReady && !isCliReady) { setIsCliReady(true); @@ -895,6 +900,21 @@ export const TerminalPanel: React.FC = React.memo(({ panel, // The "[Image] " prefix we used to add actually broke the parser's // path-detection — on Windows+WSL it caused Claude to cache the file but // never attach it to the API call (see commit 7b76ee5). + const pasteText = (text: string) => { + if (!terminal) return; + const shouldProtectMultilinePaste = isCliPanelRef.current && !tuiActiveRef.current && /[\r\n]/.test(text); + if (shouldProtectMultilinePaste) { + window.electronAPI.invoke( + 'terminal:input', + panel.id, + text.replace(/\r\n|\r|\n/g, '\x1b\r'), + ); + return; + } + + terminal.paste(text); + }; + const handlePaste = (e: ClipboardEvent) => { // Step 1: Check for images in browser clipboard (works on native Windows/macOS) const items = e.clipboardData?.items; @@ -978,7 +998,7 @@ export const TerminalPanel: React.FC = React.memo(({ panel, // No image found — forward the text content xterm would have pasted. if (text && !disposed && terminal) { - terminal.paste(text); + pasteText(text); } })(); };