Session Cache Implementation

Nucleic-Session: B2346642-3353-4BD5-9DE2-A8B77BD66C98
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-05 22:31:23 -07:00
co-authored by Nucleic
parent e126a78c12
commit 3d86f11c67
@@ -647,6 +647,48 @@ final class RemoteStore: ObservableObject {
return bySeq.values.sorted { $0.seq < $1.seq }
}
// MARK: - Offline cache (SessionCache)
/// Debounced write of the live session list to disk, so a read-only history survives a
/// disconnect / relaunch.
private func persistSummaries(_ list: [WireSessionSummary]) {
summaryPersistTask?.cancel()
summaryPersistTask = Task { [list] in
try? await Task.sleep(nanoseconds: 2_000_000_000)
guard !Task.isCancelled else { return }
await SessionCache.saveSummaries(list)
}
}
/// Seed the open transcript from disk so a cached session's history shows instantly — even fully
/// offline. A live snapshot/backfill merges on top by seq (dedup), so this never double-counts.
private func loadCachedTranscript(_ sessionID: SessionID) {
Task { [weak self] in
let cached = await SessionCache.loadEvents(sessionID)
guard let self, self.openSessionID == sessionID, !cached.isEmpty else { return }
self.openEvents = Self.mergedEvents(cached, self.openEvents)
}
}
/// Debounced write of the open transcript, called after each batch of events lands.
private func persistOpenTranscript() {
guard !demoMode, let id = openSessionID, !openEvents.isEmpty else { return }
let events = openEvents
transcriptPersistTask?.cancel()
transcriptPersistTask = Task { [events, id] in
try? await Task.sleep(nanoseconds: 1_500_000_000)
guard !Task.isCancelled else { return }
await SessionCache.saveEvents(events, for: id)
}
}
/// Flush the open transcript to disk immediately (on close), cancelling any pending debounce.
private func flushOpenTranscript(_ id: SessionID, _ events: [AgentEvent]) {
transcriptPersistTask?.cancel()
guard !demoMode, !events.isEmpty else { return }
Task { await SessionCache.saveEvents(events, for: id) }
}
/// The flat sessions list: every connected Mac's sessions, deduped by id (ids are globally
/// unique). Views handle sorting/grouping.
private func aggregatedSessions() -> [WireSessionSummary] {