import type { Presence, PresenceStatus } from "@cotal-ai/core"; import type { FeedDelivery, FeedEntry, MembershipView } from "../../mesh.js"; export type TopoNodeKind = "agent" | "channel" | "service"; export interface TopoNode { /** Kind-prefixed identity: "a:" | "c:general" | "s:planner". */ key: string; kind: TopoNodeKind; /** Display name — renderers add the #/@ prefix. */ name: string; /** Authoritative endpoint identity (agents only). */ id?: string; status?: PresenceStatus; role?: string; /** Last involvement inside the window (0 = present but silent). */ lastTs: number; /** Present in the broker-authoritative membership feed (agents only). */ member?: boolean; /** Subscribes `>` or `*` — a wide "reads all" reader; badged, not spoked per hub. */ wide?: boolean; } /** A broker-authoritative membership link — an agent subscribes a channel. Kept SEPARATE from * traffic {@link TopoEdge}s (which carry rate/count): a membership link has no traffic, so folding * it into edges would prune it (heatLevel 0) or create phantom empty matrix columns. */ export interface TopoMembership { agent: string; channel: string; /** Which broker arm proves it: `live` (a current CONNZ subscription) vs `durable` (registry only, * i.e. a member whose connection is currently down). */ state: "live" | "durable"; } export interface TopoEdge { key: string; src: string; dst: string; mode: FeedDelivery; count: number; lastTs: number; /** Recency intensity: Σ exp(-(now-ts)/τ), τ = 20s — a stateless EWMA. */ rate: number; } export interface TopoGraph { /** Agents (roster order) first, then channels, then services (each alphabetical). */ nodes: TopoNode[]; /** Ascending by rate — renderers overdraw hot edges last. */ edges: TopoEdge[]; /** Broker-authoritative membership links (the resting subscription skeleton). */ memberships: TopoMembership[]; byKey: Map; windowMs: number; now: number; /** The membership feed as the viewer last saw it (see {@link membershipFreshness}). */ membership: MembershipView; } export declare const DEFAULT_TOPO_WINDOW_MS = 120000; export declare const MEMBERSHIP_STALE_MS = 45000; /** The target node(s) a feed entry talks to — the single place delivery → node mapping lives. */ export declare function targetsOf(e: FeedEntry): { key: string; kind: TopoNodeKind; name: string; id?: string; }[]; export declare function foldTopo(feed: FeedEntry[], agents: Presence[], opts?: { windowMs?: number; now?: number; /** The broker-authoritative membership feed as MeshView last read it. Absent, or a feed the * viewer could not read, overlays nothing: the fold never draws what the wire did not say. */ membership?: MembershipView; /** Channel registry names, for expanding bounded wildcard subscriptions. */ knownChannels?: string[]; /** id → display name (defaults to the roster, then an 8-char id prefix). */ nameOf?: (id: string) => string; }): TopoGraph; /** The four things the header pill can say about the membership feed, mirroring the web graph's * pill and checked in the same order: `unreadable` first, because "traffic-only" is a claim about * the MESH (no daemon writes a feed) while a failed read is a claim about US, and the two must * never collapse; then absent or never-written (traffic-only); then the heartbeat's age. */ export type MembershipFreshness = { label: "unreadable"; color: "red"; reason: string; } | { label: "traffic-only"; color?: undefined; } | { label: "live"; color: "green"; } | { label: "stale"; color: "yellow"; }; export declare function membershipFreshness(now: number, m: MembershipView): MembershipFreshness; export declare const HEAT: readonly [" ", "░", "▒", "▓", "█"]; export declare function heatLevel(rate: number): 0 | 1 | 2 | 3 | 4; /** Display label for a node — the renderers' single prefix rule. */ export declare function nodeLabel(n: TopoNode): string; /** The feed entries that flow over one edge, oldest-first (for inspectors/detail). */ export declare function edgeEntries(feed: FeedEntry[], edge: TopoEdge, graph: TopoGraph): FeedEntry[]; //# sourceMappingURL=model.d.ts.map