({
messagesRef,
lastAssistantMessageId,
vimMode
}: Props)
| 217 | </Text>; |
| 218 | } |
| 219 | function CommandStatusLine({ |
| 220 | messagesRef, |
| 221 | lastAssistantMessageId, |
| 222 | vimMode |
| 223 | }: Props): React.ReactNode { |
| 224 | const abortControllerRef = useRef<AbortController | undefined>(undefined); |
| 225 | const permissionMode = useAppState(s => s.toolPermissionContext.mode); |
| 226 | const additionalWorkingDirectories = useAppState(s => s.toolPermissionContext.additionalWorkingDirectories); |
| 227 | const statusLineText = useAppState(s => s.statusLineText); |
| 228 | const setAppState = useSetAppState(); |
| 229 | const settings = useSettings(); |
| 230 | const { |
| 231 | addNotification |
| 232 | } = useNotifications(); |
| 233 | // AppState-sourced model — same source as API requests. getMainLoopModel() |
| 234 | // re-reads settings.json on every call, so another session's /model write |
| 235 | // would leak into this session's statusline (anthropics/claude-code#37596). |
| 236 | const mainLoopModel = useMainLoopModel(); |
| 237 | |
| 238 | // Keep latest values in refs for stable callback access |
| 239 | const settingsRef = useRef(settings); |
| 240 | settingsRef.current = settings; |
| 241 | const vimModeRef = useRef(vimMode); |
| 242 | vimModeRef.current = vimMode; |
| 243 | const permissionModeRef = useRef(permissionMode); |
| 244 | permissionModeRef.current = permissionMode; |
| 245 | const addedDirsRef = useRef(additionalWorkingDirectories); |
| 246 | addedDirsRef.current = additionalWorkingDirectories; |
| 247 | const mainLoopModelRef = useRef(mainLoopModel); |
| 248 | mainLoopModelRef.current = mainLoopModel; |
| 249 | |
| 250 | // Track previous state to detect changes and cache expensive calculations |
| 251 | const previousStateRef = useRef<{ |
| 252 | messageId: string | null; |
| 253 | exceeds200kTokens: boolean; |
| 254 | permissionMode: PermissionMode; |
| 255 | vimMode: VimMode | undefined; |
| 256 | mainLoopModel: ModelName; |
| 257 | }>({ |
| 258 | messageId: null, |
| 259 | exceeds200kTokens: false, |
| 260 | permissionMode, |
| 261 | vimMode, |
| 262 | mainLoopModel |
| 263 | }); |
| 264 | |
| 265 | // Debounce timer ref |
| 266 | const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined); |
| 267 | |
| 268 | // True when the next invocation should log its result (first run or after settings reload) |
| 269 | const logNextResultRef = useRef(true); |
| 270 | |
| 271 | // Stable update function — reads latest values from refs |
| 272 | const doUpdate = useCallback(async () => { |
| 273 | // Cancel any in-flight requests |
| 274 | abortControllerRef.current?.abort(); |
| 275 | const controller = new AbortController(); |
| 276 | abortControllerRef.current = controller; |
nothing calls this directly
no test coverage detected