perf(sidebar): index session ownership and narrow live subscriptions
Replace repeated project-by-session directory matching across sidebar hooks with a shared ownership index that resolves each unique directory once and exposes direct project and folder-scope buckets. Gate destructive folder reconciliation on authoritative session data and topology readiness, preserve last-known worktrees after discovery failures, and retain nested-project, VS Code, active/archive dedupe, and Windows drive-root semantics. Narrow cross-directory subscriptions to session and status slices so streaming deltas no longer trigger global aggregation. Reuse a cached session ID index for permission lineage checks instead of rebuilding it on every session switch. On the reported 15-project, 67-worktree, 14,561-session shape, ownership indexing averages 3.81 ms versus roughly 450 ms for the cache-only hotfix. Validation: 28 targeted tests, UI type-check, UI lint, and dead-code analysis.
This commit is contained in:
@@ -109,7 +109,11 @@ function getLiveStates(childStores: ChildStoreManager): State[] {
|
||||
return Array.from(childStores.children.values(), (store) => store.getState())
|
||||
}
|
||||
|
||||
function useLiveSyncSelector<T>(selector: (states: State[]) => T, isEqual: (left: T, right: T) => boolean = Object.is): T {
|
||||
function useLiveSyncSelector<T>(
|
||||
selector: (states: State[]) => T,
|
||||
isEqual: (left: T, right: T) => boolean = Object.is,
|
||||
subscribe?: (childStores: ChildStoreManager, notify: () => void) => () => void,
|
||||
): T {
|
||||
const { childStores } = useSyncSystem()
|
||||
const cacheRef = useRef<T | undefined>(undefined)
|
||||
const initializedRef = useRef(false)
|
||||
@@ -126,7 +130,10 @@ function useLiveSyncSelector<T>(selector: (states: State[]) => T, isEqual: (left
|
||||
}, [childStores, isEqual, selector])
|
||||
|
||||
return React.useSyncExternalStore(
|
||||
useCallback((notify) => childStores.subscribeAll(notify), [childStores]),
|
||||
useCallback(
|
||||
(notify) => subscribe ? subscribe(childStores, notify) : childStores.subscribeAll(notify),
|
||||
[childStores, subscribe],
|
||||
),
|
||||
getSnapshot,
|
||||
getSnapshot,
|
||||
)
|
||||
@@ -142,6 +149,14 @@ function useLiveSyncSelector<T>(selector: (states: State[]) => T, isEqual: (left
|
||||
export function useGlobalSessionStatus(sessionId: string): SessionStatus | undefined {
|
||||
return useLiveSyncSelector(
|
||||
useCallback((states) => findLiveSessionStatus(states, sessionId), [sessionId]),
|
||||
Object.is,
|
||||
useCallback(
|
||||
(childStores: ChildStoreManager, notify: () => void) => childStores.subscribeAllSelected(
|
||||
(state: State) => state.session_status?.[sessionId],
|
||||
notify,
|
||||
),
|
||||
[sessionId],
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -150,6 +165,13 @@ export function useAllSessionStatuses(): Record<string, SessionStatus> {
|
||||
return useLiveSyncSelector(
|
||||
useCallback((states) => aggregateLiveSessionStatuses(states), []),
|
||||
areStatusMapsEquivalent,
|
||||
useCallback(
|
||||
(childStores: ChildStoreManager, notify: () => void) => childStores.subscribeAllSelected(
|
||||
(state: State) => state.session_status,
|
||||
notify,
|
||||
),
|
||||
[],
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -157,6 +179,13 @@ export function useAllLiveSessions(): Session[] {
|
||||
return useLiveSyncSelector(
|
||||
useCallback((states) => aggregateLiveSessions(states), []),
|
||||
areSessionListsEquivalent,
|
||||
useCallback(
|
||||
(childStores: ChildStoreManager, notify: () => void) => childStores.subscribeAllSelected(
|
||||
(state: State) => state.session,
|
||||
notify,
|
||||
),
|
||||
[],
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user