@@ -1029,28 +1029,26 @@ impl BridgeShared {
10291029 let sessions = self . sessions . lock ( ) . await ;
10301030 sessions. expire_old_approvals ( ) ;
10311031
1032- // Check for stale sessions (1h without tmux, 24h with tmux)
1032+ // Get sessions idle for >1h
10331033 let candidates = sessions. get_stale_session_candidates ( 1 ) ;
10341034 drop ( sessions) ;
10351035
10361036 for session in candidates {
1037- if session. tmux_target . is_none ( ) {
1038- // No tmux info, clean up after 1h
1039- tracing:: info!( session_id = %session. id, "Cleaning up stale session (no tmux, >1h)" ) ;
1040- self . cleanup_stale_session ( & session, "inactivity timeout" )
1041- . await ;
1042- } else if let Some ( target) = & session. tmux_target {
1043- // Check if 24h+ old AND pane is dead
1044- let age_hours = ( chrono:: Utc :: now ( ) - session. last_activity ) . num_hours ( ) ;
1045- if age_hours >= 24 {
1046- let pane_alive =
1047- InputInjector :: is_pane_alive ( target, session. tmux_socket . as_deref ( ) ) ;
1048- if !pane_alive {
1049- tracing:: info!( session_id = %session. id, "Cleaning up stale session (pane dead)" ) ;
1050- self . cleanup_stale_session ( & session, "pane no longer exists" )
1051- . await ;
1052- }
1037+ if let Some ( target) = & session. tmux_target {
1038+ // Has tmux target — check if pane is still alive
1039+ let pane_alive =
1040+ InputInjector :: is_pane_alive ( target, session. tmux_socket . as_deref ( ) ) ;
1041+ if !pane_alive {
1042+ tracing:: info!( session_id = %session. id, target, "Cleaning up stale session (pane dead)" ) ;
1043+ self . cleanup_stale_session ( & session, "tmux pane no longer exists" )
1044+ . await ;
10531045 }
1046+ // Pane alive = keep session, it may just be idle
1047+ } else {
1048+ // No tmux info at all — clean up after 1h of inactivity
1049+ tracing:: info!( session_id = %session. id, "Cleaning up stale session (no tmux, >1h idle)" ) ;
1050+ self . cleanup_stale_session ( & session, "inactivity timeout (no tmux)" )
1051+ . await ;
10541052 }
10551053 }
10561054 }
@@ -1062,20 +1060,20 @@ impl BridgeShared {
10621060 let _ = self
10631061 . bot
10641062 . send_message (
1065- & format ! (
1066- "\u{1f50c} *Session ended* (terminal closed)\n \n _{}_" ,
1067- reason
1068- ) ,
1063+ & format ! ( "\u{1f50c} *Session cleaned up*\n \n _{}_" , reason) ,
10691064 & SendOptions :: default ( ) ,
10701065 Some ( tid) ,
10711066 )
10721067 . await ;
10731068
1074- if self . config . auto_delete_topics {
1075- let _ = self . bot . delete_forum_topic ( tid) . await ;
1069+ // Stale sessions are truly dead — always delete the topic to keep the group clean.
1070+ // Normal session ends respect auto_delete_topics config; stale cleanup does not.
1071+ if self . bot . delete_forum_topic ( tid) . await . unwrap_or ( false ) {
1072+ tracing:: info!( session_id = %session. id, %tid, "Deleted stale forum topic" ) ;
10761073 let sessions = self . sessions . lock ( ) . await ;
10771074 sessions. clear_thread_id ( & session. id ) ;
10781075 } else {
1076+ // Fallback to close if delete fails (missing permissions)
10791077 let _ = self . bot . close_forum_topic ( tid) . await ;
10801078 }
10811079 }
0 commit comments