({
messagesRef,
lastAssistantMessageId,
vimMode
}: Props)
| 136 | return getLastAssistantMessage(messages)?.uuid ?? null; |
| 137 | } |
| 138 | function StatusLineInner({ |
| 139 | messagesRef, |
| 140 | lastAssistantMessageId, |
| 141 | vimMode |
| 142 | }: Props): React.ReactNode { |
| 143 | const abortControllerRef = useRef<AbortController | undefined>(undefined); |
| 144 | const permissionMode = useAppState(s => s.toolPermissionContext.mode); |
| 145 | const additionalWorkingDirectories = useAppState(s => s.toolPermissionContext.additionalWorkingDirectories); |
| 146 | const statusLineText = useAppState(s => s.statusLineText); |
| 147 | const setAppState = useSetAppState(); |
| 148 | const settings = useSettings(); |
| 149 | const { |
| 150 | addNotification |
| 151 | } = useNotifications(); |
| 152 | // AppState-sourced model — same source as API requests. getMainLoopModel() |
| 153 | // re-reads settings.json on every call, so another session's /model write |
| 154 | // would leak into this session's statusline (anthropics/claude-code#37596). |
| 155 | const mainLoopModel = useMainLoopModel(); |
| 156 | |
| 157 | // Keep latest values in refs for stable callback access |
| 158 | const settingsRef = useRef(settings); |
| 159 | settingsRef.current = settings; |
| 160 | const vimModeRef = useRef(vimMode); |
| 161 | vimModeRef.current = vimMode; |
| 162 | const permissionModeRef = useRef(permissionMode); |
| 163 | permissionModeRef.current = permissionMode; |
| 164 | const addedDirsRef = useRef(additionalWorkingDirectories); |
| 165 | addedDirsRef.current = additionalWorkingDirectories; |
| 166 | const mainLoopModelRef = useRef(mainLoopModel); |
| 167 | mainLoopModelRef.current = mainLoopModel; |
| 168 | |
| 169 | // Track previous state to detect changes and cache expensive calculations |
| 170 | const previousStateRef = useRef<{ |
| 171 | messageId: string | null; |
| 172 | exceeds200kTokens: boolean; |
| 173 | permissionMode: PermissionMode; |
| 174 | vimMode: VimMode | undefined; |
| 175 | mainLoopModel: ModelName; |
| 176 | }>({ |
| 177 | messageId: null, |
| 178 | exceeds200kTokens: false, |
| 179 | permissionMode, |
| 180 | vimMode, |
| 181 | mainLoopModel |
| 182 | }); |
| 183 | |
| 184 | // Debounce timer ref |
| 185 | const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined); |
| 186 | |
| 187 | // True when the next invocation should log its result (first run or after settings reload) |
| 188 | const logNextResultRef = useRef(true); |
| 189 | |
| 190 | // Stable update function — reads latest values from refs |
| 191 | const doUpdate = useCallback(async () => { |
| 192 | // Cancel any in-flight requests |
| 193 | abortControllerRef.current?.abort(); |
| 194 | const controller = new AbortController(); |
| 195 | abortControllerRef.current = controller; |
nothing calls this directly
no test coverage detected