From e4d978da7ce5422cd4d2a92d369985df6387ad79 Mon Sep 17 00:00:00 2001
From: Taylor Mullen <ntaylormullen@google.com>
Date: Sun, 18 May 2025 01:18:32 -0700
Subject: feat(cli): Introduce toggleable shell mode with enhanced UI

- Implements a toggleable shell mode, removing the need to prefix every command with `!`.
- Users can now enter and exit shell mode by typing `!` as the first character in an empty input prompt.
- The input prompt visually indicates active shell mode with a distinct color and `! ` prefix.
- Shell command history items (`user_shell`) are now visually differentiated from regular user messages.
- This provides a cleaner and more streamlined user experience for frequent shell interactions.

Fixes https://b.corp.google.com/issues/418509745
---
 packages/cli/src/ui/components/InputPrompt.tsx | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

(limited to 'packages/cli/src/ui/components/InputPrompt.tsx')

diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx
index b1e05554..c9ebaf14 100644
--- a/packages/cli/src/ui/components/InputPrompt.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.tsx
@@ -26,6 +26,8 @@ interface InputPromptProps {
   navigateSuggestionDown: () => void;
   setEditorState: (updater: (prevState: EditorState) => EditorState) => void;
   onClearScreen: () => void;
+  shellModeActive: boolean;
+  setShellModeActive: (value: boolean) => void;
 }
 
 export interface EditorState {
@@ -48,6 +50,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
   resetCompletion,
   setEditorState,
   onClearScreen,
+  shellModeActive,
+  setShellModeActive,
 }) => {
   const handleSubmit = useCallback(
     (submittedValue: string) => {
@@ -116,6 +120,11 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
       _currentText?: string,
       _cursorOffset?: number,
     ) => {
+      if (input === '!' && query === '' && !showSuggestions) {
+        setShellModeActive(!shellModeActive);
+        onChangeAndMoveCursor(''); // Clear the '!' from input
+        return true;
+      }
       if (showSuggestions) {
         if (key.upArrow) {
           navigateSuggestionUp();
@@ -186,12 +195,21 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
       inputHistory,
       setEditorState,
       onClearScreen,
+      shellModeActive,
+      setShellModeActive,
+      onChangeAndMoveCursor,
     ],
   );
 
   return (
-    <Box borderStyle="round" borderColor={Colors.AccentBlue} paddingX={1}>
-      <Text color={Colors.AccentPurple}>&gt; </Text>
+    <Box
+      borderStyle="round"
+      borderColor={shellModeActive ? Colors.AccentYellow : Colors.AccentBlue}
+      paddingX={1}
+    >
+      <Text color={shellModeActive ? Colors.AccentYellow : Colors.AccentPurple}>
+        {shellModeActive ? '! ' : '> '}
+      </Text>
       <Box flexGrow={1}>
         <MultilineTextEditor
           key={editorState.key.toString()}
-- 
cgit v1.2.3

