Sessions Integration Feature

Nucleic-Session: FC94353F-9F0D-4BCC-AD7C-0FB14E38C2E5
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-05 01:52:57 -07:00
co-authored by Nucleic
parent 7f15890416
commit 5852ce04e7
@@ -461,13 +461,14 @@ final class RemoteStore: ObservableObject {
} }
/// The callbacks one `HostConnection` uses to drive shared/aggregate state. `hostID` is captured /// The callbacks one `HostConnection` uses to drive shared/aggregate state. `hostID` is captured
/// so a change updates the flat projection only for the active host, while badges, notifications, /// so the open-transcript forwarding fires only for the Mac that owns the open session, while the
/// and the single open transcript are handled globally across hosts. /// merged list/dashboard, badges, and notifications are rebuilt across every host on any change.
private func callbacks(for hostID: String) -> HostConnection.Callbacks { private func callbacks(for hostID: String) -> HostConnection.Callbacks {
var cb = HostConnection.Callbacks() var cb = HostConnection.Callbacks()
cb.didUpdate = { [weak self] in cb.didUpdate = { [weak self] in
guard let self else { return } guard let self else { return }
if hostID == self.activeHostID { self.mirrorActive() } // Any host's change re-merges the aggregate the flat state binds to (mesh P3).
self.rebuildAggregate()
self.refreshAggregate() self.refreshAggregate()
self.flushPendingNotificationDecision() self.flushPendingNotificationDecision()
// A host that just connected (or reconnected) needs the current Live Activity token // A host that just connected (or reconnected) needs the current Live Activity token
@@ -475,22 +476,22 @@ final class RemoteStore: ObservableObject {
self.syncLiveActivityRegistration() self.syncLiveActivityRegistration()
} }
cb.openSnapshot = { [weak self] snap in cb.openSnapshot = { [weak self] snap in
guard let self, hostID == self.activeHostID, snap.summary.sessionID == self.openSessionID else { return } guard let self, hostID == self.openSessionHostID, snap.summary.sessionID == self.openSessionID else { return }
self.openEvents = snap.recentEvents self.openEvents = snap.recentEvents
self.openApprovals = snap.pendingApprovals self.openApprovals = snap.pendingApprovals
} }
cb.openEvents = { [weak self] batch in cb.openEvents = { [weak self] batch in
guard let self, hostID == self.activeHostID, batch.sessionID == self.openSessionID else { return } guard let self, hostID == self.openSessionHostID, batch.sessionID == self.openSessionID else { return }
self.openEvents.append(contentsOf: batch.events) self.openEvents.append(contentsOf: batch.events)
} }
cb.openDiff = { [weak self] diff in cb.openDiff = { [weak self] diff in
guard let self, hostID == self.activeHostID, diff.sessionID == self.openSessionID else { return } guard let self, hostID == self.openSessionHostID, diff.sessionID == self.openSessionID else { return }
self.openDiff = diff self.openDiff = diff
self.diffLoading = false self.diffLoading = false
} }
cb.approvalRequested = { [weak self] req, title in cb.approvalRequested = { [weak self] req, title in
guard let self else { return } guard let self else { return }
if hostID == self.activeHostID, req.sessionID == self.openSessionID, if hostID == self.openSessionHostID, req.sessionID == self.openSessionID,
!self.openApprovals.contains(where: { $0.id == req.id }) { !self.openApprovals.contains(where: { $0.id == req.id }) {
self.openApprovals.append(req) self.openApprovals.append(req)
} }