import { BotIcon, CalendarClockIcon, GitForkIcon, PanelsTopLeftIcon, SquareTerminalIcon, } from "lucide-react"; import type { ReactNode } from "react"; import { CreatorMonogram } from "../creator-monogram"; import { ModelMark, modelDisplayName } from "../model-identity"; import { formatAbsoluteTime, formatExactTime, formatRelativeTime, inSentence, useMinuteNow, } from "../../../ui/relative-time"; import { StatusBadge } from "../../../ui/status-badge"; import { type CreatorRef, creatorInitials, creatorLabel } from "../../lib/creator-initials"; import { sessionHoverFacts } from "../../lib/session-hover-facts"; import type { RailSession } from "../../lib/session-list-entry"; import { cn } from "../../lib/utils"; /** One quiet fact: a 16px icon slot, then text that wraps under itself. */ function FactRow({ icon, children }: { icon: ReactNode; children: ReactNode }) { return (
{icon} {children}
); } function Timestamp({ label, iso, relative, now, }: { label: string; iso: string; relative: boolean; now: number; }) { const date = new Date(iso); if (Number.isNaN(date.getTime())) return null; const text = relative ? formatRelativeTime(date, { now }) : formatAbsoluteTime(date, { now }); return ( {label}{" "} ); } /** * The sidebar hover: what this session is doing and whether it needs you, * from the compact list row alone. Order follows importance - full title, * status with its real waiting or blocking context, model, sub-agent and * background activity, then a quiet footer. Anything empty or zero is left * out rather than shown as a blank label or "0". */ export function SessionRowHoverDetails({ session, title, descendantCount, descendantCountTruncated, showCreator = true, now: fixedNow, }: { session: RailSession; title: string; descendantCount: number; descendantCountTruncated: boolean; /** Creator attribution only helps in a workspace other people share. */ showCreator?: boolean | undefined; /** A fixed clock for tests and previews; otherwise labels refresh each minute. */ now?: number | undefined; }) { useMinuteNow(); const now = fixedNow ?? Date.now(); const facts = sessionHoverFacts(session, { descendantCount, descendantCountTruncated, now }); const createdBy: CreatorRef = session.createdBy; const creatorName = showCreator && (createdBy.kind === "service" || creatorInitials(createdBy) !== null) ? creatorLabel(createdBy) : null; const hasActivity = Boolean(facts.model || facts.subAgents || facts.commands); return (

{title}

{facts.status.label} {facts.context.map((line) => (

{line}

))}
{facts.reason ? (

{facts.reason}

) : null} {facts.origin ? (
) : null}
{hasActivity ? (
{facts.model ? ( }> {modelDisplayName(facts.model.id)} {facts.model.effort ? ( · {facts.model.effort} ) : null} ) : null} {facts.subAgents ? ( ) : null} {facts.commands ? ( ) : null}
) : null}
{creatorName ? (
{createdBy.kind === "subject" ? ( ) : ( )} {creatorName}
) : null}

); }