feat: add clickable overlay buttons for CLI prompts in Shell terminal (#480)

* feat: add clickable overlay buttons for CLI prompt selection

Detect numbered selection prompts in the xterm.js terminal buffer
and display clickable overlay buttons, allowing users to respond
by tapping instead of typing numbers. Useful on mobile/tablet devices.

Closes #427

* fix: address CodeRabbit review feedback

- Remove fallback option scanning without footer anchor to prevent
  false positives on regular numbered lists in conversation output
- Cancel pending prompt check timer on disconnect to prevent stale
  options from reappearing after reconnection

* fix: require contiguous option block above footer anchor

Stop collecting numbered options as soon as a non-matching line is
encountered, preventing false matches from non-contiguous numbered
text above the prompt.

Addresses CodeRabbit review feedback on PR #480.

* revert: allow non-contiguous option lines for multi-line labels

CLI prompts may wrap options across multiple terminal rows or include
blank separators. Revert contiguous-block requirement and document
why non-matching lines are tolerated during upward scan.
This commit is contained in:
PaloSP
2026-03-05 09:35:28 +01:00
committed by GitHub
parent 0590c5c178
commit 2444209723
5 changed files with 153 additions and 3 deletions

View File

@@ -24,6 +24,7 @@ type UseShellConnectionOptions = {
closeSocket: () => void;
clearTerminalScreen: () => void;
setAuthUrl: (nextAuthUrl: string) => void;
onOutputRef?: MutableRefObject<(() => void) | null>;
};
type UseShellConnectionResult = {
@@ -48,6 +49,7 @@ export function useShellConnection({
closeSocket,
clearTerminalScreen,
setAuthUrl,
onOutputRef,
}: UseShellConnectionOptions): UseShellConnectionResult {
const [isConnected, setIsConnected] = useState(false);
const [isConnecting, setIsConnecting] = useState(false);
@@ -91,6 +93,7 @@ export function useShellConnection({
const output = typeof message.data === 'string' ? message.data : '';
handleProcessCompletion(output);
terminalRef.current?.write(output);
onOutputRef?.current?.();
return;
}
@@ -101,7 +104,7 @@ export function useShellConnection({
}
}
},
[handleProcessCompletion, setAuthUrl, terminalRef],
[handleProcessCompletion, onOutputRef, setAuthUrl, terminalRef],
);
const connectWebSocket = useCallback(

View File

@@ -15,6 +15,7 @@ export function useShellRuntime({
autoConnect,
isRestarting,
onProcessComplete,
onOutputRef,
}: UseShellRuntimeOptions): UseShellRuntimeResult {
const terminalContainerRef = useRef<HTMLDivElement>(null);
const terminalRef = useRef<Terminal | null>(null);
@@ -118,6 +119,7 @@ export function useShellRuntime({
closeSocket,
clearTerminalScreen,
setAuthUrl: setCurrentAuthUrl,
onOutputRef,
});
useEffect(() => {