diff --git a/apps/ui/src/components/views/terminal-view.tsx b/apps/ui/src/components/views/terminal-view.tsx index db79ce0f..9f5569f5 100644 --- a/apps/ui/src/components/views/terminal-view.tsx +++ b/apps/ui/src/components/views/terminal-view.tsx @@ -240,7 +240,6 @@ export function TerminalView() { const [dragOverTabId, setDragOverTabId] = useState(null); const lastCreateTimeRef = useRef(0); const isCreatingRef = useRef(false); - const prevProjectPathRef = useRef(null); const restoringProjectPathRef = useRef(null); const [newSessionIds, setNewSessionIds] = useState>(new Set()); const [serverSessionInfo, setServerSessionInfo] = useState<{ @@ -524,11 +523,15 @@ export function TerminalView() { }, [terminalState.isUnlocked, fetchServerSettings]); // Handle project switching - save and restore terminal layouts + // Uses terminalState.lastActiveProjectPath (persisted in store) instead of a local ref + // This ensures terminals persist when navigating away from terminal route and back useEffect(() => { const currentPath = currentProject?.path || null; - const prevPath = prevProjectPathRef.current; + // Read lastActiveProjectPath directly from store to avoid dependency issues + const prevPath = useAppStore.getState().terminalState.lastActiveProjectPath; - // Skip if no change + // Skip if no change - this now correctly handles route changes within the same project + // because lastActiveProjectPath persists in the store across component unmount/remount if (currentPath === prevPath) { return; } @@ -538,12 +541,13 @@ export function TerminalView() { // Save layout for previous project (if there was one and has terminals) // BUT don't save if we were mid-restore for that project (would save incomplete state) - if (prevPath && terminalState.tabs.length > 0 && restoringProjectPathRef.current !== prevPath) { + const currentTabs = useAppStore.getState().terminalState.tabs; + if (prevPath && currentTabs.length > 0 && restoringProjectPathRef.current !== prevPath) { saveTerminalLayout(prevPath); } - // Update the previous project ref - prevProjectPathRef.current = currentPath; + // Update the stored project path + useAppStore.getState().setTerminalLastActiveProjectPath(currentPath); // Helper to kill sessions and clear state const killAndClear = async () => { diff --git a/apps/ui/src/store/app-store.ts b/apps/ui/src/store/app-store.ts index c4d7e2ca..76c61475 100644 --- a/apps/ui/src/store/app-store.ts +++ b/apps/ui/src/store/app-store.ts @@ -344,6 +344,7 @@ export interface TerminalState { scrollbackLines: number; // Number of lines to keep in scrollback buffer lineHeight: number; // Line height multiplier for terminal text maxSessions: number; // Maximum concurrent terminal sessions (server setting) + lastActiveProjectPath: string | null; // Last project path to detect route changes vs project switches } // Persisted terminal layout - now includes sessionIds for reconnection @@ -816,6 +817,7 @@ export interface AppActions { setTerminalScrollbackLines: (lines: number) => void; setTerminalLineHeight: (lineHeight: number) => void; setTerminalMaxSessions: (maxSessions: number) => void; + setTerminalLastActiveProjectPath: (projectPath: string | null) => void; addTerminalTab: (name?: string) => string; removeTerminalTab: (tabId: string) => void; setActiveTerminalTab: (tabId: string) => void; @@ -951,6 +953,7 @@ const initialState: AppState = { scrollbackLines: 5000, lineHeight: 1.0, maxSessions: 100, + lastActiveProjectPath: null, }, terminalLayoutByProject: {}, specCreatingForProject: null, @@ -2037,6 +2040,8 @@ export const useAppStore = create()( scrollbackLines: current.scrollbackLines, lineHeight: current.lineHeight, maxSessions: current.maxSessions, + // Preserve lastActiveProjectPath - it will be updated separately when needed + lastActiveProjectPath: current.lastActiveProjectPath, }, }); }, @@ -2121,6 +2126,13 @@ export const useAppStore = create()( }); }, + setTerminalLastActiveProjectPath: (projectPath) => { + const current = get().terminalState; + set({ + terminalState: { ...current, lastActiveProjectPath: projectPath }, + }); + }, + addTerminalTab: (name) => { const current = get().terminalState; const newTabId = `tab-${Date.now()}`; @@ -2669,6 +2681,7 @@ export const useAppStore = create()( activeTabId: state.terminalState?.activeTabId ?? null, activeSessionId: state.terminalState?.activeSessionId ?? null, maximizedSessionId: state.terminalState?.maximizedSessionId ?? null, + lastActiveProjectPath: state.terminalState?.lastActiveProjectPath ?? null, // Restore persisted settings defaultFontSize: persistedSettings.defaultFontSize ?? 14, defaultRunScript: persistedSettings.defaultRunScript ?? '',