({
timerStartTime,
isAtBottom,
scrollToLatest,
statusIndicatorState,
onStop,
onEndSession,
freebuffSession,
}: StatusBarProps)
| 77 | } |
| 78 | |
| 79 | export const StatusBar = ({ |
| 80 | timerStartTime, |
| 81 | isAtBottom, |
| 82 | scrollToLatest, |
| 83 | statusIndicatorState, |
| 84 | onStop, |
| 85 | onEndSession, |
| 86 | freebuffSession, |
| 87 | }: StatusBarProps) => { |
| 88 | const theme = useTheme() |
| 89 | const [elapsedSeconds, setElapsedSeconds] = useState(0) |
| 90 | |
| 91 | // Show timer when actively working (streaming or waiting for response) or paused (ask_user) |
| 92 | // This uses statusIndicatorState as the single source of truth for "is the LLM working?" |
| 93 | const shouldShowTimer = |
| 94 | statusIndicatorState?.kind === 'waiting' || |
| 95 | statusIndicatorState?.kind === 'streaming' || |
| 96 | statusIndicatorState?.kind === 'paused' |
| 97 | |
| 98 | useEffect(() => { |
| 99 | if (!timerStartTime || !shouldShowTimer) { |
| 100 | setElapsedSeconds(0) |
| 101 | return |
| 102 | } |
| 103 | |
| 104 | // When paused, don't update the timer - just keep the frozen value |
| 105 | if (statusIndicatorState?.kind === 'paused') { |
| 106 | // Calculate current elapsed time once and freeze it |
| 107 | const now = Date.now() |
| 108 | const elapsed = Math.floor((now - timerStartTime) / 1000) |
| 109 | setElapsedSeconds(elapsed) |
| 110 | return |
| 111 | } |
| 112 | |
| 113 | const updateElapsed = () => { |
| 114 | const now = Date.now() |
| 115 | const elapsed = Math.floor((now - timerStartTime) / 1000) |
| 116 | setElapsedSeconds(elapsed) |
| 117 | } |
| 118 | |
| 119 | updateElapsed() |
| 120 | const interval = setInterval(updateElapsed, 1000) |
| 121 | |
| 122 | return () => clearInterval(interval) |
| 123 | }, [timerStartTime, shouldShowTimer, statusIndicatorState?.kind]) |
| 124 | |
| 125 | const sessionProgress = useFreebuffSessionProgress(freebuffSession) |
| 126 | |
| 127 | const renderStatusIndicator = () => { |
| 128 | switch (statusIndicatorState.kind) { |
| 129 | case 'ctrlC': |
| 130 | return <span fg={theme.secondary}>Press Ctrl-C again to exit</span> |
| 131 | |
| 132 | case 'clipboard': |
| 133 | // Use green color for feedback success messages |
| 134 | const isFeedbackSuccess = |
| 135 | statusIndicatorState.message.includes('Feedback sent') |
| 136 | return ( |
nothing calls this directly
no test coverage detected