@@ -579,6 +579,13 @@ function switchToSession(sessionId: string) {
579579 // Clear unread status when switching to this session
580580 clearUnreadStatus ( sessionId ) ;
581581
582+ // Clear any pending idle timer for this session (Bug 1 fix)
583+ const existingTimer = sessionIdleTimers . get ( sessionId ) ;
584+ if ( existingTimer ) {
585+ clearTimeout ( existingTimer ) ;
586+ sessionIdleTimers . delete ( sessionId ) ;
587+ }
588+
582589 // Focus and resize
583590 session . terminal . focus ( ) ;
584591 setTimeout ( ( ) => {
@@ -624,6 +631,13 @@ function closeSession(sessionId: string) {
624631 // Update UI indicator
625632 updateSessionState ( sessionId , false ) ;
626633
634+ // Clean up idle timer (Bug 2 fix)
635+ const existingTimer = sessionIdleTimers . get ( sessionId ) ;
636+ if ( existingTimer ) {
637+ clearTimeout ( existingTimer ) ;
638+ sessionIdleTimers . delete ( sessionId ) ;
639+ }
640+
627641 // Close PTY in main process
628642 ipcRenderer . send ( "close-session" , sessionId ) ;
629643
@@ -660,6 +674,13 @@ function deleteSession(sessionId: string) {
660674 // Remove from sessions map
661675 sessions . delete ( sessionId ) ;
662676
677+ // Clean up idle timer (Bug 2 fix)
678+ const existingTimer = sessionIdleTimers . get ( sessionId ) ;
679+ if ( existingTimer ) {
680+ clearTimeout ( existingTimer ) ;
681+ sessionIdleTimers . delete ( sessionId ) ;
682+ }
683+
663684 // Delete in main process (handles worktree removal)
664685 ipcRenderer . send ( "delete-session" , sessionId ) ;
665686
@@ -690,19 +711,27 @@ ipcRenderer.on("session-output", (_event, sessionId: string, data: string) => {
690711
691712 // Only mark as unread if this is not the active session
692713 if ( activeSessionId !== sessionId && session . hasActivePty && ! session . hasUnreadActivity ) {
693- // Clear any existing idle timer
694- const existingTimer = sessionIdleTimers . get ( sessionId ) ;
695- if ( existingTimer ) {
696- clearTimeout ( existingTimer ) ;
697- }
714+ // Only track substantive output (ignore cursor movements, keepalives, etc)
715+ // Look for actual text content or common escape sequences that indicate real output
716+ const hasSubstantiveOutput = / [ a - z A - Z 0 - 9 ] / . test ( filteredData ) ||
717+ filteredData . includes ( '\n' ) ||
718+ filteredData . includes ( '\r' ) ;
719+
720+ if ( hasSubstantiveOutput ) {
721+ // Clear any existing idle timer
722+ const existingTimer = sessionIdleTimers . get ( sessionId ) ;
723+ if ( existingTimer ) {
724+ clearTimeout ( existingTimer ) ;
725+ }
698726
699- // Set a new timer - if no output for IDLE_DELAY_MS, mark as unread
700- const timer = setTimeout ( ( ) => {
701- markSessionAsUnread ( sessionId ) ;
702- sessionIdleTimers . delete ( sessionId ) ;
703- } , IDLE_DELAY_MS ) ;
727+ // Set a new timer - if no output for IDLE_DELAY_MS, mark as unread
728+ const timer = setTimeout ( ( ) => {
729+ markSessionAsUnread ( sessionId ) ;
730+ sessionIdleTimers . delete ( sessionId ) ;
731+ } , IDLE_DELAY_MS ) ;
704732
705- sessionIdleTimers . set ( sessionId , timer ) ;
733+ sessionIdleTimers . set ( sessionId , timer ) ;
734+ }
706735 }
707736 }
708737} ) ;
0 commit comments