Skip to content

Refactor web store access to granular Zustand selectors - #141

Merged
juliusmarminge merged 18 commits into
mainfrom
t3code/zustand-store-granular-selectors
Mar 2, 2026
Merged

juliusmarminge merged 18 commits into
mainfrom
t3code/zustand-store-granular-selectors

Restore lost useMemo calls in ChatView and fix threadActivities refer…

ae56cd1
Select commit
Loading
Failed to load commit list.
MacroscopeApp / Macroscope - Correctness Check succeeded Mar 2, 2026 in 8m 25s

No issues identified (66 code objects reviewed).

• Merge Base: 5c09614
• Head: ae56cd1

Details

✅ File Path Comments Posted
✅ apps/web/src/types.ts 0
✅ apps/web/src/terminalStateStore.ts 0
➖ apps/web/src/terminalStateStore.test.ts
➖ apps/web/src/worktreeCleanup.test.ts
✅ apps/web/src/components/ThreadTerminalDrawer.tsx 0
✅ apps/web/src/components/ui/combobox.tsx 0
✅ apps/web/src/components/ui/toggle-group.tsx 0
➖ apps/web/src/store.test.ts
✅ apps/web/src/routes/_chat.$threadId.tsx 0
✅ apps/web/src/routes/__root.tsx 0
✅ apps/web/src/components/BranchToolbar.tsx 0
✅ apps/web/src/components/DiffPanel.tsx 0
✅ apps/web/src/routes/_chat.settings.tsx 0
✅ apps/web/src/store.ts 0
✅ apps/web/src/components/Sidebar.tsx 0
✅ apps/web/src/components/ChatView.tsx 0

Filtered Issues Details

apps/web/src/components/ChatView.tsx
  • line 147: The function selectThreadTerminalState in apps/web/src/terminalStateStore.ts calls getDefaultThreadTerminalState(), but no such function is defined or imported in the module. The provided code defines createDefaultThreadTerminalState instead. This will cause a ReferenceError (runtime crash) immediately when ChatView renders, as ChatView unconditionally calls selectThreadTerminalState via the useTerminalStateStore hook. [ Already posted ]
apps/web/src/components/ThreadTerminalDrawer.tsx
  • line 292: The openTerminal function creates a closure over the autoFocus variable. By explicitly excluding autoFocus from the useEffect dependency array (via the added eslint-disable comment), the effect does not re-run when this prop changes. Since openTerminal performs an asynchronous operation (api.terminal.open), it reads the stale value of autoFocus from the time the effect began, not when the operation completes. [ Already posted ]
apps/web/src/terminalStateStore.ts
  • line 118: In terminalGroupsEqual, the code iterates using left.length as the bound but accesses both left[index] and right[index]. If right is shorter than left, right[index] will be undefined. Although the very first line checks left.length !== right.length, the iteration is safe. However, inside the loop, the code accesses leftGroup.id and rightGroup.id. The check if (!leftGroup || !rightGroup) handles the undefined case, returning false. [ Already posted ]
  • line 431: The function updateTerminalStateByThreadId is vulnerable to a prototype property collision that causes a runtime crash. It calls selectThreadTerminalState (line 430) with terminalStateByThreadId (a plain object) and threadId. If threadId is a built-in property name like "toString" or "constructor", selectThreadTerminalState returns the corresponding function from Object.prototype instead of a ThreadTerminalState object. This function reference is then passed as current to the updater callback (line 431). The updater (e.g., setThreadTerminalOpen) passes this value to normalizeThreadTerminalState, which attempts to access state.terminalIds (line 179). Since (function).terminalIds is undefined, the subsequent call to normalizeTerminalIds attempts to access undefined.map (line 31), throwing a TypeError. [ Already posted ]