/** * Browse vs transfer session lifecycle helpers. * * FileZilla model: a *closed* terminal SFTP side panel can soft-close its browse * SFTP channels while bulk transfers keep dedicated pool connections (and any * leased browse sessions held by in-flight streams). Switching to another side * panel tool (History / System / …) must keep browse warm — the owner stays * mounted for instant switch-back, and parking would force reconnect + reload. */ export function isBrowseSessionInteractive(params: { surfaceVisible: boolean; /** * Terminal side panel still open for this owner (another tool may be focused). * Keeps browse sessions alive across tool switches without treating that as a * full panel dismiss. */ ownerPanelOpen?: boolean; hasOwnedEditorTab: boolean; /** External editor temp files (Notepad++ etc.) still need the browse session. */ hasActiveExternalEdit?: boolean; }): boolean { return params.surfaceVisible || !!params.ownerPanelOpen || params.hasOwnedEditorTab || !!params.hasActiveExternalEdit; } export function listRemoteBrowseConnectionIds( tabs: ReadonlyArray<{ connection: { id: string; isLocal: boolean } | null; }>, ): string[] { const ids = new Set(); for (const tab of tabs) { const connection = tab.connection; if (!connection || connection.isLocal) continue; ids.add(connection.id); } return [...ids]; } /** Stable SFTP pane tab ids for editor ownership across browse reconnects. */ export function listRemoteBrowseSftpTabIds( tabs: ReadonlyArray<{ id: string; connection: { id: string; isLocal: boolean } | null; }>, ): string[] { const ids = new Set(); for (const tab of tabs) { const connection = tab.connection; if (!connection || connection.isLocal) continue; ids.add(tab.id); } return [...ids]; } export function shouldParkBrowseSessions(params: { interactive: boolean; /** True after we already soft-closed browse while the owner stayed mounted. */ browseParked: boolean; /** Defer park while unfinished transfers may still use browse sessions pre-lease. */ activeTransfersCount?: number; /** * Defer park while an external editor still holds a downloaded temp file. * Parking calls closeSftp, which deletes those temps and breaks save/sync. */ activeExternalEditCount?: number; }): boolean { if (params.activeTransfersCount && params.activeTransfersCount > 0) return false; if (params.activeExternalEditCount && params.activeExternalEditCount > 0) return false; return !params.interactive && !params.browseParked; } export function shouldRestoreBrowseSessions(params: { interactive: boolean; browseParked: boolean; }): boolean { return params.interactive && params.browseParked; } export interface BrowseSessionEntry { connectionId: string; sftpId: string; } /** Snapshot + clear the connectionId→sftpId map used by the file browser. */ export function takeBrowseSessionsForClose( sessions: Map, ): BrowseSessionEntry[] { const entries = [...sessions.entries()].map(([connectionId, sftpId]) => ({ connectionId, sftpId, })); sessions.clear(); return entries; } export function listRemoteConnectionIdsForRestore(params: { leftTabs: ReadonlyArray<{ connection: { id: string; isLocal: boolean } | null }>; rightTabs: ReadonlyArray<{ connection: { id: string; isLocal: boolean } | null }>; liveSessionConnectionIds: ReadonlySet; }): string[] { const ids = new Set(); for (const tab of [...params.leftTabs, ...params.rightTabs]) { const connection = tab.connection; if (!connection || connection.isLocal) continue; if (params.liveSessionConnectionIds.has(connection.id)) continue; ids.add(connection.id); } return [...ids]; }