import type { RailSession as Session } from "./session-list-entry.js"; export { sessionAttentionReadThroughSequence } from "../../session-attention-model.js"; export type ActiveSessionReadCandidate = Pick; export type SessionAttentionProjection = Pick; export type LocalSessionDeliveryAttention = { workspaceId: string; sessionId: string; failedMessageCount: number; }; /** * Project browser-local delivery failure truth into the rail without mutating * the durable session lifecycle or unread state. A retry, removal, or durable * acceptance clears the projection when the composer no longer owns a failed * optimistic message. */ export declare function updateLocalSessionDeliveryAttention(projection: LocalSessionDeliveryAttention): void; export declare function localSessionDeliveryAttentionCounts(workspaceId: string): ReadonlyMap; export declare function subscribeToLocalSessionDeliveryAttention(onChange: () => void): () => void; /** One foreground-view receipt per exact session event frontier. */ export declare function sessionReadProjectionKey(sessionId: string, latestEventSequence: number): string; type ActiveSessionReadEligibility = { activeSessionId: string | null; workspaceId: string; session: ActiveSessionReadCandidate | null; documentVisible: boolean; windowFocused: boolean; }; /** * An unread chat clears as soon as its exact route is the foreground * destination. The durable writer receives the exact known frontier and can * advance again when later events render. */ export declare function shouldProjectActiveSessionRead(input: ActiveSessionReadEligibility): boolean; /** * A chat is read only while the exact route is genuinely in the foreground. * Merely leaving a session route mounted in a background tab/window must not * consume its unread signal. */ export declare function shouldAcknowledgeActiveSession(input: ActiveSessionReadEligibility): boolean; /** * Apply a same-tab attention result without allowing an older list poll to * resurrect a read marker. Attention revisions order explicit mutations, * while lastSequence orders new durable activity; either older coordinate is * stale. Equal coordinates let the latest mutation response replace the page * projection immediately. At an equal coordinate, read wins over unread: a * cleanup or stale render cannot resurrect a dot after the user viewed it. * Explicit mark-unread actions still win because they increment * `attentionVersion`. The rail calls this only after an id-keyed lookup, so * both arguments represent the same session. */ export declare function applySessionAttentionProjection(current: T, projected: SessionAttentionProjection): T; export declare function latestSessionAttentionProjection(current: SessionAttentionProjection | undefined, projected: SessionAttentionProjection): SessionAttentionProjection; /** * Apply personal attention projections to rows and their loaded ancestor * aggregates in one pass. Server `treeStats` count every descendant, so a * foreground child read must adjust each loaded ancestor immediately instead * of leaving a stale blue or red parent marker until the next list poll. */ export declare function applySessionAttentionProjections(sessions: readonly T[], projections: ReadonlyMap): T[]; export declare function notifySessionAttentionChanged(projection: SessionAttentionProjection): void; export declare function subscribeToSessionAttentionChanges(onChange: (projection: SessionAttentionProjection) => void): () => void;