diff --git a/src/renderer/src/components/terminal-pane/TerminalPane.tsx b/src/renderer/src/components/terminal-pane/TerminalPane.tsx index 60b5308938f..76b189ed36b 100644 --- a/src/renderer/src/components/terminal-pane/TerminalPane.tsx +++ b/src/renderer/src/components/terminal-pane/TerminalPane.tsx @@ -45,7 +45,10 @@ import { } from '@/store/slices/runtime-environment-ssh' import { hydrateRuntimeEnvironmentSshState } from '@/runtime/runtime-environment-ssh-state' import { handleInternalTerminalFileDrop } from './terminal-drop-handler' -import { recordTerminalUserInputForLeaf } from './terminal-input-activity' +import { + markTerminalUserInputIntentForLeaf, + recordTerminalUserInputForLeaf +} from './terminal-input-activity' import { collectLeafIdsInOrder, EMPTY_LAYOUT, @@ -2029,6 +2032,9 @@ function TerminalPane( setTerminalError(formatTerminalPasteExecutionError(execution.reason)) return } + if (text) { + recordTerminalUserInputForLeaf(tabId, pane.leafId, ptyId) + } if (options?.recoverImagePasteWebglAtlas) { scheduleImagePasteWebglAtlasRecovery() } @@ -2053,7 +2059,7 @@ function TerminalPane( runtimeEnvironmentId, forceBracketedMultilineTextPaste, onPasteIntent: () => - recordTerminalUserInputForLeaf( + markTerminalUserInputIntentForLeaf( tabId, pane.leafId, paneTransportsRef.current.get(pane.id)?.getPtyId() @@ -2206,7 +2212,7 @@ function TerminalPane( runtimeEnvironmentId, forceBracketedMultilineTextPaste, onPasteIntent: () => - recordTerminalUserInputForLeaf( + markTerminalUserInputIntentForLeaf( tabId, pane.leafId, paneTransportsRef.current.get(pane.id)?.getPtyId() @@ -2696,7 +2702,7 @@ function TerminalPane( armPrimarySelectionNativePasteSuppression() clickedPane.terminal.focus() void readPrimarySelectionText(() => - recordTerminalUserInputForLeaf( + markTerminalUserInputIntentForLeaf( tabId, clickedPane.leafId, paneTransportsRef.current.get(clickedPane.id)?.getPtyId() @@ -2756,7 +2762,9 @@ function TerminalPane( }) if (execution.status !== 'pasted') { setTerminalError(formatTerminalPasteExecutionError(execution.reason)) + return } + recordTerminalUserInputForLeaf(tabId, clickedPane.leafId, ptyId) }) }, [getPrimarySelectionMiddleClickPane, tabId, worktreeId] diff --git a/src/renderer/src/components/terminal-pane/terminal-input-activity.ts b/src/renderer/src/components/terminal-pane/terminal-input-activity.ts index f1c37b9c67e..9d4ff4dd171 100644 --- a/src/renderer/src/components/terminal-pane/terminal-input-activity.ts +++ b/src/renderer/src/components/terminal-pane/terminal-input-activity.ts @@ -50,6 +50,24 @@ export function markTerminalUserInputForPtyId( } } +export function markTerminalUserInputIntentForLeaf( + tabId: string, + leafId: string, + ptyId?: string | null +): void { + try { + const state = useAppStore.getState() + const layoutPtyId = state.terminalLayoutsByTabId?.[tabId]?.ptyIdsByLeafId?.[leafId] + const tabPtyIds = state.ptyIdsByTabId?.[tabId] ?? [] + markTerminalUserInputForPtyId( + ptyId ?? layoutPtyId ?? (tabPtyIds.length === 1 ? tabPtyIds[0] : null), + makePaneKey(tabId, leafId) + ) + } catch { + // Malformed layouts cannot identify a safe draft-cancellation target. + } +} + export function recordTerminalUserInputForLeaf( tabId: string, leafId: string, diff --git a/src/renderer/src/components/terminal-pane/use-terminal-pane-context-menu.ts b/src/renderer/src/components/terminal-pane/use-terminal-pane-context-menu.ts index d8e8b2e8597..4f525b58b5b 100644 --- a/src/renderer/src/components/terminal-pane/use-terminal-pane-context-menu.ts +++ b/src/renderer/src/components/terminal-pane/use-terminal-pane-context-menu.ts @@ -41,7 +41,10 @@ import { recordCreatedTerminalPaneSplit } from './terminal-pane-split-completion import { splitTerminalPaneWithInheritedCwd } from './terminal-pane-split-with-inherited-cwd' import { useAppStore } from '@/store' import { translate } from '@/i18n/i18n' -import { recordTerminalUserInputForLeaf } from './terminal-input-activity' +import { + markTerminalUserInputIntentForLeaf, + recordTerminalUserInputForLeaf +} from './terminal-input-activity' import { copyTerminalHandleForPane } from './terminal-handle-copy' import { runCopyPaneId, runTerminalCopy } from './terminal-copy-rejection-guards' import { copyTerminalSelection } from './terminal-selection-copy' @@ -266,6 +269,9 @@ export function useTerminalPaneContextMenu({ onPasteError(formatTerminalPasteExecutionError(execution.reason)) return false } + if (text) { + recordTerminalUserInputForLeaf(tabId, pane.leafId, ptyId) + } if (options?.recoverImagePasteWebglAtlas) { scheduleImagePasteWebglAtlasRecovery() } @@ -321,7 +327,7 @@ export function useTerminalPaneContextMenu({ runtimeEnvironmentId, forceBracketedMultilineTextPaste, onPasteIntent: () => - recordTerminalUserInputForLeaf( + markTerminalUserInputIntentForLeaf( tabId, pane.leafId, paneTransportsRef.current.get(pane.id)?.getPtyId() diff --git a/src/renderer/src/lib/agent-paste-draft.test.ts b/src/renderer/src/lib/agent-paste-draft.test.ts index c40e49017aa..ed142b90b43 100644 --- a/src/renderer/src/lib/agent-paste-draft.test.ts +++ b/src/renderer/src/lib/agent-paste-draft.test.ts @@ -13,6 +13,7 @@ import { submitPromptToAgentPty } from './agent-paste-draft' import { + markTerminalUserInputIntentForLeaf, markTerminalUserInputForPtyId, recordTerminalUserInputForLeaf } from '@/components/terminal-pane/terminal-input-activity' @@ -444,7 +445,8 @@ describe('pasteDraftWhenAgentReady', () => { }) await flushMicrotasks() - recordTerminalUserInputForLeaf('tab-1', TARGET_LEAF_ID) + markTerminalUserInputIntentForLeaf('tab-1', TARGET_LEAF_ID) + expect(testState.appState.recordTerminalInput).not.toHaveBeenCalled() testState.appState.terminalLayoutsByTabId = { 'tab-1': { ptyIdsByLeafId: {