@@ -25,6 +25,16 @@ const formatCountdown = (ms: number): string => {
2525 return `${ m } :${ s . toString ( ) . padStart ( 2 , '0' ) } `
2626}
2727
28+ const formatSessionRemaining = ( ms : number ) : string => {
29+ if ( ms <= 0 ) return 'expiring…'
30+ if ( ms < COUNTDOWN_VISIBLE_MS ) return `${ formatCountdown ( ms ) } left`
31+ const totalMinutes = Math . ceil ( ms / 60_000 )
32+ if ( totalMinutes < 60 ) return `${ totalMinutes } m left`
33+ const hours = Math . floor ( totalMinutes / 60 )
34+ const minutes = totalMinutes % 60
35+ return minutes === 0 ? `${ hours } h left` : `${ hours } h ${ minutes } m left`
36+ }
37+
2838interface StatusBarProps {
2939 timerStartTime : number | null
3040 isAtBottom : boolean
@@ -79,11 +89,13 @@ export const StatusBar = ({
7989 return ( ) => clearInterval ( interval )
8090 } , [ timerStartTime , shouldShowTimer , statusIndicatorState ?. kind ] )
8191
92+ const sessionProgress = useFreebuffSessionProgress ( freebuffSession )
93+
8294 const renderStatusIndicator = ( ) => {
8395 switch ( statusIndicatorState . kind ) {
8496 case 'ctrlC' :
8597 return < span fg = { theme . secondary } > Press Ctrl-C again to exit</ span >
86-
98+
8799 case 'clipboard' :
88100 // Use green color for feedback success messages
89101 const isFeedbackSuccess = statusIndicatorState . message . includes ( 'Feedback sent' )
@@ -92,21 +104,21 @@ export const StatusBar = ({
92104 { statusIndicatorState . message }
93105 </ span >
94106 )
95-
107+
96108 case 'reconnected' :
97109 return < span fg = { theme . success } > Reconnected</ span >
98-
110+
99111 case 'retrying' :
100112 return (
101113 < ShimmerText
102114 text = "retrying..."
103115 primaryColor = { theme . warning }
104116 />
105117 )
106-
118+
107119 case 'connecting' :
108120 return < ShimmerText text = "connecting..." />
109-
121+
110122 case 'waiting' :
111123 return (
112124 < ShimmerText
@@ -115,7 +127,7 @@ export const StatusBar = ({
115127 primaryColor = { theme . secondary }
116128 />
117129 )
118-
130+
119131 case 'streaming' :
120132 return (
121133 < ShimmerText
@@ -124,11 +136,19 @@ export const StatusBar = ({
124136 primaryColor = { theme . secondary }
125137 />
126138 )
127-
139+
128140 case 'paused' :
129141 return null
130-
142+
131143 case 'idle' :
144+ if ( sessionProgress !== null ) {
145+ const isUrgent = sessionProgress . remainingMs < COUNTDOWN_VISIBLE_MS
146+ return (
147+ < span fg = { isUrgent ? theme . warning : theme . secondary } >
148+ Free session · { formatSessionRemaining ( sessionProgress . remainingMs ) }
149+ </ span >
150+ )
151+ }
132152 return null
133153 }
134154 }
@@ -144,8 +164,6 @@ export const StatusBar = ({
144164 const statusIndicatorContent = renderStatusIndicator ( )
145165 const elapsedTimeContent = renderElapsedTime ( )
146166
147- const sessionProgress = useFreebuffSessionProgress ( freebuffSession )
148-
149167 // Show gray background when there's status indicator, timer, or when the
150168 // freebuff session fill is visible (otherwise the fill would float over
151169 // transparent space).
@@ -208,7 +226,8 @@ export const StatusBar = ({
208226 < StopButton onClick = { onStop } />
209227 ) }
210228 { sessionProgress !== null &&
211- sessionProgress . remainingMs < COUNTDOWN_VISIBLE_MS && (
229+ sessionProgress . remainingMs < COUNTDOWN_VISIBLE_MS &&
230+ statusIndicatorState . kind !== 'idle' && (
212231 < text style = { { wrapMode : 'none' } } >
213232 < span fg = { theme . warning } attributes = { TextAttributes . BOLD } >
214233 { formatCountdown ( sessionProgress . remainingMs ) }
0 commit comments