@@ -223,6 +223,13 @@ impl EventLoop {
223223 return Ok ( ( ) ) ;
224224 }
225225
226+ // Handle inline approval UI when pending approval exists
227+ if self . app_state . pending_approval . is_some ( ) {
228+ if self . handle_inline_approval_key ( key_event, terminal) . await ? {
229+ return Ok ( ( ) ) ;
230+ }
231+ }
232+
226233 // Check if a card is active and handle its input first
227234 if self . card_handler . is_active ( ) && self . card_handler . handle_key ( key_event) {
228235 // Process any pending card actions
@@ -502,6 +509,183 @@ impl EventLoop {
502509 }
503510 }
504511
512+ /// Handle inline approval UI key events.
513+ /// Returns true if the key was handled (approval action taken), false otherwise.
514+ async fn handle_inline_approval_key (
515+ & mut self ,
516+ key_event : crossterm:: event:: KeyEvent ,
517+ terminal : & mut CortexTerminal ,
518+ ) -> Result < bool > {
519+ use crossterm:: event:: KeyCode ;
520+ use crate :: app:: { InlineApprovalSelection , RiskLevelSelection } ;
521+
522+ // Check if risk level submenu is visible
523+ let show_submenu = self . app_state . pending_approval
524+ . as_ref ( )
525+ . map ( |a| a. show_risk_submenu )
526+ . unwrap_or ( false ) ;
527+
528+ if show_submenu {
529+ // Handle risk level submenu keys
530+ match key_event. code {
531+ KeyCode :: Char ( '1' ) => {
532+ // Select Low risk level and approve
533+ self . handle_approve_with_risk_level ( RiskLevelSelection :: Low ) . await ?;
534+ self . render ( terminal) ?;
535+ return Ok ( true ) ;
536+ }
537+ KeyCode :: Char ( '2' ) => {
538+ // Select Medium risk level and approve
539+ self . handle_approve_with_risk_level ( RiskLevelSelection :: Medium ) . await ?;
540+ self . render ( terminal) ?;
541+ return Ok ( true ) ;
542+ }
543+ KeyCode :: Char ( '3' ) => {
544+ // Select High risk level and approve
545+ self . handle_approve_with_risk_level ( RiskLevelSelection :: High ) . await ?;
546+ self . render ( terminal) ?;
547+ return Ok ( true ) ;
548+ }
549+ KeyCode :: Esc => {
550+ // Close submenu, back to main approval UI
551+ if let Some ( ref mut approval) = self . app_state . pending_approval {
552+ approval. show_risk_submenu = false ;
553+ }
554+ self . render ( terminal) ?;
555+ return Ok ( true ) ;
556+ }
557+ KeyCode :: Left => {
558+ // Navigate risk level selection left
559+ if let Some ( ref mut approval) = self . app_state . pending_approval {
560+ approval. selected_risk_level = approval. selected_risk_level . prev ( ) ;
561+ }
562+ self . render ( terminal) ?;
563+ return Ok ( true ) ;
564+ }
565+ KeyCode :: Right => {
566+ // Navigate risk level selection right
567+ if let Some ( ref mut approval) = self . app_state . pending_approval {
568+ approval. selected_risk_level = approval. selected_risk_level . next ( ) ;
569+ }
570+ self . render ( terminal) ?;
571+ return Ok ( true ) ;
572+ }
573+ KeyCode :: Enter => {
574+ // Confirm selected risk level
575+ let risk_level = self . app_state . pending_approval
576+ . as_ref ( )
577+ . map ( |a| a. selected_risk_level )
578+ . unwrap_or_default ( ) ;
579+ self . handle_approve_with_risk_level ( risk_level) . await ?;
580+ self . render ( terminal) ?;
581+ return Ok ( true ) ;
582+ }
583+ _ => {
584+ // Consume other keys when submenu is visible
585+ return Ok ( true ) ;
586+ }
587+ }
588+ }
589+
590+ // Handle main approval UI keys
591+ match key_event. code {
592+ KeyCode :: Char ( 'y' ) | KeyCode :: Char ( 'Y' ) => {
593+ // Accept once
594+ self . handle_approve ( ) . await ?;
595+ self . render ( terminal) ?;
596+ Ok ( true )
597+ }
598+ KeyCode :: Char ( 'n' ) | KeyCode :: Char ( 'N' ) | KeyCode :: Esc => {
599+ // Reject
600+ self . handle_reject ( ) . await ?;
601+ self . render ( terminal) ?;
602+ Ok ( true )
603+ }
604+ KeyCode :: Char ( 'a' ) | KeyCode :: Char ( 'A' ) => {
605+ // Show risk level submenu
606+ if let Some ( ref mut approval) = self . app_state . pending_approval {
607+ approval. show_risk_submenu = true ;
608+ approval. selected_risk_level = RiskLevelSelection :: default ( ) ;
609+ }
610+ self . render ( terminal) ?;
611+ Ok ( true )
612+ }
613+ KeyCode :: Left => {
614+ // Navigate selection left
615+ if let Some ( ref mut approval) = self . app_state . pending_approval {
616+ approval. selected_action = approval. selected_action . prev ( ) ;
617+ }
618+ self . render ( terminal) ?;
619+ Ok ( true )
620+ }
621+ KeyCode :: Right => {
622+ // Navigate selection right
623+ if let Some ( ref mut approval) = self . app_state . pending_approval {
624+ approval. selected_action = approval. selected_action . next ( ) ;
625+ }
626+ self . render ( terminal) ?;
627+ Ok ( true )
628+ }
629+ KeyCode :: Enter => {
630+ // Confirm selected action
631+ let action = self . app_state . pending_approval
632+ . as_ref ( )
633+ . map ( |a| a. selected_action )
634+ . unwrap_or_default ( ) ;
635+ match action {
636+ InlineApprovalSelection :: AcceptOnce => {
637+ self . handle_approve ( ) . await ?;
638+ }
639+ InlineApprovalSelection :: Reject => {
640+ self . handle_reject ( ) . await ?;
641+ }
642+ InlineApprovalSelection :: AcceptAndSet => {
643+ // Show risk level submenu
644+ if let Some ( ref mut approval) = self . app_state . pending_approval {
645+ approval. show_risk_submenu = true ;
646+ approval. selected_risk_level = RiskLevelSelection :: default ( ) ;
647+ }
648+ }
649+ }
650+ self . render ( terminal) ?;
651+ Ok ( true )
652+ }
653+ _ => {
654+ // Don't consume other keys - allow them to pass through
655+ // This allows things like Ctrl+C to work
656+ Ok ( false )
657+ }
658+ }
659+ }
660+
661+ /// Handle approval with risk level - approves the tool and updates permission mode
662+ async fn handle_approve_with_risk_level (
663+ & mut self ,
664+ risk_level : crate :: app:: RiskLevelSelection ,
665+ ) -> Result < ( ) > {
666+ use crate :: app:: RiskLevelSelection ;
667+ use crate :: permissions:: PermissionMode ;
668+
669+ // Update permission mode based on selected risk level
670+ self . app_state . permission_mode = match risk_level {
671+ RiskLevelSelection :: Low => PermissionMode :: Low ,
672+ RiskLevelSelection :: Medium => PermissionMode :: Medium ,
673+ RiskLevelSelection :: High => PermissionMode :: High ,
674+ } ;
675+
676+ // Sync permission mode with the manager
677+ self . sync_permission_mode ( ) ;
678+
679+ // Show toast notification about the mode change
680+ let mode_name = self . app_state . permission_mode . display_name ( ) ;
681+ self . app_state . toasts . info ( & format ! ( "Risk level set to: {}" , mode_name) ) ;
682+
683+ // Now approve the tool
684+ self . handle_approve ( ) . await ?;
685+
686+ Ok ( ( ) )
687+ }
688+
505689 /// Handle terminal resize event
506690 fn handle_resize (
507691 & mut self ,
0 commit comments