@@ -375,7 +375,7 @@ describe('ChatInputWorkspaceStrip git refresh behavior', () => {
375375 expect ( document . querySelector ( '[data-testid="chat-input-permission-menu"]' ) ) . toBeNull ( ) ;
376376 } ) ;
377377
378- it ( 'chooses the scope per click instead of through a separate toggle ' , async ( ) => {
378+ it ( 'keeps session selection primary and opens one-off choices as a second level ' , async ( ) => {
379379 const onChange = vi . fn ( ) ;
380380 const onChangeForNextTurn = vi . fn ( ) ;
381381 await act ( async ( ) => {
@@ -409,10 +409,17 @@ describe('ChatInputWorkspaceStrip git refresh behavior', () => {
409409 expect ( onChange ) . toHaveBeenCalledWith ( 'auto' ) ;
410410 expect ( onChangeForNextTurn ) . not . toHaveBeenCalled ( ) ;
411411
412- // The trailing button is the one-off scope, and never writes the session.
412+ // One-off scope is a named second level, not an unexplained checkbox on
413+ // every session row.
413414 await act ( async ( ) => {
414415 trigger ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
415416 } ) ;
417+ expect ( document . querySelector ( '[role="menuitemcheckbox"]' ) ) . toBeNull ( ) ;
418+ await act ( async ( ) => {
419+ document
420+ . querySelector < HTMLButtonElement > ( '[data-testid="chat-input-permission-turn-scope"]' )
421+ ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
422+ } ) ;
416423 await act ( async ( ) => {
417424 document
418425 . querySelector < HTMLButtonElement > (
@@ -435,7 +442,7 @@ describe('ChatInputWorkspaceStrip git refresh behavior', () => {
435442 mode : 'ask' ,
436443 activeTurn : true ,
437444 nextTurnMode : null ,
438- scopeLabel : 'chatInput.permissionMode.activeTurnScope ' ,
445+ scopeLabel : 'This session ' ,
439446 onChange : vi . fn ( ) ,
440447 onChangeForNextTurn,
441448 } }
@@ -450,21 +457,122 @@ describe('ChatInputWorkspaceStrip git refresh behavior', () => {
450457 await act ( async ( ) => {
451458 trigger ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
452459 } ) ;
460+ expect ( document . body . textContent ) . toContain ( 'This session' ) ;
461+ expect (
462+ document . querySelector ( '[data-testid="chat-input-permission-turn-scope"]' ) ?. textContent ,
463+ ) . toContain ( 'chatInput.permissionMode.activeTurnSettings' ) ;
464+ await act ( async ( ) => {
465+ document
466+ . querySelector < HTMLButtonElement > ( '[data-testid="chat-input-permission-turn-scope"]' )
467+ ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
468+ } ) ;
453469
454470 const oneOff = document . querySelector < HTMLButtonElement > (
455471 '[data-testid="chat-input-permission-next-turn-auto"]' ,
456472 ) ;
457473 expect ( oneOff ?. getAttribute ( 'aria-label' ) ) . toBe (
458474 'chatInput.permissionMode.activeTurnOnly' ,
459475 ) ;
460- expect ( oneOff ?. getAttribute ( 'role' ) ) . toBe ( 'menuitemcheckbox' ) ;
476+ expect ( oneOff ?. getAttribute ( 'role' ) ) . toBe ( 'menuitemradio' ) ;
477+ expect ( document . body . textContent ) . toContain ( 'chatInput.permissionMode.activeTurnScope' ) ;
461478
462479 await act ( async ( ) => {
463480 oneOff ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
464481 } ) ;
465482 expect ( onChangeForNextTurn ) . toHaveBeenCalledWith ( 'auto' ) ;
466483 } ) ;
467484
485+ it ( 'clears a one-off override through the explicit follow-session choice' , async ( ) => {
486+ const onChangeForNextTurn = vi . fn ( ) ;
487+ await act ( async ( ) => {
488+ root . render (
489+ < ChatInputWorkspaceStrip
490+ repositoryPath = ""
491+ workspaceLabel = ""
492+ permissionControl = { {
493+ mode : 'auto' ,
494+ nextTurnMode : 'full_access' ,
495+ onChange : vi . fn ( ) ,
496+ onChangeForNextTurn,
497+ } }
498+ />
499+ ) ;
500+ } ) ;
501+
502+ await act ( async ( ) => {
503+ container
504+ . querySelector < HTMLButtonElement > ( '[data-testid="chat-input-permission-trigger"]' )
505+ ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
506+ } ) ;
507+ await act ( async ( ) => {
508+ document
509+ . querySelector < HTMLButtonElement > ( '[data-testid="chat-input-permission-turn-scope"]' )
510+ ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
511+ } ) ;
512+
513+ const followSession = document . querySelector < HTMLButtonElement > (
514+ '[data-testid="chat-input-permission-follow-session"]' ,
515+ ) ;
516+ expect ( followSession ?. getAttribute ( 'role' ) ) . toBe ( 'menuitemradio' ) ;
517+ expect ( followSession ?. getAttribute ( 'aria-checked' ) ) . toBe ( 'false' ) ;
518+
519+ await act ( async ( ) => {
520+ followSession ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
521+ } ) ;
522+ expect ( onChangeForNextTurn ) . toHaveBeenCalledWith ( 'full_access' ) ;
523+ expect ( document . querySelector ( '[data-testid="chat-input-permission-menu"]' ) ) . toBeNull ( ) ;
524+ } ) ;
525+
526+ it ( 'opens the one-off level on click or Right Arrow, never on hover' , async ( ) => {
527+ await act ( async ( ) => {
528+ root . render (
529+ < ChatInputWorkspaceStrip
530+ repositoryPath = ""
531+ workspaceLabel = ""
532+ permissionControl = { {
533+ mode : 'ask' ,
534+ onChange : vi . fn ( ) ,
535+ onChangeForNextTurn : vi . fn ( ) ,
536+ } }
537+ />
538+ ) ;
539+ } ) ;
540+
541+ await act ( async ( ) => {
542+ container
543+ . querySelector < HTMLButtonElement > ( '[data-testid="chat-input-permission-trigger"]' )
544+ ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
545+ } ) ;
546+ const scope = document . querySelector < HTMLButtonElement > (
547+ '[data-testid="chat-input-permission-turn-scope"]' ,
548+ ) ;
549+ await act ( async ( ) => {
550+ scope ?. dispatchEvent ( new MouseEvent ( 'pointerenter' , { bubbles : true } ) ) ;
551+ } ) ;
552+ expect ( document . querySelector ( '[data-testid="chat-input-permission-follow-session"]' ) )
553+ . toBeNull ( ) ;
554+
555+ await act ( async ( ) => {
556+ scope ?. dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'ArrowRight' , bubbles : true } ) ) ;
557+ } ) ;
558+ expect ( document . querySelector ( '[data-testid="chat-input-permission-follow-session"]' ) )
559+ . not . toBeNull ( ) ;
560+ expect ( document . querySelector ( '[role="menuitemcheckbox"]' ) ) . toBeNull ( ) ;
561+ expect (
562+ document
563+ . querySelector ( '[data-testid="chat-input-permission-turn-back"]' )
564+ ?. getAttribute ( 'aria-label' ) ,
565+ ) . toBe ( 'chatInput.permissionMode.backToSessionSettings' ) ;
566+
567+ await act ( async ( ) => {
568+ document
569+ . querySelector < HTMLElement > ( '[data-testid="chat-input-permission-menu"]' )
570+ ?. dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'ArrowLeft' , bubbles : true } ) ) ;
571+ } ) ;
572+ expect ( document . querySelector ( '[data-testid="chat-input-permission-turn-scope"]' ) )
573+ . not . toBeNull ( ) ;
574+ } ) ;
575+
468576 it ( 'keeps the mode descriptions out of the row and in the accessible name' , async ( ) => {
469577 await act ( async ( ) => {
470578 root . render (
@@ -515,6 +623,15 @@ describe('ChatInputWorkspaceStrip git refresh behavior', () => {
515623 await act ( async ( ) => {
516624 trigger ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
517625 } ) ;
626+ expect ( document . querySelector ( '[role="menuitemcheckbox"]' ) ) . toBeNull ( ) ;
627+ expect (
628+ document . querySelector ( '[data-testid="chat-input-permission-turn-scope"]' ) ?. textContent ,
629+ ) . toContain ( 'chatInput.permissionMode.fullAccess.label' ) ;
630+ await act ( async ( ) => {
631+ document
632+ . querySelector < HTMLButtonElement > ( '[data-testid="chat-input-permission-turn-scope"]' )
633+ ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
634+ } ) ;
518635 expect (
519636 document
520637 . querySelector ( '[data-testid="chat-input-permission-next-turn-full_access"]' )
@@ -542,7 +659,7 @@ describe('ChatInputWorkspaceStrip git refresh behavior', () => {
542659 ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
543660 } ) ;
544661 expect (
545- document . querySelector ( '[data-testid="chat-input-permission-next- turn-ask "]' ) ,
662+ document . querySelector ( '[data-testid="chat-input-permission-turn-scope "]' ) ,
546663 ) . toBeNull ( ) ;
547664 } ) ;
548665
@@ -581,6 +698,14 @@ describe('ChatInputWorkspaceStrip git refresh behavior', () => {
581698 expect (
582699 document . querySelector ( '[data-testid="chat-input-permission-selected-full_access"]' ) ,
583700 ) . toBeNull ( ) ;
701+ expect (
702+ document . querySelector ( '[data-testid="chat-input-permission-next-turn-full_access"]' ) ,
703+ ) . toBeNull ( ) ;
704+ await act ( async ( ) => {
705+ document
706+ . querySelector < HTMLButtonElement > ( '[data-testid="chat-input-permission-turn-scope"]' )
707+ ?. dispatchEvent ( new MouseEvent ( 'click' , { bubbles : true } ) ) ;
708+ } ) ;
584709 expect (
585710 document
586711 . querySelector ( '[data-testid="chat-input-permission-next-turn-full_access"]' )
0 commit comments