@@ -14,16 +14,16 @@ import { usePersistedState, updatePersistedState } from "./hooks/usePersistedSta
1414import { matchesKeybind , KEYBINDS } from "./utils/ui/keybinds" ;
1515import { useProjectManagement } from "./hooks/useProjectManagement" ;
1616import { useWorkspaceManagement } from "./hooks/useWorkspaceManagement" ;
17- import { useWorkspaceAggregators } from "./hooks/useWorkspaceAggregators" ;
1817import { useResumeManager } from "./hooks/useResumeManager" ;
1918import { useUnreadTracking } from "./hooks/useUnreadTracking" ;
2019import { useAutoCompactContinue } from "./hooks/useAutoCompactContinue" ;
20+ import { useWorkspaceStoreRaw , useWorkspaceRecency } from "./stores/WorkspaceStore" ;
21+ import { useGitStatusStoreRaw } from "./stores/GitStatusStore" ;
2122
2223import { CommandRegistryProvider , useCommandRegistry } from "./contexts/CommandRegistryContext" ;
2324import type { CommandAction } from "./contexts/CommandRegistryContext" ;
2425import { CommandPalette } from "./components/CommandPalette" ;
2526import { buildCoreSources , type BuildSourcesParams } from "./utils/commands/sources" ;
26- import { GitStatusProvider } from "./contexts/GitStatusContext" ;
2727
2828import type { ThinkingLevel } from "./types/thinking" ;
2929import { CUSTOM_EVENTS } from "./constants/events" ;
@@ -167,26 +167,32 @@ function AppInner() {
167167 onSelectedWorkspaceUpdate : setSelectedWorkspace ,
168168 } ) ;
169169
170- // Use workspace aggregators hook for message state
171- const { getWorkspaceState, getAggregator, workspaceStates, workspaceRecency } =
172- useWorkspaceAggregators ( workspaceMetadata ) ;
170+ // NEW: Sync workspace metadata with the stores
171+ const workspaceStore = useWorkspaceStoreRaw ( ) ;
172+ const gitStatusStore = useGitStatusStoreRaw ( ) ;
173+
174+ useEffect ( ( ) => {
175+ // Only sync when metadata has actually loaded (not empty initial state)
176+ if ( workspaceMetadata . size > 0 ) {
177+ workspaceStore . syncWorkspaces ( workspaceMetadata ) ;
178+ }
179+ } , [ workspaceMetadata , workspaceStore ] ) ;
180+
181+ useEffect ( ( ) => {
182+ // Only sync when metadata has actually loaded (not empty initial state)
183+ if ( workspaceMetadata . size > 0 ) {
184+ gitStatusStore . syncWorkspaces ( workspaceMetadata ) ;
185+ }
186+ } , [ workspaceMetadata , gitStatusStore ] ) ;
173187
174188 // Track unread message status for all workspaces
175- const { unreadStatus, toggleUnread } = useUnreadTracking ( selectedWorkspace , workspaceStates ) ;
189+ const { unreadStatus, toggleUnread } = useUnreadTracking ( selectedWorkspace ) ;
176190
177191 // Auto-resume interrupted streams on app startup and when failures occur
178- useResumeManager ( workspaceStates ) ;
192+ useResumeManager ( ) ;
179193
180194 // Handle auto-continue after compaction (when user uses /compact -c)
181- const { handleCompactStart } = useAutoCompactContinue ( workspaceStates ) ;
182-
183- const streamingModels = new Map < string , string > ( ) ;
184- for ( const metadata of workspaceMetadata . values ( ) ) {
185- const state = getWorkspaceState ( metadata . id ) ;
186- if ( state . canInterrupt ) {
187- streamingModels . set ( metadata . id , state . currentModel ) ;
188- }
189- }
195+ const { handleCompactStart } = useAutoCompactContinue ( ) ;
190196
191197 // Sync selectedWorkspace with URL hash
192198 useEffect ( ( ) => {
@@ -287,6 +293,9 @@ function AppInner() {
287293 [ ]
288294 ) ;
289295
296+ // NEW: Get workspace recency from store
297+ const workspaceRecency = useWorkspaceRecency ( ) ;
298+
290299 // Sort workspaces by recency (most recent first)
291300 // This ensures navigation follows the visual order displayed in the sidebar
292301 const sortedWorkspacesByProject = useMemo ( ( ) => {
@@ -490,7 +499,6 @@ function AppInner() {
490499 projects,
491500 workspaceMetadata,
492501 selectedWorkspace,
493- streamingModels,
494502 getThinkingLevel : getThinkingLevelForWorkspace ,
495503 onSetThinkingLevel : setThinkingLevelFromPalette ,
496504 onOpenNewWorkspaceModal : openNewWorkspaceFromPalette ,
@@ -510,15 +518,25 @@ function AppInner() {
510518 const unregister = registerSource ( ( ) => {
511519 const params = registerParamsRef . current ;
512520 if ( ! params ) return [ ] ;
513- const factories = buildCoreSources ( params ) ;
521+
522+ // Compute streaming models here (only when command palette opens)
523+ const allStates = workspaceStore . getAllStates ( ) ;
524+ const streamingModels = new Map < string , string > ( ) ;
525+ for ( const [ workspaceId , state ] of allStates ) {
526+ if ( state . canInterrupt ) {
527+ streamingModels . set ( workspaceId , state . currentModel ) ;
528+ }
529+ }
530+
531+ const factories = buildCoreSources ( { ...params , streamingModels } ) ;
514532 const actions : CommandAction [ ] = [ ] ;
515533 for ( const factory of factories ) {
516534 actions . push ( ...factory ( ) ) ;
517535 }
518536 return actions ;
519537 } ) ;
520538 return unregister ;
521- } , [ registerSource ] ) ;
539+ } , [ registerSource , workspaceStore ] ) ;
522540
523541 // Handle keyboard shortcuts
524542 useEffect ( ( ) => {
@@ -558,72 +576,67 @@ function AppInner() {
558576 < GlobalFonts />
559577 < GlobalScrollbars />
560578 < Global styles = { globalStyles } />
561- < GitStatusProvider workspaceMetadata = { workspaceMetadata } >
562- < AppContainer >
563- < LeftSidebar
564- projects = { projects }
565- workspaceMetadata = { workspaceMetadata }
566- selectedWorkspace = { selectedWorkspace }
567- onSelectWorkspace = { setSelectedWorkspace }
568- onAddProject = { ( ) => void addProject ( ) }
569- onAddWorkspace = { ( projectPath ) => void handleAddWorkspace ( projectPath ) }
570- onRemoveProject = { ( path ) => void handleRemoveProject ( path ) }
571- onRemoveWorkspace = { removeWorkspace }
572- onRenameWorkspace = { renameWorkspace }
573- getWorkspaceState = { getWorkspaceState }
574- unreadStatus = { unreadStatus }
575- onToggleUnread = { toggleUnread }
576- collapsed = { sidebarCollapsed }
577- onToggleCollapsed = { ( ) => setSidebarCollapsed ( ( prev ) => ! prev ) }
578- onGetSecrets = { handleGetSecrets }
579- onUpdateSecrets = { handleUpdateSecrets }
580- sortedWorkspacesByProject = { sortedWorkspacesByProject }
581- />
582- < MainContent >
583- < ContentArea >
584- { selectedWorkspace ? (
585- < ErrorBoundary
586- workspaceInfo = { `${ selectedWorkspace . projectName } /${ selectedWorkspace . workspacePath . split ( "/" ) . pop ( ) ?? "" } ` }
587- >
588- < AIView
589- workspaceId = { selectedWorkspace . workspaceId }
590- projectName = { selectedWorkspace . projectName }
591- branch = { selectedWorkspace . workspacePath . split ( "/" ) . pop ( ) ?? "" }
592- workspacePath = { selectedWorkspace . workspacePath }
593- workspaceState = { getWorkspaceState ( selectedWorkspace . workspaceId ) }
594- getAggregator = { getAggregator }
595- onCompactStart = { ( continueMessage ) =>
596- handleCompactStart ( selectedWorkspace . workspaceId , continueMessage )
597- }
598- />
599- </ ErrorBoundary >
600- ) : (
601- < WelcomeView >
602- < h2 > Welcome to Cmux</ h2 >
603- < p > Select a workspace from the sidebar or add a new one to get started.</ p >
604- </ WelcomeView >
605- ) }
606- </ ContentArea >
607- </ MainContent >
608- < CommandPalette
609- getSlashContext = { ( ) => ( {
610- providerNames : [ ] ,
611- workspaceId : selectedWorkspace ?. workspaceId ,
612- } ) }
579+ < AppContainer >
580+ < LeftSidebar
581+ projects = { projects }
582+ workspaceMetadata = { workspaceMetadata }
583+ selectedWorkspace = { selectedWorkspace }
584+ onSelectWorkspace = { setSelectedWorkspace }
585+ onAddProject = { ( ) => void addProject ( ) }
586+ onAddWorkspace = { ( projectPath ) => void handleAddWorkspace ( projectPath ) }
587+ onRemoveProject = { ( path ) => void handleRemoveProject ( path ) }
588+ onRemoveWorkspace = { removeWorkspace }
589+ onRenameWorkspace = { renameWorkspace }
590+ unreadStatus = { unreadStatus }
591+ onToggleUnread = { toggleUnread }
592+ collapsed = { sidebarCollapsed }
593+ onToggleCollapsed = { ( ) => setSidebarCollapsed ( ( prev ) => ! prev ) }
594+ onGetSecrets = { handleGetSecrets }
595+ onUpdateSecrets = { handleUpdateSecrets }
596+ sortedWorkspacesByProject = { sortedWorkspacesByProject }
597+ />
598+ < MainContent >
599+ < ContentArea >
600+ { selectedWorkspace ? (
601+ < ErrorBoundary
602+ workspaceInfo = { `${ selectedWorkspace . projectName } /${ selectedWorkspace . workspacePath . split ( "/" ) . pop ( ) ?? "" } ` }
603+ >
604+ < AIView
605+ workspaceId = { selectedWorkspace . workspaceId }
606+ projectName = { selectedWorkspace . projectName }
607+ branch = { selectedWorkspace . workspacePath . split ( "/" ) . pop ( ) ?? "" }
608+ workspacePath = { selectedWorkspace . workspacePath }
609+ onCompactStart = { ( continueMessage ) =>
610+ handleCompactStart ( selectedWorkspace . workspaceId , continueMessage )
611+ }
612+ />
613+ </ ErrorBoundary >
614+ ) : (
615+ < WelcomeView >
616+ < h2 > Welcome to Cmux</ h2 >
617+ < p > Select a workspace from the sidebar or add a new one to get started.</ p >
618+ </ WelcomeView >
619+ ) }
620+ </ ContentArea >
621+ </ MainContent >
622+ < CommandPalette
623+ getSlashContext = { ( ) => ( {
624+ providerNames : [ ] ,
625+ workspaceId : selectedWorkspace ?. workspaceId ,
626+ } ) }
627+ />
628+ { workspaceModalOpen && workspaceModalProject && (
629+ < NewWorkspaceModal
630+ isOpen = { workspaceModalOpen }
631+ projectPath = { workspaceModalProject }
632+ onClose = { ( ) => {
633+ setWorkspaceModalOpen ( false ) ;
634+ setWorkspaceModalProject ( null ) ;
635+ } }
636+ onAdd = { handleCreateWorkspace }
613637 />
614- { workspaceModalOpen && workspaceModalProject && (
615- < NewWorkspaceModal
616- isOpen = { workspaceModalOpen }
617- projectPath = { workspaceModalProject }
618- onClose = { ( ) => {
619- setWorkspaceModalOpen ( false ) ;
620- setWorkspaceModalProject ( null ) ;
621- } }
622- onAdd = { handleCreateWorkspace }
623- />
624- ) }
625- </ AppContainer >
626- </ GitStatusProvider >
638+ ) }
639+ </ AppContainer >
627640 </ >
628641 ) ;
629642}
0 commit comments