@@ -546,13 +546,161 @@ describe("monitorSlackProvider tool results", () => {
546546 } ) ,
547547 } ) ;
548548
549+ expect ( reactMock ) . toHaveBeenCalledWith ( {
550+ channel : "C1" ,
551+ timestamp : "456" ,
552+ name : "eyes" ,
553+ } ) ;
554+ } ) ;
555+
556+ it ( "keeps ack reaction when no reply is delivered and status reactions are disabled" , async ( ) => {
557+ replyMock . mockResolvedValue ( undefined ) ;
558+ slackTestState . config = {
559+ messages : {
560+ responsePrefix : "PFX" ,
561+ ackReaction : "👀" ,
562+ ackReactionScope : "group-mentions" ,
563+ removeAckAfterReply : true ,
564+ statusReactions : { enabled : false } ,
565+ } ,
566+ channels : {
567+ slack : {
568+ dm : { enabled : true , policy : "open" , allowFrom : [ "*" ] } ,
569+ groupPolicy : "open" ,
570+ } ,
571+ } ,
572+ } ;
573+ const client = getSlackClient ( ) ;
574+ if ( ! client ) {
575+ throw new Error ( "Slack client not registered" ) ;
576+ }
577+ const conversations = client . conversations as {
578+ info : ReturnType < typeof vi . fn > ;
579+ } ;
580+ conversations . info . mockResolvedValueOnce ( {
581+ channel : { name : "general" , is_channel : true } ,
582+ } ) ;
583+
584+ await runSlackMessageOnce ( monitorSlackProvider , {
585+ event : makeSlackMessageEvent ( {
586+ text : "<@bot-user> hello" ,
587+ ts : "456" ,
588+ channel_type : "channel" ,
589+ } ) ,
590+ } ) ;
591+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
592+ await flush ( ) ;
593+
594+ expect ( sendMock ) . not . toHaveBeenCalled ( ) ;
595+ expect ( reactMock ) . toHaveBeenCalledTimes ( 1 ) ;
549596 expect ( reactMock ) . toHaveBeenCalledWith ( {
550597 channel : "C1" ,
551598 timestamp : "456" ,
552599 name : "👀" ,
553600 } ) ;
554601 } ) ;
555602
603+ it ( "keeps ack reaction when no reply is delivered and status reactions are enabled" , async ( ) => {
604+ replyMock . mockResolvedValue ( undefined ) ;
605+ slackTestState . config = {
606+ messages : {
607+ responsePrefix : "PFX" ,
608+ ackReaction : "👀" ,
609+ ackReactionScope : "group-mentions" ,
610+ removeAckAfterReply : true ,
611+ statusReactions : {
612+ enabled : true ,
613+ timing : { debounceMs : 0 , doneHoldMs : 0 , errorHoldMs : 0 } ,
614+ } ,
615+ } ,
616+ channels : {
617+ slack : {
618+ dm : { enabled : true , policy : "open" , allowFrom : [ "*" ] } ,
619+ groupPolicy : "open" ,
620+ } ,
621+ } ,
622+ } ;
623+ const client = getSlackClient ( ) ;
624+ if ( ! client ) {
625+ throw new Error ( "Slack client not registered" ) ;
626+ }
627+ const conversations = client . conversations as {
628+ info : ReturnType < typeof vi . fn > ;
629+ } ;
630+ conversations . info . mockResolvedValueOnce ( {
631+ channel : { name : "general" , is_channel : true } ,
632+ } ) ;
633+
634+ await runSlackMessageOnce ( monitorSlackProvider , {
635+ event : makeSlackMessageEvent ( {
636+ text : "<@bot-user> hello" ,
637+ ts : "456" ,
638+ channel_type : "channel" ,
639+ } ) ,
640+ } ) ;
641+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
642+ await flush ( ) ;
643+
644+ expect ( sendMock ) . not . toHaveBeenCalled ( ) ;
645+ expect ( reactMock ) . toHaveBeenCalledTimes ( 1 ) ;
646+ expect ( reactMock ) . toHaveBeenCalledWith ( {
647+ channel : "C1" ,
648+ timestamp : "456" ,
649+ name : "eyes" ,
650+ } ) ;
651+ } ) ;
652+
653+ it ( "restores ack reaction when dispatch fails before any reply is delivered" , async ( ) => {
654+ replyMock . mockRejectedValue ( new Error ( "boom" ) ) ;
655+ slackTestState . config = {
656+ messages : {
657+ responsePrefix : "PFX" ,
658+ ackReaction : "👀" ,
659+ ackReactionScope : "group-mentions" ,
660+ removeAckAfterReply : true ,
661+ statusReactions : {
662+ enabled : true ,
663+ timing : { debounceMs : 0 , doneHoldMs : 0 , errorHoldMs : 0 } ,
664+ } ,
665+ } ,
666+ channels : {
667+ slack : {
668+ dm : { enabled : true , policy : "open" , allowFrom : [ "*" ] } ,
669+ groupPolicy : "open" ,
670+ } ,
671+ } ,
672+ } ;
673+ const client = getSlackClient ( ) ;
674+ if ( ! client ) {
675+ throw new Error ( "Slack client not registered" ) ;
676+ }
677+ const conversations = client . conversations as {
678+ info : ReturnType < typeof vi . fn > ;
679+ } ;
680+ conversations . info . mockResolvedValueOnce ( {
681+ channel : { name : "general" , is_channel : true } ,
682+ } ) ;
683+
684+ await runSlackMessageOnce ( monitorSlackProvider , {
685+ event : makeSlackMessageEvent ( {
686+ text : "<@bot-user> hello" ,
687+ ts : "456" ,
688+ channel_type : "channel" ,
689+ } ) ,
690+ } ) ;
691+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
692+ await flush ( ) ;
693+
694+ expect ( sendMock ) . not . toHaveBeenCalled ( ) ;
695+ expect ( reactMock . mock . calls . map ( ( [ args ] ) => String ( ( args as { name : string } ) . name ) ) ) . toEqual ( [
696+ "eyes" ,
697+ "scream" ,
698+ "eyes" ,
699+ "eyes" ,
700+ "scream" ,
701+ ] ) ;
702+ } ) ;
703+
556704 it ( "replies with pairing code when dmPolicy is pairing and no allowFrom is set" , async ( ) => {
557705 setPairingOnlyDirectMessages ( ) ;
558706
0 commit comments