"use client"; import { Handle, Position, type NodeProps } from "@xyflow/react"; import { StatusDot } from "@/shared/components/flow/StatusDot"; // ── Layer pill color map (10-layer model) ───────────────────────────────── const LAYER_COLORS: Record = { L1: "#3b82f6", // prose — blue L3: "#f97316", // tool — orange L4: "#22c55e", // code — green L5: "#a855f7", // MCP — purple L6: "#9ca3af", // history — gray L9: "#ec4899", // pruning — pink }; /** Map engine name → layer tags for the pill display */ const ENGINE_LAYER_MAP: Record = { rtk: ["L3", "L4"], caveman: ["L1"], headroom: ["L3"], llmlingua: ["L9"], lite: ["L1"], sigmap: ["L1", "L3"], gcf: ["L4"], cocoindex: ["L5", "L6"], "caveman:full": ["L1"], "rtk:standard": ["L3", "L4"], }; function getSavingsColor(savingsPercent: number): string { if (savingsPercent >= 30) return "#22c55e"; if (savingsPercent >= 15) return "#f59e0b"; return "#6b7280"; } // ── Node data shape ─────────────────────────────────────────────────────── export interface EngineNodeData { engine: string; originalTokens: number; compressedTokens: number; savingsPercent: number; techniquesUsed: string[]; rulesApplied?: string[]; durationMs?: number; /** visual replay state */ stepState?: "pending" | "running" | "done" | "skipped"; label?: string; [key: string]: unknown; } // ── Component ───────────────────────────────────────────────────────────── export function EngineNode({ data }: NodeProps) { const { engine, originalTokens, compressedTokens, savingsPercent, techniquesUsed, durationMs, stepState = "done", } = data as EngineNodeData; const skipped = stepState === "skipped" || originalTokens === compressedTokens; const running = stepState === "running"; const color = getSavingsColor(savingsPercent as number); const layers = ENGINE_LAYER_MAP[engine as string] ?? []; const savings = savingsPercent as number; const tokIn = originalTokens as number; const tokOut = compressedTokens as number; const techniques = (techniquesUsed as string[]).slice(0, 2); const borderColor = skipped ? "var(--color-border)" : running ? "#f59e0b" : color; return (
{/* Header */}
{running && } {engine as string} {skipped && skip}
{/* Body — token bar */} {!skipped && (
{tokIn.toLocaleString()} {tokOut.toLocaleString()}
0 ? `${(tokOut / tokIn) * 100}%` : "100%", backgroundColor: color, }} />
)} {/* Footer */}
{!skipped && ( {`-${savings.toFixed(1)}%`} )} {techniques.length > 0 && ( {techniques.join(", ")} )} {durationMs != null && ( {(durationMs as number).toFixed(1)}ms )} {/* Layer pills */} {layers.length > 0 && (
{layers.map((layer) => ( {layer} ))}
)}
); } export default EngineNode;