import { Tooltip } from "@cloudflare/kumo"; import type { CSSProperties } from "react"; import type { ProjectState } from "./contracts.ts"; export interface AgentIdentity { number: number; silk: 1 | 2 | 3; } /** Enrollment rank, never response/claim/race order. Legacy agents precede dated agents. */ export function agentIdentities(agents: ProjectState["agents"]): Map { const sorted = agents.toSorted((a, b) => { if (!a.createdAt && b.createdAt) return -1; if (a.createdAt && !b.createdAt) return 1; return ( (Date.parse(a.createdAt ?? "") || 0) - (Date.parse(b.createdAt ?? "") || 0) || a.name.localeCompare(b.name) ); }); return new Map( sorted.map((agent, index) => [ agent.name, { number: index + 1, silk: ((index % 3) + 1) as 1 | 2 | 3, }, ]), ); } export function silkStyle(identity?: AgentIdentity): CSSProperties { return { "--lane-silk": identity ? `var(--race-silk-${identity.silk})` : "var(--text-color-kumo-subtle)", } as CSSProperties; } export function Saddlecloth({ identity }: { identity?: AgentIdentity }) { // Unknown agents get no invented rank. Numbers always accompany a known silk. return ( {identity ? `Agent number ${identity.number}` : "Agent number unavailable"} ); } export type LaneMarkKind = | "claim" | "push" | "review" | "passed" | "failed" | "interrupted" | "approved" | "promoted"; export const markGlyph: Record = { claim: "●", push: "●", review: "○", passed: "✓", failed: "✗", interrupted: "!", approved: "◆", promoted: "●", }; export function LaneMarker({ kind }: { kind: LaneMarkKind | "unreached" | "reached" }) { const hurdle = kind === "passed" || kind === "failed" || kind === "interrupted"; const reached = kind !== "unreached" && kind !== "failed" && kind !== "interrupted"; return ( ); } /** FH-055-compatible API, shared with the fork graph. */ export function saddlecloth(state: ProjectState, agent: string): number | undefined { return agentIdentities(state.agents).get(agent)?.number; } export function laneSilkStyle(state: ProjectState, agent: string): CSSProperties { const style = silkStyle(agentIdentities(state.agents).get(agent)); return { ...style, "--entrant-silk": style["--lane-silk" as keyof CSSProperties], } as CSSProperties; } export function LaneRunner({ entrant, state, }: { entrant: { agent: string; repoName: string }; state: ProjectState; }) { return ( {entrant.agent} }> {entrant.repoName} ); } /** Decorative SVG lane path; callers supply only proven endpoints. */ export function LaneLine({ path }: { path: string }) { return