diff --git a/scarf/Packages/ScarfCore/Sources/ScarfCore/Models/ServerContext.swift b/scarf/Packages/ScarfCore/Sources/ScarfCore/Models/ServerContext.swift index ae6e0f2..bdfdbf6 100644 --- a/scarf/Packages/ScarfCore/Sources/ScarfCore/Models/ServerContext.swift +++ b/scarf/Packages/ScarfCore/Sources/ScarfCore/Models/ServerContext.swift @@ -219,6 +219,13 @@ extension ServerContext { public static func invalidateCaches(for contextID: ServerID) async { await UserHomeCache.shared.invalidate(contextID: contextID) } + + /// Static convenience for callers that have the ServerID but not + /// a full ServerContext (e.g. RootModel.softDisconnect). Mirrors + /// the instance method above. + public static func invalidateCachedHome(forServerID id: ServerID) async { + await UserHomeCache.shared.invalidate(contextID: id) + } } // MARK: - Convenience file I/O via the right transport diff --git a/scarf/Scarf iOS/App/ScarfIOSApp.swift b/scarf/Scarf iOS/App/ScarfIOSApp.swift index 12ddcee..a7a1eb2 100644 --- a/scarf/Scarf iOS/App/ScarfIOSApp.swift +++ b/scarf/Scarf iOS/App/ScarfIOSApp.swift @@ -182,14 +182,19 @@ final class RootModel { state = .connected(id, config, key) } - /// Soft disconnect: close any live transport but keep stored - /// credentials. Returns to the server list so the user can tap - /// another server (or the same one again). + /// Soft disconnect: return to the server list without wiping + /// credentials. Per-view controllers (ChatController, + /// IOSDashboardViewModel, etc.) tear down their transports via + /// SwiftUI `.onDisappear` when ScarfGoTabRoot unmounts; on next + /// connect we get fresh transports. We also flush the shared + /// UserHomeCache entry for the server we're leaving so a future + /// reconnect doesn't reuse a stale `$HOME` probe (minor, but + /// matters if the remote user's home directory changed — rare + /// but possible on shared hosts). func softDisconnect() async { - // Transport teardown is owned by ConnectedServerRegistry - // (added in 3.3); for now the per-view controllers own their - // own lifecycles via .onDisappear, so this is mostly a state - // change. The registry commit will thread through here. + if case .connected(let id, _, _) = state { + await ServerContext.invalidateCachedHome(forServerID: id) + } state = .serverList }