Eliminate sidebar re-render cascades by fixing both sides of the
subscription contract:
- Session-store writes preserve identity: setWorkspaces, mergeWorkspaces,
removeWorkspace, and patchWorkspaceScripts return the previous Map/entry
reference when content is unchanged.
- HostRuntimeController.updateSnapshot only notifies when a patched field
actually changed; idle probe ticks no longer replace the snapshot.
- New canonical hook surface in stores/session-store-hooks.ts
(useWorkspace, useWorkspaceFields, useWorkspaceStructure,
useWorkspaceKeys, useResolveWorkspaceIdByCwd,
useWorkspaceStatusesForBadges, useWorkspaceExecutionAuthority,
useRecommendedProjectPaths, useHasWorkspaces). These are the only
place to subscribe to workspaces.
- 15 greedy subscribers migrated to the hook surface. The sidebar is now
driven by useWorkspaceStructure for identity/ordering; each row
hydrates its own descriptor via useWorkspaceFields, so a workspace
update re-renders only its row. Archive-redirect callbacks switched to
event-time useSessionStore.getState().
- Deleted dead code: use-session-directory.ts, workspace-fetch-debug.ts,
and the unused SidebarProjectEntry aggregates (activeCount,
totalWorkspaces, aggregated statusBucket).
No user-visible behavior change. Targeted tests green (79 tests across
host-runtime, session-store, session-store-hooks, sidebar list, sidebar
row model, sidebar shortcuts, workspace source of truth).
Add `packages/app/src/constants/platform.ts` with canonical gates
(isWeb, isNative, getIsElectron) and refactor all ~100 ad-hoc
Platform.OS checks across 69 files to use shared imports.
Fix sidebar hover crash on native (onPointerEnter → onHoverIn),
fix tooltip to use breakpoint instead of platform detection, make
sidebar action buttons always visible on native where hover doesn't
work, and document the platform gating decision matrix in CLAUDE.md.
- Make PaseoLogo theme-aware (uses foreground color instead of hardcoded white)
- Add shadow tokens (sm/md/lg) to theme with per-scheme opacity, radius, and offset
- Replace all 16 hardcoded shadow instances with spreadable theme.shadow tokens
- Fix button icon color for default variant (use accentForeground, not foreground)
- Fix dark background flash on startup (root layout used hardcoded darkTheme)
- Add theme.colorScheme to replace fragile hex-string dark mode detection
- Add scrollbarHandle and surfaceWorkspace tokens to eliminate isDark branching
useHostRuntimeSession returned the full HostRuntimeSnapshot, causing
every consumer to rerender on any internal state change (probe cycles,
client generation bumps). Replace with targeted hooks that return
primitives/stable references so useSyncExternalStore skips rerenders
when the subscribed value hasn't actually changed.
New hooks: useHostRuntimeClient, useHostRuntimeConnectionStatus,
useHostRuntimeLastError, useHostRuntimeAgentDirectoryStatus,
useHostRuntimeIsDirectoryLoading. Existing useHostRuntimeIsConnected
already followed this pattern.
useHostRuntimeSnapshot kept only for settings-screen where probe
data is legitimately needed.