({ messagesRef, lastAssistantMessageId, vimMode }: Props)
| 327 | } |
| 328 | |
| 329 | function StatusLineInner({ messagesRef, lastAssistantMessageId, vimMode }: Props): React.ReactNode { |
| 330 | const abortControllerRef = useRef<AbortController | undefined>(undefined); |
| 331 | const permissionMode = useAppState(s => s.toolPermissionContext.mode); |
| 332 | const additionalWorkingDirectories = useAppState(s => s.toolPermissionContext.additionalWorkingDirectories); |
| 333 | const statusLineText = useAppState(s => s.statusLineText); |
| 334 | const setAppState = useSetAppState(); |
| 335 | const settings = useSettings(); |
| 336 | const { addNotification } = useNotifications(); |
| 337 | // AppState-sourced model — same source as API requests. getMainLoopModel() |
| 338 | // re-reads settings.json on every call, so another session's /model write |
| 339 | // would leak into this session's statusline (anthropics/claude-code#37596). |
| 340 | const mainLoopModel = useMainLoopModel(); |
| 341 | |
| 342 | // Keep latest values in refs for stable callback access |
| 343 | const settingsRef = useRef(settings); |
| 344 | settingsRef.current = settings; |
| 345 | const vimModeRef = useRef(vimMode); |
| 346 | vimModeRef.current = vimMode; |
| 347 | const permissionModeRef = useRef(permissionMode); |
| 348 | permissionModeRef.current = permissionMode; |
| 349 | const addedDirsRef = useRef(additionalWorkingDirectories); |
| 350 | addedDirsRef.current = additionalWorkingDirectories; |
| 351 | const mainLoopModelRef = useRef(mainLoopModel); |
| 352 | mainLoopModelRef.current = mainLoopModel; |
| 353 | |
| 354 | // Track previous state to detect changes and cache expensive calculations |
| 355 | const previousStateRef = useRef<{ |
| 356 | messageId: string | null; |
| 357 | exceeds200kTokens: boolean; |
| 358 | permissionMode: PermissionMode; |
| 359 | vimMode: VimMode | undefined; |
| 360 | mainLoopModel: ModelName; |
| 361 | }>({ |
| 362 | messageId: null, |
| 363 | exceeds200kTokens: false, |
| 364 | permissionMode, |
| 365 | vimMode, |
| 366 | mainLoopModel, |
| 367 | }); |
| 368 | |
| 369 | // Debounce timer ref |
| 370 | const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined); |
| 371 | |
| 372 | // True when the next invocation should log its result (first run or after settings reload) |
| 373 | const logNextResultRef = useRef(true); |
| 374 | |
| 375 | // Stable update function — reads latest values from refs |
| 376 | const doUpdate = useCallback(async () => { |
| 377 | // Cancel any in-flight requests |
| 378 | abortControllerRef.current?.abort(); |
| 379 | |
| 380 | const controller = new AbortController(); |
| 381 | abortControllerRef.current = controller; |
| 382 | |
| 383 | const msgs = messagesRef.current; |
| 384 | |
| 385 | const logResult = logNextResultRef.current; |
| 386 | logNextResultRef.current = false; |
nothing calls this directly
no test coverage detected