Merge branch 'main' into feat/mcp-tui

This commit is contained in:
LaZzyMan 2026-02-25 16:31:42 +08:00
commit 1542a2bdc4
114 changed files with 6943 additions and 1324 deletions

View file

@ -696,7 +696,6 @@ export const AppContainer = (props: AppContainerProps) => {
terminalWidth,
terminalHeight,
handleVisionSwitchRequired, // onVisionSwitchRequired
embeddedShellFocused,
);
// Track whether suggestions are visible for Tab key handling
@ -904,6 +903,8 @@ export const AppContainer = (props: AppContainerProps) => {
const ctrlCTimerRef = useRef<NodeJS.Timeout | null>(null);
const [ctrlDPressedOnce, setCtrlDPressedOnce] = useState(false);
const ctrlDTimerRef = useRef<NodeJS.Timeout | null>(null);
const [escapePressedOnce, setEscapePressedOnce] = useState(false);
const escapeTimerRef = useRef<NodeJS.Timeout | null>(null);
const [constrainHeight, setConstrainHeight] = useState<boolean>(true);
const [ideContextState, setIdeContextState] = useState<
IdeContext | undefined
@ -1180,6 +1181,47 @@ export const AppContainer = (props: AppContainerProps) => {
}
handleExit(ctrlDPressedOnce, setCtrlDPressedOnce, ctrlDTimerRef);
return;
} else if (keyMatchers[Command.ESCAPE](key)) {
// Escape key handling
// Skip if shell is focused (to allow shell's own escape handling)
if (embeddedShellFocused) {
return;
}
// If input has content, use double-press to clear
if (buffer.text.length > 0) {
if (escapePressedOnce) {
// Second press: clear input, keep the flag to allow immediate cancel
buffer.setText('');
return;
}
// First press: set flag and show prompt
setEscapePressedOnce(true);
escapeTimerRef.current = setTimeout(() => {
setEscapePressedOnce(false);
escapeTimerRef.current = null;
}, CTRL_EXIT_PROMPT_DURATION_MS);
return;
}
// Input is empty, cancel request immediately (no double-press needed)
if (streamingState === StreamingState.Responding) {
if (escapeTimerRef.current) {
clearTimeout(escapeTimerRef.current);
escapeTimerRef.current = null;
}
cancelOngoingRequest?.();
setEscapePressedOnce(false);
return;
}
// No action available, reset the flag
if (escapeTimerRef.current) {
clearTimeout(escapeTimerRef.current);
escapeTimerRef.current = null;
}
setEscapePressedOnce(false);
return;
}
let enteringConstrainHeightMode = false;
@ -1224,10 +1266,15 @@ export const AppContainer = (props: AppContainerProps) => {
ctrlCPressedOnce,
setCtrlCPressedOnce,
ctrlCTimerRef,
buffer.text.length,
ctrlDPressedOnce,
setCtrlDPressedOnce,
ctrlDTimerRef,
escapePressedOnce,
setEscapePressedOnce,
escapeTimerRef,
streamingState,
cancelOngoingRequest,
buffer,
handleSlashCommand,
activePtyId,
embeddedShellFocused,