footprint-explainable-ui 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/flowchart.ts","../src/components/StageNode/StageNode.tsx","../src/theme/ThemeProvider.tsx","../src/theme/tokens.ts","../src/theme/styles.ts","../src/theme/useDarkModeTokens.ts","../src/components/TimeTravelDebugger/TimeTravelDebugger.tsx","../src/components/MemoryInspector/MemoryInspector.tsx","../src/components/NarrativeLog/NarrativeLog.tsx","../src/components/GanttTimeline/GanttTimeline.tsx","../src/components/FlowchartView/TraceFlow.tsx","../src/components/FlowchartView/TracedFlow.tsx","../src/components/FlowchartView/_internal/devWarn.ts","../src/components/FlowchartView/_internal/notifyChange.ts","../src/components/FlowchartView/createTraceRuntimeOverlay.ts","../src/components/FlowchartView/_internal/subflowDrill.ts","../src/components/FlowchartView/_internal/overlayProjection.ts","../src/components/FlowchartView/_internal/useSubflowDrill.ts","../src/components/FlowchartView/_internal/useChartAutoRefit.ts","../src/components/FlowchartView/SubflowBreadcrumbBar.tsx","../src/components/FlowchartView/SubflowBreadcrumb.tsx","../src/components/FlowchartView/useSubflowNavigation.ts","../src/components/FlowchartView/SubflowTree.tsx","../src/components/FlowchartView/_internal/keys.ts","../src/components/FlowchartView/_internal/walkSubflowSpecInto.ts","../src/components/FlowchartView/traceStructureRecorder.ts","../src/components/FlowchartView/createNodeViewRecorder.ts","../src/components/FlowchartView/createCommitFlowRecorder.ts","../src/components/FlowchartView/createTraceBundle.ts","../src/components/FlowchartView/_internal/useTranslator.ts","../src/components/FlowchartView/walkHelpers.ts","../src/components/FlowchartView/NodeInspector.tsx","../src/components/FlowchartView/CommitInspector.tsx","../src/components/FlowchartView/buildCommitChainTree.ts","../src/components/FlowchartView/CommitChainView.tsx","../src/components/FlowchartView/TraceExplorerShell.tsx","../src/components/FlowchartView/RunSlider.tsx"],"sourcesContent":["// Flowchart components (require @xyflow/react peer dependency)\n// Import from \"footprint-explainable-ui/flowchart\"\n//\n// v6+: recorder-driven only. The legacy spec-walk path was deleted.\n// Drive the chart via `createTraceStructureRecorder` →\n// `<TraceFlow graph={...} />` (build-time) or\n// `<TracedFlow graph={...} overlay={...} scrubIndex={...} />`\n// (build + runtime).\n\nexport { StageNode } from \"./components/StageNode\";\nexport type { StageNodeData } from \"./components/StageNode\";\n\nexport { TimeTravelDebugger } from \"./components/TimeTravelDebugger\";\nexport type { TimeTravelDebuggerProps } from \"./components/TimeTravelDebugger\";\n\n// Subflow drill-down navigation (recorder-driven)\nexport { SubflowBreadcrumb } from \"./components/FlowchartView\";\nexport type { SubflowBreadcrumbProps } from \"./components/FlowchartView\";\nexport { useSubflowNavigation } from \"./components/FlowchartView\";\nexport type { SubflowNavigation, BreadcrumbEntry } from \"./components/FlowchartView\";\n\n// Subflow manifest tree (no ReactFlow dependency — pure React)\nexport { SubflowTree } from \"./components/FlowchartView\";\nexport type { SubflowTreeProps, SubflowTreeEntry } from \"./components/FlowchartView\";\n\n// v6.0+ — event-driven trace recorder + xyflow renderer (StructureRecorder\n// consumer pattern, no spec-tree post-walk required).\nexport { createTraceStructureRecorder } from \"./components/FlowchartView\";\nexport type {\n MinimalStructureRecorder,\n TraceNode,\n TraceEdge,\n TraceNodeData,\n TraceEdgeData,\n TraceGraph,\n TraceStructureRecorderHandle,\n CreateTraceStructureRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport { TraceFlow, defaultTraceFlowLayout } from \"./components/FlowchartView\";\nexport type {\n TraceFlowProps,\n TraceFlowLayout,\n TraceFlowEdgeColors,\n} from \"./components/FlowchartView\";\n\n// v7.0 — runtime overlay recorder + traced (build+runtime) component.\n// Pair with createTraceStructureRecorder for the full time-travel\n// trace UI without spec-tree post-walks.\nexport { createTraceRuntimeOverlay, sliceOverlay } from \"./components/FlowchartView\";\nexport type {\n MinimalFlowRecorder,\n RuntimeExecutionStep,\n RuntimeOverlay,\n RuntimeOverlaySlice,\n TraceRuntimeOverlayHandle,\n CreateTraceRuntimeOverlayOptions,\n} from \"./components/FlowchartView\";\n\nexport { TracedFlow } from \"./components/FlowchartView\";\nexport type { TracedFlowProps, TracedFlowColors } from \"./components/FlowchartView\";\n\n// L8.0 — landing strip exports.\nexport { createTraceBundle } from \"./components/FlowchartView\";\nexport type {\n TraceBundle,\n CreateTraceBundleOptions,\n} from \"./components/FlowchartView\";\n\nexport { useTranslator } from \"./components/FlowchartView\";\nexport type { TranslatorHandleLike } from \"./components/FlowchartView\";\n\nexport { asStageId, asRuntimeStageId } from \"./components/FlowchartView\";\nexport type { StageId, RuntimeStageId } from \"./components/FlowchartView\";\n\n// L8.1 — NodeView translator + traversal helpers + inspector renderer\nexport { createNodeViewRecorder } from \"./components/FlowchartView\";\nexport type {\n MinimalNodeViewRecorder,\n NodeView,\n NodeViewIndex,\n ExecutionRecord,\n NodeViewRecorderHandle,\n CreateNodeViewRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport {\n walkForward,\n walkBackward,\n backtraceStructural,\n forwardtraceStructural,\n} from \"./components/FlowchartView\";\nexport type { WalkOptions } from \"./components/FlowchartView\";\n\nexport { NodeInspector } from \"./components/FlowchartView\";\nexport type { NodeInspectorProps } from \"./components/FlowchartView\";\n\n// L8.2 — CommitFlow translator + data-lineage backtrace + inspector\nexport {\n createCommitFlowRecorder,\n backtraceDataFlow,\n} from \"./components/FlowchartView\";\nexport type {\n MinimalCommitFlowRecorder,\n CommitView,\n CommitFlowIndex,\n DataDependency,\n CommitFlowRecorderHandle,\n CreateCommitFlowRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport { CommitInspector } from \"./components/FlowchartView\";\nexport type { CommitInspectorProps } from \"./components/FlowchartView\";\n\n// L8.3 — series-parallel chain tree builders + git-log swim-lane renderer\nexport {\n structureAsChainTree,\n buildCommitChainTree,\n} from \"./components/FlowchartView\";\nexport type {\n StructureChain,\n StructureChainLeaf,\n CommitChain,\n CommitChainLeaf,\n ChainTreeOptions,\n} from \"./components/FlowchartView\";\n\nexport { CommitChainView } from \"./components/FlowchartView\";\nexport type { CommitChainViewProps } from \"./components/FlowchartView\";\n\n// L8.4 — composed shell wiring the full L8 stack into a master/detail UI\nexport { TraceExplorerShell } from \"./components/FlowchartView\";\nexport type {\n TraceExplorerShellProps,\n TraceExplorerSlots,\n ChainSlotProps,\n CommitInspectorSlotProps,\n NodeInspectorSlotProps,\n SliderSlotProps,\n} from \"./components/FlowchartView\";\n\n// L8.5 — time-travel cursor slider (ONE-CURSOR model)\nexport { RunSlider } from \"./components/FlowchartView\";\nexport type { RunSliderProps } from \"./components/FlowchartView\";\n","import { memo, useEffect, useRef } from \"react\";\nimport { Handle, Position } from \"@xyflow/react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport { theme } from \"../../theme\";\n\nconst KEYFRAMES_ID = \"fp-stage-node-keyframes\";\nconst KEYFRAMES_CSS = `\n@media (prefers-reduced-motion: no-preference) {\n @keyframes fp-pulse {\n 0%, 100% { opacity: 0.4; transform: scale(1); }\n 50% { opacity: 0.15; transform: scale(1.06); }\n }\n @keyframes fp-blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n}\n@media (prefers-reduced-motion: reduce) {\n @keyframes fp-pulse { 0%, 100% { opacity: 0.3; } }\n @keyframes fp-blink { 0%, 100% { opacity: 1; } }\n}\n`;\n\nexport interface StageNodeData {\n label: string;\n active?: boolean;\n done?: boolean;\n error?: boolean;\n linked?: boolean;\n /** Semantic icon hint (e.g., \"llm\", \"tool\", \"rag\", \"start\", \"parse\", \"agent\", \"guard\") */\n icon?: string;\n /** Step numbers in execution order (shown as badges — multiple when revisited via loops) */\n stepNumbers?: number[];\n /** Node was not executed (dim it) */\n dimmed?: boolean;\n /** Node is a subflow root (show nested indicator) */\n isSubflow?: boolean;\n /** Node uses lazy resolution (dashed border + cloud icon when unresolved) */\n isLazy?: boolean;\n /** Node is a decider (renders as diamond shape per flowchart convention) */\n isDecider?: boolean;\n /** Node is a fork (parallel fan-out) */\n isFork?: boolean;\n /** Human-readable description of what this stage does */\n description?: string;\n /** Subflow identifier — set when this node belongs to a subflow */\n subflowId?: string;\n /**\n * Stable stage identifier from the spec (`SpecNode.id`). Renderable as a\n * small monospace caption under the label when `showStageId` is true —\n * useful for teaching the runtimeStageId convention and for debugging\n * which node a recorder event belongs to.\n */\n stageId?: string;\n /**\n * When true, render the `stageId` as a small monospace caption beneath\n * the label. Default false. Drives the \"Show IDs\" toggle in\n * ExplainableShell.\n */\n showStageId?: boolean;\n [key: string]: unknown;\n}\n\n// ── Stage icon SVGs ───────────────────────────────────────────────────────\n// Inline SVGs for crisp rendering at any size. Consumers pass a string key\n// via SpecNode.icon; StageNode renders the matching mini-icon.\n\nconst ICON_SIZE = 16;\n\nfunction StageIcon({ type, color }: { type: string; color: string }) {\n const s = ICON_SIZE;\n const props = { width: s, height: s, viewBox: `0 0 ${s} ${s}`, fill: \"none\", style: { flexShrink: 0 } as const };\n\n switch (type) {\n // LLM / AI call — brain/sparkle\n case \"llm\":\n case \"ai\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"8\" r=\"6\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M5.5 8C5.5 6.5 6.5 5 8 5S10.5 6.5 10.5 8\" stroke={color} strokeWidth=\"1.2\" strokeLinecap=\"round\" />\n <circle cx=\"8\" cy=\"9.5\" r=\"1\" fill={color} />\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"3.5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"12.5\" y1=\"4\" x2=\"11.2\" y2=\"5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"3.5\" y1=\"4\" x2=\"4.8\" y2=\"5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Tool / function call — gear\n case \"tool\":\n case \"function\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"8\" r=\"3\" stroke={color} strokeWidth=\"1.5\" />\n {[0, 45, 90, 135, 180, 225, 270, 315].map((angle) => {\n const rad = (angle * Math.PI) / 180;\n const x1 = 8 + Math.cos(rad) * 4.5;\n const y1 = 8 + Math.sin(rad) * 4.5;\n const x2 = 8 + Math.cos(rad) * 6;\n const y2 = 8 + Math.sin(rad) * 6;\n return <line key={angle} x1={x1} y1={y1} x2={x2} y2={y2} stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />;\n })}\n </svg>\n );\n\n // RAG / retrieval — magnifying glass + doc\n case \"rag\":\n case \"search\":\n case \"retrieval\":\n return (\n <svg {...props}>\n <circle cx=\"7\" cy=\"7\" r=\"4\" stroke={color} strokeWidth=\"1.5\" />\n <line x1=\"10\" y1=\"10\" x2=\"13.5\" y2=\"13.5\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"6\" x2=\"8.5\" y2=\"6\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"8\" x2=\"7.5\" y2=\"8\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Parse / process — diamond with arrows\n case \"parse\":\n case \"process\":\n case \"transform\":\n return (\n <svg {...props}>\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" stroke={color} strokeWidth=\"1.5\" transform=\"rotate(45 8 8)\" />\n </svg>\n );\n\n // Start / seed — play triangle\n case \"start\":\n case \"seed\":\n case \"init\":\n return (\n <svg {...props}>\n <path d=\"M5 3.5L12.5 8L5 12.5V3.5Z\" fill={color} opacity=\"0.8\" />\n </svg>\n );\n\n // End / finalize — stop square\n case \"end\":\n case \"finalize\":\n case \"output\":\n return (\n <svg {...props}>\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" fill={color} opacity=\"0.8\" />\n </svg>\n );\n\n // Agent — person silhouette\n case \"agent\":\n case \"orchestrator\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"5\" r=\"2.5\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M3.5 14C3.5 11 5.5 9 8 9S12.5 11 12.5 14\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Swarm — multi-agent\n case \"swarm\":\n case \"multi-agent\":\n return (\n <svg {...props}>\n <circle cx=\"5\" cy=\"5\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <circle cx=\"11\" cy=\"5\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <circle cx=\"8\" cy=\"11\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <line x1=\"5\" y1=\"7\" x2=\"8\" y2=\"9\" stroke={color} strokeWidth=\"1\" opacity=\"0.5\" />\n <line x1=\"11\" y1=\"7\" x2=\"8\" y2=\"9\" stroke={color} strokeWidth=\"1\" opacity=\"0.5\" />\n </svg>\n );\n\n // Guard / guardrail — shield\n case \"guard\":\n case \"guardrail\":\n case \"validate\":\n return (\n <svg {...props}>\n <path d=\"M8 2L3 5V9C3 11.5 5 13.5 8 14.5C11 13.5 13 11.5 13 9V5L8 2Z\" stroke={color} strokeWidth=\"1.5\" strokeLinejoin=\"round\" />\n <path d=\"M6 8L7.5 9.5L10 6.5\" stroke={color} strokeWidth=\"1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n\n // Stream — wave\n case \"stream\":\n case \"streaming\":\n return (\n <svg {...props}>\n <path d=\"M2 8C4 5 6 11 8 8S12 5 14 8\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" fill=\"none\" />\n <path d=\"M2 11C4 8 6 14 8 11S12 8 14 11\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" fill=\"none\" opacity=\"0.5\" />\n </svg>\n );\n\n // Memory / state — database cylinder\n case \"memory\":\n case \"state\":\n case \"db\":\n return (\n <svg {...props}>\n <ellipse cx=\"8\" cy=\"4.5\" rx=\"5\" ry=\"2\" stroke={color} strokeWidth=\"1.3\" />\n <line x1=\"3\" y1=\"4.5\" x2=\"3\" y2=\"11.5\" stroke={color} strokeWidth=\"1.3\" />\n <line x1=\"13\" y1=\"4.5\" x2=\"13\" y2=\"11.5\" stroke={color} strokeWidth=\"1.3\" />\n <ellipse cx=\"8\" cy=\"11.5\" rx=\"5\" ry=\"2\" stroke={color} strokeWidth=\"1.3\" />\n </svg>\n );\n\n // Loop — circular arrow\n case \"loop\":\n case \"retry\":\n return (\n <svg {...props}>\n <path d=\"M12 8A4 4 0 1 1 8 4\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" fill=\"none\" />\n <path d=\"M8 1.5L10.5 4L8 6.5\" stroke={color} strokeWidth=\"1.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" fill=\"none\" />\n </svg>\n );\n\n // Lazy / service — cloud (deferred resolution, loaded on demand)\n case \"lazy\":\n case \"service\":\n case \"cloud\":\n return (\n <svg {...props}>\n <path\n d=\"M4.5 12C2.8 12 1.5 10.7 1.5 9C1.5 7.5 2.5 6.3 3.8 6C4 4 5.8 2.5 8 2.5C9.8 2.5 11.3 3.5 11.9 5C13.9 5.2 15.5 6.8 15.5 8.8C15.5 10.8 13.9 12.5 11.8 12.5H4.5\"\n stroke={color}\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n fill=\"none\"\n />\n </svg>\n );\n\n // Decision — diamond (already handled by isDecider shape)\n case \"decision\":\n case \"router\":\n return (\n <svg {...props}>\n <path d=\"M8 2L14 8L8 14L2 8Z\" stroke={color} strokeWidth=\"1.5\" fill=\"none\" />\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill={color} />\n </svg>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * Custom ReactFlow node for pipeline stages.\n * All colors and fonts come from `--fp-*` CSS variables (via theme).\n * Shows execution state via color, icon, step badge, and pulse animation.\n */\nexport const StageNode = memo(function StageNode({\n data,\n}: NodeProps & { data: StageNodeData }) {\n const { label, active, done, error, linked, icon, stepNumbers, dimmed, isSubflow, isLazy, isDecider, isFork, description, stageId, showStageId } = data;\n\n // Lazy nodes show cloud icon by default (unless another icon is specified)\n const effectiveIcon = icon || (isLazy ? \"lazy\" : undefined);\n // Lazy + unresolved = dashed border\n const isLazyUnresolved = isLazy && !done && !active;\n\n // Inject keyframes once into document head\n const injectedRef = useRef(false);\n useEffect(() => {\n if (injectedRef.current) return;\n if (typeof document !== \"undefined\" && !document.getElementById(KEYFRAMES_ID)) {\n const styleEl = document.createElement(\"style\");\n styleEl.id = KEYFRAMES_ID;\n styleEl.textContent = KEYFRAMES_CSS;\n document.head.appendChild(styleEl);\n }\n injectedRef.current = true;\n }, []);\n\n const isOnPath = active || done;\n\n const bg = active\n ? theme.primary\n : done\n ? theme.success\n : error\n ? theme.error\n : theme.bgSecondary;\n\n const borderColor = active\n ? theme.primary\n : done\n ? theme.success\n : error\n ? theme.error\n : theme.border;\n\n const shadow = active\n ? `0 0 16px color-mix(in srgb, ${theme.primary} 40%, transparent)`\n : done\n ? `0 0 8px color-mix(in srgb, ${theme.success} 20%, transparent)`\n : error\n ? `0 0 12px color-mix(in srgb, ${theme.error} 30%, transparent)`\n : `0 2px 8px rgba(0,0,0,0.15)`;\n\n // Colored states use white for contrast; default uses consumer's text color.\n const textColor =\n active || done || error ? \"#fff\" : theme.textPrimary;\n\n return (\n <>\n <Handle type=\"target\" position={Position.Top} style={{ opacity: 0 }} />\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n }}\n >\n {/* Step number badges — multiple when revisited via loops */}\n {stepNumbers && stepNumbers.length > 0 && isOnPath && (\n <div\n style={{\n position: \"absolute\",\n top: -10,\n left: -10,\n display: \"flex\",\n gap: 3,\n zIndex: 10,\n }}\n >\n {stepNumbers.map((num, i) => {\n const isLatest = i === stepNumbers.length - 1;\n const badgeBg = isLatest && active ? theme.primary : theme.success;\n const glow = isLatest && active\n ? `color-mix(in srgb, ${theme.primary} 50%, transparent)`\n : `color-mix(in srgb, ${theme.success} 40%, transparent)`;\n return (\n <div\n key={num}\n style={{\n width: 22,\n height: 22,\n borderRadius: \"50%\",\n background: badgeBg,\n color: \"#fff\",\n fontSize: 11,\n fontWeight: 700,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: `0 0 8px ${glow}`,\n }}\n >\n {num}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Linked pulse ring */}\n {linked && (\n <div\n style={{\n position: \"absolute\",\n inset: -6,\n borderRadius: isDecider ? 0 : `calc(${theme.radius} + 4px)`,\n clipPath: isDecider ? \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\" : undefined,\n border: `2px solid ${theme.primary}`,\n opacity: 0.4,\n animation: \"fp-pulse 2s ease-in-out infinite\",\n }}\n />\n )}\n\n {/* Active node pulse ring */}\n {active && (\n <div\n style={{\n position: \"absolute\",\n inset: -6,\n borderRadius: isDecider ? 0 : `calc(${theme.radius} + 4px)`,\n clipPath: isDecider ? \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\" : undefined,\n border: `2px solid ${theme.primary}`,\n opacity: 0.3,\n animation: \"fp-pulse 1.5s ease-out infinite\",\n }}\n />\n )}\n\n {/* Diamond for decider nodes — proper diamond via clip-path */}\n {isDecider ? (\n <div style={{ position: \"relative\", width: 120, height: 72 }}>\n {/* Diamond shape layer */}\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: bg,\n clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\",\n border: \"none\",\n boxShadow: shadow,\n transition: \"all 0.3s ease\",\n }}\n />\n {/* Border layer — slightly larger diamond behind */}\n <div\n style={{\n position: \"absolute\",\n inset: -2,\n clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\",\n background: borderColor,\n zIndex: -1,\n ...(isLazyUnresolved ? {\n background: \"transparent\",\n // Dashed border via SVG for clip-path (CSS border doesn't work with clip-path)\n } : {}),\n }}\n />\n {/* Content — centered on top of diamond */}\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 1,\n fontFamily: theme.fontSans,\n zIndex: 1,\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 4 }}>\n {effectiveIcon && <StageIcon type={effectiveIcon} color={textColor} />}\n {!effectiveIcon && (\n <span style={{ fontSize: 9, color: textColor }}>&#x25C7;</span>\n )}\n <span\n style={{\n fontSize: 11,\n fontWeight: 600,\n color: textColor,\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n </span>\n </div>\n {description && (\n <span\n style={{\n fontSize: 8,\n fontWeight: 400,\n color: textColor,\n opacity: 0.7,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 100,\n }}\n >\n {description}\n </span>\n )}\n {showStageId && stageId && (\n <span\n style={{\n fontSize: 8,\n fontFamily: \"ui-monospace, monospace\",\n color: textColor,\n opacity: 0.55,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 100,\n }}\n title={`stageId: ${stageId}`}\n >\n {stageId}\n </span>\n )}\n </div>\n </div>\n ) : (\n /* Standard rectangular node */\n <div\n style={{\n background: bg,\n border: `2px ${isLazyUnresolved ? \"dashed\" : \"solid\"} ${borderColor}`,\n borderRadius: theme.radius,\n padding: description ? \"8px 16px\" : \"10px 20px\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: description ? 2 : 0,\n boxShadow: shadow,\n transition: \"all 0.3s ease\",\n fontFamily: theme.fontSans,\n minWidth: 100,\n justifyContent: \"center\",\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n {/* Semantic icon (lazy nodes default to cloud icon) */}\n {effectiveIcon && <StageIcon type={effectiveIcon} color={textColor} />}\n\n {/* State icon */}\n {done && !effectiveIcon && (\n <span style={{ fontSize: 10, color: textColor }}>&#x2713;</span>\n )}\n {active && !effectiveIcon && (\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: \"#fff\",\n animation: \"fp-blink 1s ease-in-out infinite\",\n flexShrink: 0,\n }}\n />\n )}\n {error && !effectiveIcon && (\n <span style={{ fontSize: 10, color: textColor }}>&#x2717;</span>\n )}\n\n <span\n style={{\n fontSize: 13,\n fontWeight: 500,\n color: textColor,\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n </span>\n {/* Subflow indicator — nested boxes icon */}\n {isSubflow && (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 16,\n height: 16,\n borderRadius: 3,\n border: `1.5px solid ${textColor}`,\n position: \"relative\",\n opacity: 0.7,\n flexShrink: 0,\n }}\n >\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: 2,\n border: `1px solid ${textColor}`,\n }}\n />\n </span>\n )}\n </div>\n {/* Description subtitle */}\n {description && (\n <span\n style={{\n fontSize: 10,\n fontWeight: 400,\n color: textColor,\n opacity: 0.7,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 160,\n }}\n >\n {description}\n </span>\n )}\n {/* Stage ID caption — toggled by `showStageId`. Teaches the\n runtimeStageId convention; recorders key their data by\n this ID so consumers can render any recorder's per-stage\n output by lookup. */}\n {showStageId && stageId && (\n <span\n style={{\n fontSize: 9,\n fontFamily: \"ui-monospace, monospace\",\n color: textColor,\n opacity: 0.55,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 160,\n }}\n title={`stageId: ${stageId}`}\n >\n {stageId}\n </span>\n )}\n </div>\n )}\n </div>\n <Handle type=\"source\" position={Position.Bottom} style={{ opacity: 0 }} />\n {/* Loop handles: source exits bottom-right, target enters from right.\n Creates a clockwise arc: down → right → up → back into right side. */}\n <Handle\n id=\"loop-source\"\n type=\"source\"\n position={Position.Bottom}\n style={{ background: \"transparent\", border: \"none\", width: 6, height: 6, left: \"75%\" }}\n />\n <Handle\n id=\"loop-target\"\n type=\"target\"\n position={Position.Right}\n style={{ background: \"transparent\", border: \"none\", width: 6, height: 6 }}\n />\n </>\n );\n});\n","import { createContext, useContext } from \"react\";\nimport type { ThemeTokens } from \"./tokens\";\nimport { tokensToCSSVars } from \"./tokens\";\n\nconst ThemeContext = createContext<ThemeTokens>({});\n\nexport function useFootprintTheme(): ThemeTokens {\n return useContext(ThemeContext);\n}\n\ninterface FootprintThemeProps {\n tokens?: ThemeTokens;\n children: React.ReactNode;\n}\n\n/**\n * Optional theme provider — wraps children with CSS custom properties.\n * Consumers can also just set --fp-* CSS variables directly.\n *\n * Wrapper div uses `display: contents` so it's invisible to the\n * parent's layout (flex / grid / block). This matters because themed\n * children often need to fill a parent (flex:1 / height:100% /\n * grid cells), and a regular block `<div>` here would break that\n * chain — descendants would resolve to 0 height when the parent is\n * flex-column or a grid cell with minmax(0, 1fr). `display: contents`\n * removes the box from the render tree while keeping the DOM intact,\n * so CSS custom property inheritance (which follows the DOM) still\n * flows to children.\n *\n * Trade-off: `display: contents` elements are removed from the\n * accessibility tree in some older browser versions. Our wrapper has\n * no semantic role, so this is fine.\n */\nexport function FootprintTheme({ tokens = {}, children }: FootprintThemeProps) {\n const cssVars = tokensToCSSVars(tokens);\n\n return (\n <ThemeContext.Provider value={tokens}>\n <div\n style={{ ...(cssVars as React.CSSProperties), display: \"contents\" }}\n className=\"fp-theme-root\"\n >\n {children}\n </div>\n </ThemeContext.Provider>\n );\n}\n","/** Default theme tokens — consumers override via CSS variables or ThemeProvider. */\nexport interface ThemeTokens {\n colors?: {\n primary?: string;\n success?: string;\n error?: string;\n warning?: string;\n bgPrimary?: string;\n bgSecondary?: string;\n bgTertiary?: string;\n textPrimary?: string;\n textSecondary?: string;\n textMuted?: string;\n border?: string;\n };\n radius?: string;\n fontFamily?: {\n sans?: string;\n mono?: string;\n };\n}\n\n/** Maps ThemeTokens to CSS custom property assignments. */\nexport function tokensToCSSVars(tokens: ThemeTokens): Record<string, string> {\n const vars: Record<string, string> = {};\n if (tokens.colors) {\n const c = tokens.colors;\n if (c.primary) vars[\"--fp-color-primary\"] = c.primary;\n if (c.success) vars[\"--fp-color-success\"] = c.success;\n if (c.error) vars[\"--fp-color-error\"] = c.error;\n if (c.warning) vars[\"--fp-color-warning\"] = c.warning;\n if (c.bgPrimary) vars[\"--fp-bg-primary\"] = c.bgPrimary;\n if (c.bgSecondary) vars[\"--fp-bg-secondary\"] = c.bgSecondary;\n if (c.bgTertiary) vars[\"--fp-bg-tertiary\"] = c.bgTertiary;\n if (c.textPrimary) vars[\"--fp-text-primary\"] = c.textPrimary;\n if (c.textSecondary) vars[\"--fp-text-secondary\"] = c.textSecondary;\n if (c.textMuted) vars[\"--fp-text-muted\"] = c.textMuted;\n if (c.border) vars[\"--fp-border\"] = c.border;\n }\n if (tokens.radius) vars[\"--fp-radius\"] = tokens.radius;\n if (tokens.fontFamily?.sans) vars[\"--fp-font-sans\"] = tokens.fontFamily.sans;\n if (tokens.fontFamily?.mono) vars[\"--fp-font-mono\"] = tokens.fontFamily.mono;\n return vars;\n}\n\n/** Raw fallback values — used by tokensToCSSVars() and anywhere a real color is needed. */\nexport const rawDefaults = {\n colors: {\n primary: \"#6366f1\",\n success: \"#22c55e\",\n error: \"#ef4444\",\n warning: \"#f59e0b\",\n bgPrimary: \"#0f172a\",\n bgSecondary: \"#1e293b\",\n bgTertiary: \"#334155\",\n textPrimary: \"#f8fafc\",\n textSecondary: \"#94a3b8\",\n textMuted: \"#64748b\",\n border: \"#334155\",\n },\n radius: \"8px\",\n fontFamily: {\n sans: \"Inter, system-ui, -apple-system, sans-serif\",\n mono: \"'JetBrains Mono', 'Fira Code', monospace\",\n },\n} as const;\n\n/** Default dark theme values with CSS variable references (consumers can override via CSS). */\nexport const defaultTokens: Required<{\n [K in keyof ThemeTokens]-?: Required<ThemeTokens[K]>;\n}> = {\n colors: {\n primary: `var(--fp-color-primary, ${rawDefaults.colors.primary})`,\n success: `var(--fp-color-success, ${rawDefaults.colors.success})`,\n error: `var(--fp-color-error, ${rawDefaults.colors.error})`,\n warning: `var(--fp-color-warning, ${rawDefaults.colors.warning})`,\n bgPrimary: `var(--fp-bg-primary, ${rawDefaults.colors.bgPrimary})`,\n bgSecondary: `var(--fp-bg-secondary, ${rawDefaults.colors.bgSecondary})`,\n bgTertiary: `var(--fp-bg-tertiary, ${rawDefaults.colors.bgTertiary})`,\n textPrimary: `var(--fp-text-primary, ${rawDefaults.colors.textPrimary})`,\n textSecondary: `var(--fp-text-secondary, ${rawDefaults.colors.textSecondary})`,\n textMuted: `var(--fp-text-muted, ${rawDefaults.colors.textMuted})`,\n border: `var(--fp-border, ${rawDefaults.colors.border})`,\n },\n radius: `var(--fp-radius, ${rawDefaults.radius})`,\n fontFamily: {\n sans: `var(--fp-font-sans, ${rawDefaults.fontFamily.sans})`,\n mono: `var(--fp-font-mono, ${rawDefaults.fontFamily.mono})`,\n },\n};\n","import type { Size } from \"../types\";\n\n/**\n * Helper to resolve a CSS variable with a fallback.\n * Usage: v(\"--fp-color-primary\", \"#6366f1\")\n */\nexport function v(varName: string, fallback: string): string {\n return `var(${varName}, ${fallback})`;\n}\n\n/** Shorthand for common theme variables */\nexport const theme = {\n primary: v(\"--fp-color-primary\", \"#6366f1\"),\n success: v(\"--fp-color-success\", \"#22c55e\"),\n error: v(\"--fp-color-error\", \"#ef4444\"),\n warning: v(\"--fp-color-warning\", \"#f59e0b\"),\n bgPrimary: v(\"--fp-bg-primary\", \"#0f172a\"),\n bgSecondary: v(\"--fp-bg-secondary\", \"#1e293b\"),\n bgTertiary: v(\"--fp-bg-tertiary\", \"#334155\"),\n textPrimary: v(\"--fp-text-primary\", \"#f8fafc\"),\n textSecondary: v(\"--fp-text-secondary\", \"#94a3b8\"),\n textMuted: v(\"--fp-text-muted\", \"#64748b\"),\n border: v(\"--fp-border\", \"#334155\"),\n radius: v(\"--fp-radius\", \"8px\"),\n fontSans: v(\"--fp-font-sans\", \"Inter, system-ui, -apple-system, sans-serif\"),\n fontMono: v(\"--fp-font-mono\", \"'JetBrains Mono', 'Fira Code', monospace\"),\n} as const;\n\n/** Font sizes per size variant */\nexport const fontSize: Record<Size, { label: number; body: number; small: number }> = {\n compact: { label: 10, body: 11, small: 9 },\n default: { label: 11, body: 12, small: 10 },\n detailed: { label: 12, body: 13, small: 11 },\n};\n\n/** Padding per size variant */\nexport const padding: Record<Size, number> = {\n compact: 8,\n default: 12,\n detailed: 16,\n};\n","/**\n * useDarkModeTokens — Auto-bridge between CSS class-based dark mode and FootprintTheme.\n *\n * Watches for a `.dark` class on <html> (Tailwind convention) and returns\n * the appropriate ThemeTokens preset. Pairs with FootprintTheme:\n *\n * import { FootprintTheme, useDarkModeTokens } from 'footprint-explainable-ui';\n *\n * function MyApp() {\n * const tokens = useDarkModeTokens();\n * return (\n * <FootprintTheme tokens={tokens}>\n * <NarrativeTrace ... />\n * </FootprintTheme>\n * );\n * }\n *\n * Consumers can override the light/dark presets:\n *\n * const tokens = useDarkModeTokens({ light: warmLight, dark: warmDark });\n */\n\nimport { useState, useEffect } from \"react\";\nimport type { ThemeTokens } from \"./tokens\";\nimport { coolDark } from \"./presets\";\nimport { coolLight } from \"./presets\";\n\nexport interface DarkModeTokensOptions {\n /** Tokens to use in light mode. Defaults to coolLight. */\n light?: ThemeTokens;\n /** Tokens to use in dark mode. Defaults to coolDark. */\n dark?: ThemeTokens;\n /** CSS selector to watch for dark mode. Defaults to checking .dark on documentElement. */\n selector?: string;\n}\n\nexport function useDarkModeTokens(options?: DarkModeTokensOptions): ThemeTokens {\n const lightTokens = options?.light ?? coolLight;\n const darkTokens = options?.dark ?? coolDark;\n\n const [isDark, setIsDark] = useState(\n () => document.documentElement.classList.contains(options?.selector ?? \"dark\"),\n );\n\n useEffect(() => {\n const cls = options?.selector ?? \"dark\";\n const obs = new MutationObserver(() => {\n setIsDark(document.documentElement.classList.contains(cls));\n });\n obs.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n return () => obs.disconnect();\n }, [options?.selector]);\n\n return isDark ? darkTokens : lightTokens;\n}\n","import { useState } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\nimport { MemoryInspector } from \"../MemoryInspector\";\nimport { NarrativeLog } from \"../NarrativeLog\";\nimport { GanttTimeline } from \"../GanttTimeline\";\nimport { TraceFlow } from \"../FlowchartView/TraceFlow\";\nimport { TracedFlow } from \"../FlowchartView/TracedFlow\";\nimport type { TraceGraph } from \"../FlowchartView/traceStructureRecorder\";\nimport type { RuntimeOverlay } from \"../FlowchartView/createTraceRuntimeOverlay\";\n\nexport interface TimeTravelDebuggerProps extends BaseComponentProps {\n /** Stage snapshots */\n snapshots: StageSnapshot[];\n /** Recorder-captured build-time graph (from\n * `createTraceStructureRecorder().getGraph()`). Required for the\n * chart rendering — replaces the legacy `nodes` / `edges` props. */\n graph: TraceGraph;\n /** Optional runtime overlay (from\n * `createTraceRuntimeOverlay().getOverlay()`). When provided, the\n * chart renders via `<TracedFlow>` with per-step coloring synced to\n * the scrubber; otherwise renders via `<TraceFlow>` (build-time only). */\n runtimeOverlay?: RuntimeOverlay;\n /** Show Gantt timeline */\n showGantt?: boolean;\n /** Layout direction */\n layout?: \"horizontal\" | \"vertical\";\n /** Title */\n title?: string;\n}\n\n/**\n * Full time-travel debugger: scrubber + recorder-driven flowchart +\n * memory + narrative + gantt. This is the \"batteries included\"\n * component for pipeline debugging.\n *\n * v6+: chart rendering is recorder-driven. Pass `graph` (always) and\n * optionally `runtimeOverlay` for per-step coloring tied to the\n * scrubber.\n */\nexport function TimeTravelDebugger({\n snapshots,\n graph,\n runtimeOverlay,\n showGantt = true,\n layout = \"horizontal\",\n title = \"Time-Travel Debugger\",\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: TimeTravelDebuggerProps) {\n const [selectedIndex, setSelectedIndex] = useState(0);\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (snapshots.length === 0) {\n return (\n <div\n className={className}\n style={{\n padding: pad * 2,\n textAlign: \"center\",\n color: theme.textMuted,\n ...style,\n }}\n >\n No snapshots to debug\n </div>\n );\n }\n\n const isHorizontal = layout === \"horizontal\";\n\n // Click → jump scrubber to whichever snapshot maps to the clicked\n // stage. Matches the legacy `onNodeClick(index)` semantics: callers\n // receive a stage id, we translate to a snapshot index.\n const handleNodeClick = (stageId: string) => {\n const idx = snapshots.findIndex(\n (s) => s.stageName === stageId || s.stageLabel === stageId,\n );\n if (idx >= 0) setSelectedIndex(idx);\n };\n\n const chart = runtimeOverlay ? (\n <TracedFlow\n graph={graph}\n overlay={runtimeOverlay}\n scrubIndex={selectedIndex}\n onNodeClick={handleNodeClick}\n />\n ) : (\n <TraceFlow graph={graph} onNodeClick={handleNodeClick} />\n );\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"time-travel-debugger\">\n <h3>{title}</h3>\n <input\n type=\"range\"\n min={0}\n max={snapshots.length - 1}\n value={selectedIndex}\n onChange={(e) => setSelectedIndex(parseInt(e.target.value))}\n />\n {chart}\n <MemoryInspector\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n unstyled\n />\n <NarrativeLog\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n unstyled\n />\n {showGantt && (\n <GanttTimeline\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onSelect={setSelectedIndex}\n unstyled\n />\n )}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n background: theme.bgPrimary,\n fontFamily: theme.fontSans,\n overflow: \"hidden\",\n ...style,\n }}\n data-fp=\"time-travel-debugger\"\n >\n {/* Scrubber header */}\n <div\n style={{\n padding: `${pad}px ${pad + 4}px`,\n borderBottom: `1px solid ${theme.border}`,\n background: theme.bgSecondary,\n flexShrink: 0,\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n marginBottom: 8,\n }}\n >\n <span\n style={{\n fontSize: fs.body + 2,\n fontWeight: 600,\n color: theme.textPrimary,\n }}\n >\n {title}\n </span>\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n }}\n >\n Scrub to replay execution\n </span>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <ScrubButton\n label=\"◀\"\n disabled={selectedIndex === 0}\n onClick={() => setSelectedIndex((i) => Math.max(0, i - 1))}\n />\n <input\n type=\"range\"\n min={0}\n max={snapshots.length - 1}\n value={selectedIndex}\n onChange={(e) => setSelectedIndex(parseInt(e.target.value))}\n style={{\n flex: 1,\n height: 4,\n accentColor: theme.primary,\n cursor: \"pointer\",\n }}\n />\n <ScrubButton\n label=\"▶\"\n disabled={selectedIndex === snapshots.length - 1}\n onClick={() =>\n setSelectedIndex((i) => Math.min(snapshots.length - 1, i + 1))\n }\n />\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n flexShrink: 0,\n fontFamily: theme.fontMono,\n }}\n >\n {selectedIndex + 1}/{snapshots.length}\n </span>\n </div>\n </div>\n\n {/* Main content: flowchart + data panels */}\n <div\n style={{\n flex: 1,\n display: \"flex\",\n flexDirection: isHorizontal ? \"row\" : \"column\",\n overflow: \"hidden\",\n }}\n >\n {/* Flowchart */}\n <div\n style={{\n flex: 1,\n overflow: \"hidden\",\n borderRight: isHorizontal\n ? `1px solid ${theme.border}`\n : \"none\",\n borderBottom: !isHorizontal\n ? `1px solid ${theme.border}`\n : \"none\",\n }}\n >\n {chart}\n </div>\n\n {/* Data panel */}\n <div style={{ flex: 1, overflow: \"auto\" }}>\n <MemoryInspector\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n size={size}\n />\n <div\n style={{\n height: 1,\n background: theme.border,\n margin: `0 ${pad}px`,\n }}\n />\n <NarrativeLog\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n size={size}\n />\n </div>\n </div>\n\n {/* Gantt footer */}\n {showGantt && (\n <div\n style={{\n borderTop: `1px solid ${theme.border}`,\n background: theme.bgSecondary,\n flexShrink: 0,\n }}\n >\n <GanttTimeline\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onSelect={setSelectedIndex}\n size={size}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction ScrubButton({\n label,\n disabled,\n onClick,\n}: {\n label: string;\n disabled: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n onClick={onClick}\n disabled={disabled}\n style={{\n background: theme.bgTertiary,\n border: `1px solid ${theme.border}`,\n color: disabled ? theme.textMuted : theme.textPrimary,\n borderRadius: 6,\n width: 28,\n height: 28,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: disabled ? \"not-allowed\" : \"pointer\",\n opacity: disabled ? 0.5 : 1,\n fontSize: 12,\n flexShrink: 0,\n }}\n >\n {label}\n </button>\n );\n}\n","import { useMemo, useRef } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface MemoryInspectorProps extends BaseComponentProps {\n /** Single memory object or snapshots (will accumulate up to selectedIndex) */\n data?: Record<string, unknown>;\n /** When using snapshots mode, pass these instead of data */\n snapshots?: StageSnapshot[];\n /** Index to accumulate up to (for time-travel) */\n selectedIndex?: number;\n /** Show data types alongside values */\n showTypes?: boolean;\n /** Highlight keys that are new at this step */\n highlightNew?: boolean;\n}\n\n/** Cache for incremental memory accumulation — avoids O(n) rebuild on every slider scrub. */\ninterface MemoryCache {\n snapshots: StageSnapshot[];\n index: number;\n accumulated: Record<string, unknown>;\n}\n\n/**\n * Displays pipeline memory state as formatted JSON.\n * Supports both static (data prop) and time-travel (snapshots + selectedIndex) modes.\n */\nexport function MemoryInspector({\n data,\n snapshots,\n selectedIndex = 0,\n showTypes = false,\n highlightNew = true,\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: MemoryInspectorProps) {\n // Incremental cache: accumulate forward from last known index instead of rebuilding from 0\n const cacheRef = useRef<MemoryCache | null>(null);\n\n const { memory, newKeys } = useMemo(() => {\n if (data) {\n return { memory: data, newKeys: new Set<string>() };\n }\n if (!snapshots || snapshots.length === 0) {\n return { memory: {}, newKeys: new Set<string>() };\n }\n\n const safeIdx = Math.min(selectedIndex, snapshots.length - 1);\n let merged: Record<string, unknown>;\n const cache = cacheRef.current;\n\n if (cache && cache.snapshots === snapshots && cache.index <= safeIdx) {\n // Forward scrub: extend from cached state\n merged = { ...cache.accumulated };\n for (let i = cache.index + 1; i <= safeIdx; i++) {\n Object.assign(merged, snapshots[i]?.memory);\n }\n } else {\n // Backward scrub or new snapshots: rebuild from scratch\n merged = {};\n for (let i = 0; i <= safeIdx; i++) {\n Object.assign(merged, snapshots[i]?.memory);\n }\n }\n\n // Update cache\n cacheRef.current = { snapshots, index: safeIdx, accumulated: merged };\n\n const nk = new Set<string>();\n if (highlightNew && safeIdx > 0) {\n // Previous state is cache at safeIdx-1, or rebuild if needed\n let prev: Record<string, unknown>;\n if (cache && cache.snapshots === snapshots && cache.index === safeIdx - 1) {\n prev = cache.accumulated;\n } else {\n prev = {};\n for (let i = 0; i < safeIdx; i++) {\n Object.assign(prev, snapshots[i]?.memory);\n }\n }\n const current = snapshots[safeIdx]?.memory ?? {};\n for (const k of Object.keys(current)) {\n if (!(k in prev)) nk.add(k);\n }\n } else if (highlightNew && safeIdx === 0 && snapshots[0]) {\n for (const k of Object.keys(snapshots[0].memory)) nk.add(k);\n }\n\n return { memory: merged, newKeys: nk };\n }, [data, snapshots, selectedIndex, highlightNew]);\n\n const entries = Object.entries(memory);\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"memory-inspector\" role=\"region\" aria-label=\"Memory state\">\n <div data-fp=\"memory-label\">Memory State</div>\n <pre data-fp=\"memory-json\">\n <code>{JSON.stringify(memory, null, 2)}</code>\n </pre>\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: pad,\n fontFamily: theme.fontSans,\n ...style,\n }}\n data-fp=\"memory-inspector\"\n role=\"region\"\n aria-label=\"Memory state\"\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n Memory State\n </span>\n <div\n style={{\n marginTop: 8,\n background: theme.bgSecondary,\n border: `1px solid ${theme.border}`,\n borderRadius: theme.radius,\n padding: `${pad}px ${pad + 4}px`,\n fontFamily: theme.fontMono,\n fontSize: fs.body,\n lineHeight: 1.8,\n }}\n >\n <span style={{ color: theme.textMuted }}>{\"{\"}</span>\n {entries.length === 0 && (\n <div\n style={{\n paddingLeft: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n }}\n >\n {\"// empty\"}\n </div>\n )}\n {entries.map(([key, value], i) => {\n const isNew = newKeys.has(key);\n const isLast = i === entries.length - 1;\n return (\n <div\n key={key}\n style={{\n paddingLeft: 16,\n background: isNew\n ? `color-mix(in srgb, ${theme.success} 10%, transparent)`\n : \"transparent\",\n borderRadius: 4,\n marginLeft: -4,\n marginRight: -4,\n paddingRight: 4,\n }}\n >\n <span style={{ color: theme.primary }}>&quot;{key}&quot;</span>\n <span style={{ color: theme.textMuted }}>: </span>\n <span style={{ color: theme.success }}>\n {formatValue(value)}\n </span>\n {showTypes && (\n <span\n style={{\n color: theme.textMuted,\n fontSize: fs.small,\n marginLeft: 8,\n opacity: 0.6,\n }}\n >\n ({typeof value})\n </span>\n )}\n {!isLast && <span style={{ color: theme.textMuted }}>,</span>}\n </div>\n );\n })}\n <span style={{ color: theme.textMuted }}>{\"}\"}</span>\n </div>\n </div>\n );\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") return `\"${value}\"`;\n if (typeof value === \"object\" && value !== null) return JSON.stringify(value);\n return String(value);\n}\n","import { useMemo } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface NarrativeLogProps extends BaseComponentProps {\n /** Snapshots to display narratives from */\n snapshots: StageSnapshot[];\n /** Show narratives up to this index (for time-travel sync) */\n selectedIndex?: number;\n /** Show a single narrative string (simple mode) */\n narrative?: string;\n}\n\n/**\n * Timeline-style execution log showing what happened at each stage.\n * Supports both full snapshots mode and single-narrative mode.\n */\nexport function NarrativeLog({\n snapshots,\n selectedIndex,\n narrative,\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: NarrativeLogProps) {\n const entries = useMemo(() => {\n if (narrative) {\n return [{ label: \"Output\", text: narrative, isCurrent: true }];\n }\n const idx = selectedIndex ?? snapshots.length - 1;\n return snapshots.slice(0, idx + 1).map((s, i) => ({\n label: s.stageLabel,\n text: s.narrative,\n isCurrent: i === idx,\n }));\n }, [snapshots, selectedIndex, narrative]);\n\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"narrative-log\">\n {entries.map((entry, i) => (\n <div key={i} data-fp=\"narrative-entry\" data-current={entry.isCurrent}>\n <strong>{entry.label}</strong>\n <p>{entry.text}</p>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{ padding: pad, fontFamily: theme.fontSans, ...style }}\n data-fp=\"narrative-log\"\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n Execution Log\n </span>\n <div style={{ marginTop: 8, display: \"flex\", flexDirection: \"column\" }}>\n {entries.map((entry, i) => (\n <div\n key={i}\n style={{\n display: \"flex\",\n gap: 10,\n padding: `${pad}px 0`,\n borderBottom:\n i < entries.length - 1 ? `1px solid ${theme.border}` : \"none\",\n }}\n >\n {/* Timeline dot + line */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n width: 12,\n flexShrink: 0,\n paddingTop: 5,\n }}\n >\n <div\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: entry.isCurrent ? theme.primary : theme.success,\n flexShrink: 0,\n }}\n />\n {i < entries.length - 1 && (\n <div\n style={{\n width: 1,\n flex: 1,\n background: theme.border,\n marginTop: 4,\n }}\n />\n )}\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, minWidth: 0 }}>\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: entry.isCurrent ? theme.primary : theme.textMuted,\n }}\n >\n {entry.label}\n </span>\n <div\n style={{\n fontSize: fs.body,\n lineHeight: 1.5,\n color: entry.isCurrent ? theme.textPrimary : theme.textSecondary,\n marginTop: 2,\n }}\n >\n {entry.text}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n","import { useState, useMemo, useRef, useEffect } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface GanttTimelineProps extends BaseComponentProps {\n /** Stage snapshots with timing info */\n snapshots: StageSnapshot[];\n /** Currently selected stage index */\n selectedIndex?: number;\n /** Callback when a stage bar is clicked */\n onSelect?: (index: number) => void;\n /** Max visible rows before collapsing (0 = no collapse). Default: 5 */\n maxVisibleRows?: number;\n}\n\n/**\n * Horizontal Gantt-style timeline showing stage durations and overlap.\n * Collapses to `maxVisibleRows` with expand/collapse toggle.\n * Auto-scrolls to keep the active stage visible when collapsed.\n */\nexport function GanttTimeline({\n snapshots,\n selectedIndex = 0,\n onSelect,\n size = \"default\",\n unstyled = false,\n className,\n style,\n maxVisibleRows = 5,\n}: GanttTimelineProps) {\n const [expanded, setExpanded] = useState(false);\n const activeRowRef = useRef<HTMLDivElement | null>(null);\n const scrollContainerRef = useRef<HTMLDivElement | null>(null);\n\n const totalWallTime = useMemo(\n () => Math.max(...snapshots.map((s) => s.startMs + s.durationMs), 1),\n [snapshots]\n );\n\n const fs = fontSize[size];\n const pad = padding[size];\n const labelWidth = size === \"compact\" ? 50 : size === \"detailed\" ? 100 : 80;\n const msWidth = size === \"compact\" ? 28 : 36;\n const rowHeight = size === \"compact\" ? 18 : 22;\n\n const collapsible = maxVisibleRows > 0 && snapshots.length > maxVisibleRows;\n const showAll = expanded || !collapsible;\n\n // Auto-scroll to active row when collapsed\n useEffect(() => {\n if (!showAll && activeRowRef.current && scrollContainerRef.current) {\n activeRowRef.current.scrollIntoView({\n block: \"nearest\",\n behavior: \"smooth\",\n });\n }\n }, [selectedIndex, showAll]);\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"gantt-timeline\" role=\"listbox\" aria-label=\"Execution timeline\">\n {snapshots.map((snap, idx) => (\n <div\n key={`${snap.stageName}-${idx}`}\n data-fp=\"gantt-bar\"\n data-selected={idx === selectedIndex}\n data-visible={idx <= selectedIndex}\n role=\"option\"\n aria-selected={idx === selectedIndex}\n aria-label={`${snap.stageLabel}, ${snap.durationMs}ms`}\n onClick={() => onSelect?.(idx)}\n >\n <span data-fp=\"gantt-label\">{snap.stageLabel}</span>\n <span data-fp=\"gantt-duration\">{snap.durationMs}ms</span>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{ padding: pad, fontFamily: theme.fontSans, ...style }}\n data-fp=\"gantt-timeline\"\n >\n {/* Header with collapse toggle */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n {size === \"compact\" ? \"Timeline\" : \"Execution Timeline\"}\n </span>\n {collapsible && (\n <button\n onClick={() => setExpanded((e) => !e)}\n style={{\n background: \"none\",\n border: `1px solid ${theme.border}`,\n borderRadius: 4,\n color: theme.textSecondary,\n fontSize: fs.small,\n padding: \"2px 8px\",\n cursor: \"pointer\",\n fontFamily: theme.fontSans,\n }}\n >\n {expanded\n ? \"Collapse\"\n : `${snapshots.length - maxVisibleRows} more...`}\n </button>\n )}\n </div>\n\n {/* Scrollable rows container */}\n <div\n ref={scrollContainerRef}\n role=\"listbox\"\n aria-label=\"Execution timeline\"\n style={{\n marginTop: 8,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 4,\n ...(showAll\n ? {}\n : {\n maxHeight: maxVisibleRows * (rowHeight + 4),\n overflowY: \"auto\",\n scrollbarWidth: \"thin\",\n }),\n }}\n >\n {snapshots.map((snap, idx) => {\n const leftPct = (snap.startMs / totalWallTime) * 100;\n const widthPct = Math.max((snap.durationMs / totalWallTime) * 100, 1);\n const isSelected = idx === selectedIndex;\n const isVisible = idx <= selectedIndex;\n\n return (\n <div\n key={`${snap.stageName}-${idx}`}\n ref={isSelected ? activeRowRef : undefined}\n role=\"option\"\n aria-selected={isSelected}\n aria-label={`${snap.stageLabel}, ${snap.durationMs}ms`}\n onClick={() => onSelect?.(idx)}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: size === \"compact\" ? 4 : 8,\n cursor: onSelect ? \"pointer\" : \"default\",\n opacity: isVisible ? 1 : 0.3,\n transition: \"opacity 0.3s ease\",\n height: rowHeight,\n flexShrink: 0,\n }}\n >\n <span\n title={snap.stageLabel}\n style={{\n width: labelWidth,\n fontSize: fs.small,\n color: isSelected ? theme.primary : theme.textMuted,\n fontWeight: isSelected ? 600 : 400,\n textAlign: \"right\",\n flexShrink: 0,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {snap.stageLabel}\n </span>\n <div\n style={{\n flex: 1,\n height: size === \"compact\" ? 6 : 8,\n position: \"relative\",\n background: theme.bgTertiary,\n borderRadius: 3,\n }}\n >\n {isVisible && (\n <div\n style={{\n position: \"absolute\",\n left: `${leftPct}%`,\n top: 0,\n width: `${widthPct}%`,\n height: \"100%\",\n borderRadius: 3,\n background: isSelected ? theme.primary : theme.success,\n transition: \"width 0.3s ease\",\n }}\n />\n )}\n </div>\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n fontFamily: theme.fontMono,\n width: msWidth,\n flexShrink: 0,\n }}\n >\n {snap.durationMs}ms\n </span>\n </div>\n );\n })}\n </div>\n\n {/* Time axis */}\n <div\n style={{\n marginTop: 4,\n marginLeft: labelWidth + (size === \"compact\" ? 4 : 8),\n marginRight: msWidth + (size === \"compact\" ? 4 : 8),\n display: \"flex\",\n justifyContent: \"space-between\",\n fontSize: fs.small - 1,\n color: theme.textMuted,\n fontFamily: theme.fontMono,\n }}\n >\n <span>0ms</span>\n {size !== \"compact\" && (\n <span>{(totalWallTime / 2).toFixed(1)}ms</span>\n )}\n <span>{totalWallTime.toFixed(1)}ms</span>\n </div>\n </div>\n );\n}\n","/**\n * TraceFlow — ReactFlow renderer driven by `createTraceStructureRecorder`.\n *\n * Two input modes (mutually exclusive):\n *\n * 1. **Live mode**: pass `recorder={traceHandle}`. The component\n * subscribes via `useSyncExternalStore` to the recorder's\n * pub-sub `subscribe()` API and re-renders as the builder runs.\n * Ideal for incremental visualisation (Lens-style live chart\n * construction).\n *\n * 2. **Static mode**: pass `graph={{ nodes, edges }}`. The component\n * treats the graph as final and renders once. Ideal for post-build\n * snapshots (Trace tab, docs site).\n *\n * Layout is pluggable:\n *\n * - Pass a `layout` function `(graph) => positioned graph`. Default is\n * a simple BFS tree walk (Y_STEP=100, X_SPREAD=200).\n * - Pass the literal `\"passthrough\"` to skip layout when nodes are\n * already pre-positioned by the caller.\n *\n * @example\n * ```tsx\n * import { createTraceStructureRecorder, TraceFlow } from 'footprint-explainable-ui/flowchart';\n * import { flowChart } from 'footprintjs';\n *\n * function MyTraceUI() {\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * useEffect(() => {\n * flowChart('seed', fn, 'seed', {\n * structureRecorders: [trace.recorder],\n * }).addFunction('a', fnA, 'a').build();\n * }, [trace]);\n * return <TraceFlow recorder={trace} />;\n * }\n * ```\n */\n\nimport { useMemo, useCallback, useSyncExternalStore } from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n MarkerType,\n} from \"@xyflow/react\";\nimport type { Node, Edge } from \"@xyflow/react\";\nimport type {\n TraceGraph,\n TraceNode,\n TraceEdge,\n TraceStructureRecorderHandle,\n} from \"./traceStructureRecorder\";\nimport { StageNode } from \"../StageNode\";\nimport type { StageNodeData } from \"../StageNode\";\nimport { rawDefaults } from \"../../theme/tokens\";\nimport type { BaseComponentProps } from \"../../types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Layout\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst Y_STEP = 100;\nconst X_SPREAD = 200;\n\n/** Layout function shape — takes a graph, returns a graph with positions set. */\nexport type TraceFlowLayout = (graph: TraceGraph) => TraceGraph;\n\n/**\n * Default tree-walk layout.\n *\n * Edge-kind semantics (critical for parity)\n * ─────────────────────────────────────────\n * `fork-branch` + `decision-branch` edges are SIBLINGS at depth+1\n * (centered under the parent). A `next` edge from a node that ALSO\n * has branch edges is the \"after convergence\" target — its rank is\n * `max(deepest branch subtree) + 1`, so it sits BELOW the fan-out,\n * matching the legacy diamond layout.\n *\n * LoadOrder (fork)\n * ├── fork-branch → CheckInventory (sibling, y+1)\n * ├── fork-branch → RunFraudCheck (sibling, y+1)\n * └── next → FinalizeOrder (after convergence,\n * below deepest sibling)\n *\n * A `next` edge from a node with NO branch edges is a plain linear\n * chain — target at depth+1.\n *\n * `loop` back-edges DO NOT shape layout (they're scrub-time visual\n * markers only).\n *\n * Limitations (documented; not bugs)\n * ──────────────────────────────────\n * - Multi-root graphs render with the first-seen node as the visual\n * root; orphans stack below.\n * - Convergence where multiple branches join into a single node:\n * the node is placed under its FIRST traversed branch (first-wins).\n * For deep DAGs swap in a graph-layout library (dagre, elk).\n * - Sibling x-positions are local to each parent's subtree; no\n * global x-overlap detection across deep nested structures.\n */\nexport const defaultTraceFlowLayout: TraceFlowLayout = (graph) => {\n if (graph.nodes.length === 0) return { nodes: [], edges: graph.edges };\n\n // Split outgoing edges into two semantic groups per node:\n // - branches: fork-branch + decision-branch (siblings at y+1)\n // - linearNext: 'next' edges (after-convergence, deeper rank)\n // Loop back-edges (kind: 'loop') do NOT shape layout.\n const branchChildrenOf = new Map<string, string[]>();\n const nextChildrenOf = new Map<string, string[]>();\n const hasIncomingForward = new Set<string>();\n for (const e of graph.edges) {\n const kind = e.data?.kind;\n if (kind === \"loop\") continue;\n hasIncomingForward.add(e.target);\n if (kind === \"fork-branch\" || kind === \"decision-branch\") {\n const arr = branchChildrenOf.get(e.source) ?? [];\n arr.push(e.target);\n branchChildrenOf.set(e.source, arr);\n } else {\n // 'next' (default) — linear continuation. Treat undefined kind\n // as 'next' so forward edges without explicit kind still flow.\n const arr = nextChildrenOf.get(e.source) ?? [];\n arr.push(e.target);\n nextChildrenOf.set(e.source, arr);\n }\n }\n\n // Seed: first node (insertion order) with no incoming non-loop edge.\n const seed = graph.nodes.find((n) => !hasIncomingForward.has(n.id)) ?? graph.nodes[0]!;\n\n const positions = new Map<string, { x: number; y: number }>();\n\n /**\n * Recursive tree-walk. Returns the bottom-most y reached in this\n * subtree so the parent can position its `next` continuation BELOW\n * the deepest descendant (post-convergence semantics).\n */\n function layoutSubtree(nodeId: string, x: number, y: number): number {\n if (positions.has(nodeId)) {\n // Convergence: this node was already placed by an earlier branch.\n // Keep the original position (first-wins) and report its current\n // bottom so the caller's `next` target lands below us correctly.\n return positions.get(nodeId)!.y;\n }\n positions.set(nodeId, { x, y });\n\n // Place fork/decision branches first — they're siblings at y+1.\n let deepestBranchY = y;\n const branches = branchChildrenOf.get(nodeId) ?? [];\n if (branches.length > 0) {\n const childY = y + Y_STEP;\n const totalWidth = (branches.length - 1) * X_SPREAD;\n const startX = x - totalWidth / 2;\n for (let i = 0; i < branches.length; i++) {\n const childId = branches[i]!;\n const childX = startX + i * X_SPREAD;\n const subtreeBottom = layoutSubtree(childId, childX, childY);\n if (subtreeBottom > deepestBranchY) deepestBranchY = subtreeBottom;\n }\n }\n\n // Then place `next` continuations. If branches exist, `next` lands\n // BELOW the deepest branch (post-convergence). If no branches, it's\n // a plain linear chain — y+1.\n const nextChildren = nextChildrenOf.get(nodeId) ?? [];\n if (nextChildren.length > 0) {\n const nextY = branches.length > 0 ? deepestBranchY + Y_STEP : y + Y_STEP;\n // Multiple `next` from one node is rare (linear chains have one);\n // when it happens, distribute horizontally like branches.\n const totalWidth = (nextChildren.length - 1) * X_SPREAD;\n const startX = x - totalWidth / 2;\n let deepestNextY = nextY;\n for (let i = 0; i < nextChildren.length; i++) {\n const childId = nextChildren[i]!;\n const childX = startX + i * X_SPREAD;\n const subtreeBottom = layoutSubtree(childId, childX, nextY);\n if (subtreeBottom > deepestNextY) deepestNextY = subtreeBottom;\n }\n return deepestNextY;\n }\n\n return deepestBranchY;\n }\n\n layoutSubtree(seed.id, 0, 0);\n\n // Unreached nodes (multi-root or cycles outside the seed's tree)\n // stack below. Use a loop (not `Math.max(...spread)`) — spread\n // blows the call stack at ~10k+ args.\n let maxY = 0;\n for (const p of positions.values()) {\n if (p.y > maxY) maxY = p.y;\n }\n let orphanY = maxY + Y_STEP;\n for (const n of graph.nodes) {\n if (!positions.has(n.id)) {\n positions.set(n.id, { x: 0, y: orphanY });\n orphanY += Y_STEP;\n }\n }\n\n return {\n nodes: graph.nodes.map((n) => ({\n ...n,\n position: positions.get(n.id) ?? n.position,\n })),\n edges: graph.edges,\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Edge styling\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceFlowEdgeColors {\n next: string;\n forkBranch: string;\n decisionBranch: string;\n loop: string;\n}\n\nconst DEFAULT_EDGE_COLORS: TraceFlowEdgeColors = {\n next: rawDefaults.colors.textMuted,\n forkBranch: rawDefaults.colors.textMuted,\n decisionBranch: rawDefaults.colors.primary,\n loop: rawDefaults.colors.warning,\n};\n\nfunction styleEdge(edge: TraceEdge, colors: TraceFlowEdgeColors): Edge {\n const kind = edge.data?.kind ?? \"next\";\n const color =\n kind === \"loop\"\n ? colors.loop\n : kind === \"fork-branch\"\n ? colors.forkBranch\n : kind === \"decision-branch\"\n ? colors.decisionBranch\n : colors.next;\n const styled: Edge = {\n ...edge,\n type: kind === \"loop\" ? \"step\" : \"smoothstep\",\n animated: false,\n style: { stroke: color, strokeWidth: 1.5 },\n markerEnd: { type: MarkerType.ArrowClosed, color, width: 16, height: 16 },\n };\n if (kind === \"loop\") {\n styled.style = { ...styled.style, strokeDasharray: \"4 3\" };\n }\n return styled;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype TraceFlowSource =\n | { recorder: TraceStructureRecorderHandle; graph?: never }\n | { graph: TraceGraph; recorder?: never };\n\nexport type TraceFlowProps = BaseComponentProps &\n TraceFlowSource & {\n /** Layout function. Default: BFS tree walk. Pass the literal\n * `\"passthrough\"` to skip layout when nodes already carry positions. */\n layout?: TraceFlowLayout | \"passthrough\";\n /** Per-kind edge color overrides. */\n edgeColors?: Partial<TraceFlowEdgeColors>;\n /** Node click handler — receives the node id. */\n onNodeClick?: (id: string) => void;\n };\n\nconst nodeTypes = { stageNode: StageNode };\n\n/**\n * Convert a `TraceNode` (with `TraceNodeData`) to the `StageNode`-typed\n * node shape so the existing `<StageNode>` renderer works.\n */\nfunction toStageNode(node: TraceNode): Node {\n const data = node.data;\n const stageData: StageNodeData = {\n label: data.label,\n isDecider: data.isDecider,\n isFork: data.isFork,\n isSubflow: data.isSubflow,\n active: false,\n done: false,\n error: false,\n ...(data.description !== undefined && { description: data.description }),\n ...(data.icon !== undefined && { icon: data.icon }),\n ...(data.subflowId !== undefined && { subflowId: data.subflowId }),\n ...(data.isLazy === true && { isLazy: true }),\n };\n return {\n ...node,\n type: \"stageNode\",\n data: stageData as unknown as Record<string, unknown>,\n };\n}\n\n// Empty-graph sentinel returned by static-mode getSnapshot when no\n// graph or recorder is present. Module-scoped so React's identity check\n// sees a stable reference across renders.\nconst EMPTY_GRAPH: TraceGraph = { nodes: [], edges: [] };\n\n// ── Subscription helpers (defined at module scope so useSyncExternalStore\n// sees stable function references when the recorder doesn't change) ─\n\nfunction subscribeToRecorder(recorder: TraceStructureRecorderHandle | undefined) {\n return (listener: () => void): (() => void) => {\n if (!recorder) return () => {};\n return recorder.subscribe(listener);\n };\n}\n\nfunction getRecorderVersion(recorder: TraceStructureRecorderHandle | undefined) {\n return (): number => {\n if (!recorder) return 0;\n return recorder.version();\n };\n}\n\nexport function TraceFlow(props: TraceFlowProps) {\n // Dev-mode contract check — TypeScript enforces the discriminated union\n // at compile time, but JS consumers (or `as any` casts) can hit this.\n const proc = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n const isDev = proc?.env?.NODE_ENV !== \"production\";\n if (isDev && !props.recorder && !props.graph) {\n // eslint-disable-next-line no-console\n console.warn(\n \"[TraceFlow] neither `recorder` nor `graph` prop was provided — rendering an empty chart. Pass one of: <TraceFlow recorder={handle} /> OR <TraceFlow graph={{nodes, edges}} />.\",\n );\n }\n\n const layout = props.layout ?? defaultTraceFlowLayout;\n const edgeColors = useMemo<TraceFlowEdgeColors>(\n () => ({ ...DEFAULT_EDGE_COLORS, ...(props.edgeColors ?? {}) }),\n [props.edgeColors],\n );\n\n // Subscribe to the version counter (live mode) — equality-by-number\n // means React only re-renders when the recorder actually mutated.\n // Memoize the subscribe + getSnapshot closures by the recorder\n // identity so useSyncExternalStore doesn't re-subscribe each render.\n const subscribe = useMemo(\n () => subscribeToRecorder(props.recorder),\n [props.recorder],\n );\n const getVersion = useMemo(\n () => getRecorderVersion(props.recorder),\n [props.recorder],\n );\n const version = useSyncExternalStore(subscribe, getVersion, getVersion);\n\n // Resolve graph: live (recorder) vs static (prop). The version\n // dependency drives re-evaluation in live mode; static mode falls\n // through to the prop's identity on each render.\n const { recorder, graph: graphProp } = props;\n const graph: TraceGraph = useMemo<TraceGraph>(() => {\n if (recorder) return recorder.getGraph();\n if (graphProp) return graphProp;\n return EMPTY_GRAPH;\n }, [recorder, graphProp, version]);\n\n const positioned = useMemo<TraceGraph>(() => {\n if (layout === \"passthrough\") return graph;\n return layout(graph);\n }, [graph, layout]);\n\n const reactFlowNodes = useMemo<Node[]>(\n () => positioned.nodes.map(toStageNode),\n [positioned.nodes],\n );\n const reactFlowEdges = useMemo<Edge[]>(\n () => positioned.edges.map((e) => styleEdge(e, edgeColors)),\n [positioned.edges, edgeColors],\n );\n\n const onNodeClickRef = props.onNodeClick;\n const handleNodeClick = useCallback(\n (_: unknown, node: Node) => {\n onNodeClickRef?.(node.id);\n },\n [onNodeClickRef],\n );\n\n return (\n <div\n className={props.className}\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 300,\n ...props.style,\n }}\n >\n <ReactFlow\n nodes={reactFlowNodes}\n edges={reactFlowEdges}\n nodeTypes={nodeTypes}\n onNodeClick={handleNodeClick}\n fitView\n proOptions={{ hideAttribution: true }}\n >\n <Background variant={BackgroundVariant.Dots} gap={20} size={1} />\n </ReactFlow>\n </div>\n );\n}\n","/**\n * TracedFlow — runtime-overlay variant of `<TraceFlow>`.\n *\n * Pairs a build-time `TraceGraph` (from `createTraceStructureRecorder`)\n * with a runtime `RuntimeOverlay` (from `createTraceRuntimeOverlay`)\n * and a scrub index → renders an xyflow chart with per-node coloring\n * (done / active / error), per-edge highlighting (executed paths),\n * loop-edge side-routing, and subflow drill-down.\n *\n * The component is orchestration only. Each responsibility lives in\n * an extracted helper / hook (see `_internal/`):\n *\n * - drill state .................. useSubflowDrill\n * - container resize → fitView ... useChartAutoRefit\n * - graph filtering by drill ..... filterGraphForDrill\n * - breadcrumb path .............. buildSubflowBreadcrumb\n * - slice id normalization ....... normalizeSliceLeafIds\n * - mount status aggregation ..... aggregateMountStatus\n * - node / edge styling .......... toStageNodeWithOverlay + styleEdgeWithOverlay\n * - breadcrumb UI ................ <SubflowBreadcrumbBar>\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const runtime = useMemo(() => createTraceRuntimeOverlay(), []);\n * // ... attach both to executor, run the chart ...\n * <TracedFlow\n * graph={trace.getGraph()}\n * overlay={runtime.getOverlay()}\n * scrubIndex={sliderValue}\n * onNodeClick={(stageId) => focusStage(stageId)}\n * onSubflowChange={(mountId) => syncShellDrill(mountId)}\n * />\n * ```\n */\n\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n MarkerType,\n} from \"@xyflow/react\";\nimport type { Node, Edge, ReactFlowInstance } from \"@xyflow/react\";\nimport type { TraceGraph, TraceNode, TraceEdge } from \"./traceStructureRecorder\";\nimport type { TraceFlowLayout } from \"./TraceFlow\";\nimport { defaultTraceFlowLayout } from \"./TraceFlow\";\nimport type { RuntimeOverlay } from \"./createTraceRuntimeOverlay\";\nimport { sliceOverlay } from \"./createTraceRuntimeOverlay\";\nimport { StageNode } from \"../StageNode\";\nimport type { StageNodeData } from \"../StageNode\";\nimport { rawDefaults } from \"../../theme/tokens\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { filterGraphForDrill, buildSubflowBreadcrumb } from \"./_internal/subflowDrill\";\nimport { normalizeSliceLeafIds, aggregateMountStatus } from \"./_internal/overlayProjection\";\nimport { useSubflowDrill } from \"./_internal/useSubflowDrill\";\nimport { useChartAutoRefit } from \"./_internal/useChartAutoRefit\";\nimport { SubflowBreadcrumbBar } from \"./SubflowBreadcrumbBar\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Theming\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TracedFlowColors {\n /** Default (un-executed) node text + edge stroke. */\n default: string;\n /** Done — visually de-emphasised (lighter). */\n done: string;\n /** Active — current scrub position. */\n active: string;\n /** Error — node with recorded onError. */\n error: string;\n /** Loop back-edge color. */\n loop: string;\n}\n\nconst DEFAULT_COLORS: TracedFlowColors = {\n default: rawDefaults.colors.textMuted,\n done: rawDefaults.colors.success,\n active: rawDefaults.colors.primary,\n error: rawDefaults.colors.error,\n loop: rawDefaults.colors.warning,\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Per-node / per-edge styling (pure)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction toStageNodeWithOverlay(\n node: TraceNode,\n doneStageIds: ReadonlySet<string>,\n activeStageId: string | null,\n errorMessage: string | undefined,\n executedOrderIds: readonly string[],\n): Node {\n const isDone = doneStageIds.has(node.id);\n const isActive = activeStageId === node.id;\n const wasExecuted = isDone || isActive;\n const hasError = !!errorMessage;\n const dimmed = !wasExecuted && executedOrderIds.length > 0;\n\n // Per-stage step number(s) — a loop may visit the same node multiple times.\n let stepNumbers: number[] | undefined;\n if (executedOrderIds.length > 0) {\n const nums: number[] = [];\n for (let i = 0; i < executedOrderIds.length; i++) {\n if (executedOrderIds[i] === node.id) nums.push(i + 1);\n }\n if (nums.length > 0) stepNumbers = nums;\n }\n\n const stageData: StageNodeData = {\n label: node.data.label,\n isDecider: node.data.isDecider,\n isFork: node.data.isFork,\n isSubflow: node.data.isSubflow,\n active: isActive,\n done: isDone,\n error: hasError,\n ...(node.data.description !== undefined && { description: node.data.description }),\n ...(node.data.icon !== undefined && { icon: node.data.icon }),\n ...(node.data.subflowId !== undefined && { subflowId: node.data.subflowId }),\n ...(node.data.isLazy === true && { isLazy: true }),\n ...(dimmed && { dimmed: true }),\n ...(stepNumbers && { stepNumbers }),\n ...(errorMessage && { errorMessage }),\n } as StageNodeData;\n\n return {\n ...node,\n type: \"stageNode\",\n data: stageData as unknown as Record<string, unknown>,\n ...(dimmed && { style: { opacity: 0.35 } }),\n };\n}\n\nfunction styleEdgeWithOverlay(\n edge: TraceEdge,\n doneStageIds: ReadonlySet<string>,\n activeStageId: string | null,\n colors: TracedFlowColors,\n): Edge {\n const kind = edge.data?.kind ?? \"next\";\n const sourceExecuted = doneStageIds.has(edge.source) || activeStageId === edge.source;\n const targetExecuted = doneStageIds.has(edge.target) || activeStageId === edge.target;\n const traversed = sourceExecuted && targetExecuted;\n const isLeadingEdge = activeStageId === edge.source && !doneStageIds.has(edge.target);\n\n let color: string = colors.default;\n if (kind === \"loop\") color = colors.loop;\n else if (isLeadingEdge) color = colors.active;\n else if (traversed) color = colors.done;\n\n const styled: Edge = {\n ...edge,\n type: \"smoothstep\",\n animated: isLeadingEdge,\n style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },\n markerEnd: { type: MarkerType.ArrowClosed, color, width: 16, height: 16 },\n };\n if (kind === \"loop\") {\n // Route loop-back edges AROUND the chart via the StageNode's\n // dedicated loop-source / loop-target handles + offset path.\n styled.style = { ...styled.style, strokeDasharray: \"4 3\" };\n (styled.data as any) = {\n ...(styled.data ?? {}),\n pathOptions: { borderRadius: 14, offset: 36 },\n };\n styled.sourceHandle = \"loop-source\";\n styled.targetHandle = \"loop-target\";\n }\n return styled;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TracedFlowProps extends BaseComponentProps {\n /** Build-time graph from `createTraceStructureRecorder().getGraph()`. */\n graph: TraceGraph;\n /** Runtime overlay from `createTraceRuntimeOverlay().getOverlay()`. */\n overlay?: RuntimeOverlay;\n /** Time-travel scrub index. Defaults to the last step (latest state). */\n scrubIndex?: number;\n /** Layout function. Default: BFS tree walk over the recorder graph. */\n layout?: TraceFlowLayout | \"passthrough\";\n /** Color overrides. */\n colors?: Partial<TracedFlowColors>;\n /** Node click handler — receives stage id. */\n onNodeClick?: (stageId: string) => void;\n /**\n * Fires when the chart drills into or out of a subflow (explicit\n * user click on a mount node). Receives the mount stage id (drill\n * in) or `null` (pop back). Container shells use this to keep\n * their data panels in lock-step with the chart's drill state.\n */\n onSubflowChange?: (mountStageId: string | null) => void;\n}\n\nconst nodeTypes = { stageNode: StageNode };\n\nexport function TracedFlow({\n graph,\n overlay,\n scrubIndex,\n layout: layoutProp,\n colors: colorOverrides,\n onNodeClick,\n onSubflowChange,\n className,\n style,\n}: TracedFlowProps) {\n const layout = layoutProp ?? defaultTraceFlowLayout;\n const colors = useMemo<TracedFlowColors>(\n () => ({ ...DEFAULT_COLORS, ...(colorOverrides ?? {}) }),\n [colorOverrides],\n );\n\n // ── Drill state + visibility derivations ──────────────────────────\n const drill = useSubflowDrill(graph, onSubflowChange);\n const filteredGraph = useMemo(\n () => filterGraphForDrill(graph, drill.currentSubflowId),\n [graph, drill.currentSubflowId],\n );\n const breadcrumb = useMemo(\n () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),\n [graph, drill.currentSubflowId],\n );\n const positioned = useMemo<TraceGraph>(\n () => (layout === \"passthrough\" ? filteredGraph : layout(filteredGraph)),\n [filteredGraph, layout],\n );\n\n // ── Runtime overlay slice → leaf-normalize + mount aggregation ────\n const slice = useMemo(() => {\n const empty = {\n doneStageIds: new Set<string>(),\n activeStageId: null as string | null,\n executedStageIds: new Set<string>(),\n executedOrderIds: [] as string[],\n errors: new Map<string, string>(),\n };\n if (!overlay) return empty;\n const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);\n const normalized = normalizeSliceLeafIds(sliceOverlay(overlay, idx));\n return aggregateMountStatus(normalized, graph, drill.currentSubflowId);\n }, [overlay, scrubIndex, graph, drill.currentSubflowId]);\n\n // ── xyflow nodes + edges (re-run per scrub tick) ──────────────────\n const reactFlowNodes = useMemo<Node[]>(\n () =>\n positioned.nodes.map((n) =>\n toStageNodeWithOverlay(\n n,\n slice.doneStageIds,\n slice.activeStageId,\n slice.errors.get(n.id),\n slice.executedOrderIds,\n ),\n ),\n [positioned.nodes, slice],\n );\n const reactFlowEdges = useMemo<Edge[]>(\n () =>\n positioned.edges.map((e) =>\n styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors),\n ),\n [positioned.edges, slice, colors],\n );\n\n // ── Click handling: drill on subflow mount click, propagate click ─\n const handleNodeClick = useCallback(\n (_: unknown, node: Node) => {\n const data = (node.data ?? {}) as StageNodeData;\n if (data.isSubflow && data.subflowId) {\n drill.drillInto(data.subflowId);\n }\n onNodeClick?.(node.id);\n },\n [drill, onNodeClick],\n );\n\n // ── Container auto-refit (xyflow's fitView is mount-only) ─────────\n const wrapperRef = useRef<HTMLDivElement>(null);\n const [rfInstance, setRfInstance] = useState<ReactFlowInstance | null>(null);\n useChartAutoRefit(wrapperRef, rfInstance);\n\n return (\n <div\n ref={wrapperRef}\n className={className}\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 300,\n display: \"flex\",\n flexDirection: \"column\",\n ...style,\n }}\n >\n {breadcrumb.length > 1 && (\n <SubflowBreadcrumbBar\n entries={breadcrumb}\n onNavigate={drill.setCurrentSubflowId}\n />\n )}\n <div style={{ flex: 1, minHeight: 0 }}>\n <ReactFlow\n nodes={reactFlowNodes}\n edges={reactFlowEdges}\n nodeTypes={nodeTypes}\n onNodeClick={handleNodeClick}\n onInit={setRfInstance}\n fitView\n proOptions={{ hideAttribution: true }}\n >\n <Background variant={BackgroundVariant.Dots} gap={20} size={1} />\n </ReactFlow>\n </div>\n </div>\n );\n}\n","/**\n * Dev-mode detection without depending on `@types/node`.\n *\n * Returns `true` when running outside an explicitly production env.\n * Browser builds (no `process` global) treat as dev — acceptable for\n * a debugging library: a user-visible warning in a browser is a\n * debugging signal anyway.\n *\n * Shared by every translator's notify path + orphan-event warnings.\n */\nexport function isDevModeEnv(): boolean {\n const proc = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n return proc?.env?.NODE_ENV !== \"production\";\n}\n\n/**\n * Dev-mode `console.warn` shim. No-op in production. Lazy message\n * construction (`messageFn`) — avoids string-concat cost when prod.\n */\nexport function devWarn(messageFn: () => string, ...extras: unknown[]): void {\n if (!isDevModeEnv()) return;\n // eslint-disable-next-line no-console\n console.warn(messageFn(), ...extras);\n}\n","/**\n * `createNotifier` — shared pub-sub + monotonic version + microtask\n * batching, extracted from `traceStructureRecorder` and\n * `createTraceRuntimeOverlay` (which duplicated this pattern).\n *\n * Every translator needs the same shape to integrate with React's\n * `useSyncExternalStore`:\n * - `subscribe(listener)` returns unsubscribe\n * - `version()` returns monotonic int (snapshot identity)\n * - `notify()` bumps version + fires listeners (error-isolated)\n *\n * Microtask batching\n * ──────────────────\n * A single stage execution fires multiple recorder events (Structure\n * `onStageAdded` + `onEdgeAdded` for each edge; Flow `onStageExecuted`;\n * Scope `onCommit`). With 3+ translators subscribed, that's 6+ React\n * re-renders per stage. The batcher coalesces all `notify()` calls\n * within one microtask into a SINGLE listener fire — version still\n * bumps per event (so consumers that poll `version()` from outside\n * React see every change), but listener invocations are deduplicated.\n *\n * Trade-off: listeners observe the FINAL state after a microtask\n * batch, not every intermediate state. Acceptable for UI consumers\n * (React renders the final state anyway). Non-React consumers that\n * need every event should call `getSnapshot()` from inside event\n * handlers, not rely on the listener for granularity.\n *\n * Error isolation\n * ───────────────\n * A throwing listener is caught + warned in dev. Other listeners\n * still fire. Mirrors footprintjs's recorder dispatcher pattern.\n */\n\nimport { devWarn } from \"./devWarn\";\n\nexport interface Notifier {\n /** Subscribe a listener; returns unsubscribe. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps once per `notify()` call. */\n version(): number;\n /** Bump version + schedule a listener flush (coalesced via microtask). */\n notify(): void;\n /** Force-flush any pending coalesced notification immediately. Used\n * by tests that need synchronous observation. */\n flushPending(): void;\n /** Reset the notifier — clears listeners is NOT done (consumers\n * manage their own subscriptions). Only the pending-flush flag\n * and version stay as-is (no consumer should observe a version\n * rollback). */\n // (intentionally no reset for version — monotonicity is load-bearing\n // for useSyncExternalStore snapshot equality)\n}\n\nexport function createNotifier(label = \"notifier\"): Notifier {\n const listeners = new Set<() => void>();\n let v = 0;\n let pending = false;\n\n function flush(): void {\n if (!pending) return;\n pending = false;\n // Snapshot listeners into an array BEFORE iteration. A listener\n // that synchronously subscribes/unsubscribes another listener\n // would otherwise leave Set-iteration semantics implementation-\n // defined. Array snapshot guarantees: every listener registered\n // AT THIS FLUSH-START fires exactly once; listeners added during\n // a callback wait for the next notify cycle.\n const snapshot = Array.from(listeners);\n for (const l of snapshot) {\n try {\n l();\n } catch (err) {\n devWarn(\n () =>\n `[${label}] subscribe() listener threw — isolated; other subscribers continue.`,\n err,\n );\n }\n }\n }\n\n return {\n subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n version(): number {\n return v;\n },\n notify(): void {\n v += 1;\n if (pending) return;\n pending = true;\n // Coalesce within a single microtask. `queueMicrotask` is\n // available in every supported runtime (Node 11+, all browsers).\n queueMicrotask(flush);\n },\n flushPending(): void {\n flush();\n },\n };\n}\n","/**\n * createTraceRuntimeOverlay — event-driven runtime overlay for `<TracedFlow>`.\n *\n * The runtime twin of `createTraceStructureRecorder` (L7.7). Where the\n * structure recorder accumulates the build-time graph SHAPE from\n * `StructureRecorder` events, this recorder accumulates the runtime\n * EXECUTION STATE (which nodes ran, current active, errors) from\n * `FlowRecorder` events. The two compose into the full time-travel\n * trace UI:\n *\n * StructureRecorder events → TraceGraph (nodes + edges, id-keyed)\n * FlowRecorder events → RuntimeOverlay (per-node state, id-keyed)\n * │\n * ▼\n * <TracedFlow graph={...} overlay={...} scrubIndex={i} />\n *\n * **Universal key**: `runtimeStageId = [subflowPath/]stageId#executionIndex`.\n * Loops re-execute the same stageId with bumping executionIndex — the\n * overlay records each execution as a distinct step in `executionOrder`\n * but updates the SAME node-by-id in `doneStageIds` (because the build-\n * time graph has one node per spec — loops re-visit it).\n *\n * Per L7.7 panel guidance: the consumer pattern mirrors recorder error\n * isolation, exposes a pub-sub `subscribe(listener)` + monotonic\n * `version()` for `useSyncExternalStore` integration, and accumulates\n * pure data with zero React coupling.\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local type aliases mirroring footprintjs FlowRecorder\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Same rationale as traceStructureRecorder.ts: explainable-ui has no\n// `footprintjs` dep declared (consumer wires it). We mirror the\n// subset of `FlowRecorder` we consume. If footprintjs changes the\n// interface, this module's types update in lockstep.\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface RuntimeStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n /** Discriminator for which kind of stage completed. footprintjs v6+\n * fires this event uniformly for every stage kind (proposal #003);\n * consumers route by `stageType` without a chart-spec lookup. */\n readonly stageType: 'linear' | 'decider' | 'fork' | 'selector' | 'subflow-mount';\n readonly traversalContext: TraversalContext;\n}\n\ninterface RuntimeErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface RuntimeRunStartEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface RuntimeRunEndEvent {\n readonly traversalContext?: TraversalContext;\n}\n\n/** Minimal FlowRecorder interface mirror — see top-of-file rationale.\n *\n * As of footprintjs v6 (proposal #003), `onStageExecuted` fires\n * uniformly for ALL stage kinds — linear / decider / fork / selector\n * / subflow-mount. The event payload carries a `stageType` field for\n * consumers that need to route by kind. We no longer need separate\n * `onDecision` / `onFork` / `onSelected` handlers to track \"did this\n * stage run\" — a single `onStageExecuted` handler suffices. */\nexport interface MinimalFlowRecorder {\n readonly id: string;\n onStageExecuted?(event: RuntimeStageExecutedEvent): void;\n onError?(event: RuntimeErrorEvent): void;\n onRunStart?(event: RuntimeRunStartEvent): void;\n onRunEnd?(event: RuntimeRunEndEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Runtime overlay shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * One entry in the execution timeline. `<TracedFlow>` keys time-travel\n * scrubbing on the index into this array — at index `i`, all entries\n * `0..i-1` are \"done\", entry `i` is \"active\".\n */\nexport interface RuntimeExecutionStep {\n /** `[subflowPath/]stageId#executionIndex` — universal key. */\n readonly runtimeStageId: string;\n /** Base stage id (without `#N`) — matches the `TraceGraph` node id. */\n readonly stageId: string;\n /** Human-readable label (from event.stageName). */\n readonly stageName: string;\n /** When this step recorded, in ms since recorder start. */\n readonly timestampMs: number;\n}\n\nexport interface RuntimeOverlay {\n /** Ordered execution history — drives time-travel scrubbing. */\n readonly executionOrder: readonly RuntimeExecutionStep[];\n /** Per-base-stageId error message (most-recent wins). */\n readonly errors: ReadonlyMap<string, string>;\n /** True after `onRunStart` until `onRunEnd` — useful for \"still running\" indicators. */\n readonly running: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceRuntimeOverlayHandle {\n /** The recorder to attach via `executor.attachFlowRecorder(handle.recorder)`. */\n recorder: MinimalFlowRecorder;\n /** Returns a defensive copy of the current overlay state. */\n getOverlay(): RuntimeOverlay;\n /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps once per overlay-mutating event. */\n version(): number;\n /** Reset for reuse across runs. Does NOT bump version or notify (matches\n * traceStructureRecorder's reset contract). */\n reset(): void;\n}\n\nexport interface CreateTraceRuntimeOverlayOptions {\n id?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport { createNotifier } from \"./_internal/notifyChange\";\n\n/**\n * Strip `#executionIndex` suffix to get the base stage id.\n *\n * **WARNING (invariant I3)**: use ONLY for DISPLAY. NEVER for matching\n * commitLog stageIds — those use the full path-prefixed id (e.g.,\n * `'sf-a/sf-b/inner'`) as emitted by the engine. Parsing back to the\n * unqualified inner name loses uniqueness across subflow instances.\n */\nfunction parseStageIdFromRuntimeStageId(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createTraceRuntimeOverlay(\n options: CreateTraceRuntimeOverlayOptions = {},\n): TraceRuntimeOverlayHandle {\n const id = options.id ?? \"trace-runtime-overlay\";\n const startTime = performance.now();\n\n let executionOrder: RuntimeExecutionStep[] = [];\n // Defensive dedupe by runtimeStageId — should be moot post-#003\n // since the engine fires `onStageExecuted` exactly once per stage\n // execution, but a future change or a misbehaving recorder upstream\n // could still produce duplicates; keep the set as belt-and-suspenders.\n const recordedRuntimeStageIds = new Set<string>();\n const errors = new Map<string, string>();\n let running = false;\n const notifier = createNotifier(\"traceRuntimeOverlay\");\n const notifyChange = notifier.notify;\n\n function pushStep(runtimeStageId: string, stageId: string, stageName: string): void {\n if (recordedRuntimeStageIds.has(runtimeStageId)) return;\n recordedRuntimeStageIds.add(runtimeStageId);\n executionOrder.push({\n runtimeStageId,\n stageId,\n stageName,\n timestampMs: performance.now() - startTime,\n });\n notifyChange();\n }\n\n const recorder: MinimalFlowRecorder = {\n id,\n onRunStart() {\n running = true;\n notifyChange();\n },\n onRunEnd() {\n running = false;\n notifyChange();\n },\n onStageExecuted(event) {\n // footprintjs v6 (#003) fires this for EVERY stage kind —\n // linear / decider / fork / selector / subflow-mount — so\n // we no longer need separate handlers for the branching events.\n const runtimeStageId = event.traversalContext.runtimeStageId;\n const baseStageId = parseStageIdFromRuntimeStageId(runtimeStageId);\n pushStep(runtimeStageId, baseStageId, event.stageName);\n },\n onError(event) {\n const fallbackId =\n event.stageId ??\n (event.traversalContext\n ? parseStageIdFromRuntimeStageId(event.traversalContext.runtimeStageId)\n : event.stageName);\n errors.set(fallbackId, event.message ?? \"error\");\n notifyChange();\n },\n };\n\n return {\n recorder,\n getOverlay(): RuntimeOverlay {\n return {\n executionOrder: executionOrder.map((s) => ({ ...s })),\n errors: new Map(errors),\n running,\n };\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n executionOrder = [];\n recordedRuntimeStageIds.clear();\n errors.clear();\n running = false;\n // Note: reset does NOT bump version or notify (matches\n // traceStructureRecorder contract — see its `reset()` JSDoc\n // for the consumer-facing recipe).\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Overlay slicing for time-travel\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Snapshot of overlay state AT a specific scrub index. Drives node\n * coloring in `<TracedFlow>`.\n */\nexport interface RuntimeOverlaySlice {\n /** Base stage ids that completed before the active scrub position. */\n readonly doneStageIds: ReadonlySet<string>;\n /** The currently-active stage id (or `null` when scrub is at 0 with no exec yet). */\n readonly activeStageId: string | null;\n /** Union of done + active — convenient for \"executed at all\" checks. */\n readonly executedStageIds: ReadonlySet<string>;\n /** The full ordered list of base stage ids up through the active position —\n * used by renderers that want to number stages by occurrence (e.g.,\n * show \"3rd loop iteration\" badges). */\n readonly executedOrderIds: readonly string[];\n /** Pass-through errors map for the renderer. */\n readonly errors: ReadonlyMap<string, string>;\n}\n\n/**\n * Slice `overlay.executionOrder` at the given index:\n *\n * - `executionOrder[0..index-1]` → \"done\"\n * - `executionOrder[index]` → \"active\"\n * - `index >= executionOrder.length` → all done, no active\n *\n * Returns an empty slice when overlay has no execution history.\n */\nexport function sliceOverlay(\n overlay: RuntimeOverlay,\n index: number,\n): RuntimeOverlaySlice {\n const order = overlay.executionOrder;\n if (order.length === 0) {\n return {\n doneStageIds: new Set(),\n activeStageId: null,\n executedStageIds: new Set(),\n executedOrderIds: [],\n errors: overlay.errors,\n };\n }\n const clampedIndex = Math.max(0, Math.min(index, order.length - 1));\n const doneStageIds = new Set<string>();\n for (let i = 0; i < clampedIndex; i++) {\n doneStageIds.add(order[i]!.stageId);\n }\n const activeStep = order[clampedIndex];\n const activeStageId = activeStep ? activeStep.stageId : null;\n const executedStageIds = new Set(doneStageIds);\n if (activeStageId) executedStageIds.add(activeStageId);\n const executedOrderIds = order.slice(0, clampedIndex + 1).map((s) => s.stageId);\n return {\n doneStageIds,\n activeStageId,\n executedStageIds,\n executedOrderIds,\n errors: overlay.errors,\n };\n}\n","/**\n * Pure helpers for subflow drill-down on a `TraceGraph`.\n *\n * Filtering and breadcrumb computation are derived from the\n * `TraceNodeData.subflowOf` field that the structure recorder sets\n * at `onSubflowMounted` time. Both functions are pure (no I/O, no\n * React) so they can be unit-tested in isolation and reused by any\n * renderer.\n */\n\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\n/**\n * Filter the trace graph by drill-down scope.\n *\n * - `currentSubflowId === null` → show top-level (nodes with no\n * `subflowOf`). Subflow internals are hidden; their mount node\n * stays visible as a single clickable card.\n * - `currentSubflowId === 'X'` → show only nodes where\n * `subflowOf === 'X'` (the drilled-in subflow's internals).\n *\n * Edges follow the same filter — only edges where both endpoints\n * are in the visible set survive. When nothing would be filtered\n * out, returns the original graph reference (preserves upstream\n * memoization).\n */\nexport function filterGraphForDrill(\n graph: TraceGraph,\n currentSubflowId: string | null,\n): TraceGraph {\n if (graph.nodes.length === 0) return graph;\n const matchesScope = (subflowOf: string | undefined): boolean =>\n currentSubflowId === null ? subflowOf === undefined : subflowOf === currentSubflowId;\n const visibleIds = new Set<string>();\n for (const n of graph.nodes) {\n if (matchesScope(n.data?.subflowOf)) visibleIds.add(n.id);\n }\n if (visibleIds.size === graph.nodes.length) return graph;\n return {\n nodes: graph.nodes.filter((n) => visibleIds.has(n.id)),\n edges: graph.edges.filter((e) => visibleIds.has(e.source) && visibleIds.has(e.target)),\n };\n}\n\n/** Entry in the breadcrumb path. `subflowId === null` is the root. */\nexport interface BreadcrumbEntry {\n subflowId: string | null;\n label: string;\n}\n\n/**\n * Build the breadcrumb path for the current drill level.\n *\n * Always starts with the root `{ subflowId: null, label: 'Chart' }`.\n * When drilled into a subflow, appends one entry with the mount\n * node's display label (falling back to the subflow id). Multi-level\n * drill chains are NOT supported by the current chart UX (drill is\n * always from root or sibling — clicking a deeper subflow's mount\n * replaces the current scope), so the path has at most 2 entries.\n */\nexport function buildSubflowBreadcrumb(\n graph: TraceGraph,\n currentSubflowId: string | null,\n): BreadcrumbEntry[] {\n const out: BreadcrumbEntry[] = [{ subflowId: null, label: \"Chart\" }];\n if (currentSubflowId !== null) {\n const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);\n out.push({\n subflowId: currentSubflowId,\n label: mount?.data?.label ?? currentSubflowId,\n });\n }\n return out;\n}\n","/**\n * Pure helpers for projecting a raw `RuntimeOverlaySlice` into the\n * shape `<TracedFlow>` needs for per-node coloring:\n *\n * 1. `normalizeSliceLeafIds` — strips subflow path prefixes from\n * stage ids so they match `TraceNode.id` (graph stores LEAF ids\n * like `charge-card`; overlay records path-prefixed ids like\n * `payment/charge-card`).\n * 2. `aggregateMountStatus` — when execution is INSIDE a subflow,\n * light up the mount node in the parent view as\n * done/active based on its internals' statuses.\n *\n * Both are pure (no I/O, no React). Composed in TracedFlow as\n * `aggregate(normalize(raw))`.\n */\n\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\nexport interface OverlaySlice {\n doneStageIds: ReadonlySet<string>;\n activeStageId: string | null;\n executedStageIds: ReadonlySet<string>;\n executedOrderIds: readonly string[];\n errors: ReadonlyMap<string, string>;\n}\n\n/** Strip everything before the last `/` — `'payment/charge-card'` → `'charge-card'`. */\nfunction leafId(id: string): string {\n const i = id.lastIndexOf(\"/\");\n return i >= 0 ? id.slice(i + 1) : id;\n}\n\n/**\n * Normalize all stage ids in a slice to LEAF ids so they line up\n * with `TraceNode.id` keys for coloring lookups.\n */\nexport function normalizeSliceLeafIds(slice: OverlaySlice): OverlaySlice {\n return {\n doneStageIds: new Set(Array.from(slice.doneStageIds).map(leafId)),\n activeStageId: slice.activeStageId ? leafId(slice.activeStageId) : null,\n executedStageIds: new Set(Array.from(slice.executedStageIds).map(leafId)),\n executedOrderIds: slice.executedOrderIds.map(leafId),\n errors: new Map(Array.from(slice.errors).map(([k, v]) => [leafId(k), v])),\n };\n}\n\n/**\n * Aggregate subflow internals' status onto their mount nodes.\n *\n * - Mount is DONE when EVERY internal stage is done.\n * - Mount is ACTIVE when ANY internal is active or done — but only\n * when we're viewing the TOP-LEVEL chart (`currentSubflowId ===\n * null`). When drilled INTO a subflow, the active highlight goes\n * on the actual subflow stage, not on the parent's mount.\n *\n * Pre-condition: slice has already been leaf-normalized so its\n * stage ids match `graph.nodes[].id`.\n */\nexport function aggregateMountStatus(\n slice: OverlaySlice,\n graph: TraceGraph,\n currentSubflowId: string | null,\n): OverlaySlice {\n if (graph.nodes.length === 0) return slice;\n const mounts = graph.nodes.filter((n) => n.data?.isSubflow && n.data?.subflowId);\n if (mounts.length === 0) return slice;\n const doneIds = new Set(slice.doneStageIds);\n let activeId = slice.activeStageId;\n for (const mount of mounts) {\n const sfId = mount.data!.subflowId as string;\n const members = graph.nodes.filter((n) => n.data?.subflowOf === sfId);\n if (members.length === 0) continue;\n const anyActive = members.some((m) => m.id === slice.activeStageId);\n const anyDone = members.some((m) => slice.doneStageIds.has(m.id));\n const allDone = members.every((m) => slice.doneStageIds.has(m.id));\n if (allDone) doneIds.add(mount.id);\n else if ((anyActive || anyDone) && currentSubflowId === null) {\n activeId = mount.id;\n }\n }\n return { ...slice, doneStageIds: doneIds, activeStageId: activeId };\n}\n","/**\n * useSubflowDrill — drill state for the chart's view scope.\n *\n * - Owns `currentSubflowId: string | null` (null = top-level)\n * - Exposes `drillInto(subflowId)` and `drillUp()` for navigation\n * - Notifies the host via `onSubflowChange(mountStageId | null)`\n * whenever the drill state changes — host wires this to its own\n * drill-stack so data panels follow\n *\n * Drill changes are EXPLICIT — there's no auto-drill on scrub. The\n * mount node's status reflects \"execution is inside\" via\n * `aggregateMountStatus` (see overlayProjection.ts).\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\nexport interface SubflowDrillHandle {\n /** Current drill scope. `null` = top-level. */\n currentSubflowId: string | null;\n /** Navigate INTO the given subflow (by `subflowId`). */\n drillInto: (subflowId: string) => void;\n /** Pop back up to the parent / top-level. */\n drillUp: () => void;\n /** Direct setter for breadcrumb navigation (any target including `null`). */\n setCurrentSubflowId: (id: string | null) => void;\n}\n\nexport function useSubflowDrill(\n graph: TraceGraph,\n onSubflowChange?: (mountStageId: string | null) => void,\n): SubflowDrillHandle {\n const [currentSubflowId, setCurrentSubflowId] = useState<string | null>(null);\n\n // Reset drill state when the graph IDENTITY changes (e.g., the\n // user switched to a different sample in the playground sidebar).\n // Without this, the drill state from sample A persists into\n // sample B's rendering — `currentSubflowId='payment'` survives the\n // chart swap, but sample B has no 'payment' subflow, so the filter\n // returns no visible nodes (blank chart).\n //\n // Also reset when the currently-drilled subflow no longer exists\n // in the new graph (defensive — graph mutations could remove a\n // subflow without changing the wrapper reference).\n const lastGraphRef = useRef<TraceGraph | null>(null);\n if (lastGraphRef.current !== graph) {\n lastGraphRef.current = graph;\n if (\n currentSubflowId !== null &&\n !graph.nodes.some((n) => n.data?.subflowId === currentSubflowId)\n ) {\n // Schedule reset for next render (can't setState during render).\n queueMicrotask(() => setCurrentSubflowId(null));\n }\n }\n\n // Notify the host when drill changes. Resolve the mount stage id\n // from the graph (the parent-chart node whose `subflowId` matches).\n const lastNotifiedRef = useRef<string | null | undefined>(undefined);\n useEffect(() => {\n if (lastNotifiedRef.current === currentSubflowId) return;\n lastNotifiedRef.current = currentSubflowId;\n if (currentSubflowId === null) {\n onSubflowChange?.(null);\n } else {\n const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);\n if (mount) onSubflowChange?.(mount.id);\n }\n }, [currentSubflowId, graph, onSubflowChange]);\n\n const drillInto = useCallback((subflowId: string) => {\n setCurrentSubflowId(subflowId);\n }, []);\n const drillUp = useCallback(() => {\n setCurrentSubflowId(null);\n }, []);\n\n return { currentSubflowId, drillInto, drillUp, setCurrentSubflowId };\n}\n","/**\n * useChartAutoRefit — keep an xyflow chart fitted to its container.\n *\n * xyflow's `fitView` prop only runs on mount; it does NOT re-fit\n * when the container resizes. This hook closes that gap by:\n *\n * 1. Observing the wrapper element via `ResizeObserver` →\n * `instance.fitView({ duration, padding })` on the next animation\n * frame (so the new container size is measured first).\n * 2. Also listening to `window resize` events — `ExplainableShell`\n * dispatches synthetic resize events when its detail panels\n * toggle (those size changes may be animated and not yet\n * measurable by ResizeObserver on the first tick).\n *\n * Without this hook the chart shrinks once on Details-open and\n * never grows back when Details closes.\n */\n\nimport { useEffect } from \"react\";\nimport type { RefObject } from \"react\";\nimport type { ReactFlowInstance } from \"@xyflow/react\";\n\nexport function useChartAutoRefit(\n wrapperRef: RefObject<HTMLElement | null>,\n rfInstance: ReactFlowInstance | null,\n options: { duration?: number; padding?: number } = {},\n): void {\n const duration = options.duration ?? 200;\n const padding = options.padding ?? 0.1;\n\n useEffect(() => {\n const el = wrapperRef.current;\n if (!el || !rfInstance) return;\n let raf = 0;\n const refit = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() => {\n rfInstance.fitView({ duration, padding });\n });\n };\n const ro = new ResizeObserver(refit);\n ro.observe(el);\n window.addEventListener(\"resize\", refit);\n return () => {\n ro.disconnect();\n window.removeEventListener(\"resize\", refit);\n cancelAnimationFrame(raf);\n };\n }, [rfInstance, wrapperRef, duration, padding]);\n}\n","/**\n * SubflowBreadcrumbBar — clickable trail of subflow drill levels.\n *\n * Chart › Outer Subflow › Inner Subflow\n *\n * The last entry renders disabled (you're already here). Earlier\n * entries are clickable — fire `onNavigate(subflowId)` (null = root).\n *\n * Pure presentation: takes the precomputed `entries` array (built by\n * `buildSubflowBreadcrumb` in `_internal/subflowDrill.ts`). No drill\n * state lives here.\n */\n\nimport type { BreadcrumbEntry } from \"./_internal/subflowDrill\";\nimport { rawDefaults } from \"../../theme/tokens\";\n\nexport interface SubflowBreadcrumbBarProps {\n entries: BreadcrumbEntry[];\n onNavigate: (subflowId: string | null) => void;\n}\n\nexport function SubflowBreadcrumbBar({ entries, onNavigate }: SubflowBreadcrumbBarProps) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"6px 12px\",\n fontSize: 11,\n background: rawDefaults.colors.bgSecondary,\n borderBottom: `1px solid ${rawDefaults.colors.border}`,\n flexShrink: 0,\n }}\n aria-label=\"Subflow breadcrumb\"\n >\n {entries.map((entry, i) => {\n const isLast = i === entries.length - 1;\n return (\n <span\n key={entry.subflowId ?? \"__top__\"}\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n >\n <button\n type=\"button\"\n onClick={() => onNavigate(entry.subflowId)}\n disabled={isLast}\n style={{\n background: \"transparent\",\n border: \"none\",\n padding: 0,\n fontSize: 11,\n fontWeight: isLast ? 600 : 500,\n color: isLast ? rawDefaults.colors.textPrimary : rawDefaults.colors.primary,\n cursor: isLast ? \"default\" : \"pointer\",\n textDecoration: isLast ? \"none\" : \"underline\",\n fontFamily: \"inherit\",\n }}\n >\n {entry.label}\n </button>\n {!isLast && <span style={{ color: rawDefaults.colors.textMuted }}>›</span>}\n </span>\n );\n })}\n </div>\n );\n}\n","import { memo } from \"react\";\nimport { theme } from \"../../theme\";\nimport type { BreadcrumbEntry } from \"./useSubflowNavigation\";\n\nexport interface SubflowBreadcrumbProps {\n breadcrumbs: BreadcrumbEntry[];\n onNavigate: (level: number) => void;\n}\n\n/**\n * Breadcrumb bar for subflow drill-down navigation.\n * Shows: Root > SubflowA > SubflowB — clicking any crumb navigates back.\n */\nexport const SubflowBreadcrumb = memo(function SubflowBreadcrumb({\n breadcrumbs,\n onNavigate,\n}: SubflowBreadcrumbProps) {\n if (breadcrumbs.length <= 1) return null;\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n padding: \"6px 12px\",\n background: theme.bgSecondary,\n borderBottom: `1px solid ${theme.border}`,\n fontSize: 12,\n fontFamily: theme.fontSans,\n flexShrink: 0,\n overflowX: \"auto\",\n }}\n >\n {breadcrumbs.map((crumb, i) => {\n const isLast = i === breadcrumbs.length - 1;\n return (\n <span key={`${crumb.label}-${i}`} style={{ display: \"flex\", alignItems: \"center\", gap: 4 }}>\n {i > 0 && (\n <span style={{ color: theme.textMuted, fontSize: 10 }}>\n ›\n </span>\n )}\n {isLast ? (\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <span\n style={{\n color: theme.primary,\n fontWeight: 600,\n }}\n >\n {crumb.label}\n </span>\n {crumb.description && (\n <span\n style={{\n color: theme.textMuted,\n fontWeight: 400,\n fontSize: 11,\n }}\n >\n — {crumb.description}\n </span>\n )}\n </span>\n ) : (\n <button\n onClick={() => onNavigate(i)}\n style={{\n background: \"none\",\n border: \"none\",\n color: theme.textSecondary,\n cursor: \"pointer\",\n padding: \"2px 4px\",\n borderRadius: 4,\n fontSize: 12,\n fontFamily: \"inherit\",\n fontWeight: 500,\n transition: \"color 0.15s\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.color = `${theme.primary}`;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.color = `${theme.textSecondary}`;\n }}\n >\n {crumb.label}\n </button>\n )}\n </span>\n );\n })}\n </div>\n );\n});\n","/**\n * useSubflowNavigation — drill-down breadcrumb tracker for recorder-driven charts.\n *\n * Recorder-driven (v6+): replaces the legacy SpecNode-walk path. Accepts\n * a `TraceGraph` (from `createTraceStructureRecorder`) and tracks WHICH\n * subflow the user has drilled into.\n *\n * Limitation (intentional — recorder graph is flat / mount-only):\n * The StructureRecorder records the MOUNT of each subflow in the\n * parent chart, not the inner structure of each child chart. So\n * \"drill into a subflow\" today returns the SAME graph with the\n * `currentSubflowId` marker advanced — there is no separate\n * child-graph to swap in. Filtering nodes by\n * `data.subflowId === <selected>` would only surface mount nodes,\n * not the child chart's stages.\n *\n * TODO(recorder-driven-nesting): when child charts attach their own\n * `traceStructureRecorder` and surface those graphs via a registry,\n * accept `Map<subflowId, TraceGraph>` and swap `currentGraph` to the\n * child's graph on drill-down. Consumers can then render\n * `<TraceFlow graph={currentGraph} />` per level.\n */\n\nimport { useState, useCallback, useMemo } from \"react\";\nimport type { TraceGraph } from \"./traceStructureRecorder\";\n\nexport interface BreadcrumbEntry {\n /** Display name for this level */\n label: string;\n /** The subflow id that was drilled into to reach this level\n * (undefined for root). */\n subflowId?: string;\n /** Human-readable description of this subflow */\n description?: string;\n}\n\nexport interface SubflowNavigation {\n /** Current breadcrumb path (root → ... → current) */\n breadcrumbs: BreadcrumbEntry[];\n /** Current graph — today identical to the root graph (see file-level\n * TODO). Consumers should still treat this as the source of truth so\n * they remain forward-compatible once per-subflow graphs are wired in. */\n currentGraph: TraceGraph;\n /** Subflow id of the level the user is currently inside (null at root). */\n currentSubflowId: string | null;\n /** Display name of the subflow node we drilled into (null at root). */\n currentSubflowNodeName: string | null;\n /** Call when a node is clicked — drills in if it's a subflow.\n * Returns true when the click pushed a new level. */\n handleNodeClick: (nodeId: string) => boolean;\n /** Navigate to a specific breadcrumb level (0 = root) */\n navigateTo: (level: number) => void;\n /** Whether we're currently inside a subflow (not at root) */\n isInSubflow: boolean;\n}\n\nconst EMPTY_GRAPH: TraceGraph = { nodes: [], edges: [] };\n\n/**\n * Hook that tracks subflow drill-down state for a recorder-driven chart.\n *\n * Maintains a breadcrumb stack. When a subflow node is clicked the\n * stack pushes a new entry; breadcrumb clicks pop back to that level.\n * See file-level docs for the deferred per-subflow graph swap.\n */\nexport function useSubflowNavigation(\n rootGraph: TraceGraph | null,\n): SubflowNavigation {\n const [stack, setStack] = useState<BreadcrumbEntry[]>([]);\n\n const safeRootGraph = rootGraph ?? EMPTY_GRAPH;\n\n // Lookup: subflow id → mount node display name. Populated from the\n // recorder graph so click handlers can resolve the node-id the\n // consumer passes.\n const subflowMounts = useMemo(() => {\n const map = new Map<\n string,\n { subflowId: string; label: string; description?: string }\n >();\n for (const node of safeRootGraph.nodes) {\n if (!node.data?.isSubflow) continue;\n const subflowId =\n typeof node.data.subflowId === \"string\" ? node.data.subflowId : node.id;\n const label =\n typeof node.data.label === \"string\" ? node.data.label : node.id;\n const entry: { subflowId: string; label: string; description?: string } = {\n subflowId,\n label,\n };\n if (typeof node.data.description === \"string\") {\n entry.description = node.data.description;\n }\n // Key by stable id AND by the node id callers usually pass.\n map.set(node.id, entry);\n map.set(subflowId, entry);\n }\n return map;\n }, [safeRootGraph]);\n\n const breadcrumbs: BreadcrumbEntry[] = useMemo(() => {\n const rootLabel = \"Flowchart\";\n const root: BreadcrumbEntry = { label: rootLabel };\n return [root, ...stack];\n }, [stack]);\n\n const handleNodeClick = useCallback(\n (nodeId: string): boolean => {\n const mount = subflowMounts.get(nodeId);\n if (!mount) return false;\n setStack((prev) => {\n const entry: BreadcrumbEntry = {\n label: mount.label,\n subflowId: mount.subflowId,\n };\n if (mount.description !== undefined) entry.description = mount.description;\n return [...prev, entry];\n });\n return true;\n },\n [subflowMounts],\n );\n\n const navigateTo = useCallback((level: number) => {\n if (level === 0) {\n setStack([]);\n } else {\n setStack((prev) => prev.slice(0, level));\n }\n }, []);\n\n const top = stack[stack.length - 1];\n return {\n breadcrumbs,\n // TODO(recorder-driven-nesting): swap to per-subflow graph when\n // child charts attach their own recorders.\n currentGraph: safeRootGraph,\n currentSubflowId: top?.subflowId ?? null,\n currentSubflowNodeName: top?.label ?? null,\n handleNodeClick,\n navigateTo,\n isInSubflow: stack.length > 0,\n };\n}\n","/**\n * SubflowTree — collapsible sidebar listing mounted subflows.\n *\n * Recorder-driven (v6+): derives the tree from a `TraceGraph` produced\n * by `createTraceStructureRecorder`. Filters nodes by\n * `data.isSubflow === true` and lists them as `SubflowTreeEntry[]`\n * keyed by `subflowId`.\n *\n * Limitation (intentional — recorder graph is flat / mount-only):\n * Subflow-within-subflow nesting is NOT represented. The\n * StructureRecorder records the MOUNT of each subflow in the parent\n * chart, not the inner structure of each child chart. Rendering the\n * nested tree requires a separate recorder attached to each child\n * chart instance (deferred — see TODO below).\n *\n * Shared navigation layer — humans click through the tree just like\n * LLMs call getSubflowManifest() / getSubflowSpec().\n *\n * TODO(recorder-driven-nesting): when child charts attach their own\n * `traceStructureRecorder` and surface those graphs via a parent\n * registry, accept `Map<subflowId, TraceGraph>` and recurse to\n * restore the nested rendering the legacy SpecNode-walk supported.\n *\n * All colors come from `--fp-*` CSS variables set by the consumer.\n */\nimport { memo, useState, useCallback, useMemo } from \"react\";\nimport { theme } from \"../../theme\";\nimport type { TraceGraph } from \"./traceStructureRecorder\";\nimport type { BaseComponentProps } from \"../../types\";\n\nexport interface SubflowTreeEntry {\n /** Node name / identifier */\n name: string;\n /** Human-readable description */\n description?: string;\n /** Subflow ID (when this node represents a subflow) */\n subflowId?: string;\n /** Whether this node is a subflow root (has nested structure) */\n isSubflow?: boolean;\n /** Nested children (subflow stages) — always undefined in the\n * current recorder-driven implementation; see file-level TODO. */\n children?: SubflowTreeEntry[];\n}\n\nexport interface SubflowTreeProps extends BaseComponentProps {\n /** Recorder-captured graph from `createTraceStructureRecorder().getGraph()`. */\n graph: TraceGraph;\n /** Currently active stage name (highlights in tree) */\n activeStage?: string | null;\n /** Set of completed stage names */\n doneStages?: Set<string>;\n /** Called when a tree node is clicked */\n onNodeSelect?: (name: string, isSubflow: boolean) => void;\n}\n\n/** Extracts subflow entries from a recorder graph. Insertion-order preserving. */\nexport function graphToSubflowEntries(graph: TraceGraph): SubflowTreeEntry[] {\n if (!graph?.nodes?.length) return [];\n const entries: SubflowTreeEntry[] = [];\n for (const node of graph.nodes) {\n if (!node.data?.isSubflow) continue;\n const entry: SubflowTreeEntry = {\n name: typeof node.data.label === \"string\" ? node.data.label : node.id,\n isSubflow: true,\n };\n if (typeof node.data.description === \"string\") entry.description = node.data.description;\n if (typeof node.data.subflowId === \"string\") entry.subflowId = node.data.subflowId;\n entries.push(entry);\n }\n return entries;\n}\n\n/** Single tree node row */\nconst TreeNode = memo(function TreeNode({\n entry,\n depth,\n activeStage,\n doneStages,\n onNodeSelect,\n}: {\n entry: SubflowTreeEntry;\n depth: number;\n activeStage?: string | null;\n doneStages?: Set<string>;\n onNodeSelect?: (name: string, isSubflow: boolean) => void;\n}) {\n const [expanded, setExpanded] = useState(true);\n const hasChildren = entry.children && entry.children.length > 0;\n const isActive = activeStage === entry.name;\n const isDone = doneStages?.has(entry.name);\n\n const handleClick = useCallback(() => {\n if (hasChildren) {\n setExpanded((prev) => !prev);\n }\n onNodeSelect?.(entry.name, !!entry.isSubflow);\n }, [hasChildren, onNodeSelect, entry.name, entry.isSubflow]);\n\n return (\n <>\n <button\n onClick={handleClick}\n data-fp=\"subflow-tree-node\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n width: \"100%\",\n border: \"none\",\n background: isActive\n ? `color-mix(in srgb, ${theme.primary} 15%, transparent)`\n : \"transparent\",\n cursor: \"pointer\",\n padding: `4px 8px 4px ${8 + depth * 16}px`,\n fontFamily: theme.fontSans,\n fontSize: 12,\n textAlign: \"left\",\n borderRadius: 4,\n transition: \"background 0.15s\",\n }}\n onMouseEnter={(e) => {\n if (!isActive) {\n e.currentTarget.style.background = `color-mix(in srgb, ${theme.textMuted} 10%, transparent)`;\n }\n }}\n onMouseLeave={(e) => {\n if (!isActive) {\n e.currentTarget.style.background = \"transparent\";\n }\n }}\n >\n {/* Expand/collapse chevron for subflows */}\n {hasChildren ? (\n <span\n style={{\n fontSize: 10,\n color: theme.textMuted,\n width: 12,\n textAlign: \"center\",\n flexShrink: 0,\n transition: \"transform 0.15s\",\n transform: expanded ? \"rotate(90deg)\" : \"rotate(0deg)\",\n display: \"inline-block\",\n }}\n >\n ▶\n </span>\n ) : (\n <span style={{ width: 12, flexShrink: 0 }} />\n )}\n\n {/* Status dot */}\n <span\n style={{\n width: 6,\n height: 6,\n borderRadius: \"50%\",\n flexShrink: 0,\n background: isActive\n ? theme.primary\n : isDone\n ? theme.success\n : theme.border,\n }}\n />\n\n {/* Label + description */}\n <span style={{ display: \"flex\", flexDirection: \"column\", minWidth: 0 }}>\n <span\n style={{\n color: isActive\n ? theme.primary\n : isDone\n ? theme.textPrimary\n : theme.textSecondary,\n fontWeight: isActive ? 600 : entry.isSubflow ? 500 : 400,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {entry.name}\n {entry.isSubflow && (\n <span style={{ opacity: 0.5, marginLeft: 4, fontSize: 10 }}>⊞</span>\n )}\n </span>\n {entry.description && (\n <span\n style={{\n color: theme.textMuted,\n fontSize: 10,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {entry.description}\n </span>\n )}\n </span>\n </button>\n\n {/* Children */}\n {hasChildren && expanded && (\n <div>\n {entry.children!.map((child, i) => (\n <TreeNode\n key={child.subflowId ?? `${child.name}-${i}`}\n entry={child}\n depth={depth + 1}\n activeStage={activeStage}\n doneStages={doneStages}\n onNodeSelect={onNodeSelect}\n />\n ))}\n </div>\n )}\n </>\n );\n});\n\n/** Section label used for \"Flowchart\" and \"Subflows\" headings. */\nconst SectionLabel = memo(function SectionLabel({ children }: { children: string }) {\n return (\n <div\n style={{\n padding: \"4px 12px 8px\",\n fontSize: 10,\n fontWeight: 600,\n textTransform: \"uppercase\",\n letterSpacing: \"0.05em\",\n color: theme.textMuted,\n }}\n >\n {children}\n </div>\n );\n});\n\nexport const SubflowTree = memo(function SubflowTree({\n graph,\n activeStage,\n doneStages,\n onNodeSelect,\n unstyled = false,\n className,\n style,\n}: SubflowTreeProps) {\n const subflowStages = useMemo(() => graphToSubflowEntries(graph), [graph]);\n\n // Don't render anything if there are no subflows\n if (subflowStages.length === 0) return null;\n\n return (\n <div\n className={className}\n data-fp=\"subflow-tree\"\n style={{\n ...(unstyled\n ? {}\n : {\n fontFamily: theme.fontSans,\n fontSize: 12,\n background: theme.bgPrimary,\n borderRight: `1px solid ${theme.border}`,\n overflowY: \"auto\",\n overflowX: \"hidden\",\n padding: \"8px 0\",\n }),\n ...style,\n }}\n >\n {!unstyled && <SectionLabel>Subflows</SectionLabel>}\n {subflowStages.map((entry, i) => (\n <TreeNode\n key={entry.subflowId ?? `${entry.name}-${i}`}\n entry={entry}\n depth={0}\n activeStage={activeStage}\n doneStages={doneStages}\n onNodeSelect={onNodeSelect}\n />\n ))}\n </div>\n );\n});\n","/**\n * Branded types for translator key discipline.\n *\n * The footprintjs/trace contract uses two distinct identity strings:\n *\n * - **StageId**: the stable identifier the user picks at build time\n * (e.g. `'load-order'`, `'check-inventory'`). Identity per chart spec.\n *\n * - **RuntimeStageId**: `[subflowPath/]stageId#executionIndex` — the\n * per-execution identity. A loop visiting the same stage 3 times\n * produces 3 distinct RuntimeStageIds with the same StageId base.\n *\n * Translator outputs index per-stage data by StageId (`Map<StageId, ...>`)\n * AND per-execution data by RuntimeStageId (`Map<RuntimeStageId, ...>`).\n * Both are `string` at runtime — TypeScript can't distinguish them\n * without help. Branded types make `byStageId.get(runtimeStageId)` a\n * **compile-time error** instead of a silent `undefined` at runtime.\n *\n * Why branded types over wrapper classes\n * ──────────────────────────────────────\n * - Zero runtime cost (the brand exists only at the type level)\n * - JSON-serializable as-is (no `toJSON` glue needed)\n * - Interop with consumer code that uses raw `string` is one cast\n * (`stageId as StageId`) when the consumer is sure of the source.\n *\n * Usage pattern\n * ─────────────\n * ```ts\n * import type { StageId, RuntimeStageId } from './_internal/keys';\n *\n * // In a translator, when accepting input from a footprintjs event:\n * const sid = event.stageId as StageId;\n * const rsid = event.traversalContext.runtimeStageId as RuntimeStageId;\n *\n * // In a consumer reading from the index:\n * const node = index.byStageId.get(stageId); // typechecks\n * const node = index.byStageId.get(runtimeStageId); // TS ERROR ✓\n * ```\n *\n * Helper to derive a StageId from a RuntimeStageId — strips `#N` suffix\n * and optional subflow path. **Use only for DISPLAY**, NEVER for matching\n * commitLog stageIds (see invariant I3 in `traceStructureRecorder.ts`).\n */\n\n// String-literal brands (NOT `unique symbol`) — survive `.d.ts` emit\n// across module boundaries. Unique-symbol brands get serialized as\n// new local symbols when consumers compile their own .d.ts, causing\n// \"missing property [unique symbol]\" errors. String literals stay\n// nominal because the literal value is identical across builds.\n\n/** Stable per-spec identifier (e.g. `'load-order'`). */\nexport type StageId = string & { readonly __brand: \"StageId\" };\n\n/** Per-execution identifier (e.g. `'load-order#0'` or `'sf-foo/inner#3'`). */\nexport type RuntimeStageId = string & { readonly __brand: \"RuntimeStageId\" };\n\n/**\n * Tag a raw string as a `StageId`. Use at translator boundaries when\n * ingesting from a footprintjs event payload (the source guarantees\n * the string IS a stage id). Zero runtime cost.\n */\nexport function asStageId(s: string): StageId {\n return s as StageId;\n}\n\n/**\n * Tag a raw string as a `RuntimeStageId`. Use at translator boundaries\n * when ingesting from a `traversalContext.runtimeStageId`. Zero\n * runtime cost.\n */\nexport function asRuntimeStageId(s: string): RuntimeStageId {\n return s as RuntimeStageId;\n}\n","/**\n * walkSubflowSpecInto — walks a footprintjs v6.0+ `subflowSpec` payload\n * from `StructureSubflowMountedEvent` and emits nodes + edges into the\n * trace recorder's existing upsert helpers.\n *\n * This is the local mirror of `walkSubflowSpec` from `footprintjs/trace`\n * — kept local to preserve explainable-ui's zero-`footprintjs`-dep\n * boundary (see traceStructureRecorder.ts top-of-file rationale).\n *\n * Stage IDs come pre-prefixed from footprintjs's `_prefixNodeTree`\n * (e.g. `'sf-tools/execute-tool-calls'`), so we use them as-is for\n * node ids. The `subflowPath` is set on `data.subflowOf` to mark which\n * subflow each inner stage belongs to.\n */\n\nimport type { Node, Edge } from \"@xyflow/react\";\nimport { asStageId } from \"./keys\";\nimport type { TraceEdgeData, TraceNodeData } from \"../traceStructureRecorder\";\n\n/** Minimal duck-typed spec shape — mirrors the slice of\n * `SerializedPipelineStructure` we need. */\ninterface SpecNode {\n readonly id: string;\n readonly name: string;\n readonly type?: \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n readonly icon?: string;\n readonly description?: string;\n readonly children?: readonly SpecNode[];\n readonly next?: SpecNode;\n readonly loopTarget?: string;\n readonly isLoopReference?: boolean;\n readonly isSubflowRoot?: boolean;\n readonly subflowId?: string;\n readonly subflowName?: string;\n readonly subflowStructure?: SpecNode;\n readonly isPausable?: boolean;\n readonly isLazy?: boolean;\n}\n\ninterface WalkSink {\n upsertNode(node: Node<TraceNodeData>): void;\n pushEdge(edge: Edge<TraceEdgeData>): void;\n}\n\nexport function walkSubflowSpecInto(\n spec: SpecNode,\n subflowPath: string,\n sink: WalkSink,\n): void {\n walkNode(spec, subflowPath, sink, new Set<string>());\n}\n\nfunction walkNode(\n node: SpecNode,\n subflowPath: string,\n sink: WalkSink,\n visited: Set<string>,\n): void {\n if (visited.has(node.id)) return;\n visited.add(node.id);\n if (node.isLoopReference) return;\n\n // Nested subflow mount — recurse into its structure with composed path.\n if (node.isSubflowRoot && node.subflowId !== undefined && node.subflowStructure) {\n const nestedPath = `${subflowPath}/${node.subflowId}`;\n walkNode(node.subflowStructure, nestedPath, sink, visited);\n // Fall through so the mount node itself is emitted in the parent\n // subflow's scope below.\n }\n\n // Emit the stage node, tagged with subflowOf.\n const type = node.type ?? \"stage\";\n const isDecider = type === \"decider\" || type === \"selector\";\n const isFork = type === \"fork\";\n const isStreaming = type === \"streaming\";\n const isSubflow = !!node.isSubflowRoot;\n\n const stageId = asStageId(node.id);\n const data: TraceNodeData = {\n label: node.name,\n isDecider,\n isFork,\n isStreaming,\n isSubflow,\n subflowOf: subflowPath,\n prevIds: [],\n nextIds: [],\n };\n if (node.description !== undefined) data.description = node.description;\n if (node.icon !== undefined) data.icon = node.icon;\n if (node.subflowId !== undefined) data.subflowId = node.subflowId;\n if (node.isLazy === true) data.isLazy = true;\n if (node.isPausable === true) data.isPausable = true;\n\n sink.upsertNode({\n id: node.id,\n type: \"stage\",\n position: { x: 0, y: 0 },\n data,\n });\n\n // Children (decider/selector/fork branches).\n if (node.children && node.children.length > 0) {\n const edgeKind: \"fork-branch\" | \"decision-branch\" = type === \"fork\" ? \"fork-branch\" : \"decision-branch\";\n for (const child of node.children) {\n const edgeId = `${node.id}->${child.id}:${edgeKind}${edgeKind === \"decision-branch\" ? `:${child.id}` : \"\"}`;\n const edgeData: TraceEdgeData = { kind: edgeKind };\n if (edgeKind === \"decision-branch\") edgeData.label = child.id;\n const edge: Edge<TraceEdgeData> = {\n id: edgeId,\n source: node.id,\n target: child.id,\n data: edgeData,\n };\n if (edgeKind === \"decision-branch\") edge.label = child.id;\n sink.pushEdge(edge);\n walkNode(child, subflowPath, sink, visited);\n }\n }\n\n // Linear next or loop back-edge.\n if (node.next) {\n if (node.next.isLoopReference && node.loopTarget) {\n sink.pushEdge({\n id: `${node.id}->${node.loopTarget}:loop`,\n source: node.id,\n target: node.loopTarget,\n data: { kind: \"loop\" },\n });\n } else {\n const edgeId = `${node.id}->${node.next.id}:next`;\n sink.pushEdge({\n id: edgeId,\n source: node.id,\n target: node.next.id,\n data: { kind: \"next\" },\n });\n walkNode(node.next, subflowPath, sink, visited);\n }\n }\n // Suppress unused-binding warning for stageId (kept for parity with\n // recorder upsertNode signature; xyflow node `id` is the string form).\n void stageId;\n}\n","/**\n * traceStructureRecorder — event-driven xyflow Node[] + Edge[] collector.\n *\n * Implements footprintjs v6.0+ `StructureRecorder` interface. Accumulates\n * an unpositioned graph (xyflow node + edge shape) as the chart is being\n * built — no spec tree walk required.\n *\n * Why event-driven\n * ────────────────\n * The recorder fires SYNCHRONOUSLY at every spec-mutation moment during\n * construction. By the time `.build()` returns, the recorder's\n * `getGraph()` returns the complete graph — zero extra walking\n * (the \"collect during traversal, never post-process\" rule footprintjs\n * documents in its core principle).\n *\n * Bonus: the same recorder shape can drive incremental UI updates if\n * the builder is constructed asynchronously (e.g., a UI builder where\n * each \"add stage\" click re-renders the live graph).\n *\n * Layout is a separate concern\n * ────────────────────────────\n * This module produces UNPOSITIONED nodes (no `position` field set;\n * xyflow defaults to `{x: 0, y: 0}`). Apply a layout algorithm\n * downstream — either:\n *\n * - a graph algorithm (dagre / elk / d3-force)\n * - manual positioning via your own walk over `recorder.getGraph()`\n *\n * The `<TraceFlow>` component wires a default BFS layout.\n *\n * @example\n * ```ts\n * import { flowChart } from 'footprintjs';\n * import { createTraceStructureRecorder } from 'footprint-explainable-ui/flowchart';\n *\n * const trace = createTraceStructureRecorder();\n * const chart = flowChart('seed', fn, 'seed', {\n * structureRecorders: [trace.recorder],\n * })\n * .addFunction('a', fnA, 'a')\n * .build();\n *\n * const { nodes, edges } = trace.getGraph();\n * // → nodes: [{ id: 'seed', data: { label: 'seed', ... } }, { id: 'a', ... }]\n * // → edges: [{ id: 'seed->a', source: 'seed', target: 'a', data: { kind: 'next' } }]\n *\n * <ReactFlow nodes={layout(nodes)} edges={edges} />\n * ```\n */\n\nimport type { Node, Edge } from \"@xyflow/react\";\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport type { StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { walkSubflowSpecInto } from \"./_internal/walkSubflowSpecInto\";\n\nexport type { StageId, RuntimeStageId } from \"./_internal/keys\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local type aliases mirroring footprintjs/StructureRecorder\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Rationale for redefining these here instead of `import type` from\n// 'footprintjs': footprint-explainable-ui has no `footprintjs` dependency\n// declared in package.json (intentional — consumers wire it). So we mirror\n// the public interface shape. If footprintjs changes the StructureRecorder\n// interface, this module's types must update in lockstep — tracked by the\n// type-conformance test in `test/unit/traceStructureRecorder.test.ts`.\n\ntype StructureNodeType = \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n\ninterface StructureSpecRef {\n readonly id: string;\n readonly name: string;\n readonly type?: StructureNodeType;\n readonly description?: string;\n readonly icon?: string;\n readonly isSubflowRoot?: boolean;\n readonly subflowId?: string;\n readonly isLazy?: boolean;\n readonly [key: string]: unknown;\n}\n\ninterface StageAddedEvent {\n readonly stageId: string;\n readonly name: string;\n readonly type: StructureNodeType;\n readonly isPausable?: boolean;\n readonly spec: StructureSpecRef;\n}\n\ntype EdgeKind = \"next\" | \"fork-branch\" | \"decision-branch\";\n\ninterface EdgeAddedEvent {\n readonly from: string;\n readonly to: string;\n readonly kind: EdgeKind;\n readonly label?: string;\n}\n\ninterface LoopEdgeAddedEvent {\n readonly from: string;\n readonly to: string;\n}\n\ninterface DeciderCompleteEvent {\n readonly decider: string;\n readonly type: \"decider\" | \"selector\";\n readonly branchIds: readonly string[];\n readonly defaultBranch?: string;\n}\n\ninterface SubflowMountedEvent {\n readonly subflowId: string;\n readonly subflowName: string;\n readonly rootStageId: string;\n readonly isLazy?: boolean;\n /**\n * The mounted subflow's complete spec — added in footprintjs v6.0\n * (proposal #001). Present for eager mounts, UNDEFINED for lazy\n * mounts (the subflow isn't resolved yet at mount-event-fire-time).\n * When present, the consumer walks it to materialize inner nodes +\n * edges directly with `subflowOf` set — no retroactive tagging\n * needed.\n *\n * Typed as `unknown` because the upstream `SerializedPipelineStructure`\n * shape has no index signature and we want to stay loosely-coupled\n * (see top-of-file rationale for the no-`footprintjs`-dep boundary).\n * `walkSubflowSpecInto` accepts the duck-typed shape it actually\n * walks.\n */\n readonly subflowSpec?: unknown;\n /**\n * Local mount id within the parent (matches `subflowId` for top-level\n * mounts; composed `'parent/child'` for nested). Tagged onto every\n * inner stage's `data.subflowOf` during the walk.\n */\n readonly subflowPath?: string;\n}\n\n/**\n * Minimal StructureRecorder interface — mirrors footprintjs v6.0+.\n *\n * Named with the `Minimal` prefix to make the local-mirror nature\n * explicit at consumer call sites — a consumer importing both this\n * type and the upstream `StructureRecorder` from `footprintjs` won't\n * collide, and code reviewers see at a glance which boundary the type\n * crosses.\n *\n * The upstream `footprintjs.StructureRecorder` is structurally\n * compatible (this type's shape is a subset of upstream's), so passing\n * an instance of this to `flowChart(..., { structureRecorders: [...] })`\n * typechecks cleanly.\n */\nexport interface MinimalStructureRecorder {\n readonly id: string;\n onStageAdded?(event: StageAddedEvent): void;\n onEdgeAdded?(event: EdgeAddedEvent): void;\n onLoopEdgeAdded?(event: LoopEdgeAddedEvent): void;\n onDeciderComplete?(event: DeciderCompleteEvent): void;\n onSubflowMounted?(event: SubflowMountedEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// xyflow node + edge data shapes\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Per-node data attached to the xyflow `Node`. Consumed by the\n * `StageNode` renderer (shape mirrors what the renderer expects).\n */\nexport interface TraceNodeData extends Record<string, unknown> {\n label: string;\n isDecider: boolean;\n isFork: boolean;\n isSubflow: boolean;\n /** True when the event carried `type: 'streaming'` (the spec was added\n * via `addStreamingFunction`). Renderers that style streaming stages\n * distinctly key on this flag. */\n isStreaming: boolean;\n description?: string;\n icon?: string;\n subflowId?: string;\n isLazy?: boolean;\n isPausable?: boolean;\n /** Set later by `onDeciderComplete` when the decider's branch list is\n * sealed. Useful for renderers that want to render decider with a\n * branch-count badge. */\n branchIds?: readonly string[];\n defaultBranch?: string;\n /**\n * The subflow this node belongs to, OR `undefined` for top-level\n * parent-chart stages. Tracked via a stack-based heuristic during\n * event ingestion:\n *\n * - Push on `onSubflowMounted({subflowId, rootStageId})` →\n * top-of-stack = `{subflowId, mountStageId}`\n * - `onStageAdded` tags new nodes with the top-of-stack `subflowId`\n * (the mount node itself stays UNtagged — it's part of the parent\n * chain)\n * - Pop on `onEdgeAdded` where `from === mount.id` (a mount's\n * outgoing edge to a sibling means the parent chain has resumed);\n * the wrongly-tagged target node is re-tagged to the parent scope\n *\n * Mount nodes (where `isSubflow=true`) have `subflowOf` reflecting\n * their OWN parent context, NOT the subflow they mount. So a parent's\n * mount node has `subflowOf=undefined` (top-level parent), and the\n * subflow's INTERNAL stages have `subflowOf=<mount.subflowId>`.\n *\n * Renderers use this to filter the chart by drill-down level: show\n * only nodes where `subflowOf === currentDrillSubflowId` (undefined\n * for top-level view, mount.subflowId after drilling in).\n */\n subflowOf?: string;\n /**\n * **L8.0 — STRUCTURAL prev/next**: stage ids that lead into / out of\n * this node, derived live from incoming/outgoing edges. Excludes\n * `loop` back-edges (visual only — per invariant I1).\n *\n * Convergence-correct: a fork-join node carries an ENTRY per branch\n * child (e.g., `FinalizeOrder.prevIds = ['CheckInventory', 'RunFraudCheck']`).\n *\n * \"Structural\" qualifier: this is the chart-SHAPE prev/next, not\n * runtime execution order. For runtime ancestry use `CommitView`\n * fields on `CommitFlowIndex` (L8.2).\n */\n prevIds: StageId[];\n nextIds: StageId[];\n}\n\n/** Per-edge data attached to the xyflow `Edge`. */\nexport interface TraceEdgeData extends Record<string, unknown> {\n kind: EdgeKind | \"loop\";\n label?: string;\n}\n\nexport type TraceNode = Node<TraceNodeData>;\nexport type TraceEdge = Edge<TraceEdgeData>;\n\nexport interface TraceGraph {\n nodes: TraceNode[];\n edges: TraceEdge[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceStructureRecorderHandle {\n /** The recorder to register via `flowChart(..., { structureRecorders: [handle.recorder] })`\n * or `.attachStructureRecorder(handle.recorder)`. */\n recorder: MinimalStructureRecorder;\n /** Returns a defensive copy of the current graph state. Safe to call\n * multiple times; safe to mutate the returned arrays without affecting\n * the recorder's internal state. */\n getGraph(): TraceGraph;\n /** Direct read-only access for hot-path consumers (Lens slider scrubbing).\n * Returns the LIVE internal arrays — do NOT mutate. Prefer `getGraph()`\n * unless you measure a performance cost. */\n getGraphRef(): Readonly<TraceGraph>;\n /**\n * Subscribe to graph-change notifications. Pub-sub model — multiple\n * listeners can subscribe; each fires after every event that mutates\n * the graph (per-event, NOT batched). Returns an unsubscribe function.\n * Designed for React's `useSyncExternalStore` consumption.\n *\n * Listeners are NOT invoked during `reset()`. **Consumer guidance**:\n * if you need to clear a live `<TraceFlow recorder={handle} />`\n * mid-mount, either (a) unmount the component before calling\n * `reset()` and re-mount after, OR (b) drive a fresh recorder\n * instance via state. See `reset()` JSDoc for the rationale.\n */\n subscribe(listener: () => void): () => void;\n /**\n * Monotonically-increasing version counter — bumps once per\n * graph-mutating event. Pair with `getGraph()` in\n * `useSyncExternalStore` snapshot equality:\n * ```ts\n * const version = useSyncExternalStore(handle.subscribe, () => handle.version());\n * const graph = useMemo(() => handle.getGraph(), [version]);\n * ```\n * Avoids defensive-copy allocation on every render while keeping\n * React's identity-check happy.\n */\n version(): number;\n /** Reset the recorder for reuse across multiple builds. After this,\n * the recorder behaves like a freshly-constructed instance. */\n reset(): void;\n}\n\nexport interface CreateTraceStructureRecorderOptions {\n /** Recorder id — surfaces in `StructureBuildError.recorderId` when\n * the recorder throws. Defaults to `'trace-structure'`. Use distinct\n * ids if you attach multiple instances. */\n id?: string;\n /** Optional callback fired after each event mutates the graph. Useful\n * for incremental-render UIs (Lens) that want to re-render between\n * builder operations. NOT invoked during the initial `attachStructureRecorder`\n * seed replay; consumers can call `getGraph()` directly after attach. */\n onChange?: (graph: Readonly<TraceGraph>) => void;\n}\n\nexport function createTraceStructureRecorder(\n options: CreateTraceStructureRecorderOptions = {},\n): TraceStructureRecorderHandle {\n const id = options.id ?? \"trace-structure\";\n const onChange = options.onChange;\n\n let nodes: TraceNode[] = [];\n let edges: TraceEdge[] = [];\n // Indexes — O(1) lookup for decider-completion + subflow-mounted updates.\n const nodeIndex = new Map<string, number>();\n const seenEdgeIds = new Set<string>();\n // L8.0 — per-node prev/next indexes maintained as edges arrive. The\n // arrays land on `TraceNode.data.prevIds` / `data.nextIds` so basic\n // TraceGraph consumers get convergence-correct neighbor info \"for\n // free\" (no separate NodeView translator needed for chart rendering).\n const prevIdsOf = new Map<string, StageId[]>();\n const nextIdsOf = new Map<string, StageId[]>();\n // Pub-sub + version via shared infra (microtask-batched listener fan-out).\n const notifier = createNotifier(\"traceStructureRecorder\");\n\n function notifyChange(): void {\n if (onChange) {\n try {\n onChange({ nodes, edges });\n } catch (err) {\n devWarn(\n () => \"[traceStructureRecorder] onChange callback threw — isolated.\",\n err,\n );\n }\n }\n notifier.notify();\n }\n\n function upsertNode(node: TraceNode): void {\n const existing = nodeIndex.get(node.id);\n if (existing !== undefined) {\n // Merge: later events may carry richer data (e.g., onDeciderComplete\n // → branchIds). Preserve any fields the new event didn't set.\n nodes[existing] = {\n ...nodes[existing],\n ...node,\n data: { ...nodes[existing]!.data, ...node.data },\n };\n } else {\n nodeIndex.set(node.id, nodes.length);\n nodes.push(node);\n }\n }\n\n function pushEdge(edge: TraceEdge): void {\n // Dedupe by id — the seed replay path could otherwise double-add\n // if a consumer attaches the same recorder twice (allowed by design,\n // but the graph should still be sane).\n if (seenEdgeIds.has(edge.id)) return;\n seenEdgeIds.add(edge.id);\n edges.push(edge);\n\n // L8.0 — maintain prev/next indexes. Loop back-edges do NOT\n // contribute (invariant I1: loops are visual annotations only).\n const kind = edge.data?.kind;\n if (kind === \"loop\") return;\n const source = asStageId(edge.source);\n const target = asStageId(edge.target);\n const nextArr = nextIdsOf.get(source) ?? [];\n nextArr.push(target);\n nextIdsOf.set(source, nextArr);\n const prevArr = prevIdsOf.get(target) ?? [];\n prevArr.push(source);\n prevIdsOf.set(target, prevArr);\n\n // Sync the index changes onto the LIVE node-data arrays so\n // consumers reading `node.data.prevIds`/`nextIds` see fresh values\n // after each edge event. We mutate in place rather than re-cloning\n // the node — `getGraph()` returns defensive copies anyway.\n syncNeighborsOnto(source);\n syncNeighborsOnto(target);\n }\n\n function syncNeighborsOnto(stageId: StageId): void {\n const idx = nodeIndex.get(stageId);\n if (idx === undefined) return; // node not yet announced — will sync at onStageAdded\n const node = nodes[idx]!;\n // L8.0 panel must-fix: ATOMIC REPLACE — copy the arrays from the\n // index, don't share the map's array refs. A consumer using\n // `getGraphRef()` who caches `node.data.prevIds` would otherwise\n // see their cached array silently grow when a new edge fires.\n // The slice() cost is one allocation per edge per touched node —\n // negligible vs. the consumer-safety win.\n const prevs = prevIdsOf.get(stageId);\n const nexts = nextIdsOf.get(stageId);\n node.data.prevIds = prevs ? prevs.slice() : [];\n node.data.nextIds = nexts ? nexts.slice() : [];\n }\n\n const recorder: MinimalStructureRecorder = {\n id,\n onStageAdded(event) {\n const spec = event.spec;\n const type = event.type;\n const isDecider = type === \"decider\" || type === \"selector\";\n const isFork = type === \"fork\";\n const isStreaming = type === \"streaming\";\n const isSubflow = !!spec.isSubflowRoot;\n\n const stageId = asStageId(event.stageId);\n const data: TraceNodeData = {\n label: event.name,\n isDecider,\n isFork,\n isStreaming,\n isSubflow,\n // L8.0 — seed prev/next from any edges that already fired\n // pointing AT this node. Convergence case: a fork-branch edge\n // from LoadOrder fires BEFORE the child's onStageAdded; this\n // line ensures the child's prevIds picks up the back-pointer.\n // Atomic copy (not shared ref) — see `syncNeighborsOnto` for\n // the panel-flagged consumer-safety rationale.\n prevIds: (prevIdsOf.get(stageId) ?? []).slice(),\n nextIds: (nextIdsOf.get(stageId) ?? []).slice(),\n };\n if (spec.description !== undefined) data.description = spec.description;\n if (spec.icon !== undefined) data.icon = spec.icon;\n if (spec.subflowId !== undefined) data.subflowId = spec.subflowId;\n if (spec.isLazy === true) data.isLazy = true;\n if (event.isPausable === true) data.isPausable = true;\n // subflowOf gets set RETROACTIVELY in onSubflowMounted (the\n // builder fires inner-stage events BEFORE the mount event, so\n // we can't tag at stage-add time — we tag at mount time by\n // identifying untagged disconnected subgraphs).\n\n upsertNode({\n id: event.stageId,\n type: \"stage\",\n // No layout here — downstream consumer applies positions.\n position: { x: 0, y: 0 },\n data,\n });\n notifyChange();\n },\n\n onEdgeAdded(event) {\n const edgeId = `${event.from}->${event.to}:${event.kind}${event.label ? `:${event.label}` : \"\"}`;\n const data: TraceEdgeData = { kind: event.kind };\n if (event.label !== undefined) data.label = event.label;\n const edge: TraceEdge = {\n id: edgeId,\n source: event.from,\n target: event.to,\n data,\n };\n if (event.label !== undefined) edge.label = event.label;\n pushEdge(edge);\n notifyChange();\n },\n\n onLoopEdgeAdded(event) {\n const edgeId = `${event.from}->${event.to}:loop`;\n pushEdge({\n id: edgeId,\n source: event.from,\n target: event.to,\n data: { kind: \"loop\" },\n });\n notifyChange();\n },\n\n onDeciderComplete(event) {\n // Patch the already-added decider node with its sealed branch info.\n const existing = nodeIndex.get(event.decider);\n if (existing === undefined) {\n // The decider node SHOULD have been added via onStageAdded\n // before its branches were declared. If this fires for an\n // unknown id, the upstream builder reordered events —\n // visualisation will silently degrade. Warn in dev so the bug\n // is visible at its source.\n devWarn(\n () =>\n `[traceStructureRecorder] onDeciderComplete fired for unknown stageId \"${event.decider}\" — branch metadata dropped. Did the upstream fire onStageAdded for this id first?`,\n );\n return;\n }\n const node = nodes[existing]!;\n const data: TraceNodeData = {\n ...node.data,\n branchIds: event.branchIds,\n };\n if (event.defaultBranch !== undefined) data.defaultBranch = event.defaultBranch;\n nodes[existing] = { ...node, data };\n notifyChange();\n },\n\n onSubflowMounted(event) {\n // The mount node was already announced via `onStageAdded`; here\n // we patch in the subflow-specific data fields, then materialize\n // the subflow's inner structure.\n const existing = nodeIndex.get(event.rootStageId);\n if (existing === undefined) {\n devWarn(\n () =>\n `[traceStructureRecorder] onSubflowMounted fired for unknown rootStageId \"${event.rootStageId}\" (subflowId=\"${event.subflowId}\") — subflow metadata dropped. Did the upstream fire onStageAdded for the mount node first?`,\n );\n return;\n }\n const node = nodes[existing]!;\n const data: TraceNodeData = {\n ...node.data,\n isSubflow: true,\n subflowId: event.subflowId,\n };\n if (event.isLazy === true) data.isLazy = true;\n nodes[existing] = { ...node, data };\n\n // Eager mounts (footprintjs v6.0+): walk the full subflow spec\n // delivered on the event to emit inner nodes + edges with\n // `subflowOf` set directly. Lazy mounts arrive with no spec —\n // their internal structure isn't known until the resolver runs\n // at runtime; the mount node alone is rendered (consumer apps\n // can subscribe to runtime events to fill in detail if desired).\n const subflowPath = event.subflowPath ?? event.subflowId;\n if (event.subflowSpec) {\n // Cast: type is `unknown` at the event boundary (see\n // SubflowMountedEvent JSDoc); walkSubflowSpecInto accepts\n // the duck-typed structural shape it actually traverses.\n walkSubflowSpecInto(event.subflowSpec as Parameters<typeof walkSubflowSpecInto>[0], subflowPath, {\n upsertNode,\n pushEdge,\n });\n }\n notifyChange();\n },\n };\n\n return {\n recorder,\n getGraph(): TraceGraph {\n return {\n nodes: nodes.map((n) => ({ ...n, data: { ...n.data } })),\n edges: edges.map((e) => ({ ...e, data: e.data ? { ...e.data } : undefined })),\n };\n },\n getGraphRef(): Readonly<TraceGraph> {\n return { nodes, edges };\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n nodes = [];\n edges = [];\n nodeIndex.clear();\n seenEdgeIds.clear();\n prevIdsOf.clear();\n nextIdsOf.clear();\n // Why `reset()` does NOT bump version or notify listeners:\n // a notify here would cause `<TraceFlow recorder={handle} />`\n // to re-render with an empty graph for one frame, then re-render\n // again when the next builder event fires — visible flicker for\n // users who reset between builds. The recommended pattern is to\n // recycle the recorder OUTSIDE the React tree (e.g., via a\n // factory hook keyed on a \"build epoch\" so React unmounts and\n // re-mounts <TraceFlow> across builds). See `subscribe()` JSDoc\n // for the consumer-facing recipe.\n },\n };\n}\n","/**\n * createNodeViewRecorder — per-stage summary translator.\n *\n * Implements footprintjs v6.0+ `CombinedRecorder` (Flow + Scope) and\n * produces a `NodeViewIndex` — per-stage data keyed by both `StageId`\n * (chart-shape lookup) and `RuntimeStageId` (per-execution lookup).\n *\n * Composition (panel guidance, L8.0 review)\n * ─────────────────────────────────────────\n * NodeView does NOT duplicate the structural prev/next index — it\n * READS those fields from the structure translator's\n * `node.data.prevIds`/`nextIds`. The structure translator already\n * maintains convergence-correct, loop-excluded neighbors. Duplicating\n * the index here would re-introduce edge-ordering bugs we just\n * solved.\n *\n * The NodeView translator owns ONLY runtime-derived per-stage state:\n * - `executions[]` — every FlowRecorder.onStageExecuted event for\n * this stage (loop-friendly: N executions of one stage produce\n * N entries, each with its own runtimeStageId).\n * - `commitRuntimeStageIds[]` — refs to commits made by this stage\n * (the canonical CommitView lives in CommitFlowIndex from L8.2;\n * NodeView stores only the join key).\n *\n * Plus derived convenience fields: `visitedInRun`, `executionCount`,\n * `firstExecutedAt`, `lastExecutedAt`, `totalDurationMs`, `errorCount`.\n *\n * Version bumping\n * ───────────────\n * NodeView bumps its own version on EITHER:\n * (a) a Flow/Scope event arrives (own state mutates), OR\n * (b) the structure translator's version bumps (structural data\n * the index projects from changed).\n *\n * So `useTranslator(nodeView, ...)` re-renders when EITHER changes —\n * one subscription, full reactive coverage.\n *\n * @example\n * ```tsx\n * import { createTraceStructureRecorder, createNodeViewRecorder, useTranslator } from 'footprint-explainable-ui/flowchart';\n *\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const nodeView = useMemo(() => createNodeViewRecorder({ structure: trace }), [trace]);\n *\n * useEffect(() => {\n * executor.attachFlowRecorder(nodeView.recorder);\n * executor.attachScopeRecorder(nodeView.recorder);\n * }, [nodeView]);\n *\n * const index = useTranslator(nodeView, () => nodeView.getIndex());\n * const finalize = index.byStageId.get(asStageId('FinalizeOrder'));\n * // finalize.prevIds → ['CheckInventory', 'RunFraudCheck'] (from structure)\n * // finalize.executions → [{ runtimeStageId, iteration, startMs, endMs, ... }]\n * // finalize.visitedInRun → true\n * // finalize.commitRuntimeStageIds → ['finalize-order#3', ...]\n * ```\n */\n\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport { asStageId, asRuntimeStageId } from \"./_internal/keys\";\nimport type { StageId, RuntimeStageId } from \"./_internal/keys\";\nimport type { TraceStructureRecorderHandle, TraceNode } from \"./traceStructureRecorder\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local mirrors of footprintjs runtime recorder interfaces\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Same rationale as other translators: explainable-ui has no\n// `footprintjs` dep — we mirror the subset we consume. Structural\n// compatibility means our `recorder` passes through to\n// `executor.attachFlowRecorder()` / `attachScopeRecorder()` cleanly.\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface FlowStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly traversalContext: TraversalContext;\n readonly startTime?: number;\n readonly endTime?: number;\n}\n\ninterface FlowErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface FlowRunLifecycleEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface ScopeCommitEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly updates?: Record<string, unknown>;\n readonly reads?: readonly string[];\n}\n\n/**\n * Minimal CombinedRecorder interface mirror — subset of footprintjs's\n * Flow + Scope recorder interfaces NodeView consumes. Implements both\n * channels in one object; consumer attaches via\n * `executor.attachFlowRecorder()` AND `executor.attachScopeRecorder()`\n * (or `executor.attachCombinedRecorder()` if available).\n */\nexport interface MinimalNodeViewRecorder {\n readonly id: string;\n // Flow channel\n onStageExecuted?(event: FlowStageExecutedEvent): void;\n onError?(event: FlowErrorEvent): void;\n onRunStart?(event: FlowRunLifecycleEvent): void;\n onRunEnd?(event: FlowRunLifecycleEvent): void;\n // Scope channel\n onCommit?(event: ScopeCommitEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** One execution of a stage. A stage that runs N times in a loop\n * produces N `ExecutionRecord` entries on the NodeView.executions[]. */\nexport interface ExecutionRecord {\n /** `[subflowPath/]stageId#executionIndex` — universal join key. */\n readonly runtimeStageId: RuntimeStageId;\n /** Loop iteration (0-indexed). undefined when the engine didn't\n * populate it (rare). */\n readonly iteration?: number;\n /** ms since executor start. */\n readonly startMs?: number;\n /** ms since executor start. */\n readonly endMs?: number;\n /** Set when `onError` fired for this execution. */\n readonly errorMessage?: string;\n}\n\n/**\n * Per-stage summary. Joins STRUCTURAL data (from the structure\n * translator's TraceNode.data) with RUNTIME data (executions + commit\n * refs accumulated by this translator).\n */\nexport interface NodeView {\n // ── Identity ────────────────────────────────────────────────────\n readonly stageId: StageId;\n readonly label: string;\n\n // ── Structural (read-through from structure translator) ─────────\n readonly type: \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n readonly isDecider: boolean;\n readonly isFork: boolean;\n readonly isSubflow: boolean;\n readonly isStreaming: boolean;\n readonly isPausable: boolean;\n readonly description?: string;\n readonly icon?: string;\n readonly subflowId?: string;\n readonly branchIds?: readonly string[];\n readonly defaultBranch?: string;\n /** From the structure translator (loop-excluded, convergence-correct). */\n readonly prevIds: StageId[];\n readonly nextIds: StageId[];\n\n // ── Visit data (runtime) ────────────────────────────────────────\n readonly executions: ExecutionRecord[];\n /** Derived: `executions.length > 0`. */\n readonly visitedInRun: boolean;\n /** Derived: `executions.length` (loop iteration count). */\n readonly executionCount: number;\n /** Derived: first execution `startMs`, or `null` if not yet executed. */\n readonly firstExecutedAt: number | null;\n /** Derived: last execution `endMs`, or `null`. */\n readonly lastExecutedAt: number | null;\n /** Derived: sum of `endMs - startMs` across executions. */\n readonly totalDurationMs: number;\n /** Derived: count of executions with an errorMessage. */\n readonly errorCount: number;\n\n // ── Commit refs (join key into CommitFlowIndex from L8.2) ───────\n /** Run-time stage ids of commits made by this stage. Look up the\n * canonical CommitView via `commitFlow.byRuntimeStageId.get(id)`. */\n readonly commitRuntimeStageIds: RuntimeStageId[];\n}\n\n/** Index of NodeView keyed by both StageId and RuntimeStageId. The\n * branded types prevent `byStageId.get(runtimeStageId)` silent-undefined. */\nexport interface NodeViewIndex {\n readonly byStageId: ReadonlyMap<StageId, NodeView>;\n readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, NodeView>;\n /** All NodeViews — insertion order matches structure translator. */\n readonly all: readonly NodeView[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface NodeViewRecorderHandle {\n /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`\n * AND `executor.attachScopeRecorder()` (footprintjs routes by\n * method-shape detection). */\n recorder: MinimalNodeViewRecorder;\n /** Returns a defensive copy of the current index state. */\n getIndex(): NodeViewIndex;\n /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps on Flow/Scope event OR when\n * the structure translator's version bumps (since NodeView projects\n * from its data). */\n version(): number;\n /** Reset runtime state. Does NOT bump version or notify (consistent\n * with traceStructureRecorder + createTraceRuntimeOverlay). */\n reset(): void;\n}\n\nexport interface CreateNodeViewRecorderOptions {\n /** Recorder id (surfaces in error attribution). */\n id?: string;\n /** REQUIRED — the structure translator handle. NodeView projects\n * structural fields (`prevIds`, `nextIds`, `label`, etc.) from\n * this on every `getIndex()` call. */\n structure: TraceStructureRecorderHandle;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Strip `#executionIndex` from runtimeStageId to recover the base\n * stageId. **Use only for in-translator matching where both sides\n * use full-path-prefixed stageIds consistently** (invariant I3 — do\n * NOT use this to match commitLog stageIds across subflow boundaries). */\nfunction baseStageIdOf(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createNodeViewRecorder(\n options: CreateNodeViewRecorderOptions,\n): NodeViewRecorderHandle {\n const id = options.id ?? \"node-view\";\n const structure = options.structure;\n if (!structure) {\n throw new Error(\n \"[createNodeViewRecorder] `structure` option is required. \" +\n \"Pass the handle returned by `createTraceStructureRecorder()`.\",\n );\n }\n\n // Per-stage execution + commit-ref state. Keyed by base stageId.\n // Loops produce multiple entries with the same stageId / different\n // runtimeStageIds.\n let executionsOf: Map<StageId, ExecutionRecord[]> = new Map();\n let commitRefsOf: Map<StageId, RuntimeStageId[]> = new Map();\n // Reverse lookup: runtimeStageId → its base stageId. Lets\n // `byRuntimeStageId` map directly to a NodeView without\n // re-parsing.\n let stageIdOfRuntimeStageId: Map<RuntimeStageId, StageId> = new Map();\n\n const notifier = createNotifier(\"node-view\");\n\n // Subscribe to structure translator — when its graph changes\n // (e.g., new stage announced during incremental build), bump our\n // version so consumers re-derive the projection.\n const unsubStructure = structure.subscribe(() => notifier.notify());\n\n function recordExecution(event: FlowStageExecutedEvent): void {\n // L8.1 Panel 2 must-fix: guard against malformed event payloads\n // (asymmetric with recordError's existing guard). Upstream MAY\n // fire with traversalContext absent if the engine's runtime\n // observer chain is reorganised — fail soft, not hard.\n const rsid = event.traversalContext?.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onStageExecuted event without traversalContext.runtimeStageId — execution attribution dropped (stage=${event.stageName}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const runtimeStageId = asRuntimeStageId(rsid);\n const execList = executionsOf.get(stageId) ?? [];\n const record: ExecutionRecord = {\n runtimeStageId,\n ...(event.traversalContext.iteration !== undefined && {\n iteration: event.traversalContext.iteration,\n }),\n ...(event.startTime !== undefined && { startMs: event.startTime }),\n ...(event.endTime !== undefined && { endMs: event.endTime }),\n };\n execList.push(record);\n executionsOf.set(stageId, execList);\n stageIdOfRuntimeStageId.set(runtimeStageId, stageId);\n notifier.notify();\n }\n\n function recordError(event: FlowErrorEvent): void {\n const rsid = event.traversalContext?.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onError event without traversalContext.runtimeStageId — error attribution dropped (stage=${event.stageName}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const runtimeStageId = asRuntimeStageId(rsid);\n const execList = executionsOf.get(stageId);\n // L8.1 Panel 1 must-fix: match by runtimeStageId equality (NOT\n // array position). With interleaved-stage events under footprintjs's\n // FlowRecorder dispatcher, \"most-recent execution by array index\"\n // can attach an error to the wrong execution. Looking up by\n // runtimeStageId is the correct join key.\n const matchIdx = execList\n ? execList.findIndex((e) => e.runtimeStageId === runtimeStageId)\n : -1;\n if (!execList || matchIdx === -1) {\n // Error before onStageExecuted? Synthesize a minimal execution\n // record so consumers see the error.\n const synth: ExecutionRecord = {\n runtimeStageId,\n errorMessage: event.message ?? \"error\",\n };\n if (execList) {\n execList.push(synth);\n } else {\n executionsOf.set(stageId, [synth]);\n }\n } else {\n const match = execList[matchIdx]!;\n execList[matchIdx] = { ...match, errorMessage: event.message ?? \"error\" };\n }\n stageIdOfRuntimeStageId.set(runtimeStageId, stageId);\n notifier.notify();\n }\n\n function recordCommit(event: ScopeCommitEvent): void {\n // Read runtimeStageId directly from the onCommit payload\n // (panel L8.0 ordering invariant: Scope.onCommit fires BEFORE\n // Flow.onStageExecuted; don't rely on Flow event arriving first).\n const rsid = event.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onCommit event without runtimeStageId — commit attribution dropped (stage=${event.stage ?? event.stageId ?? \"?\"}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const refs = commitRefsOf.get(stageId) ?? [];\n refs.push(asRuntimeStageId(rsid));\n commitRefsOf.set(stageId, refs);\n stageIdOfRuntimeStageId.set(asRuntimeStageId(rsid), stageId);\n notifier.notify();\n }\n\n const recorder: MinimalNodeViewRecorder = {\n id,\n onStageExecuted: recordExecution,\n onError: recordError,\n onCommit: recordCommit,\n // onRunStart / onRunEnd — no-op for now (state stays alive across\n // runs; consumers call .reset() between runs if they want fresh\n // state). Listed for shape conformance with FlowRecorder.\n onRunStart() {\n /* no-op */\n },\n onRunEnd() {\n /* no-op */\n },\n };\n\n function buildView(structNode: TraceNode): NodeView {\n const stageId = asStageId(structNode.id);\n const execs = executionsOf.get(stageId) ?? [];\n const commitRefs = commitRefsOf.get(stageId) ?? [];\n\n // Derived visit-data fields\n const visitedInRun = execs.length > 0;\n const executionCount = execs.length;\n const firstExecutedAt = execs.length > 0 && execs[0]!.startMs !== undefined\n ? execs[0]!.startMs!\n : null;\n const lastExecutedAt = execs.length > 0 && execs[execs.length - 1]!.endMs !== undefined\n ? execs[execs.length - 1]!.endMs!\n : null;\n let totalDurationMs = 0;\n let errorCount = 0;\n for (const e of execs) {\n if (e.startMs !== undefined && e.endMs !== undefined) {\n totalDurationMs += e.endMs - e.startMs;\n }\n if (e.errorMessage) errorCount++;\n }\n\n const d = structNode.data;\n return {\n stageId,\n label: d.label,\n type: (structNode.type as NodeView[\"type\"]) ?? \"stage\",\n isDecider: d.isDecider,\n isFork: d.isFork,\n isSubflow: d.isSubflow,\n isStreaming: d.isStreaming,\n isPausable: d.isPausable === true,\n ...(d.description !== undefined && { description: d.description }),\n ...(d.icon !== undefined && { icon: d.icon }),\n ...(d.subflowId !== undefined && { subflowId: d.subflowId }),\n // L8.1 Panel 2 must-fix: branchIds is a live ref from the\n // structure translator's internal graph — defensive copy via\n // slice() prevents consumer mutation from corrupting it.\n ...(d.branchIds !== undefined && { branchIds: d.branchIds.slice() }),\n ...(d.defaultBranch !== undefined && { defaultBranch: d.defaultBranch }),\n // Note: structure translator always sets prevIds/nextIds (never\n // undefined). The slice() copies defend against consumer mutation.\n prevIds: d.prevIds.slice(),\n nextIds: d.nextIds.slice(),\n executions: execs.map((e) => ({ ...e })),\n visitedInRun,\n executionCount,\n firstExecutedAt,\n lastExecutedAt,\n totalDurationMs,\n errorCount,\n commitRuntimeStageIds: commitRefs.slice(),\n };\n }\n\n // L8.1 Panel 5 optimization: version-keyed cache. `getIndex()` is\n // called per React render that observes a version bump; with N\n // translators subscribed + StrictMode double-invoke, a single\n // stage event can produce 6+ full rebuilds. Cache the last index\n // keyed on `(ownVersion, structureVersion)` — return the cached\n // index when neither has changed since the previous build.\n let cachedIndex: NodeViewIndex | null = null;\n let cachedOwnVersion = -1;\n let cachedStructureVersion = -1;\n\n return {\n recorder,\n getIndex(): NodeViewIndex {\n const own = notifier.version();\n const struct = structure.version();\n if (\n cachedIndex !== null &&\n cachedOwnVersion === own &&\n cachedStructureVersion === struct\n ) {\n return cachedIndex;\n }\n // Read structure live — we project from its current graph each\n // call. Defensive-copy via getGraph() would over-allocate; we\n // use getGraphRef() and tolerate the read-only contract (we\n // don't mutate structure data).\n const graphRef = structure.getGraphRef();\n const byStageId = new Map<StageId, NodeView>();\n const byRuntimeStageId = new Map<RuntimeStageId, NodeView>();\n const all: NodeView[] = [];\n for (const structNode of graphRef.nodes) {\n const view = buildView(structNode);\n byStageId.set(view.stageId, view);\n all.push(view);\n // Reverse map: every execution's runtimeStageId → this view.\n for (const exec of view.executions) {\n byRuntimeStageId.set(exec.runtimeStageId, view);\n }\n // Commit refs also point back to this view (a stage's\n // runtimeStageId for its execution is the same key its\n // commit carries).\n for (const rsid of view.commitRuntimeStageIds) {\n byRuntimeStageId.set(rsid, view);\n }\n }\n cachedIndex = { byStageId, byRuntimeStageId, all };\n cachedOwnVersion = own;\n cachedStructureVersion = struct;\n return cachedIndex;\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n executionsOf = new Map();\n commitRefsOf = new Map();\n stageIdOfRuntimeStageId = new Map();\n // L8.1 — invalidate the version-keyed cache. We do NOT bump\n // version (matches the other translators' reset contract — see\n // traceStructureRecorder's `reset()` JSDoc for the consumer\n // recipe), but the cache MUST be cleared so the next\n // `getIndex()` rebuilds from the freshly-empty state instead\n // of returning a stale snapshot.\n cachedIndex = null;\n cachedOwnVersion = -1;\n cachedStructureVersion = -1;\n // We intentionally do NOT unsubscribe from structure here; the\n // handle is still alive across resets.\n void unsubStructure;\n },\n };\n}\n","/**\n * createCommitFlowRecorder — per-commit summary translator.\n *\n * Owns the canonical `CommitView[]` — captured from Scope `onCommit`\n * events as the chart runs. Each CommitView joins:\n *\n * - **Identity**: runtimeStageId, stageId, commitIdx\n * - **Structural**: prev/next stage ids (read from structure\n * translator's `TraceNode.data.prevIds`/`nextIds`)\n * - **Runtime prev/next**: derived via \"most-recent-per-structural-\n * prev\" rule over the commitLog (loop-safe, convergence-aware)\n * - **Data dependencies**: per-read-key lineage via\n * `findLastWriter` over the commitLog\n * - **Payload**: updates + reads\n *\n * Composition (panel guidance, L8.1 review)\n * ─────────────────────────────────────────\n * Per Panel 1 rule \"translators MUST subscribe to structure\n * directly, never to peer translators\", CommitFlow subscribes to\n * the structure handle (NOT to NodeView). Linear dependency tree\n * keeps notify cascades O(depth) instead of O(N²).\n *\n * NodeView (L8.1) stores `commitRuntimeStageIds[]` — refs only —\n * pointing into CommitFlow's `byRuntimeStageId`. The canonical\n * payload lives HERE; NodeView is the per-stage projection.\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const commitFlow = useMemo(\n * () => createCommitFlowRecorder({ structure: trace }),\n * [trace],\n * );\n * useEffect(() => {\n * executor.attachFlowRecorder(commitFlow.recorder);\n * executor.attachScopeRecorder(commitFlow.recorder);\n * }, [commitFlow]);\n *\n * const index = useTranslator(commitFlow, () => commitFlow.getIndex());\n * const c = index.byRuntimeStageId.get(asRuntimeStageId('finalize-order#3'));\n * c.structuralPrevIds // ['CheckInventory', 'RunFraudCheck']\n * c.runtimePrevIds // ['check-inventory#1', 'run-fraud-check#2']\n * c.dataDependencies // [{ key:'inStock', sourceRuntimeStageId:'check-inventory#1', sourceCommitIdx:1 }, ...]\n *\n * const lineage = backtraceDataFlow(index, asRuntimeStageId('finalize-order#3'));\n * // → ancestry chain of commits whose writes contributed to this commit's reads\n * ```\n */\n\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport { asStageId, asRuntimeStageId } from \"./_internal/keys\";\nimport type { StageId, RuntimeStageId } from \"./_internal/keys\";\nimport type { TraceStructureRecorderHandle } from \"./traceStructureRecorder\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local mirrors of footprintjs runtime recorder interfaces\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface FlowStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly traversalContext: TraversalContext;\n}\n\ninterface FlowErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface FlowRunLifecycleEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface ScopeReadEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly key?: string;\n}\n\ninterface ScopeCommitEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly updates?: Record<string, unknown>;\n readonly reads?: readonly string[];\n}\n\n/**\n * Minimal CombinedRecorder mirror — subset of footprintjs's Flow +\n * Scope channels CommitFlow consumes.\n */\nexport interface MinimalCommitFlowRecorder {\n readonly id: string;\n // Flow channel — for runtimeStageId enrichment + error attribution\n onStageExecuted?(event: FlowStageExecutedEvent): void;\n onError?(event: FlowErrorEvent): void;\n onRunStart?(event: FlowRunLifecycleEvent): void;\n onRunEnd?(event: FlowRunLifecycleEvent): void;\n // Scope channel — the canonical commit + read data source\n onRead?(event: ScopeReadEvent): void;\n onCommit?(event: ScopeCommitEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * One data-dependency edge — a read key in this commit AND the commit\n * whose `updates` last wrote that key before this commit's index.\n *\n * `sourceRuntimeStageId` and `sourceCommitIdx` are BOTH `null` when no\n * prior commit wrote the key (panel-flagged: NEVER `undefined` — forces\n * consumers to handle absence as load-bearing).\n */\nexport interface DataDependency {\n readonly key: string;\n readonly sourceRuntimeStageId: RuntimeStageId | null;\n readonly sourceCommitIdx: number | null;\n}\n\n/**\n * Per-commit summary. Joins structural data (from the structure\n * translator) with runtime data (commitLog timeline) into a single\n * consumer-friendly shape.\n *\n * Three \"prev\" views — pick the right one for your UI:\n * ─────────────────────────────────────────────────────\n * | Field | Answers |\n * |----------------------|--------------------------------------------|\n * | `structuralPrevIds` | \"what COULD flow in\" (chart shape) |\n * | `runtimePrevIds` | \"what DID flow in by stage\" (execution |\n * | | timeline; loop-aware) |\n * | `dataDependencies` | \"which commit wrote the bytes I read\" |\n * | | (causal data lineage; per-key) |\n *\n * The three answers usually align on simple charts (linear; single\n * fork-merge). They DIVERGE in interesting ways under loops (runtime\n * differs by iteration; data-deps may skip uninvolved stages) and\n * conditional branches (structural sees all options; runtime + data\n * see only the chosen path).\n */\nexport interface CommitView {\n // ── Identity ────────────────────────────────────────────────────\n readonly runtimeStageId: RuntimeStageId;\n readonly stageId: StageId;\n /** Position in the chronologically-ordered commitLog. */\n readonly commitIdx: number;\n\n // ── Structural (from structure translator) ──────────────────────\n /** Stage ids that lead into this stage in the chart (loop-excluded). */\n readonly structuralPrevIds: StageId[];\n readonly structuralNextIds: StageId[];\n\n // ── Runtime (derived: structural prev ∩ commitLog up-to-here) ──\n /**\n * For each structural prev stage that EXECUTED IN THIS RUN before\n * this commit, the most-recent runtimeStageId of that prev's commit.\n * Loop-safe: in iteration 2, runtime prev points at iteration 2's\n * commits (not iteration 1's).\n */\n readonly runtimePrevIds: RuntimeStageId[];\n /**\n * For each structural next stage that EXECUTED IN THIS RUN after\n * this commit, the soonest runtimeStageId. Symmetric to prev.\n */\n readonly runtimeNextIds: RuntimeStageId[];\n\n // ── Data flow (per-key lineage via findLastWriter) ──────────────\n /**\n * One entry per key in `reads`. `sourceRuntimeStageId` points at the\n * commit whose `updates` last set this key BEFORE this commit's\n * index; `null` when no prior writer (typically: read of a key\n * declared as default but never written by another stage).\n */\n readonly dataDependencies: DataDependency[];\n\n // ── Payload ─────────────────────────────────────────────────────\n /**\n * The commit's writes. **Shallow-copied** at intake — top-level\n * keys are owned, but nested object values are SHARED references\n * to whatever the upstream `onCommit` payload carried. Consumers\n * MUST NOT mutate nested values; doing so corrupts the recorder's\n * internal state and propagates through `findLastWriter` to every\n * subsequent `getIndex()` call.\n */\n readonly updates: Record<string, unknown>;\n readonly reads: string[];\n}\n\n/** Indexed CommitView access. */\nexport interface CommitFlowIndex {\n /** Ordered list — index === commitIdx. */\n readonly commits: readonly CommitView[];\n /** Lookup by runtimeStageId (the universal join key). */\n readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, CommitView>;\n /**\n * Data-dependency edges — `from` and `to` are commitIdx ints; `key`\n * is the data key that flowed from one commit to the other. Same\n * data as walking each CommitView's `dataDependencies` — exposed as\n * a flat edge list for graph algorithms and rendering.\n *\n * **When to use which**:\n * - `view.dataDependencies` — render ONE commit's inputs in a\n * detail panel (e.g., `<CommitInspector>`).\n * - `index.dataEdges` — draw the FULL data-flow DAG (React Flow\n * edges, GraphViz, dependency matrix, etc.). One pass over the\n * flat list = the whole graph.\n *\n * Edges are `Object.freeze()`d at construction — type `readonly` is\n * compile-time; freeze is the runtime enforcement.\n */\n readonly dataEdges: readonly { readonly from: number; readonly to: number; readonly key: string }[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CommitFlowRecorderHandle {\n /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`\n * AND `executor.attachScopeRecorder()`. */\n recorder: MinimalCommitFlowRecorder;\n /** Returns a defensive copy of the current index state. */\n getIndex(): CommitFlowIndex;\n /** Pub-sub: returns unsubscribe. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps on Scope/Flow event OR when\n * the structure translator's version bumps. */\n version(): number;\n /** Reset runtime state. Does NOT bump version or notify (consistent\n * with other translators' reset contracts). */\n reset(): void;\n}\n\nexport interface CreateCommitFlowRecorderOptions {\n /** Recorder id (surfaces in error attribution). */\n id?: string;\n /** REQUIRED — structure translator handle for structural prev/next\n * projection. CommitFlow subscribes to its version. */\n structure: TraceStructureRecorderHandle;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Strip `#executionIndex` from a runtimeStageId to recover the base\n * stageId. **Invariant I3**: matches commitLog stageIds when the\n * runtimeStageId already carries the full subflow path prefix the\n * engine emits. Do NOT manually re-parse subflow paths. */\nfunction baseStageIdOf(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createCommitFlowRecorder(\n options: CreateCommitFlowRecorderOptions,\n): CommitFlowRecorderHandle {\n const id = options.id ?? \"commit-flow\";\n const structure = options.structure;\n if (!structure) {\n throw new Error(\n \"[createCommitFlowRecorder] `structure` option is required. \" +\n \"Pass the handle returned by `createTraceStructureRecorder()`.\",\n );\n }\n\n // Internal raw commit storage — `RawCommit` is the un-projected\n // version (no structural/runtime joins yet). The full `CommitView`\n // gets computed on `getIndex()` (cached by version key).\n interface RawCommit {\n runtimeStageId: RuntimeStageId;\n stageId: StageId;\n commitIdx: number;\n updates: Record<string, unknown>;\n reads: string[];\n }\n let rawCommits: RawCommit[] = [];\n\n const notifier = createNotifier(\"commit-flow\");\n const unsubStructure = structure.subscribe(() => notifier.notify());\n\n function recordCommit(event: ScopeCommitEvent): void {\n // L8.0 ordering invariant — Scope.onCommit fires BEFORE Flow's\n // onStageExecuted. We read runtimeStageId directly from the\n // onCommit payload, NEVER waiting for a Flow event to enrich.\n const rsid = event.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createCommitFlowRecorder] onCommit without runtimeStageId — commit dropped (stage=${event.stage ?? event.stageId ?? \"?\"}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n rawCommits.push({\n runtimeStageId: asRuntimeStageId(rsid),\n stageId,\n commitIdx: rawCommits.length,\n updates: event.updates ? { ...event.updates } : {},\n reads: event.reads ? [...event.reads] : [],\n });\n notifier.notify();\n }\n\n // Flow channel handlers — no-ops for the canonical commit-data\n // capture (Scope.onCommit already carries runtimeStageId). Listed\n // so the recorder shape matches FlowRecorder and `attachTo()` can\n // attach via attachFlowRecorder for parity with other translators.\n // onError doesn't influence CommitView state today — errors belong\n // to NodeView's per-stage projection.\n const recorder: MinimalCommitFlowRecorder = {\n id,\n onCommit: recordCommit,\n onStageExecuted() {\n /* no-op — CommitFlow is commit-centric, not execution-centric */\n },\n onError() {\n /* no-op */\n },\n onRunStart() {\n /* no-op */\n },\n onRunEnd() {\n /* no-op */\n },\n };\n\n function buildIndex(): CommitFlowIndex {\n // Snapshot structure once — `getGraphRef()` returns live refs;\n // we only read from `node.data.prevIds`/`nextIds` (read-only).\n const graphRef = structure.getGraphRef();\n const nodeByStageId = new Map<string, (typeof graphRef.nodes)[number]>();\n for (const n of graphRef.nodes) nodeByStageId.set(n.id, n);\n\n // Precompute per-key writer index for findLastWriter (linear-time\n // build, O(1) lookup per read in the per-commit loop below).\n // Maps key → ordered list of {commitIdx, runtimeStageId} for\n // commits that wrote this key.\n interface KeyWriter {\n commitIdx: number;\n runtimeStageId: RuntimeStageId;\n }\n const writersOf = new Map<string, KeyWriter[]>();\n for (const rc of rawCommits) {\n for (const k of Object.keys(rc.updates)) {\n const list = writersOf.get(k) ?? [];\n list.push({ commitIdx: rc.commitIdx, runtimeStageId: rc.runtimeStageId });\n writersOf.set(k, list);\n }\n }\n\n // Precompute per-stage commit-index lists for runtimePrev/Next\n // derivation. Each stageId → ordered list of commitIdx where that\n // stage committed.\n const commitsOfStage = new Map<string, number[]>();\n for (const rc of rawCommits) {\n const list = commitsOfStage.get(rc.stageId) ?? [];\n list.push(rc.commitIdx);\n commitsOfStage.set(rc.stageId, list);\n }\n\n const commits: CommitView[] = [];\n const byRuntimeStageId = new Map<RuntimeStageId, CommitView>();\n const dataEdges: { from: number; to: number; key: string }[] = [];\n\n for (const rc of rawCommits) {\n const structNode = nodeByStageId.get(rc.stageId);\n const structuralPrevIds = (structNode?.data.prevIds ?? []).slice();\n const structuralNextIds = (structNode?.data.nextIds ?? []).slice();\n\n // runtimePrevIds — for each structural prev, the most-recent\n // commit with that stageId BEFORE rc.commitIdx.\n const runtimePrevIds: RuntimeStageId[] = [];\n for (const pStageId of structuralPrevIds) {\n const list = commitsOfStage.get(pStageId);\n if (!list) continue;\n // Walk backwards to find the highest commitIdx strictly less\n // than rc.commitIdx (invariant I2: strict `<`, not `<=`).\n let chosenIdx: number | null = null;\n for (let i = list.length - 1; i >= 0; i--) {\n if (list[i]! < rc.commitIdx) {\n chosenIdx = list[i]!;\n break;\n }\n }\n if (chosenIdx !== null) {\n runtimePrevIds.push(rawCommits[chosenIdx]!.runtimeStageId);\n }\n }\n\n // runtimeNextIds — for each structural next, the soonest commit\n // with that stageId AFTER rc.commitIdx.\n const runtimeNextIds: RuntimeStageId[] = [];\n for (const nStageId of structuralNextIds) {\n const list = commitsOfStage.get(nStageId);\n if (!list) continue;\n let chosenIdx: number | null = null;\n for (let i = 0; i < list.length; i++) {\n if (list[i]! > rc.commitIdx) {\n chosenIdx = list[i]!;\n break;\n }\n }\n if (chosenIdx !== null) {\n runtimeNextIds.push(rawCommits[chosenIdx]!.runtimeStageId);\n }\n }\n\n // Data dependencies — per-read-key findLastWriter.\n const dataDependencies: DataDependency[] = [];\n for (const key of rc.reads) {\n const writers = writersOf.get(key);\n let source: KeyWriter | null = null;\n if (writers) {\n for (let i = writers.length - 1; i >= 0; i--) {\n if (writers[i]!.commitIdx < rc.commitIdx) {\n source = writers[i]!;\n break;\n }\n }\n }\n if (source) {\n dataDependencies.push({\n key,\n sourceRuntimeStageId: source.runtimeStageId,\n sourceCommitIdx: source.commitIdx,\n });\n // L8.2 Panel 2 must-fix: freeze each edge so consumers can't\n // mutate the exposed objects. `readonly` is type-only; this\n // is the runtime enforcement.\n dataEdges.push(\n Object.freeze({ from: source.commitIdx, to: rc.commitIdx, key }),\n );\n } else {\n // Panel must-fix: use `null` (not `undefined`) for missing\n // source — forces consumers to handle absence load-bearingly.\n dataDependencies.push({\n key,\n sourceRuntimeStageId: null,\n sourceCommitIdx: null,\n });\n }\n }\n\n const view: CommitView = {\n runtimeStageId: rc.runtimeStageId,\n stageId: rc.stageId,\n commitIdx: rc.commitIdx,\n structuralPrevIds,\n structuralNextIds,\n runtimePrevIds,\n runtimeNextIds,\n dataDependencies,\n updates: { ...rc.updates },\n reads: rc.reads.slice(),\n };\n commits.push(view);\n byRuntimeStageId.set(view.runtimeStageId, view);\n }\n\n return { commits, byRuntimeStageId, dataEdges };\n }\n\n // L8.1 Panel 5 optimization: version-keyed cache. Same pattern as\n // NodeView — rebuild on (ownVersion, structureVersion) change.\n let cachedIndex: CommitFlowIndex | null = null;\n let cachedOwnVersion = -1;\n let cachedStructureVersion = -1;\n\n return {\n recorder,\n getIndex(): CommitFlowIndex {\n const own = notifier.version();\n const struct = structure.version();\n if (\n cachedIndex !== null &&\n cachedOwnVersion === own &&\n cachedStructureVersion === struct\n ) {\n return cachedIndex;\n }\n cachedIndex = buildIndex();\n cachedOwnVersion = own;\n cachedStructureVersion = struct;\n return cachedIndex;\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n rawCommits = [];\n // Cache invalidation — version doesn't bump (panel reset contract),\n // but next getIndex() must rebuild from the freshly-empty state.\n cachedIndex = null;\n cachedOwnVersion = -1;\n cachedStructureVersion = -1;\n // Subscription to structure is INTENTIONALLY kept across resets\n // (matches NodeView's reset contract). The handle is alive for\n // the recorder's full lifetime; consumer that wants full\n // disposal should drop the handle reference + let GC reclaim.\n // Referenced here purely to keep the closure alive for the\n // unsub's lexical scope.\n void unsubStructure;\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Data-flow backtrace helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Walk data-dependency edges BACKWARD from a starting commit. Returns\n * the lineage chain — every ancestor commit whose writes transitively\n * contributed to the starting commit's reads.\n *\n * BFS order, commitIdx-ascending (oldest first). Includes the starting\n * commit at the END of the returned array.\n *\n * Cycle defense: visited set + recursion cap at `index.commits.length`\n * (per L8 panel must-fix — defends against future malformed graphs).\n *\n * @example\n * ```ts\n * const lineage = backtraceDataFlow(commitIndex, asRuntimeStageId('finalize-order#3'));\n * // → [load-order#0, check-inventory#1, run-fraud-check#2, finalize-order#3]\n * // (the commits whose updates fed FinalizeOrder's reads)\n * ```\n */\nexport function backtraceDataFlow(\n index: CommitFlowIndex,\n startRuntimeStageId: RuntimeStageId,\n): CommitView[] {\n const start = index.byRuntimeStageId.get(startRuntimeStageId);\n if (!start) return [];\n // L8.2 Panel 1 must-fix: dropped the `hops < cap` counter. The\n // visited-set IS the real cycle defense — it guarantees each\n // commitIdx is dequeued AT MOST ONCE, so the loop body executes\n // ≤ `index.commits.length` times by construction. The old `hops`\n // counter could short-circuit BEFORE the visited-set saturated in\n // dense-data graphs (every commit reads from every prior), dropping\n // legitimate work. Visited-set + head-index queue is sufficient and\n // correct.\n const visitedIdx = new Set<number>([start.commitIdx]);\n const queue: number[] = [start.commitIdx];\n const collectedIdxs = new Set<number>([start.commitIdx]);\n let head = 0;\n while (head < queue.length) {\n const cur = index.commits[queue[head++]!];\n if (!cur) continue;\n for (const dep of cur.dataDependencies) {\n if (dep.sourceCommitIdx === null) continue;\n if (visitedIdx.has(dep.sourceCommitIdx)) continue;\n visitedIdx.add(dep.sourceCommitIdx);\n collectedIdxs.add(dep.sourceCommitIdx);\n queue.push(dep.sourceCommitIdx);\n }\n }\n // Return commits ordered by commitIdx ascending (chronological).\n return Array.from(collectedIdxs)\n .sort((a, b) => a - b)\n .map((idx) => index.commits[idx]!)\n .filter((c): c is CommitView => c !== undefined);\n}\n","/**\n * `createTraceBundle` — one factory wires every shipped translator\n * + provides a single `attachTo(executor)` call that registers all\n * runtime recorders.\n *\n * Bundle shape (as of L8.2)\n * ─────────────────────────\n * - `structure` — build-time `TraceGraph` (StructureRecorder).\n * - `runtimeOverlay` — execution overlay for time-travel (FlowRecorder).\n * - `nodeView` — per-stage summary index, CombinedRecorder\n * (FlowRecorder + ScopeRecorder).\n * - `commitFlow` — per-commit summary + data-lineage,\n * CombinedRecorder (ScopeRecorder + FlowRecorder).\n *\n * Goal: collapse the 5-line \"create + attach + subscribe\" boilerplate\n * into one call for the common case. Consumers that want à-la-carte\n * setup can still construct each translator directly (the underlying\n * factories are unchanged).\n *\n * Independence: each translator subscribes ONLY to `structure` (per\n * L8.1 Panel 1 rule — translators must never subscribe to peers).\n * Linear dependency tree keeps notify cascades O(depth), not O(N²).\n *\n * @example\n * ```tsx\n * import { createTraceBundle } from 'footprint-explainable-ui/flowchart';\n *\n * function MyTraceUI() {\n * const bundle = useMemo(() => createTraceBundle(), []);\n * useEffect(() => {\n * const chart = flowChart('seed', fn, 'seed', {\n * structureRecorders: [bundle.structure.recorder],\n * }).addFunction('a', fnA, 'a').build();\n * const executor = new FlowChartExecutor(chart);\n * bundle.attachTo(executor);\n * executor.run({ input });\n * }, [bundle]);\n *\n * return <TracedFlow recorder={bundle.structure} overlay={bundle.runtimeOverlay} />;\n * }\n * ```\n *\n * **Recorder-attach lifecycle**: `attachTo(executor)` attaches THREE\n * FlowRecorders (`runtimeOverlay`, `nodeView`, `commitFlow`) and TWO\n * ScopeRecorders (`nodeView`, `commitFlow`). Each translator has a\n * distinct `recorder.id`, so footprintjs's id-idempotency rule\n * doesn't collide. The build-time `structure.recorder` is NOT\n * auto-attached — it must be passed to `flowChart(..., {\n * structureRecorders: [...] })` because builder recorders register\n * BEFORE `executor` exists. Consumers wire that one explicitly (see\n * example above). This matches footprintjs's two-phase recorder\n * model (build vs runtime).\n */\n\nimport { devWarn } from \"./_internal/devWarn\";\nimport {\n createTraceStructureRecorder,\n type TraceStructureRecorderHandle,\n type CreateTraceStructureRecorderOptions,\n} from \"./traceStructureRecorder\";\nimport {\n createTraceRuntimeOverlay,\n type TraceRuntimeOverlayHandle,\n type CreateTraceRuntimeOverlayOptions,\n} from \"./createTraceRuntimeOverlay\";\nimport {\n createNodeViewRecorder,\n type NodeViewRecorderHandle,\n type CreateNodeViewRecorderOptions,\n} from \"./createNodeViewRecorder\";\nimport {\n createCommitFlowRecorder,\n type CommitFlowRecorderHandle,\n type CreateCommitFlowRecorderOptions,\n} from \"./createCommitFlowRecorder\";\n\n/** Minimal executor surface — mirrors the bits of footprintjs's\n * `FlowChartExecutor` the bundle calls into. Local to keep\n * explainable-ui dep-free from footprintjs. */\ninterface MinimalExecutor {\n attachFlowRecorder(recorder: unknown): void;\n attachScopeRecorder?(recorder: unknown): void;\n}\n\nexport interface TraceBundle {\n structure: TraceStructureRecorderHandle;\n runtimeOverlay: TraceRuntimeOverlayHandle;\n /** L8.1 — per-stage summary translator. Reads `prevIds`/`nextIds`\n * from `structure` (no duplication), accumulates `executions[]`\n * + commit refs from Flow + Scope events. */\n nodeView: NodeViewRecorderHandle;\n /** L8.2 — per-commit summary translator. Owns canonical CommitView[].\n * Derives structural prev/next from `structure`, runtimePrev/Next\n * from \"most-recent-per-prev\" over commitLog, and dataDependencies\n * via findLastWriter per read key. */\n commitFlow: CommitFlowRecorderHandle;\n /**\n * Attach RUNTIME recorders (FlowRecorder, ScopeRecorder) to a\n * footprintjs executor. The build-time `structure.recorder` is NOT\n * covered — pass it to `flowChart(..., { structureRecorders: [...] })`\n * at construction time instead (see file header example).\n */\n attachTo(executor: MinimalExecutor): void;\n}\n\nexport interface CreateTraceBundleOptions {\n /** Per-translator options. All optional. */\n structure?: CreateTraceStructureRecorderOptions;\n runtimeOverlay?: CreateTraceRuntimeOverlayOptions;\n nodeView?: Omit<CreateNodeViewRecorderOptions, \"structure\">;\n commitFlow?: Omit<CreateCommitFlowRecorderOptions, \"structure\">;\n}\n\nexport function createTraceBundle(\n options: CreateTraceBundleOptions = {},\n): TraceBundle {\n const structure = createTraceStructureRecorder(options.structure);\n const runtimeOverlay = createTraceRuntimeOverlay(options.runtimeOverlay);\n // NodeView needs the structure handle — wired internally so the\n // consumer doesn't have to pass it. The bundle is the consumer-\n // ergonomics layer; à-la-carte consumers can construct\n // createNodeViewRecorder directly with their own structure handle.\n const nodeView = createNodeViewRecorder({\n ...(options.nodeView ?? {}),\n structure,\n });\n const commitFlow = createCommitFlowRecorder({\n ...(options.commitFlow ?? {}),\n structure,\n });\n\n return {\n structure,\n runtimeOverlay,\n nodeView,\n commitFlow,\n attachTo(executor: MinimalExecutor): void {\n // All three runtime translators attach as FlowRecorders (each\n // has its own distinct `recorder.id`, so the dispatcher's\n // id-idempotency rule doesn't collide). NodeView + CommitFlow\n // ALSO implement ScopeRecorder (onCommit) — attached via\n // attachScopeRecorder when the executor exposes it.\n //\n // Footprintjs v6.0+ exposes both methods; older executors\n // gracefully degrade (commit-side data drops with a dev-warn).\n executor.attachFlowRecorder(runtimeOverlay.recorder);\n executor.attachFlowRecorder(nodeView.recorder);\n executor.attachFlowRecorder(commitFlow.recorder);\n if (typeof executor.attachScopeRecorder === \"function\") {\n executor.attachScopeRecorder(nodeView.recorder);\n executor.attachScopeRecorder(commitFlow.recorder);\n } else {\n // Old/partial executor without ScopeRecorder support. NodeView\n // + CommitFlow will silently miss commit events — surface this\n // to consumers debugging \"why are commitRuntimeStageIds empty?\".\n devWarn(\n () =>\n \"[createTraceBundle] executor.attachScopeRecorder is missing — NodeView.commitRuntimeStageIds[] AND CommitFlow.commits[] will be empty. Upgrade to footprintjs v6.0+.\",\n );\n }\n },\n };\n}\n","/**\n * `useTranslator(handle, getSnapshot)` — React adapter for any translator\n * exposing the standard `subscribe()` + `version()` shape.\n *\n * Wraps `useSyncExternalStore` so consumers don't repeat the boilerplate\n * for every translator. The `version` is the snapshot identity — when it\n * changes, React re-renders; `getSnapshot` then returns the consumer-\n * chosen view (full graph, slice, etc.).\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const graph = useTranslator(trace, () => trace.getGraph());\n * return <TraceFlow graph={graph} />;\n * ```\n *\n * **Why a hook (vs each component wiring `useSyncExternalStore` itself)**:\n * three reasons. (1) Reduces 4 lines of `useSyncExternalStore + useMemo`\n * boilerplate to one line. (2) Standardises the snapshot-identity\n * convention (version int) — consumers can't accidentally pass a getter\n * whose return identity changes every call (which would re-render\n * forever). (3) Stable subscribe/getVersion refs via memoization on the\n * handle identity — no re-subscribe on parent re-renders.\n */\n\nimport { useMemo, useSyncExternalStore } from \"react\";\n\nexport interface TranslatorHandleLike {\n subscribe(listener: () => void): () => void;\n version(): number;\n}\n\n/**\n * Subscribe to a translator + return a typed snapshot computed by the\n * caller. The snapshot recomputes whenever `version()` changes.\n *\n * `getSnapshot` is called inside a `useMemo` keyed on the version\n * integer — so consumers can return fresh objects from `getSnapshot`\n * (e.g., `handle.getGraph()` returns a defensive copy) without\n * triggering infinite re-renders.\n */\nexport function useTranslator<T>(\n handle: TranslatorHandleLike,\n getSnapshot: () => T,\n): T {\n const subscribe = useMemo(() => handle.subscribe.bind(handle), [handle]);\n const getVersion = useMemo(() => handle.version.bind(handle), [handle]);\n const version = useSyncExternalStore(subscribe, getVersion, getVersion);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => getSnapshot(), [version, getSnapshot]);\n}\n","/**\n * Graph traversal helpers — pure functions over a `NodeViewIndex`.\n *\n * Bi-directional structural walks (`walkForward` / `walkBackward`) plus\n * convenience wrappers (`backtraceStructural` / `forwardtraceStructural`).\n *\n * Cycle defense (panel L8 must-fix)\n * ──────────────────────────────────\n * Every traversal carries a `visited: Set<StageId>` and caps recursion\n * at `index.all.length` (the total node count). Defends against:\n * - Future bugs where a malformed graph includes a non-loop cycle\n * - Manual edge injection bypassing the structure-recorder fix\n * - Duplicate edges that survive dedupe due to source/target\n * collisions\n * Loop back-edges (`data.kind === 'loop'`) already excluded at the\n * structure-recorder layer (invariant I1), so they never enter\n * `prevIds`/`nextIds` — no extra filtering here.\n *\n * BFS order\n * ─────────\n * Walks return nodes in BFS order — root first, then immediate\n * neighbors, then their neighbors. Matches breadcrumb-friendly\n * \"closest-first\" display order.\n *\n * Always-arrays returns\n * ─────────────────────\n * All helpers return `NodeView[]`. Empty array (NOT null/undefined)\n * means \"no path\" or \"node not found\". Consumers `.map()` /\n * `.length`-check without null-handling boilerplate.\n */\n\nimport type { NodeView, NodeViewIndex } from \"./createNodeViewRecorder\";\nimport type { StageId } from \"./_internal/keys\";\n\nexport interface WalkOptions {\n /** Hard cap on hops. Default: `index.all.length` (one full traversal). */\n maxDepth?: number;\n /** When true, only return nodes that have `visitedInRun === true`.\n * Useful for \"in THIS run, what fed me?\" queries (runtime-aware walk). */\n onlyVisited?: boolean;\n /** When true, INCLUDE the start node in the returned array. Default:\n * false (caller already has the start node; the walk returns its\n * ancestors/descendants). */\n includeStart?: boolean;\n}\n\n/**\n * Walk forward (`nextIds`) from `startId`. BFS order. Cycle-safe.\n * Returns `[]` if `startId` is unknown.\n *\n * Convergence semantics: a node reachable via multiple paths appears\n * ONCE in the result (visited-set dedupes).\n */\nexport function walkForward(\n index: NodeViewIndex,\n startId: StageId,\n options: WalkOptions = {},\n): NodeView[] {\n return bfsWalk(index, startId, (n) => n.nextIds, options);\n}\n\n/**\n * Walk backward (`prevIds`) from `startId`. BFS order. Cycle-safe.\n * Returns `[]` if `startId` is unknown.\n *\n * Convergence semantics: a fork-join's `walkBackward` returns BOTH\n * branch parents (and their ancestors), each once.\n */\nexport function walkBackward(\n index: NodeViewIndex,\n startId: StageId,\n options: WalkOptions = {},\n): NodeView[] {\n return bfsWalk(index, startId, (n) => n.prevIds, options);\n}\n\n/**\n * Backtrace from `stageId` to a structural root (no prev) OR a split\n * point (multiple prevs). Returns the chain from `stageId` BACK to\n * the root, root-first. Includes `stageId` at the END.\n *\n * Defines \"split\" as `prevIds.length > 1 OR prevIds.length === 0`\n * (per L8 panel recommendation) — stops at convergence points AND at\n * the seed. Useful for breadcrumb display where \"innermost serial\n * run\" is the meaningful path.\n */\nexport function backtraceStructural(\n index: NodeViewIndex,\n stageId: StageId,\n options: Pick<WalkOptions, \"maxDepth\" | \"onlyVisited\"> = {},\n): NodeView[] {\n const start = index.byStageId.get(stageId);\n if (!start) return [];\n const chain: NodeView[] = [start];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>([stageId]);\n let cur: NodeView | undefined = start;\n let hops = 0;\n while (cur && hops < cap) {\n if (cur.prevIds.length === 0 || cur.prevIds.length > 1) {\n // Reached seed (no prevs) or split (multi-prev convergence).\n break;\n }\n const nextId = cur.prevIds[0]!;\n if (visited.has(nextId)) break; // cycle guard\n visited.add(nextId);\n const next: NodeView | undefined = index.byStageId.get(nextId);\n if (!next) break;\n if (options.onlyVisited && !next.visitedInRun) break;\n chain.unshift(next);\n cur = next;\n hops++;\n }\n return chain;\n}\n\n/**\n * Forward-trace from `stageId` to a structural leaf (no next) OR a\n * fork point (multiple nexts). Returns the chain from `stageId`\n * FORWARD to the leaf/fork, with `stageId` at the START.\n */\nexport function forwardtraceStructural(\n index: NodeViewIndex,\n stageId: StageId,\n options: Pick<WalkOptions, \"maxDepth\" | \"onlyVisited\"> = {},\n): NodeView[] {\n const start = index.byStageId.get(stageId);\n if (!start) return [];\n const chain: NodeView[] = [start];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>([stageId]);\n let cur: NodeView | undefined = start;\n let hops = 0;\n while (cur && hops < cap) {\n if (cur.nextIds.length === 0 || cur.nextIds.length > 1) break;\n const nextId = cur.nextIds[0]!;\n if (visited.has(nextId)) break;\n visited.add(nextId);\n const next: NodeView | undefined = index.byStageId.get(nextId);\n if (!next) break;\n if (options.onlyVisited && !next.visitedInRun) break;\n chain.push(next);\n cur = next;\n hops++;\n }\n return chain;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction bfsWalk(\n index: NodeViewIndex,\n startId: StageId,\n neighborsOf: (n: NodeView) => StageId[],\n options: WalkOptions,\n): NodeView[] {\n const start = index.byStageId.get(startId);\n if (!start) return [];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>();\n visited.add(startId);\n const out: NodeView[] = [];\n if (options.includeStart) out.push(start);\n // Queue holds [node, depthFromStart]. depthFromStart = 0 for the\n // start node; neighbors are depth 1; etc. We bail when depth > cap.\n //\n // L8.1 Panel 5 optimization: use a head-index pointer instead of\n // `queue.shift()`. shift() is O(n) (re-indexes the array on every\n // pop) → BFS over 50+ nodes degrades to O(n²). The head-index\n // pattern is O(1) per pop, O(n) total — standard interview answer.\n const queue: Array<[NodeView, number]> = [[start, 0]];\n let head = 0;\n while (head < queue.length) {\n const [node, depth] = queue[head++]!;\n if (depth >= cap) continue;\n for (const neighborId of neighborsOf(node)) {\n if (visited.has(neighborId)) continue;\n visited.add(neighborId);\n const neighbor = index.byStageId.get(neighborId);\n if (!neighbor) continue;\n if (options.onlyVisited && !neighbor.visitedInRun) continue;\n out.push(neighbor);\n queue.push([neighbor, depth + 1]);\n }\n }\n return out;\n}\n","/**\n * NodeInspector — debug/teaching panel for a single stage's\n * per-node summary from a `NodeViewIndex`.\n *\n * Demonstrates the canonical L8.1 consumer pattern:\n * 1. Read the `NodeView` for `selectedId` from the index\n * 2. Use `backtraceStructural` / `forwardtraceStructural` for the\n * prev/next chains\n * 3. Render: identity, structural neighbors (clickable to navigate),\n * visit data (count + duration + error state), commit refs.\n *\n * Composable: this is a small demo renderer. Real consumers wire\n * their own layout — the data shape is the contract.\n */\n\nimport { useMemo } from \"react\";\nimport type { NodeViewIndex, NodeView } from \"./createNodeViewRecorder\";\nimport type { StageId } from \"./_internal/keys\";\nimport { backtraceStructural, forwardtraceStructural } from \"./walkHelpers\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface NodeInspectorProps extends BaseComponentProps {\n /** The NodeView index (from `nodeView.getIndex()` or `useTranslator`).\n *\n * **Pure data prop** (NOT the recorder handle) — by design. Lets\n * consumers wrap in `useTranslator(nodeView, () => nodeView.getIndex())`\n * at the parent, or pass a static index from tests / Storybook /\n * SSR. Mirrors `<CommitInspector index={...}>` for consistency. */\n index: NodeViewIndex;\n /** Which stage to inspect. When `null`, renders the placeholder. */\n selectedId: StageId | null;\n /** Click handler — receives a stageId for breadcrumb navigation. */\n onNavigate?: (stageId: StageId) => void;\n /** When true, the prev/next chains include only `visitedInRun` nodes\n * (runtime-filtered view). */\n onlyVisited?: boolean;\n}\n\nexport function NodeInspector({\n index,\n selectedId,\n onNavigate,\n onlyVisited = false,\n className,\n style,\n}: NodeInspectorProps) {\n const view = selectedId ? index.byStageId.get(selectedId) ?? null : null;\n\n // Backtrace (root-first chain ending at this stage) — recomputes\n // when index version OR selectedId OR onlyVisited changes.\n const prevChain = useMemo(\n () => (view ? backtraceStructural(index, view.stageId, { onlyVisited }) : []),\n [index, view, onlyVisited],\n );\n // Forward-trace (this stage → leaf or fork).\n const nextChain = useMemo(\n () => (view ? forwardtraceStructural(index, view.stageId, { onlyVisited }) : []),\n [index, view, onlyVisited],\n );\n\n if (!view) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n Select a stage to inspect.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 14,\n color: theme.textPrimary,\n fontSize: 13,\n overflow: \"auto\",\n ...style,\n }}\n >\n {/* ── Identity ──────────────────────────────────────────── */}\n <div style={{ marginBottom: 16 }}>\n <div style={{ fontSize: 16, fontWeight: 700, color: theme.textPrimary }}>\n {view.label}\n </div>\n <div style={{ fontSize: 11, fontFamily: \"monospace\", color: theme.textMuted, marginTop: 2 }}>\n {view.stageId} · {view.type}\n {view.isDecider && \" · decider\"}\n {view.isFork && \" · fork\"}\n {view.isSubflow && \" · subflow\"}\n {view.isStreaming && \" · streaming\"}\n {view.isPausable && \" · pausable\"}\n </div>\n {view.description && (\n <div style={{ fontSize: 12, color: theme.textSecondary, marginTop: 6 }}>\n {view.description}\n </div>\n )}\n </div>\n\n {/* ── Visit data ────────────────────────────────────────── */}\n <Section title=\"Runtime\">\n <Row label=\"Visited\" value={view.visitedInRun ? \"yes\" : \"no\"} />\n {view.visitedInRun && (\n <>\n <Row label=\"Executions\" value={String(view.executionCount)} />\n {view.firstExecutedAt !== null && (\n <Row label=\"First at\" value={`${view.firstExecutedAt.toFixed(1)}ms`} />\n )}\n {view.lastExecutedAt !== null && (\n <Row label=\"Last at\" value={`${view.lastExecutedAt.toFixed(1)}ms`} />\n )}\n {view.totalDurationMs > 0 && (\n <Row label=\"Total\" value={`${view.totalDurationMs.toFixed(1)}ms`} />\n )}\n {view.errorCount > 0 && (\n <Row label=\"Errors\" value={String(view.errorCount)} valueColor={theme.error} />\n )}\n </>\n )}\n </Section>\n\n {/* ── Structural prev chain (clickable breadcrumb) ──────── */}\n {prevChain.length > 1 && (\n <Section title={`Prev chain (${prevChain.length - 1} hops)`}>\n <Crumbs nodes={prevChain.slice(0, -1)} onClick={onNavigate} />\n </Section>\n )}\n {view.prevIds.length > 1 && (\n <Section title=\"Multiple prev (convergence)\">\n <Crumbs\n nodes={view.prevIds\n .map((id) => index.byStageId.get(id))\n .filter((n): n is NodeView => n !== undefined)}\n onClick={onNavigate}\n />\n </Section>\n )}\n\n {/* ── Structural next chain ─────────────────────────────── */}\n {nextChain.length > 1 && (\n <Section title={`Next chain (${nextChain.length - 1} hops)`}>\n <Crumbs nodes={nextChain.slice(1)} onClick={onNavigate} />\n </Section>\n )}\n {view.nextIds.length > 1 && (\n <Section title=\"Multiple next (fork/decider)\">\n <Crumbs\n nodes={view.nextIds\n .map((id) => index.byStageId.get(id))\n .filter((n): n is NodeView => n !== undefined)}\n onClick={onNavigate}\n />\n </Section>\n )}\n\n {/* ── Commit refs (join key into CommitFlowIndex from L8.2) ── */}\n {view.commitRuntimeStageIds.length > 0 && (\n <Section title={`Commits (${view.commitRuntimeStageIds.length})`}>\n <div style={{ fontFamily: \"monospace\", fontSize: 11, color: theme.textSecondary }}>\n {view.commitRuntimeStageIds.map((rsid) => (\n <div key={rsid}>{rsid}</div>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n\n// ── Sub-components ─────────────────────────────────────────────────\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div style={{ marginBottom: 14 }}>\n <div\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n marginBottom: 6,\n }}\n >\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nfunction Row({ label, value, valueColor }: { label: string; value: string; valueColor?: string }) {\n return (\n <div style={{ display: \"flex\", justifyContent: \"space-between\", fontSize: 12, padding: \"2px 0\" }}>\n <span style={{ color: theme.textMuted }}>{label}</span>\n <span style={{ color: valueColor ?? theme.textSecondary, fontFamily: \"monospace\" }}>{value}</span>\n </div>\n );\n}\n\nfunction Crumbs({ nodes, onClick }: { nodes: NodeView[]; onClick?: (id: StageId) => void }) {\n if (nodes.length === 0) return null;\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {nodes.map((n, i) => (\n <span key={n.stageId} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n <button\n onClick={onClick ? () => onClick(n.stageId) : undefined}\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"3px 8px\",\n borderRadius: 4,\n border: `1px solid ${theme.border}`,\n background: \"transparent\",\n color: n.visitedInRun ? theme.success : theme.textSecondary,\n cursor: onClick ? \"pointer\" : \"default\",\n }}\n >\n {n.label}\n </button>\n {i < nodes.length - 1 && <span style={{ color: theme.textMuted, fontSize: 10 }}>›</span>}\n </span>\n ))}\n </div>\n );\n}\n","/**\n * CommitInspector — demo renderer for a single CommitView from a\n * `CommitFlowIndex`. Mirrors `<NodeInspector>` but commit-centric:\n *\n * - Identity: runtimeStageId + stageId + commitIdx\n * - Structural: prev/next stage ids (the chart-shape neighbors)\n * - Runtime: runtimePrev/Next commit refs (the actual prev/next\n * executions in this run — useful for time-travel breadcrumbs)\n * - Data lineage: `dataDependencies[]` per read key + a one-click\n * `backtraceDataFlow` walk showing the full ancestry chain\n * - Payload: updates + reads\n */\n\nimport { useMemo } from \"react\";\nimport type {\n CommitFlowIndex,\n CommitView,\n} from \"./createCommitFlowRecorder\";\nimport { backtraceDataFlow } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface CommitInspectorProps extends BaseComponentProps {\n /** The CommitFlow index (from `commitFlow.getIndex()` or `useTranslator`).\n *\n * **Pure data prop** (NOT the recorder handle) — by design. Lets\n * consumers wrap in `useTranslator(commitFlow, () => commitFlow.getIndex())`\n * at the parent, or pass a static index from tests / Storybook /\n * SSR. Mirrors `<NodeInspector index={...}>` for consistency. */\n index: CommitFlowIndex;\n /** Which commit to inspect (by runtimeStageId). null → placeholder. */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Click handler — receives a runtimeStageId for time-travel\n * navigation. Used by all clickable references (runtime prev/next,\n * data-dep sources, lineage chain). */\n onNavigate?: (runtimeStageId: RuntimeStageId) => void;\n}\n\nexport function CommitInspector({\n index,\n selectedRuntimeStageId,\n onNavigate,\n className,\n style,\n}: CommitInspectorProps) {\n const view = selectedRuntimeStageId\n ? index.byRuntimeStageId.get(selectedRuntimeStageId) ?? null\n : null;\n\n // Backtrace ancestry chain — recomputes when index version OR\n // selectedRuntimeStageId changes.\n const lineage = useMemo(\n () =>\n view ? backtraceDataFlow(index, view.runtimeStageId) : [],\n [index, view],\n );\n\n if (!view) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n Select a commit to inspect.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 14,\n color: theme.textPrimary,\n fontSize: 13,\n overflow: \"auto\",\n ...style,\n }}\n >\n {/* ── Identity ──────────────────────────────────────────── */}\n <div style={{ marginBottom: 16 }}>\n <div style={{ fontSize: 16, fontWeight: 700, color: theme.textPrimary }}>\n {view.stageId}\n </div>\n <div\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n color: theme.textMuted,\n marginTop: 2,\n }}\n >\n {view.runtimeStageId} · commitIdx {view.commitIdx}\n </div>\n </div>\n\n {/* ── Structural neighbors ──────────────────────────────── */}\n {view.structuralPrevIds.length > 0 && (\n <Section title=\"Structural prev (chart shape)\">\n <PlainTags labels={view.structuralPrevIds} />\n </Section>\n )}\n {view.structuralNextIds.length > 0 && (\n <Section title=\"Structural next (chart shape)\">\n <PlainTags labels={view.structuralNextIds} />\n </Section>\n )}\n\n {/* ── Runtime neighbors (clickable for time-travel) ─────── */}\n {view.runtimePrevIds.length > 0 && (\n <Section title=\"Runtime prev (this execution)\">\n <RuntimeRefs refs={view.runtimePrevIds} onClick={onNavigate} />\n </Section>\n )}\n {view.runtimeNextIds.length > 0 && (\n <Section title=\"Runtime next (this execution)\">\n <RuntimeRefs refs={view.runtimeNextIds} onClick={onNavigate} />\n </Section>\n )}\n\n {/* ── Payload ───────────────────────────────────────────── */}\n {Object.keys(view.updates).length > 0 && (\n <Section title={`Updates (${Object.keys(view.updates).length})`}>\n <KeyValueGrid entries={Object.entries(view.updates)} />\n </Section>\n )}\n {view.reads.length > 0 && (\n <Section title={`Reads (${view.reads.length})`}>\n <PlainTags labels={view.reads} />\n </Section>\n )}\n\n {/* ── Data dependencies (per-key lineage) ───────────────── */}\n {view.dataDependencies.length > 0 && (\n <Section title={`Data dependencies (${view.dataDependencies.length})`}>\n <table style={{ fontSize: 11, fontFamily: \"monospace\", width: \"100%\", borderCollapse: \"collapse\" }}>\n <tbody>\n {view.dataDependencies.map((dep) => (\n <tr key={dep.key}>\n <td style={{ color: theme.textSecondary, padding: \"2px 8px 2px 0\" }}>\n {dep.key}\n </td>\n <td style={{ color: dep.sourceRuntimeStageId ? theme.textPrimary : theme.textMuted }}>\n {dep.sourceRuntimeStageId ? (\n <button\n onClick={onNavigate ? () => onNavigate(dep.sourceRuntimeStageId!) : undefined}\n style={crumbButtonStyle(onNavigate !== undefined)}\n >\n ← {dep.sourceRuntimeStageId}\n </button>\n ) : (\n <em>(no prior writer — default or external)</em>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </Section>\n )}\n\n {/* ── Lineage chain (full data-flow backtrace) ──────────── */}\n {lineage.length > 1 && (\n <Section title={`Lineage chain (${lineage.length - 1} ancestor commits)`}>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {lineage.slice(0, -1).map((c, i) => (\n <span key={c.runtimeStageId} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n <button\n onClick={onNavigate ? () => onNavigate(c.runtimeStageId) : undefined}\n style={crumbButtonStyle(onNavigate !== undefined)}\n >\n {c.runtimeStageId}\n </button>\n {i < lineage.length - 2 && (\n <span style={{ color: theme.textMuted, fontSize: 10 }}>→</span>\n )}\n </span>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n\n// ── Sub-components ─────────────────────────────────────────────────\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div style={{ marginBottom: 14 }}>\n <div\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n marginBottom: 6,\n }}\n >\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nfunction PlainTags({ labels }: { labels: readonly string[] }) {\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 4 }}>\n {labels.map((l) => (\n <span\n key={l}\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"2px 6px\",\n borderRadius: 3,\n background: \"var(--fp-bg-secondary, transparent)\",\n color: theme.textSecondary,\n }}\n >\n {l}\n </span>\n ))}\n </div>\n );\n}\n\nfunction RuntimeRefs({\n refs,\n onClick,\n}: {\n refs: readonly RuntimeStageId[];\n onClick?: (rsid: RuntimeStageId) => void;\n}) {\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {refs.map((r) => (\n <button\n key={r}\n onClick={onClick ? () => onClick(r) : undefined}\n style={crumbButtonStyle(onClick !== undefined)}\n >\n {r}\n </button>\n ))}\n </div>\n );\n}\n\nfunction KeyValueGrid({ entries }: { entries: ReadonlyArray<[string, unknown]> }) {\n return (\n <table style={{ fontSize: 11, fontFamily: \"monospace\", width: \"100%\", borderCollapse: \"collapse\" }}>\n <tbody>\n {entries.map(([k, v]) => (\n <tr key={k}>\n <td style={{ color: theme.textSecondary, padding: \"2px 8px 2px 0\", verticalAlign: \"top\" }}>\n {k}\n </td>\n <td style={{ color: theme.textPrimary, wordBreak: \"break-word\" }}>\n {typeof v === \"object\" ? JSON.stringify(v) : String(v)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n\nfunction crumbButtonStyle(clickable: boolean): React.CSSProperties {\n return {\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"3px 8px\",\n borderRadius: 4,\n border: `1px solid ${theme.border}`,\n background: \"transparent\",\n color: theme.textSecondary,\n cursor: clickable ? \"pointer\" : \"default\",\n };\n}\n","/**\n * Series-parallel chain tree builders — pure functions over `TraceGraph`\n * (structural) + `CommitFlowIndex` (runtime).\n *\n * When to reach for this vs. flat commitLog\n * ─────────────────────────────────────────\n * Use `commitLog` when you want chronological replay / slider scrubbing\n * (\"what happened in order\"). Use the chain tree when you want to\n * render parallel structure visually or answer \"which branch ran?\"\n * questions — flat `commitLog[idx-1]` loses the fork shape.\n *\n * Pairs with `<CommitInspector>` for git-log-style master/detail —\n * `<CommitChainView>` picks, `<CommitInspector>` inspects.\n * Complements the per-stage view from `createNodeViewRecorder`.\n *\n * Why a chain tree\n * ────────────────\n * Footprintjs charts are **series-parallel DAGs by construction** —\n * the builder primitives compose serially (`addFunction`) or in\n * parallel (`addListOfFunction` / `addDeciderFunction`). Series-\n * parallel DAGs are provably representable as expression trees,\n * so we can decompose any footprintjs chart into a nested\n * `(serial | parallel | leaf)` shape that renders cleanly as\n * swim lanes.\n *\n * Two builders, one tree shape\n * ────────────────────────────\n * - `structureAsChainTree(graph, options?)` — STRUCTURAL view.\n * No commitLog. Decomposes the chart shape into S-P primitives.\n * Renders the full chart (all branches of a decider, etc.) even\n * before running.\n *\n * - `buildCommitChainTree(graph, commitFlow, options?)` — RUNTIME\n * view. Each leaf carries the commits[] that fired for that stage\n * in this run. Loops produce a leaf with N commits. Branches that\n * never executed in this run appear as empty `commits[]` leaves\n * (consumer can filter).\n *\n * Algorithm scope (correctness contract)\n * ──────────────────────────────────────\n * These builders are tuned for **series-parallel charts** — every\n * fork in footprintjs's builder has a matching merge point. For\n * non-S-P or malformed graphs the tree is still finite and stable\n * (cycle defense guarantees termination), but the shape may not\n * reflect a clean S-P decomposition.\n *\n * - Forks with **no common descendant** drop the outer-walk tail at\n * the fork node. Real footprintjs charts always re-merge.\n * - Edges with `data.kind === undefined` are treated as `'next'`.\n * Multiple linear-next edges from a single source follow only the\n * first (deterministic by insertion order); a dev-mode warning\n * fires when this is observed (`isDevMode()` from footprintjs).\n *\n * Cycle defense (L8 panel must-fix carried forward)\n * ─────────────────────────────────────────────────\n * Every recursive walk carries a `visited: Set<StageId>` to defend\n * against malformed graphs (manual edge injection, future builder\n * bugs). Loop edges (`kind === 'loop'`) are excluded at the\n * structure-recorder layer per invariant I1, so they never enter\n * prev/next — no extra filtering needed here. Convergence detection\n * uses BFS bounded by `graph.nodes.length`.\n *\n * @example\n * ```ts\n * const trace = createTraceStructureRecorder();\n * // ... build a fork chart ...\n *\n * const sChain = structureAsChainTree(trace.getGraph());\n * // → { kind: 'serial', items: [\n * // { kind: 'leaf', stageId: 'LoadOrder' },\n * // { kind: 'parallel', branches: [\n * // { kind: 'leaf', stageId: 'CheckInventory' },\n * // { kind: 'leaf', stageId: 'RunFraudCheck' },\n * // ]},\n * // { kind: 'leaf', stageId: 'FinalizeOrder' },\n * // ]}\n *\n * const commitFlow = createCommitFlowRecorder({ structure: trace });\n * // ... run chart ...\n * const cChain = buildCommitChainTree(trace.getGraph(), commitFlow.getIndex());\n * // → same shape, but each leaf carries `commits: CommitView[]`\n * ```\n */\n\nimport type { TraceGraph } from \"./traceStructureRecorder\";\nimport type { CommitFlowIndex, CommitView } from \"./createCommitFlowRecorder\";\nimport type { StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { devWarn } from \"./_internal/devWarn\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Structural chain tree leaf (no commits). */\nexport interface StructureChainLeaf {\n readonly kind: \"leaf\";\n readonly stageId: StageId;\n}\n\n/** Structural chain tree node — recursive S-P composition over stage ids. */\nexport type StructureChain =\n | StructureChainLeaf\n | { readonly kind: \"serial\"; readonly items: readonly StructureChain[] }\n | { readonly kind: \"parallel\"; readonly branches: readonly StructureChain[] };\n\n/** Commit chain tree leaf — carries all commits for the stage (loop-aware). */\nexport interface CommitChainLeaf {\n readonly kind: \"leaf\";\n readonly stageId: StageId;\n /** All commits that fired for this stage in this run, in commitIdx\n * ascending order. Loop iteration N has commits[N]. Empty array\n * when the stage never executed in this run.\n *\n * **Ownership**: references are shared with\n * `CommitFlowIndex.commits` (no deep copy). The same shallow-copy /\n * nested-shared-value contract documented on `CommitView.updates`\n * applies. Do not mutate. */\n readonly commits: readonly CommitView[];\n}\n\n/** Commit chain tree — recursive S-P composition with commit leaves. */\nexport type CommitChain =\n | CommitChainLeaf\n | { readonly kind: \"serial\"; readonly items: readonly CommitChain[] }\n | { readonly kind: \"parallel\"; readonly branches: readonly CommitChain[] };\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Per-stage indexes computed once per build call. */\ninterface GraphIndex {\n byStageId: Map<StageId, { branchChildren: StageId[]; linearNext: StageId[] }>;\n allNodeIds: StageId[];\n}\n\nfunction indexGraph(graph: TraceGraph): GraphIndex {\n const byStageId = new Map<\n StageId,\n { branchChildren: StageId[]; linearNext: StageId[] }\n >();\n const allNodeIds: StageId[] = [];\n\n for (const node of graph.nodes) {\n const stageId = asStageId(node.id);\n allNodeIds.push(stageId);\n // node.data already carries prevIds/nextIds (L8.0 enrichment), but\n // we split outgoing into branch vs linear based on edge kind below.\n byStageId.set(stageId, { branchChildren: [], linearNext: [] });\n }\n\n for (const edge of graph.edges) {\n const kind = edge.data?.kind;\n if (kind === \"loop\") continue;\n const sourceEntry = byStageId.get(asStageId(edge.source));\n if (!sourceEntry) continue;\n // Skip edges whose target is not in the node set (malformed graph\n // defense — walker would bail on entry === undefined anyway, but\n // pruning here keeps branchChildren/linearNext clean for the\n // ambiguity warning below).\n const target = asStageId(edge.target);\n if (!byStageId.has(target)) continue;\n if (kind === \"fork-branch\" || kind === \"decision-branch\") {\n sourceEntry.branchChildren.push(target);\n } else {\n // 'next' or any unspecified kind treated as linear.\n sourceEntry.linearNext.push(target);\n }\n }\n\n return { byStageId, allNodeIds };\n}\n\n/** Find the seed: first node with no incoming non-loop edge. Falls back\n * to the first node in insertion order. */\nfunction findSeed(graph: TraceGraph, fromStageId?: StageId): StageId | null {\n if (fromStageId) {\n const n = graph.nodes.find((n) => n.id === fromStageId);\n return n ? asStageId(n.id) : null;\n }\n const hasIncoming = new Set<string>();\n for (const e of graph.edges) {\n if (e.data?.kind !== \"loop\") hasIncoming.add(e.target);\n }\n const seed = graph.nodes.find((n) => !hasIncoming.has(n.id)) ?? graph.nodes[0];\n return seed ? asStageId(seed.id) : null;\n}\n\n/**\n * BFS forward from `startId`. Returns ordered visit list (BFS order)\n * + reachable set. Skips `loop`-kind edges per invariant I1.\n */\nfunction bfsReachable(\n startId: StageId,\n index: GraphIndex,\n): { order: StageId[]; reachable: Set<StageId> } {\n const reachable = new Set<StageId>([startId]);\n const order: StageId[] = [startId];\n const queue: StageId[] = [startId];\n let head = 0;\n while (head < queue.length) {\n const cur = queue[head++]!;\n const entry = index.byStageId.get(cur);\n if (!entry) continue;\n for (const next of [...entry.branchChildren, ...entry.linearNext]) {\n if (reachable.has(next)) continue;\n reachable.add(next);\n order.push(next);\n queue.push(next);\n }\n }\n return { order, reachable };\n}\n\n/**\n * Find the convergence point of a fork — the FIRST node (BFS order\n * from branch[0]) reachable from EVERY branch. Returns `null` if no\n * common descendant (branches diverge without re-merging — does not\n * happen in series-parallel footprintjs charts).\n *\n * For strict S-P charts, the first node in branch[0]'s BFS order that\n * sits in every reachable set IS the true convergence (dominator).\n * For non-S-P graphs this is a best-effort approximation.\n */\nfunction findConvergence(\n branches: readonly StageId[],\n index: GraphIndex,\n): StageId | null {\n if (branches.length < 2) return null;\n // Compute reachable + order for branch[0] once; reuse the same walk\n // for both ordering AND the first reachable set (panel 5 must-fix).\n const firstWalk = bfsReachable(branches[0]!, index);\n const reachableSets: Set<StageId>[] = [firstWalk.reachable];\n for (let i = 1; i < branches.length; i++) {\n reachableSets.push(bfsReachable(branches[i]!, index).reachable);\n }\n // Exclude the branch starting points themselves — they're not the\n // convergence of their own subtree.\n const startSet = new Set(branches);\n for (const candidate of firstWalk.order) {\n if (startSet.has(candidate)) continue;\n if (reachableSets.every((s) => s.has(candidate))) {\n return candidate;\n }\n }\n return null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Recursive walker — produces a StructureChain\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Walk forward from `startId`, stopping at `untilId` (exclusive). Returns\n * the chain for the [startId, untilId) segment. `untilId === null` means\n * walk to the end (terminal nodes).\n *\n * Cycle defense: passes a `visited: Set<StageId>` through recursion. A\n * node already in `visited` is skipped (returns null), so the same\n * StageId appears at most once in the resulting tree.\n */\nfunction walkChain(\n startId: StageId,\n untilId: StageId | null,\n index: GraphIndex,\n visited: Set<StageId>,\n): StructureChain | null {\n const items: StructureChain[] = [];\n let cur: StageId | null = startId;\n while (cur !== null && cur !== untilId) {\n if (visited.has(cur)) break;\n visited.add(cur);\n const entry = index.byStageId.get(cur);\n if (!entry) break;\n\n const branches = entry.branchChildren;\n const linearNexts = entry.linearNext;\n\n // Always emit the current node as a leaf — its OWN position in the\n // chain. Parallel/serial wrappers follow if applicable.\n items.push({ kind: \"leaf\", stageId: cur });\n\n if (branches.length >= 2) {\n // Fork — find convergence + recurse into each branch.\n const convergence = findConvergence(branches, index);\n const branchChains: StructureChain[] = [];\n for (const b of branches) {\n // Each branch walks with a per-branch clone of `visited` for\n // traversal isolation. After the branch returns, its markers\n // are unioned into the outer scope so the post-convergence\n // walk doesn't re-emit nodes that any branch already covered.\n // This is correct dedup for S-P graphs (branches don't share\n // pre-convergence nodes) and is what keeps the recursion\n // bounded for malformed graphs (cycle defense).\n const branchVisited = new Set(visited);\n const sub = walkChain(b, convergence, index, branchVisited);\n if (sub !== null) branchChains.push(sub);\n for (const v of branchVisited) visited.add(v);\n }\n if (branchChains.length > 0) {\n items.push({ kind: \"parallel\", branches: branchChains });\n }\n cur = convergence;\n } else if (branches.length === 1 && linearNexts.length === 0) {\n // Single branch — treat as linear continuation.\n cur = branches[0]!;\n } else if (linearNexts.length >= 1) {\n // Linear continuation. Multiple linearNexts is ambiguous for S-P\n // decomposition; we follow the first (deterministic per-recorder\n // insertion order) and warn in dev mode so consumers building\n // unusual graph shapes are alerted.\n if (linearNexts.length > 1) {\n devWarn(\n () =>\n `[buildCommitChainTree] stage '${cur}' has ${linearNexts.length} linear-next edges; chain decomposition follows only the first ('${linearNexts[0]}'). Use 'fork-branch' or 'decision-branch' edge kinds to express parallel/conditional splits.`,\n );\n }\n cur = linearNexts[0]!;\n } else {\n // Terminal node.\n cur = null;\n }\n }\n\n if (items.length === 0) return null;\n if (items.length === 1) return items[0]!;\n return { kind: \"serial\", items };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API: structureAsChainTree\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ChainTreeOptions {\n /** Stage id to start the walk from. Defaults to the chart's seed\n * (first node with no incoming non-loop edge). */\n rootStageId?: StageId;\n}\n\n/**\n * Build a structural chain tree for a chart. Pure function over\n * `TraceGraph` — no runtime data required. Useful for rendering the\n * chart shape before any execution (static documentation, etc.).\n */\nexport function structureAsChainTree(\n graph: TraceGraph,\n options: ChainTreeOptions = {},\n): StructureChain | null {\n if (graph.nodes.length === 0) return null;\n const index = indexGraph(graph);\n const seed = findSeed(graph, options.rootStageId);\n if (!seed) return null;\n const visited = new Set<StageId>();\n return walkChain(seed, null, index, visited);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API: buildCommitChainTree\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a commit-decorated chain tree. Same S-P shape as\n * `structureAsChainTree`, but each leaf carries the commits[] that\n * fired for that stage in this run (in commitIdx ascending order).\n *\n * Loop semantics: a stage that ran N times has a leaf with\n * `commits.length === N`. The consumer's renderer decides whether to\n * display them as a single \"ran 3×\" badge or unroll into N visible\n * boxes — both views are supported by the same data.\n *\n * Branches that never executed in this run appear with empty\n * `commits[]`. Consumers wanting \"runtime-only\" view can filter them\n * out.\n */\nexport function buildCommitChainTree(\n graph: TraceGraph,\n commitFlow: CommitFlowIndex,\n options: ChainTreeOptions = {},\n): CommitChain | null {\n const structural = structureAsChainTree(graph, options);\n if (!structural) return null;\n // Index commits by stageId for O(1) leaf decoration.\n const commitsByStageId = new Map<StageId, CommitView[]>();\n for (const c of commitFlow.commits) {\n const list = commitsByStageId.get(c.stageId) ?? [];\n list.push(c);\n commitsByStageId.set(c.stageId, list);\n }\n return decorate(structural, commitsByStageId);\n}\n\nfunction decorate(\n node: StructureChain,\n commitsByStageId: ReadonlyMap<StageId, readonly CommitView[]>,\n): CommitChain {\n if (node.kind === \"leaf\") {\n return {\n kind: \"leaf\",\n stageId: node.stageId,\n commits: commitsByStageId.get(node.stageId) ?? [],\n };\n }\n if (node.kind === \"serial\") {\n return {\n kind: \"serial\",\n items: node.items.map((n) => decorate(n, commitsByStageId)),\n };\n }\n return {\n kind: \"parallel\",\n branches: node.branches.map((b) => decorate(b, commitsByStageId)),\n };\n}\n","/**\n * CommitChainView — git-log-style swim-lane renderer for a\n * `CommitChain` or `StructureChain` (from `buildCommitChainTree` or\n * `structureAsChainTree`).\n *\n * Pair with `<CommitInspector>` for master/detail — this picks,\n * that inspects.\n *\n * Time-travel dimming (L8.5)\n * ──────────────────────────\n * Pass `revealedThroughCommitIdx={N}` (typically driven by\n * `<RunSlider>` via the ONE-CURSOR model) to dim commits with\n * `commitIdx > N`. Dimmed commits stay in the DOM (stable layout)\n * and stay CLICKABLE (clicking jumps the cursor forward to that\n * commit). Use `null` (default) to reveal all, `-1` to reveal none\n * (e.g., stale-cursor sentinel from `<TraceExplorerShell>`).\n *\n * Layout rules\n * ────────────\n * serial → vertical stack of children; subtle connector between them\n * parallel → horizontal row of branch columns (swim lanes), each\n * column is its own chain\n * leaf → one box per commit (loop unrolls into N boxes); empty\n * commits[] (or `StructureChain` leaf) renders a dashed\n * \"not executed in this run\" box\n *\n * Pure data prop: pass `chain` directly. For live updates, wrap with\n * `useTranslator(commitFlow, () => buildCommitChainTree(graph, commitFlow.getIndex()))`\n * at the parent. Mirrors the consumer pattern used by `<NodeInspector>`\n * and `<CommitInspector>`.\n *\n * Pre-execution rendering: pass a `StructureChain` directly (from\n * `structureAsChainTree(graph)`) — every leaf renders as the\n * \"not executed yet\" placeholder. No need to manufacture an empty\n * `CommitFlowIndex`.\n *\n * Selection: `selectedRuntimeStageId` highlights one commit box;\n * `onSelectCommit` fires when any commit box is clicked.\n *\n * Future extension: the recursive renderer is factored as\n * `<ChainShell renderLeaf={...}>` so a future `<StructureChainView>`\n * can reuse the same layout primitives with a different leaf renderer.\n *\n * @example\n * ```tsx\n * const chain = useTranslator(commitFlow, () =>\n * buildCommitChainTree(trace.getGraph(), commitFlow.getIndex()),\n * );\n * const [selected, setSelected] = useState<RuntimeStageId | null>(null);\n * return (\n * <div style={{ display: 'flex' }}>\n * <CommitChainView\n * chain={chain}\n * selectedRuntimeStageId={selected}\n * onSelectCommit={setSelected}\n * />\n * <CommitInspector index={commitFlow.getIndex()} selectedRuntimeStageId={selected} />\n * </div>\n * );\n * ```\n */\n\nimport type {\n CommitChain,\n CommitChainLeaf,\n StructureChain,\n StructureChainLeaf,\n} from \"./buildCommitChainTree\";\nimport type { CommitView } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId, StageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface CommitChainViewProps extends BaseComponentProps {\n /** The chain tree. Accepts BOTH `CommitChain` (from\n * `buildCommitChainTree`) and `StructureChain` (from\n * `structureAsChainTree` — pre-execution view). null → placeholder. */\n chain: CommitChain | StructureChain | null;\n /** Highlighted commit (by runtimeStageId). Only meaningful for\n * `CommitChain` input (StructureChain has no commits to select). */\n selectedRuntimeStageId?: RuntimeStageId | null;\n /** Fires when a commit box is clicked — pass to `<CommitInspector>`\n * for master/detail wiring. Not fired for \"not executed\" leaves. */\n onSelectCommit?: (runtimeStageId: RuntimeStageId) => void;\n /** Optional label resolver — default uses the bare stageId. Consumers\n * can map id → friendly name (e.g., from a NodeViewIndex). */\n resolveLabel?: (stageId: StageId) => string;\n /** Time-travel cursor: commits with `commitIdx > revealedThroughCommitIdx`\n * render dimmed (still visible — keeps layout stable). Pairs with\n * `<RunSlider>` in the ONE-CURSOR model.\n *\n * Semantics:\n * - `null` (default) — reveal ALL commits (no time-travel applied).\n * - `N >= 0` — reveal commits 0..N inclusive; dim commits with\n * `commitIdx > N`.\n * - `N < 0` (e.g., `-1`) — reveal NONE; all commits dim. Use this\n * sentinel for \"cursor is stale / unresolved\" so the chain doesn't\n * accidentally fall back to fully-revealed when the consumer wants\n * no-reveal. */\n revealedThroughCommitIdx?: number | null;\n}\n\nexport function CommitChainView({\n chain,\n selectedRuntimeStageId = null,\n onSelectCommit,\n resolveLabel,\n revealedThroughCommitIdx = null,\n className,\n style,\n}: CommitChainViewProps) {\n if (!chain) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n No chain to display.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 12,\n color: theme.textPrimary,\n fontSize: 12,\n overflow: \"auto\",\n ...style,\n }}\n >\n <ChainShell\n node={chain}\n renderLeaf={(leaf) => (\n <Leaf\n leaf={leaf}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={onSelectCommit}\n resolveLabel={resolveLabel}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n )}\n />\n </div>\n );\n}\n\n// ── Recursive layout shell (reusable by future StructureChainView) ──\n\ntype AnyChain = CommitChain | StructureChain;\ntype AnyLeaf = CommitChainLeaf | StructureChainLeaf;\n\ninterface ChainShellProps {\n node: AnyChain;\n renderLeaf: (leaf: AnyLeaf) => React.ReactNode;\n}\n\nfunction ChainShell({ node, renderLeaf }: ChainShellProps): React.ReactElement {\n if (node.kind === \"leaf\") {\n return <>{renderLeaf(node)}</>;\n }\n\n if (node.kind === \"serial\") {\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 0,\n }}\n >\n {node.items.map((child, i) => (\n <div\n key={chainKey(child, i)}\n style={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\" }}\n >\n <ChainShell node={child} renderLeaf={renderLeaf} />\n {i < node.items.length - 1 && <Connector orientation=\"vertical\" />}\n </div>\n ))}\n </div>\n );\n }\n\n // parallel → swim lanes\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 0,\n }}\n >\n <ForkMarker />\n <div\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n gap: 18,\n padding: \"4px 0\",\n borderLeft: `1px dashed ${theme.border}`,\n borderRight: `1px dashed ${theme.border}`,\n paddingLeft: 12,\n paddingRight: 12,\n }}\n >\n {node.branches.map((branch, i) => (\n <div\n key={chainKey(branch, i)}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n minWidth: 120,\n }}\n >\n <ChainShell node={branch} renderLeaf={renderLeaf} />\n </div>\n ))}\n </div>\n <ForkMarker />\n </div>\n );\n}\n\n/**\n * Stable React key for serial/parallel children — derived from the\n * subtree shape so a rerender with shifted branches doesn't mis-pair\n * subtree state. Falls back to `index` only when the leaf can't be\n * located (defensive — shouldn't happen).\n */\nfunction chainKey(node: AnyChain, fallbackIndex: number): string {\n const leaf = firstLeafOf(node);\n return leaf ? `${node.kind}:${leaf.stageId}` : `${node.kind}:idx${fallbackIndex}`;\n}\n\nfunction firstLeafOf(node: AnyChain): AnyLeaf | null {\n if (node.kind === \"leaf\") return node;\n if (node.kind === \"serial\") {\n for (const item of node.items) {\n const l = firstLeafOf(item);\n if (l) return l;\n }\n return null;\n }\n for (const branch of node.branches) {\n const l = firstLeafOf(branch);\n if (l) return l;\n }\n return null;\n}\n\n// ── Leaf (one or N commit boxes for loop iterations) ────────────────\n\nfunction Leaf({\n leaf,\n selectedRuntimeStageId,\n onSelectCommit,\n resolveLabel,\n revealedThroughCommitIdx,\n}: {\n leaf: AnyLeaf;\n selectedRuntimeStageId: RuntimeStageId | null;\n onSelectCommit?: (rsid: RuntimeStageId) => void;\n resolveLabel?: (stageId: StageId) => string;\n revealedThroughCommitIdx: number | null;\n}) {\n const label = resolveLabel ? resolveLabel(leaf.stageId) : leaf.stageId;\n const commits: readonly CommitView[] =\n \"commits\" in leaf ? leaf.commits : [];\n\n if (commits.length === 0) {\n return (\n <div\n style={{\n ...boxBaseStyle,\n borderStyle: \"dashed\",\n color: theme.textMuted,\n background: \"transparent\",\n }}\n title={`${leaf.stageId} — not executed in this run`}\n >\n <div style={{ fontWeight: 600 }}>{label}</div>\n <div style={{ fontSize: 10, fontStyle: \"italic\" }}>not executed</div>\n </div>\n );\n }\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\", gap: 4 }}>\n {commits.map((c, i) => {\n const isSelected = c.runtimeStageId === selectedRuntimeStageId;\n const clickable = onSelectCommit !== undefined;\n // Time-travel dimming: when revealedThroughCommitIdx is set,\n // commits BEYOND the cursor render dimmed (still in the DOM\n // so layout stays stable as the cursor slides). Commits are\n // STILL clickable (clicking jumps the time cursor forward).\n // We use aria-disabled (not aria-hidden) so screen-readers\n // perceive the element + state, per WAI-ARIA's \"MUST NOT use\n // aria-hidden on focusable elements\" rule.\n const isRevealed =\n revealedThroughCommitIdx === null ||\n c.commitIdx <= revealedThroughCommitIdx;\n return (\n <button\n key={c.commitIdx}\n type=\"button\"\n onClick={clickable ? () => onSelectCommit(c.runtimeStageId) : undefined}\n style={{\n ...boxBaseStyle,\n cursor: clickable ? \"pointer\" : \"default\",\n borderColor: isSelected ? theme.success : theme.border,\n borderWidth: isSelected ? 2 : 1,\n background: isSelected ? \"rgba(34,197,94,0.08)\" : \"transparent\",\n color: theme.textPrimary,\n textAlign: \"left\",\n fontFamily: \"inherit\",\n padding: \"6px 10px\",\n opacity: isRevealed ? 1 : 0.35,\n }}\n aria-disabled={!isRevealed}\n aria-current={isSelected ? \"true\" : undefined}\n title={c.runtimeStageId}\n >\n <div style={{ fontWeight: 600 }}>\n {label}\n {commits.length > 1 && (\n <span style={{ color: theme.textMuted, fontWeight: 400, marginLeft: 6 }}>\n iter {i + 1}/{commits.length}\n </span>\n )}\n </div>\n <div\n style={{\n fontSize: 10,\n fontFamily: \"monospace\",\n color: theme.textMuted,\n marginTop: 2,\n }}\n >\n #{c.commitIdx} · {c.runtimeStageId}\n </div>\n </button>\n );\n })}\n </div>\n );\n}\n\n// ── Decorations ─────────────────────────────────────────────────────\n\nfunction Connector({ orientation }: { orientation: \"vertical\" | \"horizontal\" }) {\n return orientation === \"vertical\" ? (\n <div\n aria-hidden\n style={{\n width: 1,\n height: 12,\n background: theme.border,\n }}\n />\n ) : (\n <div\n aria-hidden\n style={{\n height: 1,\n width: 12,\n background: theme.border,\n }}\n />\n );\n}\n\nfunction ForkMarker() {\n return (\n <div\n aria-hidden\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: theme.border,\n margin: \"2px 0\",\n }}\n />\n );\n}\n\nconst boxBaseStyle: React.CSSProperties = {\n display: \"inline-block\",\n minWidth: 110,\n padding: \"6px 10px\",\n border: `1px solid ${theme.border}`,\n borderRadius: 4,\n fontSize: 12,\n color: theme.textPrimary,\n background: \"transparent\",\n};\n","/**\n * TraceExplorerShell — composed master/detail layout that wires the\n * full L8 translator stack into a single drop-in component.\n *\n * **Composes**: [`<CommitChainView>`](./CommitChainView.tsx),\n * [`<CommitInspector>`](./CommitInspector.tsx),\n * [`<NodeInspector>`](./NodeInspector.tsx) over a [`TraceBundle`](./createTraceBundle.ts).\n *\n * The L8 stack is intentionally factored as independent pieces\n * (structure / runtimeOverlay / nodeView / commitFlow / chain\n * builder / inspectors). Consumers can wire à-la-carte for custom\n * layouts. `<TraceExplorerShell>` is the \"I want the canonical\n * trace-explorer UI without writing 50 lines of `useTranslator`\n * plumbing\" entry point — pass a `bundle`, get a master/detail UI.\n *\n * **Prerequisite**: call `bundle.attachTo(executor)` (see\n * `createTraceBundle` for the recorder-attach lifecycle) BEFORE\n * rendering this component. The shell only consumes events; it does\n * not trigger them. Without the attach step, every pane will show its\n * placeholder.\n *\n * Layout\n * ──────\n * ┌─────────────────────────────────────────────────┐\n * │ RunSlider (time-travel cursor) │\n * ├──────────────────────────┬──────────────────────┤\n * │ CommitChainView │ CommitInspector │\n * │ (master, click a box) │ (detail, selected) │\n * │ │ │\n * ├──────────────────────────┴──────────────────────┤\n * │ NodeInspector (resolved from selected stageId) │\n * └─────────────────────────────────────────────────┘\n *\n * The slider is the **ONE-CURSOR** affordance: dragging it moves\n * the same cursor that clicking a commit moves. Commits past the\n * cursor render dimmed in the chain view (`revealedThroughCommitIdx`\n * threaded through automatically). Pass `slots: { slider: null }`\n * to hide the slider (e.g., for static post-run views).\n *\n * Selection model\n * ───────────────\n * ONE cursor (`selectedRuntimeStageId`) drives both detail panes.\n * Clicking a commit in the chain view updates the cursor; the\n * `<CommitInspector>` shows that commit; the `<NodeInspector>`\n * shows the stage that commit belongs to (derived by stripping the\n * `#executionIndex` suffix from the runtimeStageId).\n *\n * Controlled mode: pass `selectedRuntimeStageId` + `onSelectionChange`\n * to drive selection from outside (URL hash, parent state, etc.).\n * Uncontrolled mode: omit both — the shell owns the cursor.\n * `onSelectionChange` also fires in uncontrolled mode for\n * observability (logging, analytics).\n *\n * Composition rule (L8 architecture, carried forward)\n * ───────────────────────────────────────────────────\n * This shell consumes ONLY the bundle's translator handles via\n * `useTranslator`. It NEVER subscribes to peer translators directly\n * (would violate the linear-dep-tree rule). It builds the chain\n * tree fresh on each commitFlow version bump — cheap, cache-friendly\n * (every input index is version-keyed-cached upstream, and\n * `commitFlow` transitively re-notifies on `structure` changes per\n * the L8.2 contract, so structure-only events also propagate).\n *\n * Customization\n * ─────────────\n * The default layout is a CSS grid. Override via `slots` to swap any\n * panel for a custom renderer. Slot props mirror the sibling-\n * inspector pattern — they receive PURE DATA (the typed index/chain),\n * NOT the bundle. This keeps slots usable from tests / Storybook /\n * SSR and means slot authors do not have to re-subscribe to\n * translators (the shell does that once).\n *\n * Stability note: `slots` should be stable across renders (define at\n * module scope or wrap with `useMemo`). The shell memoizes the\n * resolved component refs to defend against accidental remounts.\n *\n * @example Minimal\n * ```tsx\n * const bundle = useMemo(() => createTraceBundle(), []);\n * useEffect(() => {\n * const chart = flowChart('seed', fn, 'seed', undefined, undefined, {\n * structureRecorders: [bundle.structure.recorder],\n * }).build();\n * const executor = new FlowChartExecutor(chart);\n * bundle.attachTo(executor); // Prerequisite — see createTraceBundle.\n * executor.run({ input });\n * }, [bundle]);\n *\n * return <TraceExplorerShell bundle={bundle} />;\n * ```\n *\n * @example Controlled selection (sync to URL hash)\n * ```tsx\n * const [sel, setSel] = useState<RuntimeStageId | null>(null);\n * return (\n * <TraceExplorerShell\n * bundle={bundle}\n * selectedRuntimeStageId={sel}\n * onSelectionChange={setSel}\n * />\n * );\n * ```\n *\n * @example Custom chain pane (typed data slot)\n * ```tsx\n * const slots = useMemo(() => ({\n * chain: ({ chain, selectedRuntimeStageId, onSelectCommit }) => (\n * <MyCustomTimeline chain={chain} cursor={selectedRuntimeStageId} onPick={onSelectCommit} />\n * ),\n * }), []);\n * return <TraceExplorerShell bundle={bundle} slots={slots} />;\n * ```\n */\n\nimport { useMemo, useState, useCallback } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport type { TraceBundle } from \"./createTraceBundle\";\nimport type { RuntimeStageId, StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { useTranslator } from \"./_internal/useTranslator\";\nimport { buildCommitChainTree, type CommitChain } from \"./buildCommitChainTree\";\nimport { CommitChainView } from \"./CommitChainView\";\nimport { CommitInspector } from \"./CommitInspector\";\nimport { NodeInspector } from \"./NodeInspector\";\nimport { RunSlider } from \"./RunSlider\";\nimport type { CommitFlowIndex } from \"./createCommitFlowRecorder\";\nimport type { NodeViewIndex } from \"./createNodeViewRecorder\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\n/**\n * Slot prop bags — slots receive PURE DATA (chain/index), NOT the\n * bundle. Mirrors the sibling-inspector convention so slot bodies are\n * usable from tests / Storybook / SSR and avoid re-subscribing to\n * translators. Each callback is wired by the shell to the shared\n * selection cursor.\n */\nexport interface ChainSlotProps {\n /** Live chain tree, derived from the bundle. `null` before any\n * commits arrive. */\n chain: CommitChain | null;\n /** Currently selected commit (shared cursor). */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor. */\n onSelectCommit: (rsid: RuntimeStageId) => void;\n /** Time-travel reveal cursor (derived from selectedRuntimeStageId\n * via ONE-CURSOR model). Commits with commitIdx > this value\n * render dimmed. `null` reveals all, `-1` reveals none, `N >= 0`\n * reveals up to commit N. **Optional in custom slots** — slot\n * authors that don't implement time-travel dimming can ignore it\n * (matches the standalone `<CommitChainView>` prop optionality). */\n revealedThroughCommitIdx?: number | null;\n}\nexport interface CommitInspectorSlotProps {\n /** Live commitFlow index. */\n index: CommitFlowIndex;\n /** Currently selected commit (shared cursor). */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor (e.g., for clickable\n * data-dep / lineage breadcrumbs). */\n onNavigate: (rsid: RuntimeStageId) => void;\n}\nexport interface NodeInspectorSlotProps {\n /** Live nodeView index. */\n index: NodeViewIndex;\n /** StageId derived from `selectedRuntimeStageId`. */\n selectedStageId: StageId | null;\n /** Wire to the shared selection cursor (e.g., for prev/next chain\n * breadcrumbs). Resolves the stage to its first commit. */\n onNavigate: (stageId: StageId) => void;\n}\nexport interface SliderSlotProps {\n /** Live commitFlow index. */\n index: CommitFlowIndex;\n /** Currently selected commit — same cursor as the chain selection\n * per the ONE-CURSOR model. */\n cursorRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor. */\n onCursorChange: (rsid: RuntimeStageId | null) => void;\n}\n\nexport interface TraceExplorerSlots {\n /** Override the chain (master) pane. Use to swap the swim-lane\n * renderer for a timeline/Gantt/custom layout while keeping the\n * same selection contract. */\n chain?: React.ComponentType<ChainSlotProps>;\n /** Override the commit (detail) pane. Use to add custom commit-\n * detail formatting (e.g., domain-specific updates rendering). */\n commitInspector?: React.ComponentType<CommitInspectorSlotProps>;\n /** Override the node (stage-summary) pane. Use to surface per-stage\n * custom KPIs / annotations alongside the default execution data. */\n nodeInspector?: React.ComponentType<NodeInspectorSlotProps>;\n /** Override the slider (top time-travel bar). Pass `null` to HIDE\n * the slider entirely (e.g., for static post-run views with no\n * scrub affordance). */\n slider?: React.ComponentType<SliderSlotProps> | null;\n}\n\nexport interface TraceExplorerShellProps extends BaseComponentProps {\n /** The translator bundle from `createTraceBundle()`. MUST have had\n * `bundle.attachTo(executor)` called before any commits arrive,\n * otherwise every pane shows its placeholder. */\n bundle: TraceBundle;\n /** Controlled selection (omit for uncontrolled). `null` clears. */\n selectedRuntimeStageId?: RuntimeStageId | null;\n /** Fires on selection changes. In controlled mode, required for\n * selection to take effect. In uncontrolled mode, fires as an\n * observation hook (logging/analytics) — the shell still owns the\n * state.\n *\n * Memoize via `useCallback` to avoid downstream re-renders. */\n onSelectionChange?: (rsid: RuntimeStageId | null) => void;\n /** Optional slot overrides. Should be stable across renders\n * (define at module scope or `useMemo`). */\n slots?: TraceExplorerSlots;\n}\n\nexport function TraceExplorerShell({\n bundle,\n selectedRuntimeStageId: controlledSel,\n onSelectionChange,\n slots,\n className,\n style,\n}: TraceExplorerShellProps) {\n // Controlled vs uncontrolled selection. Standard React idiom.\n const [internalSel, setInternalSel] = useState<RuntimeStageId | null>(null);\n const isControlled = controlledSel !== undefined;\n const selectedRuntimeStageId = isControlled ? controlledSel : internalSel;\n\n const handleSelect = useCallback(\n (rsid: RuntimeStageId | null) => {\n if (!isControlled) setInternalSel(rsid);\n // Fire in both modes — controlled mode requires it for parent\n // sync; uncontrolled mode fires for observability (logging,\n // analytics, URL sync without taking control).\n onSelectionChange?.(rsid);\n },\n [isControlled, onSelectionChange],\n );\n const handleSelectCommit = useCallback(\n (rsid: RuntimeStageId) => handleSelect(rsid),\n [handleSelect],\n );\n\n // Derive selected stageId from selectedRuntimeStageId by stripping\n // the '#executionIndex' suffix. Mirrors footprintjs/trace\n // `parseRuntimeStageId` invariant — kept inline because\n // explainable-ui is dep-free from footprintjs (subflow prefix is\n // preserved; nodeView keys subflow stages by the full path-prefixed\n // form per footprintjs convention).\n const selectedStageId = useMemo<StageId | null>(() => {\n if (!selectedRuntimeStageId) return null;\n const hashIdx = selectedRuntimeStageId.lastIndexOf(\"#\");\n // hashIdx === 0 → empty stageId (malformed input) → no selection.\n if (hashIdx <= 0) return null;\n return asStageId(selectedRuntimeStageId.slice(0, hashIdx));\n }, [selectedRuntimeStageId]);\n\n // Resolve slot components ONCE per slots-identity change — defends\n // against consumer footgun of passing inline `slots={{...}}` every\n // render which would otherwise remount default panes.\n const ChainPane = useMemo(\n () => slots?.chain ?? DefaultChainPane,\n [slots?.chain],\n );\n const CommitPane = useMemo(\n () => slots?.commitInspector ?? DefaultCommitPane,\n [slots?.commitInspector],\n );\n const NodePane = useMemo(\n () => slots?.nodeInspector ?? DefaultNodePane,\n [slots?.nodeInspector],\n );\n // Slider has tri-state semantics: undefined = use default; null =\n // hide; ComponentType = override. `slots?.slider === null` is the\n // \"hide\" signal; absent key = default.\n const SliderPane = useMemo<React.ComponentType<SliderSlotProps> | null>(() => {\n if (slots && \"slider\" in slots) {\n return slots.slider ?? null;\n }\n return DefaultSliderPane;\n }, [slots]);\n\n // Subscribe ONCE here to the three translators; pass the resolved\n // data down to slots (whether default or custom). Slots NEVER need\n // to subscribe themselves.\n const chain = useTranslator(bundle.commitFlow, () =>\n buildCommitChainTree(bundle.structure.getGraph(), bundle.commitFlow.getIndex()),\n );\n const commitIndex = useTranslator(bundle.commitFlow, () =>\n bundle.commitFlow.getIndex(),\n );\n const nodeIndex = useTranslator(bundle.nodeView, () => bundle.nodeView.getIndex());\n\n // Stage-click → resolve first commit and select it. One-shot lookup\n // outside useTranslator (no subscription) is intentional — this\n // fires on click, not in a render path. Picking commits[0] is the\n // documented semantic; loops resolve to iteration 1.\n const handleStageNavigate = useCallback(\n (stageId: StageId) => {\n const candidates = commitIndex.commits.filter((c) => c.stageId === stageId);\n const first = candidates[0];\n handleSelect(first ? first.runtimeStageId : null);\n },\n [commitIndex, handleSelect],\n );\n\n // Cursor → commitIdx for chain dimming. ONE-CURSOR model: the same\n // cursor that drives selection also drives time-travel reveal.\n //\n // Three states (distinguished — Panel 1 must-fix L8.5):\n // - no cursor (`null`) → `null` (reveal ALL)\n // - cursor resolves to a commit → that commit's commitIdx\n // - cursor is STALE (rsid unknown to index, e.g. removed by reset)\n // → `-1` (reveal NONE), NOT `null` — prevents incoherent \"stale\n // cursor falls back to fully-revealed\" state.\n const revealedThroughCommitIdx = useMemo<number | null>(() => {\n if (!selectedRuntimeStageId) return null;\n const view = commitIndex.byRuntimeStageId.get(selectedRuntimeStageId);\n return view ? view.commitIdx : -1;\n }, [selectedRuntimeStageId, commitIndex]);\n\n // Layout: when the slider is hidden (`slots.slider === null`),\n // collapse the slider row so the grid doesn't reserve empty space.\n const layoutStyle = useMemo<CSSProperties>(\n () => (SliderPane ? SHELL_STYLE_WITH_SLIDER : SHELL_STYLE_NO_SLIDER),\n [SliderPane],\n );\n\n return (\n <div className={className} style={{ ...layoutStyle, ...style }}>\n {SliderPane && (\n <Pane area=\"slider\">\n <SliderPane\n index={commitIndex}\n cursorRuntimeStageId={selectedRuntimeStageId}\n onCursorChange={handleSelect}\n />\n </Pane>\n )}\n <Pane area=\"chain\">\n <ChainPane\n chain={chain}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={handleSelectCommit}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n </Pane>\n <Pane area=\"commit\">\n <CommitPane\n index={commitIndex}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onNavigate={handleSelectCommit}\n />\n </Pane>\n <Pane area=\"node\">\n <NodePane\n index={nodeIndex}\n selectedStageId={selectedStageId}\n onNavigate={handleStageNavigate}\n />\n </Pane>\n </div>\n );\n}\n\n// ── Default panes (pure data props, no internal subscriptions) ──────\n\nfunction DefaultChainPane({\n chain,\n selectedRuntimeStageId,\n onSelectCommit,\n revealedThroughCommitIdx,\n}: ChainSlotProps) {\n return (\n <CommitChainView\n chain={chain}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={onSelectCommit}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n );\n}\n\nfunction DefaultCommitPane({\n index,\n selectedRuntimeStageId,\n onNavigate,\n}: CommitInspectorSlotProps) {\n return (\n <CommitInspector\n index={index}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onNavigate={onNavigate}\n />\n );\n}\n\nfunction DefaultNodePane({ index, selectedStageId, onNavigate }: NodeInspectorSlotProps) {\n return (\n <NodeInspector index={index} selectedId={selectedStageId} onNavigate={onNavigate} />\n );\n}\n\nfunction DefaultSliderPane({\n index,\n cursorRuntimeStageId,\n onCursorChange,\n}: SliderSlotProps) {\n return (\n <RunSlider\n index={index}\n cursorRuntimeStageId={cursorRuntimeStageId}\n onCursorChange={onCursorChange}\n />\n );\n}\n\n// ── Layout helpers ──────────────────────────────────────────────────\n\nconst SHELL_STYLE_WITH_SLIDER: CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: \"minmax(280px, 1fr) minmax(320px, 1fr)\",\n gridTemplateRows: \"auto 1fr auto\",\n gridTemplateAreas: '\"slider slider\" \"chain commit\" \"node node\"',\n gap: 12,\n padding: 12,\n background: theme.bgPrimary,\n color: theme.textPrimary,\n};\n\nconst SHELL_STYLE_NO_SLIDER: CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: \"minmax(280px, 1fr) minmax(320px, 1fr)\",\n gridTemplateRows: \"1fr auto\",\n gridTemplateAreas: '\"chain commit\" \"node node\"',\n gap: 12,\n padding: 12,\n background: theme.bgPrimary,\n color: theme.textPrimary,\n};\n\nconst PANE_BASE_STYLE: CSSProperties = {\n border: `1px solid ${theme.border}`,\n borderRadius: 6,\n background: theme.bgSecondary,\n overflow: \"auto\",\n minHeight: 0, // permit shrinking inside grid\n};\n\nfunction Pane({ area, children }: { area: string; children: React.ReactNode }) {\n // Wrap each pane as an accessibility landmark so screen readers can\n // jump between panels.\n return (\n <div role=\"region\" aria-label={area} style={{ ...PANE_BASE_STYLE, gridArea: area }}>\n {children}\n </div>\n );\n}\n","/**\n * RunSlider — time-travel cursor over the commit timeline.\n *\n * Implements the **ONE-CURSOR** model from the Lens architecture: the\n * slider position IS the same `runtimeStageId` cursor that selection\n * uses everywhere else (chain view, inspectors). Moving the slider\n * advances the cursor; clicking a commit in the chain view moves the\n * slider. Same underlying state, two affordances.\n *\n * Internal mapping\n * ────────────────\n * Slider value is a `commitIdx` integer in `[0, commits.length - 1]`.\n * - slider value N ↔ `commits[N].runtimeStageId` (the cursor)\n * - cursor === null ↔ slider at value 0 (initial/empty state)\n *\n * When `commits[]` grows mid-run the slider's max bound expands\n * automatically (`index.commits.length` re-evaluates on every\n * render via the consumer's `useTranslator` subscription). The\n * cursor does NOT auto-advance — consumers that want \"follow latest\n * commit\" behavior wire a `useEffect` on `index.commits.length`.\n *\n * @example\n * ```tsx\n * const [cursor, setCursor] = useState<RuntimeStageId | null>(null);\n * const index = useTranslator(commitFlow, () => commitFlow.getIndex());\n * return (\n * <RunSlider\n * index={index}\n * cursorRuntimeStageId={cursor}\n * onCursorChange={setCursor}\n * />\n * );\n * ```\n *\n * @example Follow-latest behavior (consumer-owned)\n * ```tsx\n * useEffect(() => {\n * const last = index.commits[index.commits.length - 1];\n * if (last) setCursor(last.runtimeStageId);\n * }, [index.commits.length]);\n * ```\n *\n * Pairs with `<CommitChainView>` (via shared `revealedThroughCommitIdx`\n * to dim future commits) and `<TraceExplorerShell>` (which wires the\n * slider as a top bar driving the same cursor as the chain selection).\n */\n\nimport { useCallback, useMemo } from \"react\";\nimport type { CommitFlowIndex, CommitView } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface RunSliderProps extends BaseComponentProps {\n /** Live commit flow index (pure data prop — pass via\n * `useTranslator(commitFlow, () => commitFlow.getIndex())`).\n * Source: `createCommitFlowRecorder` — see `<CommitInspector>` for\n * the canonical consumer pattern. */\n index: CommitFlowIndex;\n /** The shared time cursor. `null` = no commit yet selected (slider\n * sits at value 0). */\n cursorRuntimeStageId: RuntimeStageId | null;\n /** Fires when the slider moves. */\n onCursorChange: (rsid: RuntimeStageId | null) => void;\n /** Optional label callback. Default renders `\"#commitIdx · stageId\"`.\n * Receives the full resolved `commit` + the `index` for richer\n * labels (step name, duration from a sibling translator, etc.). */\n renderLabel?: (info: {\n commitIdx: number;\n total: number;\n runtimeStageId: RuntimeStageId | null;\n /** Resolved commit at the cursor, or `null` when index is empty. */\n commit: CommitView | null;\n /** Full index — for cross-lookups (e.g., finding the previous\n * commit's stage label). */\n index: CommitFlowIndex;\n }) => React.ReactNode;\n}\n\nexport function RunSlider({\n index,\n cursorRuntimeStageId,\n onCursorChange,\n renderLabel,\n className,\n style,\n}: RunSliderProps) {\n const total = index.commits.length;\n\n // Map cursor → slider value. If cursor is null OR unknown to the\n // index, value 0 (placeholder).\n const cursorCommitIdx = useMemo<number>(() => {\n if (!cursorRuntimeStageId) return 0;\n const view = index.byRuntimeStageId.get(cursorRuntimeStageId);\n return view ? view.commitIdx : 0;\n }, [index, cursorRuntimeStageId]);\n\n const handleSliderChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = Number(e.target.value);\n const view = index.commits[value];\n onCursorChange(view ? view.runtimeStageId : null);\n },\n [index, onCursorChange],\n );\n\n const label = useMemo(() => {\n const commit = index.commits[cursorCommitIdx] ?? null;\n const rsid = cursorRuntimeStageId ?? commit?.runtimeStageId ?? null;\n if (renderLabel)\n return renderLabel({\n commitIdx: cursorCommitIdx,\n total,\n runtimeStageId: rsid,\n commit,\n index,\n });\n if (total === 0) return <span style={{ color: theme.textMuted }}>No commits yet</span>;\n return (\n <span style={{ fontFamily: \"monospace\", fontSize: 11, color: theme.textSecondary }}>\n #{cursorCommitIdx + 1} / {total} · {commit?.runtimeStageId ?? \"—\"}\n </span>\n );\n }, [renderLabel, cursorCommitIdx, total, index, cursorRuntimeStageId]);\n\n // Disabled state — slider is non-interactive when there are 0 or 1\n // commits (sliding has no effect).\n const disabled = total < 2;\n\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 12,\n padding: \"8px 12px\",\n background: theme.bgSecondary,\n border: `1px solid ${theme.border}`,\n borderRadius: 6,\n ...style,\n }}\n >\n <span\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n }}\n >\n Time\n </span>\n <input\n type=\"range\"\n min={0}\n max={Math.max(0, total - 1)}\n step={1}\n value={Math.min(cursorCommitIdx, Math.max(0, total - 1))}\n onChange={handleSliderChange}\n disabled={disabled}\n aria-label=\"Commit time cursor\"\n aria-valuemin={0}\n aria-valuemax={Math.max(0, total - 1)}\n aria-valuenow={cursorCommitIdx}\n aria-valuetext={\n total === 0 ? \"no commits\" : `commit ${cursorCommitIdx + 1} of ${total}`\n }\n style={{ flex: 1, accentColor: theme.success }}\n />\n <div style={{ minWidth: 200, textAlign: \"right\" }}>{label}</div>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","StageNode","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","v","v","import_react","import_react","padding","import_jsx_runtime","import_jsx_runtime","nodeTypes","import_jsx_runtime","import_react","import_jsx_runtime","SubflowBreadcrumb","import_react","EMPTY_GRAPH","import_react","import_jsx_runtime","TreeNode","SectionLabel","SubflowTree","baseStageIdOf","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","Section","v","n","v","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/flowchart.ts","../src/components/StageNode/StageNode.tsx","../src/theme/ThemeProvider.tsx","../src/theme/tokens.ts","../src/theme/styles.ts","../src/theme/useDarkModeTokens.ts","../src/components/TimeTravelDebugger/TimeTravelDebugger.tsx","../src/components/MemoryInspector/MemoryInspector.tsx","../src/components/NarrativeLog/NarrativeLog.tsx","../src/components/GanttTimeline/GanttTimeline.tsx","../src/components/FlowchartView/TraceFlow.tsx","../src/components/FlowchartView/TracedFlow.tsx","../src/components/FlowchartView/_internal/devWarn.ts","../src/components/FlowchartView/_internal/notifyChange.ts","../src/components/FlowchartView/createTraceRuntimeOverlay.ts","../src/components/FlowchartView/_internal/subflowDrill.ts","../src/components/FlowchartView/_internal/overlayProjection.ts","../src/components/FlowchartView/_internal/useSubflowDrill.ts","../src/components/FlowchartView/_internal/useChartAutoRefit.ts","../src/components/FlowchartView/SubflowBreadcrumbBar.tsx","../src/components/FlowchartView/SubflowBreadcrumb.tsx","../src/components/FlowchartView/useSubflowNavigation.ts","../src/components/FlowchartView/SubflowTree.tsx","../src/components/FlowchartView/_internal/keys.ts","../src/components/FlowchartView/_internal/walkSubflowSpecInto.ts","../src/components/FlowchartView/traceStructureRecorder.ts","../src/components/FlowchartView/createNodeViewRecorder.ts","../src/components/FlowchartView/createCommitFlowRecorder.ts","../src/components/FlowchartView/createTraceBundle.ts","../src/components/FlowchartView/_internal/useTranslator.ts","../src/components/FlowchartView/walkHelpers.ts","../src/components/FlowchartView/NodeInspector.tsx","../src/components/FlowchartView/CommitInspector.tsx","../src/components/FlowchartView/buildCommitChainTree.ts","../src/components/FlowchartView/CommitChainView.tsx","../src/components/FlowchartView/TraceExplorerShell.tsx","../src/components/FlowchartView/RunSlider.tsx"],"sourcesContent":["// Flowchart components (require @xyflow/react peer dependency)\n// Import from \"footprint-explainable-ui/flowchart\"\n//\n// v6+: recorder-driven only. The legacy spec-walk path was deleted.\n// Drive the chart via `createTraceStructureRecorder` →\n// `<TraceFlow graph={...} />` (build-time) or\n// `<TracedFlow graph={...} overlay={...} scrubIndex={...} />`\n// (build + runtime).\n\nexport { StageNode } from \"./components/StageNode\";\nexport type { StageNodeData } from \"./components/StageNode\";\n\nexport { TimeTravelDebugger } from \"./components/TimeTravelDebugger\";\nexport type { TimeTravelDebuggerProps } from \"./components/TimeTravelDebugger\";\n\n// Subflow drill-down navigation (recorder-driven)\nexport { SubflowBreadcrumb } from \"./components/FlowchartView\";\nexport type { SubflowBreadcrumbProps } from \"./components/FlowchartView\";\nexport { useSubflowNavigation } from \"./components/FlowchartView\";\nexport type { SubflowNavigation, BreadcrumbEntry } from \"./components/FlowchartView\";\n\n// Subflow manifest tree (no ReactFlow dependency — pure React)\nexport { SubflowTree } from \"./components/FlowchartView\";\nexport type { SubflowTreeProps, SubflowTreeEntry } from \"./components/FlowchartView\";\n\n// v6.0+ — event-driven trace recorder + xyflow renderer (StructureRecorder\n// consumer pattern, no spec-tree post-walk required).\nexport { createTraceStructureRecorder } from \"./components/FlowchartView\";\nexport type {\n MinimalStructureRecorder,\n TraceNode,\n TraceEdge,\n TraceNodeData,\n TraceEdgeData,\n TraceGraph,\n TraceStructureRecorderHandle,\n CreateTraceStructureRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport { TraceFlow, defaultTraceFlowLayout } from \"./components/FlowchartView\";\nexport type {\n TraceFlowProps,\n TraceFlowLayout,\n TraceFlowEdgeColors,\n} from \"./components/FlowchartView\";\n\n// v7.0 — runtime overlay recorder + traced (build+runtime) component.\n// Pair with createTraceStructureRecorder for the full time-travel\n// trace UI without spec-tree post-walks.\nexport { createTraceRuntimeOverlay, sliceOverlay } from \"./components/FlowchartView\";\nexport type {\n MinimalFlowRecorder,\n RuntimeExecutionStep,\n RuntimeOverlay,\n RuntimeOverlaySlice,\n TraceRuntimeOverlayHandle,\n CreateTraceRuntimeOverlayOptions,\n} from \"./components/FlowchartView\";\n\nexport { TracedFlow } from \"./components/FlowchartView\";\nexport type { TracedFlowProps, TracedFlowColors } from \"./components/FlowchartView\";\n\n// L8.0 — landing strip exports.\nexport { createTraceBundle } from \"./components/FlowchartView\";\nexport type {\n TraceBundle,\n CreateTraceBundleOptions,\n} from \"./components/FlowchartView\";\n\nexport { useTranslator } from \"./components/FlowchartView\";\nexport type { TranslatorHandleLike } from \"./components/FlowchartView\";\n\nexport { asStageId, asRuntimeStageId } from \"./components/FlowchartView\";\nexport type { StageId, RuntimeStageId } from \"./components/FlowchartView\";\n\n// L8.1 — NodeView translator + traversal helpers + inspector renderer\nexport { createNodeViewRecorder } from \"./components/FlowchartView\";\nexport type {\n MinimalNodeViewRecorder,\n NodeView,\n NodeViewIndex,\n ExecutionRecord,\n NodeViewRecorderHandle,\n CreateNodeViewRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport {\n walkForward,\n walkBackward,\n backtraceStructural,\n forwardtraceStructural,\n} from \"./components/FlowchartView\";\nexport type { WalkOptions } from \"./components/FlowchartView\";\n\nexport { NodeInspector } from \"./components/FlowchartView\";\nexport type { NodeInspectorProps } from \"./components/FlowchartView\";\n\n// L8.2 — CommitFlow translator + data-lineage backtrace + inspector\nexport {\n createCommitFlowRecorder,\n backtraceDataFlow,\n} from \"./components/FlowchartView\";\nexport type {\n MinimalCommitFlowRecorder,\n CommitView,\n CommitFlowIndex,\n DataDependency,\n CommitFlowRecorderHandle,\n CreateCommitFlowRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport { CommitInspector } from \"./components/FlowchartView\";\nexport type { CommitInspectorProps } from \"./components/FlowchartView\";\n\n// L8.3 — series-parallel chain tree builders + git-log swim-lane renderer\nexport {\n structureAsChainTree,\n buildCommitChainTree,\n} from \"./components/FlowchartView\";\nexport type {\n StructureChain,\n StructureChainLeaf,\n CommitChain,\n CommitChainLeaf,\n ChainTreeOptions,\n} from \"./components/FlowchartView\";\n\nexport { CommitChainView } from \"./components/FlowchartView\";\nexport type { CommitChainViewProps } from \"./components/FlowchartView\";\n\n// L8.4 — composed shell wiring the full L8 stack into a master/detail UI\nexport { TraceExplorerShell } from \"./components/FlowchartView\";\nexport type {\n TraceExplorerShellProps,\n TraceExplorerSlots,\n ChainSlotProps,\n CommitInspectorSlotProps,\n NodeInspectorSlotProps,\n SliderSlotProps,\n} from \"./components/FlowchartView\";\n\n// L8.5 — time-travel cursor slider (ONE-CURSOR model)\nexport { RunSlider } from \"./components/FlowchartView\";\nexport type { RunSliderProps } from \"./components/FlowchartView\";\n","import { memo, useEffect, useRef } from \"react\";\nimport { Handle, Position } from \"@xyflow/react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport { theme } from \"../../theme\";\n\nconst KEYFRAMES_ID = \"fp-stage-node-keyframes\";\nconst KEYFRAMES_CSS = `\n@media (prefers-reduced-motion: no-preference) {\n @keyframes fp-pulse {\n 0%, 100% { opacity: 0.4; transform: scale(1); }\n 50% { opacity: 0.15; transform: scale(1.06); }\n }\n @keyframes fp-blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n}\n@media (prefers-reduced-motion: reduce) {\n @keyframes fp-pulse { 0%, 100% { opacity: 0.3; } }\n @keyframes fp-blink { 0%, 100% { opacity: 1; } }\n}\n`;\n\nexport interface StageNodeData {\n label: string;\n active?: boolean;\n done?: boolean;\n error?: boolean;\n linked?: boolean;\n /** Semantic icon hint (e.g., \"llm\", \"tool\", \"rag\", \"start\", \"parse\", \"agent\", \"guard\") */\n icon?: string;\n /** Step numbers in execution order (shown as badges — multiple when revisited via loops) */\n stepNumbers?: number[];\n /** Node was not executed (dim it) */\n dimmed?: boolean;\n /** Node is a subflow root (show nested indicator) */\n isSubflow?: boolean;\n /** Node uses lazy resolution (dashed border + cloud icon when unresolved) */\n isLazy?: boolean;\n /** Node is a decider (renders as diamond shape per flowchart convention) */\n isDecider?: boolean;\n /** Node is a fork (parallel fan-out) */\n isFork?: boolean;\n /** Human-readable description of what this stage does */\n description?: string;\n /** Subflow identifier — set when this node belongs to a subflow */\n subflowId?: string;\n /**\n * Stable stage identifier from the spec (`SpecNode.id`). Renderable as a\n * small monospace caption under the label when `showStageId` is true —\n * useful for teaching the runtimeStageId convention and for debugging\n * which node a recorder event belongs to.\n */\n stageId?: string;\n /**\n * When true, render the `stageId` as a small monospace caption beneath\n * the label. Default false. Drives the \"Show IDs\" toggle in\n * ExplainableShell.\n */\n showStageId?: boolean;\n [key: string]: unknown;\n}\n\n// ── Stage icon SVGs ───────────────────────────────────────────────────────\n// Inline SVGs for crisp rendering at any size. Consumers pass a string key\n// via SpecNode.icon; StageNode renders the matching mini-icon.\n\nconst ICON_SIZE = 16;\n\nfunction StageIcon({ type, color }: { type: string; color: string }) {\n const s = ICON_SIZE;\n const props = { width: s, height: s, viewBox: `0 0 ${s} ${s}`, fill: \"none\", style: { flexShrink: 0 } as const };\n\n switch (type) {\n // LLM / AI call — brain/sparkle\n case \"llm\":\n case \"ai\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"8\" r=\"6\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M5.5 8C5.5 6.5 6.5 5 8 5S10.5 6.5 10.5 8\" stroke={color} strokeWidth=\"1.2\" strokeLinecap=\"round\" />\n <circle cx=\"8\" cy=\"9.5\" r=\"1\" fill={color} />\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"3.5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"12.5\" y1=\"4\" x2=\"11.2\" y2=\"5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"3.5\" y1=\"4\" x2=\"4.8\" y2=\"5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Tool / function call — gear\n case \"tool\":\n case \"function\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"8\" r=\"3\" stroke={color} strokeWidth=\"1.5\" />\n {[0, 45, 90, 135, 180, 225, 270, 315].map((angle) => {\n const rad = (angle * Math.PI) / 180;\n const x1 = 8 + Math.cos(rad) * 4.5;\n const y1 = 8 + Math.sin(rad) * 4.5;\n const x2 = 8 + Math.cos(rad) * 6;\n const y2 = 8 + Math.sin(rad) * 6;\n return <line key={angle} x1={x1} y1={y1} x2={x2} y2={y2} stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />;\n })}\n </svg>\n );\n\n // RAG / retrieval — magnifying glass + doc\n case \"rag\":\n case \"search\":\n case \"retrieval\":\n return (\n <svg {...props}>\n <circle cx=\"7\" cy=\"7\" r=\"4\" stroke={color} strokeWidth=\"1.5\" />\n <line x1=\"10\" y1=\"10\" x2=\"13.5\" y2=\"13.5\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"6\" x2=\"8.5\" y2=\"6\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"8\" x2=\"7.5\" y2=\"8\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Parse / process — diamond with arrows\n case \"parse\":\n case \"process\":\n case \"transform\":\n return (\n <svg {...props}>\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" stroke={color} strokeWidth=\"1.5\" transform=\"rotate(45 8 8)\" />\n </svg>\n );\n\n // Start / seed — play triangle\n case \"start\":\n case \"seed\":\n case \"init\":\n return (\n <svg {...props}>\n <path d=\"M5 3.5L12.5 8L5 12.5V3.5Z\" fill={color} opacity=\"0.8\" />\n </svg>\n );\n\n // End / finalize — stop square\n case \"end\":\n case \"finalize\":\n case \"output\":\n return (\n <svg {...props}>\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" fill={color} opacity=\"0.8\" />\n </svg>\n );\n\n // Agent — person silhouette\n case \"agent\":\n case \"orchestrator\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"5\" r=\"2.5\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M3.5 14C3.5 11 5.5 9 8 9S12.5 11 12.5 14\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Swarm — multi-agent\n case \"swarm\":\n case \"multi-agent\":\n return (\n <svg {...props}>\n <circle cx=\"5\" cy=\"5\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <circle cx=\"11\" cy=\"5\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <circle cx=\"8\" cy=\"11\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <line x1=\"5\" y1=\"7\" x2=\"8\" y2=\"9\" stroke={color} strokeWidth=\"1\" opacity=\"0.5\" />\n <line x1=\"11\" y1=\"7\" x2=\"8\" y2=\"9\" stroke={color} strokeWidth=\"1\" opacity=\"0.5\" />\n </svg>\n );\n\n // Guard / guardrail — shield\n case \"guard\":\n case \"guardrail\":\n case \"validate\":\n return (\n <svg {...props}>\n <path d=\"M8 2L3 5V9C3 11.5 5 13.5 8 14.5C11 13.5 13 11.5 13 9V5L8 2Z\" stroke={color} strokeWidth=\"1.5\" strokeLinejoin=\"round\" />\n <path d=\"M6 8L7.5 9.5L10 6.5\" stroke={color} strokeWidth=\"1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n\n // Stream — wave\n case \"stream\":\n case \"streaming\":\n return (\n <svg {...props}>\n <path d=\"M2 8C4 5 6 11 8 8S12 5 14 8\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" fill=\"none\" />\n <path d=\"M2 11C4 8 6 14 8 11S12 8 14 11\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" fill=\"none\" opacity=\"0.5\" />\n </svg>\n );\n\n // Memory / state — database cylinder\n case \"memory\":\n case \"state\":\n case \"db\":\n return (\n <svg {...props}>\n <ellipse cx=\"8\" cy=\"4.5\" rx=\"5\" ry=\"2\" stroke={color} strokeWidth=\"1.3\" />\n <line x1=\"3\" y1=\"4.5\" x2=\"3\" y2=\"11.5\" stroke={color} strokeWidth=\"1.3\" />\n <line x1=\"13\" y1=\"4.5\" x2=\"13\" y2=\"11.5\" stroke={color} strokeWidth=\"1.3\" />\n <ellipse cx=\"8\" cy=\"11.5\" rx=\"5\" ry=\"2\" stroke={color} strokeWidth=\"1.3\" />\n </svg>\n );\n\n // Loop — circular arrow\n case \"loop\":\n case \"retry\":\n return (\n <svg {...props}>\n <path d=\"M12 8A4 4 0 1 1 8 4\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" fill=\"none\" />\n <path d=\"M8 1.5L10.5 4L8 6.5\" stroke={color} strokeWidth=\"1.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" fill=\"none\" />\n </svg>\n );\n\n // Lazy / service — cloud (deferred resolution, loaded on demand)\n case \"lazy\":\n case \"service\":\n case \"cloud\":\n return (\n <svg {...props}>\n <path\n d=\"M4.5 12C2.8 12 1.5 10.7 1.5 9C1.5 7.5 2.5 6.3 3.8 6C4 4 5.8 2.5 8 2.5C9.8 2.5 11.3 3.5 11.9 5C13.9 5.2 15.5 6.8 15.5 8.8C15.5 10.8 13.9 12.5 11.8 12.5H4.5\"\n stroke={color}\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n fill=\"none\"\n />\n </svg>\n );\n\n // Decision — diamond (already handled by isDecider shape)\n case \"decision\":\n case \"router\":\n return (\n <svg {...props}>\n <path d=\"M8 2L14 8L8 14L2 8Z\" stroke={color} strokeWidth=\"1.5\" fill=\"none\" />\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill={color} />\n </svg>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * Custom ReactFlow node for pipeline stages.\n * All colors and fonts come from `--fp-*` CSS variables (via theme).\n * Shows execution state via color, icon, step badge, and pulse animation.\n */\nexport const StageNode = memo(function StageNode({\n data,\n}: NodeProps & { data: StageNodeData }) {\n const { label, active, done, error, linked, icon, stepNumbers, dimmed, isSubflow, isLazy, isDecider, isFork, description, stageId, showStageId } = data;\n\n // Lazy nodes show cloud icon by default (unless another icon is specified)\n const effectiveIcon = icon || (isLazy ? \"lazy\" : undefined);\n // Lazy + unresolved = dashed border\n const isLazyUnresolved = isLazy && !done && !active;\n\n // Inject keyframes once into document head\n const injectedRef = useRef(false);\n useEffect(() => {\n if (injectedRef.current) return;\n if (typeof document !== \"undefined\" && !document.getElementById(KEYFRAMES_ID)) {\n const styleEl = document.createElement(\"style\");\n styleEl.id = KEYFRAMES_ID;\n styleEl.textContent = KEYFRAMES_CSS;\n document.head.appendChild(styleEl);\n }\n injectedRef.current = true;\n }, []);\n\n const isOnPath = active || done;\n\n const bg = active\n ? theme.primary\n : done\n ? theme.success\n : error\n ? theme.error\n : theme.bgSecondary;\n\n const borderColor = active\n ? theme.primary\n : done\n ? theme.success\n : error\n ? theme.error\n : theme.border;\n\n const shadow = active\n ? `0 0 16px color-mix(in srgb, ${theme.primary} 40%, transparent)`\n : done\n ? `0 0 8px color-mix(in srgb, ${theme.success} 20%, transparent)`\n : error\n ? `0 0 12px color-mix(in srgb, ${theme.error} 30%, transparent)`\n : `0 2px 8px rgba(0,0,0,0.15)`;\n\n // Colored states use white for contrast; default uses consumer's text color.\n const textColor =\n active || done || error ? \"#fff\" : theme.textPrimary;\n\n return (\n <>\n <Handle type=\"target\" position={Position.Top} style={{ opacity: 0 }} />\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n }}\n >\n {/* Step number badges — multiple when revisited via loops */}\n {stepNumbers && stepNumbers.length > 0 && isOnPath && (\n <div\n style={{\n position: \"absolute\",\n top: -10,\n left: -10,\n display: \"flex\",\n gap: 3,\n zIndex: 10,\n }}\n >\n {stepNumbers.map((num, i) => {\n const isLatest = i === stepNumbers.length - 1;\n const badgeBg = isLatest && active ? theme.primary : theme.success;\n const glow = isLatest && active\n ? `color-mix(in srgb, ${theme.primary} 50%, transparent)`\n : `color-mix(in srgb, ${theme.success} 40%, transparent)`;\n return (\n <div\n key={num}\n style={{\n width: 22,\n height: 22,\n borderRadius: \"50%\",\n background: badgeBg,\n color: \"#fff\",\n fontSize: 11,\n fontWeight: 700,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: `0 0 8px ${glow}`,\n }}\n >\n {num}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Linked pulse ring */}\n {linked && (\n <div\n style={{\n position: \"absolute\",\n inset: -6,\n borderRadius: isDecider ? 0 : `calc(${theme.radius} + 4px)`,\n clipPath: isDecider ? \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\" : undefined,\n border: `2px solid ${theme.primary}`,\n opacity: 0.4,\n animation: \"fp-pulse 2s ease-in-out infinite\",\n }}\n />\n )}\n\n {/* Active node pulse ring */}\n {active && (\n <div\n style={{\n position: \"absolute\",\n inset: -6,\n borderRadius: isDecider ? 0 : `calc(${theme.radius} + 4px)`,\n clipPath: isDecider ? \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\" : undefined,\n border: `2px solid ${theme.primary}`,\n opacity: 0.3,\n animation: \"fp-pulse 1.5s ease-out infinite\",\n }}\n />\n )}\n\n {/* Diamond for decider nodes — proper diamond via clip-path */}\n {isDecider ? (\n <div style={{ position: \"relative\", width: 120, height: 72 }}>\n {/* Diamond shape layer */}\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: bg,\n clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\",\n border: \"none\",\n boxShadow: shadow,\n transition: \"all 0.3s ease\",\n }}\n />\n {/* Border layer — slightly larger diamond behind */}\n <div\n style={{\n position: \"absolute\",\n inset: -2,\n clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\",\n background: borderColor,\n zIndex: -1,\n ...(isLazyUnresolved ? {\n background: \"transparent\",\n // Dashed border via SVG for clip-path (CSS border doesn't work with clip-path)\n } : {}),\n }}\n />\n {/* Content — centered on top of diamond */}\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 1,\n fontFamily: theme.fontSans,\n zIndex: 1,\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 4 }}>\n {effectiveIcon && <StageIcon type={effectiveIcon} color={textColor} />}\n {!effectiveIcon && (\n <span style={{ fontSize: 9, color: textColor }}>&#x25C7;</span>\n )}\n <span\n style={{\n fontSize: 11,\n fontWeight: 600,\n color: textColor,\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n </span>\n </div>\n {description && (\n <span\n style={{\n fontSize: 8,\n fontWeight: 400,\n color: textColor,\n opacity: 0.7,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 100,\n }}\n >\n {description}\n </span>\n )}\n {showStageId && stageId && (\n <span\n style={{\n fontSize: 8,\n fontFamily: \"ui-monospace, monospace\",\n color: textColor,\n opacity: 0.55,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 100,\n }}\n title={`stageId: ${stageId}`}\n >\n {stageId}\n </span>\n )}\n </div>\n </div>\n ) : (\n /* Standard rectangular node */\n <div\n style={{\n background: bg,\n border: `2px ${isLazyUnresolved ? \"dashed\" : \"solid\"} ${borderColor}`,\n borderRadius: theme.radius,\n padding: description ? \"8px 16px\" : \"10px 20px\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: description ? 2 : 0,\n boxShadow: shadow,\n transition: \"all 0.3s ease\",\n fontFamily: theme.fontSans,\n minWidth: 100,\n justifyContent: \"center\",\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n {/* Semantic icon (lazy nodes default to cloud icon) */}\n {effectiveIcon && <StageIcon type={effectiveIcon} color={textColor} />}\n\n {/* State icon */}\n {done && !effectiveIcon && (\n <span style={{ fontSize: 10, color: textColor }}>&#x2713;</span>\n )}\n {active && !effectiveIcon && (\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: \"#fff\",\n animation: \"fp-blink 1s ease-in-out infinite\",\n flexShrink: 0,\n }}\n />\n )}\n {error && !effectiveIcon && (\n <span style={{ fontSize: 10, color: textColor }}>&#x2717;</span>\n )}\n\n <span\n style={{\n fontSize: 13,\n fontWeight: 500,\n color: textColor,\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n </span>\n {/* Subflow indicator — nested boxes icon */}\n {isSubflow && (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 16,\n height: 16,\n borderRadius: 3,\n border: `1.5px solid ${textColor}`,\n position: \"relative\",\n opacity: 0.7,\n flexShrink: 0,\n }}\n >\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: 2,\n border: `1px solid ${textColor}`,\n }}\n />\n </span>\n )}\n </div>\n {/* Description subtitle */}\n {description && (\n <span\n style={{\n fontSize: 10,\n fontWeight: 400,\n color: textColor,\n opacity: 0.7,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 160,\n }}\n >\n {description}\n </span>\n )}\n {/* Stage ID caption — toggled by `showStageId`. Teaches the\n runtimeStageId convention; recorders key their data by\n this ID so consumers can render any recorder's per-stage\n output by lookup. */}\n {showStageId && stageId && (\n <span\n style={{\n fontSize: 9,\n fontFamily: \"ui-monospace, monospace\",\n color: textColor,\n opacity: 0.55,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 160,\n }}\n title={`stageId: ${stageId}`}\n >\n {stageId}\n </span>\n )}\n </div>\n )}\n </div>\n <Handle type=\"source\" position={Position.Bottom} style={{ opacity: 0 }} />\n {/* Loop handles: source exits bottom-right, target enters from right.\n Creates a clockwise arc: down → right → up → back into right side. */}\n <Handle\n id=\"loop-source\"\n type=\"source\"\n position={Position.Bottom}\n style={{ background: \"transparent\", border: \"none\", width: 6, height: 6, left: \"75%\" }}\n />\n <Handle\n id=\"loop-target\"\n type=\"target\"\n position={Position.Right}\n style={{ background: \"transparent\", border: \"none\", width: 6, height: 6 }}\n />\n </>\n );\n});\n","import { createContext, useContext } from \"react\";\nimport type { ThemeTokens } from \"./tokens\";\nimport { tokensToCSSVars } from \"./tokens\";\n\nconst ThemeContext = createContext<ThemeTokens>({});\n\nexport function useFootprintTheme(): ThemeTokens {\n return useContext(ThemeContext);\n}\n\ninterface FootprintThemeProps {\n tokens?: ThemeTokens;\n children: React.ReactNode;\n}\n\n/**\n * Optional theme provider — wraps children with CSS custom properties.\n * Consumers can also just set --fp-* CSS variables directly.\n *\n * Wrapper div uses `display: contents` so it's invisible to the\n * parent's layout (flex / grid / block). This matters because themed\n * children often need to fill a parent (flex:1 / height:100% /\n * grid cells), and a regular block `<div>` here would break that\n * chain — descendants would resolve to 0 height when the parent is\n * flex-column or a grid cell with minmax(0, 1fr). `display: contents`\n * removes the box from the render tree while keeping the DOM intact,\n * so CSS custom property inheritance (which follows the DOM) still\n * flows to children.\n *\n * Trade-off: `display: contents` elements are removed from the\n * accessibility tree in some older browser versions. Our wrapper has\n * no semantic role, so this is fine.\n */\nexport function FootprintTheme({ tokens = {}, children }: FootprintThemeProps) {\n const cssVars = tokensToCSSVars(tokens);\n\n return (\n <ThemeContext.Provider value={tokens}>\n <div\n style={{ ...(cssVars as React.CSSProperties), display: \"contents\" }}\n className=\"fp-theme-root\"\n >\n {children}\n </div>\n </ThemeContext.Provider>\n );\n}\n","/** Default theme tokens — consumers override via CSS variables or ThemeProvider. */\nexport interface ThemeTokens {\n colors?: {\n primary?: string;\n success?: string;\n error?: string;\n warning?: string;\n bgPrimary?: string;\n bgSecondary?: string;\n bgTertiary?: string;\n textPrimary?: string;\n textSecondary?: string;\n textMuted?: string;\n border?: string;\n };\n radius?: string;\n fontFamily?: {\n sans?: string;\n mono?: string;\n };\n}\n\n/** Maps ThemeTokens to CSS custom property assignments. */\nexport function tokensToCSSVars(tokens: ThemeTokens): Record<string, string> {\n const vars: Record<string, string> = {};\n if (tokens.colors) {\n const c = tokens.colors;\n if (c.primary) vars[\"--fp-color-primary\"] = c.primary;\n if (c.success) vars[\"--fp-color-success\"] = c.success;\n if (c.error) vars[\"--fp-color-error\"] = c.error;\n if (c.warning) vars[\"--fp-color-warning\"] = c.warning;\n if (c.bgPrimary) vars[\"--fp-bg-primary\"] = c.bgPrimary;\n if (c.bgSecondary) vars[\"--fp-bg-secondary\"] = c.bgSecondary;\n if (c.bgTertiary) vars[\"--fp-bg-tertiary\"] = c.bgTertiary;\n if (c.textPrimary) vars[\"--fp-text-primary\"] = c.textPrimary;\n if (c.textSecondary) vars[\"--fp-text-secondary\"] = c.textSecondary;\n if (c.textMuted) vars[\"--fp-text-muted\"] = c.textMuted;\n if (c.border) vars[\"--fp-border\"] = c.border;\n }\n if (tokens.radius) vars[\"--fp-radius\"] = tokens.radius;\n if (tokens.fontFamily?.sans) vars[\"--fp-font-sans\"] = tokens.fontFamily.sans;\n if (tokens.fontFamily?.mono) vars[\"--fp-font-mono\"] = tokens.fontFamily.mono;\n return vars;\n}\n\n/** Raw fallback values — used by tokensToCSSVars() and anywhere a real color is needed. */\nexport const rawDefaults = {\n colors: {\n primary: \"#6366f1\",\n success: \"#22c55e\",\n error: \"#ef4444\",\n warning: \"#f59e0b\",\n bgPrimary: \"#0f172a\",\n bgSecondary: \"#1e293b\",\n bgTertiary: \"#334155\",\n textPrimary: \"#f8fafc\",\n textSecondary: \"#94a3b8\",\n textMuted: \"#64748b\",\n border: \"#334155\",\n },\n radius: \"8px\",\n fontFamily: {\n sans: \"Inter, system-ui, -apple-system, sans-serif\",\n mono: \"'JetBrains Mono', 'Fira Code', monospace\",\n },\n} as const;\n\n/** Default dark theme values with CSS variable references (consumers can override via CSS). */\nexport const defaultTokens: Required<{\n [K in keyof ThemeTokens]-?: Required<ThemeTokens[K]>;\n}> = {\n colors: {\n primary: `var(--fp-color-primary, ${rawDefaults.colors.primary})`,\n success: `var(--fp-color-success, ${rawDefaults.colors.success})`,\n error: `var(--fp-color-error, ${rawDefaults.colors.error})`,\n warning: `var(--fp-color-warning, ${rawDefaults.colors.warning})`,\n bgPrimary: `var(--fp-bg-primary, ${rawDefaults.colors.bgPrimary})`,\n bgSecondary: `var(--fp-bg-secondary, ${rawDefaults.colors.bgSecondary})`,\n bgTertiary: `var(--fp-bg-tertiary, ${rawDefaults.colors.bgTertiary})`,\n textPrimary: `var(--fp-text-primary, ${rawDefaults.colors.textPrimary})`,\n textSecondary: `var(--fp-text-secondary, ${rawDefaults.colors.textSecondary})`,\n textMuted: `var(--fp-text-muted, ${rawDefaults.colors.textMuted})`,\n border: `var(--fp-border, ${rawDefaults.colors.border})`,\n },\n radius: `var(--fp-radius, ${rawDefaults.radius})`,\n fontFamily: {\n sans: `var(--fp-font-sans, ${rawDefaults.fontFamily.sans})`,\n mono: `var(--fp-font-mono, ${rawDefaults.fontFamily.mono})`,\n },\n};\n","import type { Size } from \"../types\";\n\n/**\n * Helper to resolve a CSS variable with a fallback.\n * Usage: v(\"--fp-color-primary\", \"#6366f1\")\n */\nexport function v(varName: string, fallback: string): string {\n return `var(${varName}, ${fallback})`;\n}\n\n/** Shorthand for common theme variables */\nexport const theme = {\n primary: v(\"--fp-color-primary\", \"#6366f1\"),\n success: v(\"--fp-color-success\", \"#22c55e\"),\n error: v(\"--fp-color-error\", \"#ef4444\"),\n warning: v(\"--fp-color-warning\", \"#f59e0b\"),\n bgPrimary: v(\"--fp-bg-primary\", \"#0f172a\"),\n bgSecondary: v(\"--fp-bg-secondary\", \"#1e293b\"),\n bgTertiary: v(\"--fp-bg-tertiary\", \"#334155\"),\n textPrimary: v(\"--fp-text-primary\", \"#f8fafc\"),\n textSecondary: v(\"--fp-text-secondary\", \"#94a3b8\"),\n textMuted: v(\"--fp-text-muted\", \"#64748b\"),\n border: v(\"--fp-border\", \"#334155\"),\n radius: v(\"--fp-radius\", \"8px\"),\n fontSans: v(\"--fp-font-sans\", \"Inter, system-ui, -apple-system, sans-serif\"),\n fontMono: v(\"--fp-font-mono\", \"'JetBrains Mono', 'Fira Code', monospace\"),\n} as const;\n\n/** Font sizes per size variant */\nexport const fontSize: Record<Size, { label: number; body: number; small: number }> = {\n compact: { label: 10, body: 11, small: 9 },\n default: { label: 11, body: 12, small: 10 },\n detailed: { label: 12, body: 13, small: 11 },\n};\n\n/** Padding per size variant */\nexport const padding: Record<Size, number> = {\n compact: 8,\n default: 12,\n detailed: 16,\n};\n","/**\n * useDarkModeTokens — Auto-bridge between CSS class-based dark mode and FootprintTheme.\n *\n * Watches for a `.dark` class on <html> (Tailwind convention) and returns\n * the appropriate ThemeTokens preset. Pairs with FootprintTheme:\n *\n * import { FootprintTheme, useDarkModeTokens } from 'footprint-explainable-ui';\n *\n * function MyApp() {\n * const tokens = useDarkModeTokens();\n * return (\n * <FootprintTheme tokens={tokens}>\n * <NarrativeTrace ... />\n * </FootprintTheme>\n * );\n * }\n *\n * Consumers can override the light/dark presets:\n *\n * const tokens = useDarkModeTokens({ light: warmLight, dark: warmDark });\n */\n\nimport { useState, useEffect } from \"react\";\nimport type { ThemeTokens } from \"./tokens\";\nimport { coolDark } from \"./presets\";\nimport { coolLight } from \"./presets\";\n\nexport interface DarkModeTokensOptions {\n /** Tokens to use in light mode. Defaults to coolLight. */\n light?: ThemeTokens;\n /** Tokens to use in dark mode. Defaults to coolDark. */\n dark?: ThemeTokens;\n /** CSS selector to watch for dark mode. Defaults to checking .dark on documentElement. */\n selector?: string;\n}\n\nexport function useDarkModeTokens(options?: DarkModeTokensOptions): ThemeTokens {\n const lightTokens = options?.light ?? coolLight;\n const darkTokens = options?.dark ?? coolDark;\n\n const [isDark, setIsDark] = useState(\n () => document.documentElement.classList.contains(options?.selector ?? \"dark\"),\n );\n\n useEffect(() => {\n const cls = options?.selector ?? \"dark\";\n const obs = new MutationObserver(() => {\n setIsDark(document.documentElement.classList.contains(cls));\n });\n obs.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n return () => obs.disconnect();\n }, [options?.selector]);\n\n return isDark ? darkTokens : lightTokens;\n}\n","import { useState } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\nimport { MemoryInspector } from \"../MemoryInspector\";\nimport { NarrativeLog } from \"../NarrativeLog\";\nimport { GanttTimeline } from \"../GanttTimeline\";\nimport { TraceFlow } from \"../FlowchartView/TraceFlow\";\nimport { TracedFlow } from \"../FlowchartView/TracedFlow\";\nimport type { TraceGraph } from \"../FlowchartView/traceStructureRecorder\";\nimport type { RuntimeOverlay } from \"../FlowchartView/createTraceRuntimeOverlay\";\n\nexport interface TimeTravelDebuggerProps extends BaseComponentProps {\n /** Stage snapshots */\n snapshots: StageSnapshot[];\n /** Recorder-captured build-time graph (from\n * `createTraceStructureRecorder().getGraph()`). Required for the\n * chart rendering — replaces the legacy `nodes` / `edges` props. */\n graph: TraceGraph;\n /** Optional runtime overlay (from\n * `createTraceRuntimeOverlay().getOverlay()`). When provided, the\n * chart renders via `<TracedFlow>` with per-step coloring synced to\n * the scrubber; otherwise renders via `<TraceFlow>` (build-time only). */\n runtimeOverlay?: RuntimeOverlay;\n /** Show Gantt timeline */\n showGantt?: boolean;\n /** Layout direction */\n layout?: \"horizontal\" | \"vertical\";\n /** Title */\n title?: string;\n}\n\n/**\n * Full time-travel debugger: scrubber + recorder-driven flowchart +\n * memory + narrative + gantt. This is the \"batteries included\"\n * component for pipeline debugging.\n *\n * v6+: chart rendering is recorder-driven. Pass `graph` (always) and\n * optionally `runtimeOverlay` for per-step coloring tied to the\n * scrubber.\n */\nexport function TimeTravelDebugger({\n snapshots,\n graph,\n runtimeOverlay,\n showGantt = true,\n layout = \"horizontal\",\n title = \"Time-Travel Debugger\",\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: TimeTravelDebuggerProps) {\n const [selectedIndex, setSelectedIndex] = useState(0);\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (snapshots.length === 0) {\n return (\n <div\n className={className}\n style={{\n padding: pad * 2,\n textAlign: \"center\",\n color: theme.textMuted,\n ...style,\n }}\n >\n No snapshots to debug\n </div>\n );\n }\n\n const isHorizontal = layout === \"horizontal\";\n\n // Click → jump scrubber to whichever snapshot maps to the clicked\n // stage. Matches the legacy `onNodeClick(index)` semantics: callers\n // receive a stage id, we translate to a snapshot index.\n const handleNodeClick = (stageId: string) => {\n const idx = snapshots.findIndex(\n (s) => s.stageName === stageId || s.stageLabel === stageId,\n );\n if (idx >= 0) setSelectedIndex(idx);\n };\n\n const chart = runtimeOverlay ? (\n <TracedFlow\n graph={graph}\n overlay={runtimeOverlay}\n scrubIndex={selectedIndex}\n onNodeClick={handleNodeClick}\n />\n ) : (\n <TraceFlow graph={graph} onNodeClick={handleNodeClick} />\n );\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"time-travel-debugger\">\n <h3>{title}</h3>\n <input\n type=\"range\"\n min={0}\n max={snapshots.length - 1}\n value={selectedIndex}\n onChange={(e) => setSelectedIndex(parseInt(e.target.value))}\n />\n {chart}\n <MemoryInspector\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n unstyled\n />\n <NarrativeLog\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n unstyled\n />\n {showGantt && (\n <GanttTimeline\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onSelect={setSelectedIndex}\n unstyled\n />\n )}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n background: theme.bgPrimary,\n fontFamily: theme.fontSans,\n overflow: \"hidden\",\n ...style,\n }}\n data-fp=\"time-travel-debugger\"\n >\n {/* Scrubber header */}\n <div\n style={{\n padding: `${pad}px ${pad + 4}px`,\n borderBottom: `1px solid ${theme.border}`,\n background: theme.bgSecondary,\n flexShrink: 0,\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n marginBottom: 8,\n }}\n >\n <span\n style={{\n fontSize: fs.body + 2,\n fontWeight: 600,\n color: theme.textPrimary,\n }}\n >\n {title}\n </span>\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n }}\n >\n Scrub to replay execution\n </span>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <ScrubButton\n label=\"◀\"\n disabled={selectedIndex === 0}\n onClick={() => setSelectedIndex((i) => Math.max(0, i - 1))}\n />\n <input\n type=\"range\"\n min={0}\n max={snapshots.length - 1}\n value={selectedIndex}\n onChange={(e) => setSelectedIndex(parseInt(e.target.value))}\n style={{\n flex: 1,\n height: 4,\n accentColor: theme.primary,\n cursor: \"pointer\",\n }}\n />\n <ScrubButton\n label=\"▶\"\n disabled={selectedIndex === snapshots.length - 1}\n onClick={() =>\n setSelectedIndex((i) => Math.min(snapshots.length - 1, i + 1))\n }\n />\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n flexShrink: 0,\n fontFamily: theme.fontMono,\n }}\n >\n {selectedIndex + 1}/{snapshots.length}\n </span>\n </div>\n </div>\n\n {/* Main content: flowchart + data panels */}\n <div\n style={{\n flex: 1,\n display: \"flex\",\n flexDirection: isHorizontal ? \"row\" : \"column\",\n overflow: \"hidden\",\n }}\n >\n {/* Flowchart */}\n <div\n style={{\n flex: 1,\n overflow: \"hidden\",\n borderRight: isHorizontal\n ? `1px solid ${theme.border}`\n : \"none\",\n borderBottom: !isHorizontal\n ? `1px solid ${theme.border}`\n : \"none\",\n }}\n >\n {chart}\n </div>\n\n {/* Data panel */}\n <div style={{ flex: 1, overflow: \"auto\" }}>\n <MemoryInspector\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n size={size}\n />\n <div\n style={{\n height: 1,\n background: theme.border,\n margin: `0 ${pad}px`,\n }}\n />\n <NarrativeLog\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n size={size}\n />\n </div>\n </div>\n\n {/* Gantt footer */}\n {showGantt && (\n <div\n style={{\n borderTop: `1px solid ${theme.border}`,\n background: theme.bgSecondary,\n flexShrink: 0,\n }}\n >\n <GanttTimeline\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onSelect={setSelectedIndex}\n size={size}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction ScrubButton({\n label,\n disabled,\n onClick,\n}: {\n label: string;\n disabled: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n onClick={onClick}\n disabled={disabled}\n style={{\n background: theme.bgTertiary,\n border: `1px solid ${theme.border}`,\n color: disabled ? theme.textMuted : theme.textPrimary,\n borderRadius: 6,\n width: 28,\n height: 28,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: disabled ? \"not-allowed\" : \"pointer\",\n opacity: disabled ? 0.5 : 1,\n fontSize: 12,\n flexShrink: 0,\n }}\n >\n {label}\n </button>\n );\n}\n","import { useMemo, useRef } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface MemoryInspectorProps extends BaseComponentProps {\n /** Single memory object or snapshots (will accumulate up to selectedIndex) */\n data?: Record<string, unknown>;\n /** When using snapshots mode, pass these instead of data */\n snapshots?: StageSnapshot[];\n /** Index to accumulate up to (for time-travel) */\n selectedIndex?: number;\n /** Show data types alongside values */\n showTypes?: boolean;\n /** Highlight keys that are new at this step */\n highlightNew?: boolean;\n}\n\n/** Cache for incremental memory accumulation — avoids O(n) rebuild on every slider scrub. */\ninterface MemoryCache {\n snapshots: StageSnapshot[];\n index: number;\n accumulated: Record<string, unknown>;\n}\n\n/**\n * Displays pipeline memory state as formatted JSON.\n * Supports both static (data prop) and time-travel (snapshots + selectedIndex) modes.\n */\nexport function MemoryInspector({\n data,\n snapshots,\n selectedIndex = 0,\n showTypes = false,\n highlightNew = true,\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: MemoryInspectorProps) {\n // Incremental cache: accumulate forward from last known index instead of rebuilding from 0\n const cacheRef = useRef<MemoryCache | null>(null);\n\n const { memory, newKeys } = useMemo(() => {\n if (data) {\n return { memory: data, newKeys: new Set<string>() };\n }\n if (!snapshots || snapshots.length === 0) {\n return { memory: {}, newKeys: new Set<string>() };\n }\n\n const safeIdx = Math.min(selectedIndex, snapshots.length - 1);\n let merged: Record<string, unknown>;\n const cache = cacheRef.current;\n\n if (cache && cache.snapshots === snapshots && cache.index <= safeIdx) {\n // Forward scrub: extend from cached state\n merged = { ...cache.accumulated };\n for (let i = cache.index + 1; i <= safeIdx; i++) {\n Object.assign(merged, snapshots[i]?.memory);\n }\n } else {\n // Backward scrub or new snapshots: rebuild from scratch\n merged = {};\n for (let i = 0; i <= safeIdx; i++) {\n Object.assign(merged, snapshots[i]?.memory);\n }\n }\n\n // Update cache\n cacheRef.current = { snapshots, index: safeIdx, accumulated: merged };\n\n const nk = new Set<string>();\n if (highlightNew && safeIdx > 0) {\n // Previous state is cache at safeIdx-1, or rebuild if needed\n let prev: Record<string, unknown>;\n if (cache && cache.snapshots === snapshots && cache.index === safeIdx - 1) {\n prev = cache.accumulated;\n } else {\n prev = {};\n for (let i = 0; i < safeIdx; i++) {\n Object.assign(prev, snapshots[i]?.memory);\n }\n }\n const current = snapshots[safeIdx]?.memory ?? {};\n for (const k of Object.keys(current)) {\n if (!(k in prev)) nk.add(k);\n }\n } else if (highlightNew && safeIdx === 0 && snapshots[0]) {\n for (const k of Object.keys(snapshots[0].memory)) nk.add(k);\n }\n\n return { memory: merged, newKeys: nk };\n }, [data, snapshots, selectedIndex, highlightNew]);\n\n const entries = Object.entries(memory);\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"memory-inspector\" role=\"region\" aria-label=\"Memory state\">\n <div data-fp=\"memory-label\">Memory State</div>\n <pre data-fp=\"memory-json\">\n <code>{JSON.stringify(memory, null, 2)}</code>\n </pre>\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: pad,\n fontFamily: theme.fontSans,\n ...style,\n }}\n data-fp=\"memory-inspector\"\n role=\"region\"\n aria-label=\"Memory state\"\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n Memory State\n </span>\n <div\n style={{\n marginTop: 8,\n background: theme.bgSecondary,\n border: `1px solid ${theme.border}`,\n borderRadius: theme.radius,\n padding: `${pad}px ${pad + 4}px`,\n fontFamily: theme.fontMono,\n fontSize: fs.body,\n lineHeight: 1.8,\n }}\n >\n <span style={{ color: theme.textMuted }}>{\"{\"}</span>\n {entries.length === 0 && (\n <div\n style={{\n paddingLeft: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n }}\n >\n {\"// empty\"}\n </div>\n )}\n {entries.map(([key, value], i) => {\n const isNew = newKeys.has(key);\n const isLast = i === entries.length - 1;\n return (\n <div\n key={key}\n style={{\n paddingLeft: 16,\n background: isNew\n ? `color-mix(in srgb, ${theme.success} 10%, transparent)`\n : \"transparent\",\n borderRadius: 4,\n marginLeft: -4,\n marginRight: -4,\n paddingRight: 4,\n }}\n >\n <span style={{ color: theme.primary }}>&quot;{key}&quot;</span>\n <span style={{ color: theme.textMuted }}>: </span>\n <span style={{ color: theme.success }}>\n {formatValue(value)}\n </span>\n {showTypes && (\n <span\n style={{\n color: theme.textMuted,\n fontSize: fs.small,\n marginLeft: 8,\n opacity: 0.6,\n }}\n >\n ({typeof value})\n </span>\n )}\n {!isLast && <span style={{ color: theme.textMuted }}>,</span>}\n </div>\n );\n })}\n <span style={{ color: theme.textMuted }}>{\"}\"}</span>\n </div>\n </div>\n );\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") return `\"${value}\"`;\n if (typeof value === \"object\" && value !== null) return JSON.stringify(value);\n return String(value);\n}\n","import { useMemo } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface NarrativeLogProps extends BaseComponentProps {\n /** Snapshots to display narratives from */\n snapshots: StageSnapshot[];\n /** Show narratives up to this index (for time-travel sync) */\n selectedIndex?: number;\n /** Show a single narrative string (simple mode) */\n narrative?: string;\n}\n\n/**\n * Timeline-style execution log showing what happened at each stage.\n * Supports both full snapshots mode and single-narrative mode.\n */\nexport function NarrativeLog({\n snapshots,\n selectedIndex,\n narrative,\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: NarrativeLogProps) {\n const entries = useMemo(() => {\n if (narrative) {\n return [{ label: \"Output\", text: narrative, isCurrent: true }];\n }\n const idx = selectedIndex ?? snapshots.length - 1;\n return snapshots.slice(0, idx + 1).map((s, i) => ({\n label: s.stageLabel,\n text: s.narrative,\n isCurrent: i === idx,\n }));\n }, [snapshots, selectedIndex, narrative]);\n\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"narrative-log\">\n {entries.map((entry, i) => (\n <div key={i} data-fp=\"narrative-entry\" data-current={entry.isCurrent}>\n <strong>{entry.label}</strong>\n <p>{entry.text}</p>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{ padding: pad, fontFamily: theme.fontSans, ...style }}\n data-fp=\"narrative-log\"\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n Execution Log\n </span>\n <div style={{ marginTop: 8, display: \"flex\", flexDirection: \"column\" }}>\n {entries.map((entry, i) => (\n <div\n key={i}\n style={{\n display: \"flex\",\n gap: 10,\n padding: `${pad}px 0`,\n borderBottom:\n i < entries.length - 1 ? `1px solid ${theme.border}` : \"none\",\n }}\n >\n {/* Timeline dot + line */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n width: 12,\n flexShrink: 0,\n paddingTop: 5,\n }}\n >\n <div\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: entry.isCurrent ? theme.primary : theme.success,\n flexShrink: 0,\n }}\n />\n {i < entries.length - 1 && (\n <div\n style={{\n width: 1,\n flex: 1,\n background: theme.border,\n marginTop: 4,\n }}\n />\n )}\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, minWidth: 0 }}>\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: entry.isCurrent ? theme.primary : theme.textMuted,\n }}\n >\n {entry.label}\n </span>\n <div\n style={{\n fontSize: fs.body,\n lineHeight: 1.5,\n color: entry.isCurrent ? theme.textPrimary : theme.textSecondary,\n marginTop: 2,\n }}\n >\n {entry.text}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n","import { useState, useMemo, useRef, useEffect } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface GanttTimelineProps extends BaseComponentProps {\n /** Stage snapshots with timing info */\n snapshots: StageSnapshot[];\n /** Currently selected stage index */\n selectedIndex?: number;\n /** Callback when a stage bar is clicked */\n onSelect?: (index: number) => void;\n /** Max visible rows before collapsing (0 = no collapse). Default: 5 */\n maxVisibleRows?: number;\n}\n\n/**\n * Horizontal Gantt-style timeline showing stage durations and overlap.\n * Collapses to `maxVisibleRows` with expand/collapse toggle.\n * Auto-scrolls to keep the active stage visible when collapsed.\n */\nexport function GanttTimeline({\n snapshots,\n selectedIndex = 0,\n onSelect,\n size = \"default\",\n unstyled = false,\n className,\n style,\n maxVisibleRows = 5,\n}: GanttTimelineProps) {\n const [expanded, setExpanded] = useState(false);\n const activeRowRef = useRef<HTMLDivElement | null>(null);\n const scrollContainerRef = useRef<HTMLDivElement | null>(null);\n\n const totalWallTime = useMemo(\n () => Math.max(...snapshots.map((s) => s.startMs + s.durationMs), 1),\n [snapshots]\n );\n\n const fs = fontSize[size];\n const pad = padding[size];\n const labelWidth = size === \"compact\" ? 50 : size === \"detailed\" ? 100 : 80;\n const msWidth = size === \"compact\" ? 28 : 36;\n const rowHeight = size === \"compact\" ? 18 : 22;\n\n const collapsible = maxVisibleRows > 0 && snapshots.length > maxVisibleRows;\n const showAll = expanded || !collapsible;\n\n // Auto-scroll to active row when collapsed\n useEffect(() => {\n if (!showAll && activeRowRef.current && scrollContainerRef.current) {\n activeRowRef.current.scrollIntoView({\n block: \"nearest\",\n behavior: \"smooth\",\n });\n }\n }, [selectedIndex, showAll]);\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"gantt-timeline\" role=\"listbox\" aria-label=\"Execution timeline\">\n {snapshots.map((snap, idx) => (\n <div\n key={`${snap.stageName}-${idx}`}\n data-fp=\"gantt-bar\"\n data-selected={idx === selectedIndex}\n data-visible={idx <= selectedIndex}\n role=\"option\"\n aria-selected={idx === selectedIndex}\n aria-label={`${snap.stageLabel}, ${snap.durationMs}ms`}\n onClick={() => onSelect?.(idx)}\n >\n <span data-fp=\"gantt-label\">{snap.stageLabel}</span>\n <span data-fp=\"gantt-duration\">{snap.durationMs}ms</span>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{ padding: pad, fontFamily: theme.fontSans, ...style }}\n data-fp=\"gantt-timeline\"\n >\n {/* Header with collapse toggle */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n {size === \"compact\" ? \"Timeline\" : \"Execution Timeline\"}\n </span>\n {collapsible && (\n <button\n onClick={() => setExpanded((e) => !e)}\n style={{\n background: \"none\",\n border: `1px solid ${theme.border}`,\n borderRadius: 4,\n color: theme.textSecondary,\n fontSize: fs.small,\n padding: \"2px 8px\",\n cursor: \"pointer\",\n fontFamily: theme.fontSans,\n }}\n >\n {expanded\n ? \"Collapse\"\n : `${snapshots.length - maxVisibleRows} more...`}\n </button>\n )}\n </div>\n\n {/* Scrollable rows container */}\n <div\n ref={scrollContainerRef}\n role=\"listbox\"\n aria-label=\"Execution timeline\"\n style={{\n marginTop: 8,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 4,\n ...(showAll\n ? {}\n : {\n maxHeight: maxVisibleRows * (rowHeight + 4),\n overflowY: \"auto\",\n scrollbarWidth: \"thin\",\n }),\n }}\n >\n {snapshots.map((snap, idx) => {\n const leftPct = (snap.startMs / totalWallTime) * 100;\n const widthPct = Math.max((snap.durationMs / totalWallTime) * 100, 1);\n const isSelected = idx === selectedIndex;\n const isVisible = idx <= selectedIndex;\n\n return (\n <div\n key={`${snap.stageName}-${idx}`}\n ref={isSelected ? activeRowRef : undefined}\n role=\"option\"\n aria-selected={isSelected}\n aria-label={`${snap.stageLabel}, ${snap.durationMs}ms`}\n onClick={() => onSelect?.(idx)}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: size === \"compact\" ? 4 : 8,\n cursor: onSelect ? \"pointer\" : \"default\",\n opacity: isVisible ? 1 : 0.3,\n transition: \"opacity 0.3s ease\",\n height: rowHeight,\n flexShrink: 0,\n }}\n >\n <span\n title={snap.stageLabel}\n style={{\n width: labelWidth,\n fontSize: fs.small,\n color: isSelected ? theme.primary : theme.textMuted,\n fontWeight: isSelected ? 600 : 400,\n textAlign: \"right\",\n flexShrink: 0,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {snap.stageLabel}\n </span>\n <div\n style={{\n flex: 1,\n height: size === \"compact\" ? 6 : 8,\n position: \"relative\",\n background: theme.bgTertiary,\n borderRadius: 3,\n }}\n >\n {isVisible && (\n <div\n style={{\n position: \"absolute\",\n left: `${leftPct}%`,\n top: 0,\n width: `${widthPct}%`,\n height: \"100%\",\n borderRadius: 3,\n background: isSelected ? theme.primary : theme.success,\n transition: \"width 0.3s ease\",\n }}\n />\n )}\n </div>\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n fontFamily: theme.fontMono,\n width: msWidth,\n flexShrink: 0,\n }}\n >\n {snap.durationMs}ms\n </span>\n </div>\n );\n })}\n </div>\n\n {/* Time axis */}\n <div\n style={{\n marginTop: 4,\n marginLeft: labelWidth + (size === \"compact\" ? 4 : 8),\n marginRight: msWidth + (size === \"compact\" ? 4 : 8),\n display: \"flex\",\n justifyContent: \"space-between\",\n fontSize: fs.small - 1,\n color: theme.textMuted,\n fontFamily: theme.fontMono,\n }}\n >\n <span>0ms</span>\n {size !== \"compact\" && (\n <span>{(totalWallTime / 2).toFixed(1)}ms</span>\n )}\n <span>{totalWallTime.toFixed(1)}ms</span>\n </div>\n </div>\n );\n}\n","/**\n * TraceFlow — ReactFlow renderer driven by `createTraceStructureRecorder`.\n *\n * Two input modes (mutually exclusive):\n *\n * 1. **Live mode**: pass `recorder={traceHandle}`. The component\n * subscribes via `useSyncExternalStore` to the recorder's\n * pub-sub `subscribe()` API and re-renders as the builder runs.\n * Ideal for incremental visualisation (Lens-style live chart\n * construction).\n *\n * 2. **Static mode**: pass `graph={{ nodes, edges }}`. The component\n * treats the graph as final and renders once. Ideal for post-build\n * snapshots (Trace tab, docs site).\n *\n * Layout is pluggable:\n *\n * - Pass a `layout` function `(graph) => positioned graph`. Default is\n * a simple BFS tree walk (Y_STEP=100, X_SPREAD=200).\n * - Pass the literal `\"passthrough\"` to skip layout when nodes are\n * already pre-positioned by the caller.\n *\n * @example\n * ```tsx\n * import { createTraceStructureRecorder, TraceFlow } from 'footprint-explainable-ui/flowchart';\n * import { flowChart } from 'footprintjs';\n *\n * function MyTraceUI() {\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * useEffect(() => {\n * flowChart('seed', fn, 'seed', {\n * structureRecorders: [trace.recorder],\n * }).addFunction('a', fnA, 'a').build();\n * }, [trace]);\n * return <TraceFlow recorder={trace} />;\n * }\n * ```\n */\n\nimport type * as React from \"react\";\nimport { useMemo, useCallback, useSyncExternalStore } from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n MarkerType,\n} from \"@xyflow/react\";\nimport type { Node, Edge, NodeTypes, EdgeTypes } from \"@xyflow/react\";\nimport type {\n TraceGraph,\n TraceNode,\n TraceEdge,\n TraceStructureRecorderHandle,\n} from \"./traceStructureRecorder\";\nimport { StageNode } from \"../StageNode\";\nimport type { StageNodeData } from \"../StageNode\";\nimport { rawDefaults } from \"../../theme/tokens\";\nimport type { BaseComponentProps } from \"../../types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Layout\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst Y_STEP = 100;\nconst X_SPREAD = 200;\n\n/** Layout function shape — takes a graph, returns a graph with positions set. */\nexport type TraceFlowLayout = (graph: TraceGraph) => TraceGraph;\n\n/**\n * Default tree-walk layout.\n *\n * Edge-kind semantics (critical for parity)\n * ─────────────────────────────────────────\n * `fork-branch` + `decision-branch` edges are SIBLINGS at depth+1\n * (centered under the parent). A `next` edge from a node that ALSO\n * has branch edges is the \"after convergence\" target — its rank is\n * `max(deepest branch subtree) + 1`, so it sits BELOW the fan-out,\n * matching the legacy diamond layout.\n *\n * LoadOrder (fork)\n * ├── fork-branch → CheckInventory (sibling, y+1)\n * ├── fork-branch → RunFraudCheck (sibling, y+1)\n * └── next → FinalizeOrder (after convergence,\n * below deepest sibling)\n *\n * A `next` edge from a node with NO branch edges is a plain linear\n * chain — target at depth+1.\n *\n * `loop` back-edges DO NOT shape layout (they're scrub-time visual\n * markers only).\n *\n * Limitations (documented; not bugs)\n * ──────────────────────────────────\n * - Multi-root graphs render with the first-seen node as the visual\n * root; orphans stack below.\n * - Convergence where multiple branches join into a single node:\n * the node is placed under its FIRST traversed branch (first-wins).\n * For deep DAGs swap in a graph-layout library (dagre, elk).\n * - Sibling x-positions are local to each parent's subtree; no\n * global x-overlap detection across deep nested structures.\n */\nexport const defaultTraceFlowLayout: TraceFlowLayout = (graph) => {\n if (graph.nodes.length === 0) return { nodes: [], edges: graph.edges };\n\n // Split outgoing edges into two semantic groups per node:\n // - branches: fork-branch + decision-branch (siblings at y+1)\n // - linearNext: 'next' edges (after-convergence, deeper rank)\n // Loop back-edges (kind: 'loop') do NOT shape layout.\n const branchChildrenOf = new Map<string, string[]>();\n const nextChildrenOf = new Map<string, string[]>();\n const hasIncomingForward = new Set<string>();\n for (const e of graph.edges) {\n const kind = e.data?.kind;\n if (kind === \"loop\") continue;\n hasIncomingForward.add(e.target);\n if (kind === \"fork-branch\" || kind === \"decision-branch\") {\n const arr = branchChildrenOf.get(e.source) ?? [];\n arr.push(e.target);\n branchChildrenOf.set(e.source, arr);\n } else {\n // 'next' (default) — linear continuation. Treat undefined kind\n // as 'next' so forward edges without explicit kind still flow.\n const arr = nextChildrenOf.get(e.source) ?? [];\n arr.push(e.target);\n nextChildrenOf.set(e.source, arr);\n }\n }\n\n // Seed: first node (insertion order) with no incoming non-loop edge.\n const seed = graph.nodes.find((n) => !hasIncomingForward.has(n.id)) ?? graph.nodes[0]!;\n\n const positions = new Map<string, { x: number; y: number }>();\n\n /**\n * Recursive tree-walk. Returns the bottom-most y reached in this\n * subtree so the parent can position its `next` continuation BELOW\n * the deepest descendant (post-convergence semantics).\n */\n function layoutSubtree(nodeId: string, x: number, y: number): number {\n if (positions.has(nodeId)) {\n // Convergence: this node was already placed by an earlier branch.\n // Keep the original position (first-wins) and report its current\n // bottom so the caller's `next` target lands below us correctly.\n return positions.get(nodeId)!.y;\n }\n positions.set(nodeId, { x, y });\n\n // Place fork/decision branches first — they're siblings at y+1.\n let deepestBranchY = y;\n const branches = branchChildrenOf.get(nodeId) ?? [];\n if (branches.length > 0) {\n const childY = y + Y_STEP;\n const totalWidth = (branches.length - 1) * X_SPREAD;\n const startX = x - totalWidth / 2;\n for (let i = 0; i < branches.length; i++) {\n const childId = branches[i]!;\n const childX = startX + i * X_SPREAD;\n const subtreeBottom = layoutSubtree(childId, childX, childY);\n if (subtreeBottom > deepestBranchY) deepestBranchY = subtreeBottom;\n }\n }\n\n // Then place `next` continuations. If branches exist, `next` lands\n // BELOW the deepest branch (post-convergence). If no branches, it's\n // a plain linear chain — y+1.\n const nextChildren = nextChildrenOf.get(nodeId) ?? [];\n if (nextChildren.length > 0) {\n const nextY = branches.length > 0 ? deepestBranchY + Y_STEP : y + Y_STEP;\n // Multiple `next` from one node is rare (linear chains have one);\n // when it happens, distribute horizontally like branches.\n const totalWidth = (nextChildren.length - 1) * X_SPREAD;\n const startX = x - totalWidth / 2;\n let deepestNextY = nextY;\n for (let i = 0; i < nextChildren.length; i++) {\n const childId = nextChildren[i]!;\n const childX = startX + i * X_SPREAD;\n const subtreeBottom = layoutSubtree(childId, childX, nextY);\n if (subtreeBottom > deepestNextY) deepestNextY = subtreeBottom;\n }\n return deepestNextY;\n }\n\n return deepestBranchY;\n }\n\n layoutSubtree(seed.id, 0, 0);\n\n // Unreached nodes (multi-root or cycles outside the seed's tree)\n // stack below. Use a loop (not `Math.max(...spread)`) — spread\n // blows the call stack at ~10k+ args.\n let maxY = 0;\n for (const p of positions.values()) {\n if (p.y > maxY) maxY = p.y;\n }\n let orphanY = maxY + Y_STEP;\n for (const n of graph.nodes) {\n if (!positions.has(n.id)) {\n positions.set(n.id, { x: 0, y: orphanY });\n orphanY += Y_STEP;\n }\n }\n\n return {\n nodes: graph.nodes.map((n) => ({\n ...n,\n position: positions.get(n.id) ?? n.position,\n })),\n edges: graph.edges,\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Edge styling\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceFlowEdgeColors {\n next: string;\n forkBranch: string;\n decisionBranch: string;\n loop: string;\n}\n\nconst DEFAULT_EDGE_COLORS: TraceFlowEdgeColors = {\n next: rawDefaults.colors.textMuted,\n forkBranch: rawDefaults.colors.textMuted,\n decisionBranch: rawDefaults.colors.primary,\n loop: rawDefaults.colors.warning,\n};\n\nfunction styleEdge(edge: TraceEdge, colors: TraceFlowEdgeColors): Edge {\n const kind = edge.data?.kind ?? \"next\";\n const color =\n kind === \"loop\"\n ? colors.loop\n : kind === \"fork-branch\"\n ? colors.forkBranch\n : kind === \"decision-branch\"\n ? colors.decisionBranch\n : colors.next;\n const styled: Edge = {\n ...edge,\n type: kind === \"loop\" ? \"step\" : \"smoothstep\",\n animated: false,\n style: { stroke: color, strokeWidth: 1.5 },\n markerEnd: { type: MarkerType.ArrowClosed, color, width: 16, height: 16 },\n };\n if (kind === \"loop\") {\n styled.style = { ...styled.style, strokeDasharray: \"4 3\" };\n }\n return styled;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype TraceFlowSource =\n | { recorder: TraceStructureRecorderHandle; graph?: never }\n | { graph: TraceGraph; recorder?: never };\n\nexport type TraceFlowProps = BaseComponentProps &\n TraceFlowSource & {\n /** Layout function. Default: BFS tree walk. Pass the literal\n * `\"passthrough\"` to skip layout when nodes already carry positions. */\n layout?: TraceFlowLayout | \"passthrough\";\n /** Per-kind edge color overrides. */\n edgeColors?: Partial<TraceFlowEdgeColors>;\n /** Node click handler — receives the node id. */\n onNodeClick?: (id: string) => void;\n /**\n * Consumer-supplied xyflow node types. Merged with the built-in\n * `{ stageNode: StageNode }` registry — keys you supply OVERRIDE\n * the default for that node type. Pass `{ stageNode: MyNode }` to\n * replace the default stage renderer entirely, or add new keys\n * for nodes you build yourself (any nodes you push into the\n * graph with `type: 'customKey'` will use your component).\n */\n nodeTypes?: NodeTypes;\n /**\n * Consumer-supplied xyflow edge types. Merged with no built-in\n * defaults — pass `{ myEdge: MyEdge }` to register custom edge\n * components for nodes/edges you build with `type: 'myEdge'`.\n */\n edgeTypes?: EdgeTypes;\n /**\n * Children rendered INSIDE the `<ReactFlow>` element, after the\n * built-in `<Background>`. Use this slot to mount xyflow\n * accessory components like `<Controls />`, `<MiniMap />`, or a\n * custom legend. If unset, only the default Background is rendered.\n *\n * @example\n * ```tsx\n * import { Controls, MiniMap } from '@xyflow/react';\n * <TraceFlow recorder={r}>\n * <Controls />\n * <MiniMap />\n * </TraceFlow>\n * ```\n */\n children?: React.ReactNode;\n };\n\nconst DEFAULT_NODE_TYPES: NodeTypes = { stageNode: StageNode };\n\n/**\n * Convert a `TraceNode` (with `TraceNodeData`) to the `StageNode`-typed\n * node shape so the built-in `<StageNode>` renderer works.\n *\n * Pass-through contract: if the consumer pushed a node with a custom\n * `type` (anything OTHER than the recorder's default `'stage'`), this\n * function returns the node UNCHANGED so xyflow's `nodeTypes` lookup\n * sees the consumer's chosen key. This is what makes the `nodeTypes`\n * extension point useful — without it every node would be force-typed\n * to `'stageNode'` and consumer registrations would never route.\n */\nfunction toStageNode(node: TraceNode): Node {\n // Consumer-supplied custom type — pass through unchanged.\n // Recorders produce nodes with `type: 'stage'` (the recorder's\n // default); anything else is consumer-authored and must be respected.\n if (node.type !== undefined && node.type !== \"stage\") {\n return node as Node;\n }\n\n const data = node.data;\n const stageData: StageNodeData = {\n label: data.label,\n isDecider: data.isDecider,\n isFork: data.isFork,\n isSubflow: data.isSubflow,\n active: false,\n done: false,\n error: false,\n ...(data.description !== undefined && { description: data.description }),\n ...(data.icon !== undefined && { icon: data.icon }),\n ...(data.subflowId !== undefined && { subflowId: data.subflowId }),\n ...(data.isLazy === true && { isLazy: true }),\n };\n return {\n ...node,\n type: \"stageNode\",\n data: stageData as unknown as Record<string, unknown>,\n };\n}\n\n// Empty-graph sentinel returned by static-mode getSnapshot when no\n// graph or recorder is present. Module-scoped so React's identity check\n// sees a stable reference across renders.\nconst EMPTY_GRAPH: TraceGraph = { nodes: [], edges: [] };\n\n// ── Subscription helpers (defined at module scope so useSyncExternalStore\n// sees stable function references when the recorder doesn't change) ─\n\nfunction subscribeToRecorder(recorder: TraceStructureRecorderHandle | undefined) {\n return (listener: () => void): (() => void) => {\n if (!recorder) return () => {};\n return recorder.subscribe(listener);\n };\n}\n\nfunction getRecorderVersion(recorder: TraceStructureRecorderHandle | undefined) {\n return (): number => {\n if (!recorder) return 0;\n return recorder.version();\n };\n}\n\nexport function TraceFlow(props: TraceFlowProps) {\n // Dev-mode contract check — TypeScript enforces the discriminated union\n // at compile time, but JS consumers (or `as any` casts) can hit this.\n const proc = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n const isDev = proc?.env?.NODE_ENV !== \"production\";\n if (isDev && !props.recorder && !props.graph) {\n // eslint-disable-next-line no-console\n console.warn(\n \"[TraceFlow] neither `recorder` nor `graph` prop was provided — rendering an empty chart. Pass one of: <TraceFlow recorder={handle} /> OR <TraceFlow graph={{nodes, edges}} />.\",\n );\n }\n\n const layout = props.layout ?? defaultTraceFlowLayout;\n const edgeColors = useMemo<TraceFlowEdgeColors>(\n () => ({ ...DEFAULT_EDGE_COLORS, ...(props.edgeColors ?? {}) }),\n [props.edgeColors],\n );\n\n // Subscribe to the version counter (live mode) — equality-by-number\n // means React only re-renders when the recorder actually mutated.\n // Memoize the subscribe + getSnapshot closures by the recorder\n // identity so useSyncExternalStore doesn't re-subscribe each render.\n const subscribe = useMemo(\n () => subscribeToRecorder(props.recorder),\n [props.recorder],\n );\n const getVersion = useMemo(\n () => getRecorderVersion(props.recorder),\n [props.recorder],\n );\n const version = useSyncExternalStore(subscribe, getVersion, getVersion);\n\n // Resolve graph: live (recorder) vs static (prop). The version\n // dependency drives re-evaluation in live mode; static mode falls\n // through to the prop's identity on each render.\n const { recorder, graph: graphProp } = props;\n const graph: TraceGraph = useMemo<TraceGraph>(() => {\n if (recorder) return recorder.getGraph();\n if (graphProp) return graphProp;\n return EMPTY_GRAPH;\n }, [recorder, graphProp, version]);\n\n const positioned = useMemo<TraceGraph>(() => {\n if (layout === \"passthrough\") return graph;\n return layout(graph);\n }, [graph, layout]);\n\n const reactFlowNodes = useMemo<Node[]>(\n () => positioned.nodes.map(toStageNode),\n [positioned.nodes],\n );\n const reactFlowEdges = useMemo<Edge[]>(\n () => positioned.edges.map((e) => styleEdge(e, edgeColors)),\n [positioned.edges, edgeColors],\n );\n\n const onNodeClickRef = props.onNodeClick;\n const handleNodeClick = useCallback(\n (_: unknown, node: Node) => {\n onNodeClickRef?.(node.id);\n },\n [onNodeClickRef],\n );\n\n const { nodeTypes: userNodeTypes, edgeTypes: userEdgeTypes } = props;\n const mergedNodeTypes = useMemo<NodeTypes>(\n () => (userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES),\n [userNodeTypes],\n );\n\n return (\n <div\n className={props.className}\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 300,\n ...props.style,\n }}\n >\n <ReactFlow\n nodes={reactFlowNodes}\n edges={reactFlowEdges}\n nodeTypes={mergedNodeTypes}\n {...(userEdgeTypes && { edgeTypes: userEdgeTypes })}\n onNodeClick={handleNodeClick}\n fitView\n proOptions={{ hideAttribution: true }}\n >\n <Background variant={BackgroundVariant.Dots} gap={20} size={1} />\n {props.children}\n </ReactFlow>\n </div>\n );\n}\n","/**\n * TracedFlow — runtime-overlay variant of `<TraceFlow>`.\n *\n * Pairs a build-time `TraceGraph` (from `createTraceStructureRecorder`)\n * with a runtime `RuntimeOverlay` (from `createTraceRuntimeOverlay`)\n * and a scrub index → renders an xyflow chart with per-node coloring\n * (done / active / error), per-edge highlighting (executed paths),\n * loop-edge side-routing, and subflow drill-down.\n *\n * The component is orchestration only. Each responsibility lives in\n * an extracted helper / hook (see `_internal/`):\n *\n * - drill state .................. useSubflowDrill\n * - container resize → fitView ... useChartAutoRefit\n * - graph filtering by drill ..... filterGraphForDrill\n * - breadcrumb path .............. buildSubflowBreadcrumb\n * - slice id normalization ....... normalizeSliceLeafIds\n * - mount status aggregation ..... aggregateMountStatus\n * - node / edge styling .......... toStageNodeWithOverlay + styleEdgeWithOverlay\n * - breadcrumb UI ................ <SubflowBreadcrumbBar>\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const runtime = useMemo(() => createTraceRuntimeOverlay(), []);\n * // ... attach both to executor, run the chart ...\n * <TracedFlow\n * graph={trace.getGraph()}\n * overlay={runtime.getOverlay()}\n * scrubIndex={sliderValue}\n * onNodeClick={(stageId) => focusStage(stageId)}\n * onSubflowChange={(mountId) => syncShellDrill(mountId)}\n * />\n * ```\n */\n\nimport type * as React from \"react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n MarkerType,\n} from \"@xyflow/react\";\nimport type { Node, Edge, NodeTypes, EdgeTypes, ReactFlowInstance } from \"@xyflow/react\";\nimport type { TraceGraph, TraceNode, TraceEdge } from \"./traceStructureRecorder\";\nimport type { TraceFlowLayout } from \"./TraceFlow\";\nimport { defaultTraceFlowLayout } from \"./TraceFlow\";\nimport type { RuntimeOverlay } from \"./createTraceRuntimeOverlay\";\nimport { sliceOverlay } from \"./createTraceRuntimeOverlay\";\nimport { StageNode } from \"../StageNode\";\nimport type { StageNodeData } from \"../StageNode\";\nimport { rawDefaults } from \"../../theme/tokens\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { filterGraphForDrill, buildSubflowBreadcrumb } from \"./_internal/subflowDrill\";\nimport { normalizeSliceLeafIds, aggregateMountStatus } from \"./_internal/overlayProjection\";\nimport { useSubflowDrill } from \"./_internal/useSubflowDrill\";\nimport { useChartAutoRefit } from \"./_internal/useChartAutoRefit\";\nimport { SubflowBreadcrumbBar } from \"./SubflowBreadcrumbBar\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Theming\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TracedFlowColors {\n /** Default (un-executed) node text + edge stroke. */\n default: string;\n /** Done — visually de-emphasised (lighter). */\n done: string;\n /** Active — current scrub position. */\n active: string;\n /** Error — node with recorded onError. */\n error: string;\n /** Loop back-edge color. */\n loop: string;\n}\n\nconst DEFAULT_COLORS: TracedFlowColors = {\n default: rawDefaults.colors.textMuted,\n done: rawDefaults.colors.success,\n active: rawDefaults.colors.primary,\n error: rawDefaults.colors.error,\n loop: rawDefaults.colors.warning,\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Per-node / per-edge styling (pure)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction toStageNodeWithOverlay(\n node: TraceNode,\n doneStageIds: ReadonlySet<string>,\n activeStageId: string | null,\n errorMessage: string | undefined,\n executedOrderIds: readonly string[],\n): Node {\n // Pass-through contract — see TraceFlow.toStageNode for rationale.\n // If consumer pushed a node with a non-default `type`, return it\n // unchanged so xyflow's nodeTypes registry routes to the consumer's\n // component instead of the built-in StageNode. The runtime overlay\n // (done/active/error) is intentionally NOT applied to consumer\n // custom nodes — the consumer's component owns its visual state.\n if (node.type !== undefined && node.type !== \"stage\") {\n return node as Node;\n }\n\n const isDone = doneStageIds.has(node.id);\n const isActive = activeStageId === node.id;\n const wasExecuted = isDone || isActive;\n const hasError = !!errorMessage;\n const dimmed = !wasExecuted && executedOrderIds.length > 0;\n\n // Per-stage step number(s) — a loop may visit the same node multiple times.\n let stepNumbers: number[] | undefined;\n if (executedOrderIds.length > 0) {\n const nums: number[] = [];\n for (let i = 0; i < executedOrderIds.length; i++) {\n if (executedOrderIds[i] === node.id) nums.push(i + 1);\n }\n if (nums.length > 0) stepNumbers = nums;\n }\n\n const stageData: StageNodeData = {\n label: node.data.label,\n isDecider: node.data.isDecider,\n isFork: node.data.isFork,\n isSubflow: node.data.isSubflow,\n active: isActive,\n done: isDone,\n error: hasError,\n ...(node.data.description !== undefined && { description: node.data.description }),\n ...(node.data.icon !== undefined && { icon: node.data.icon }),\n ...(node.data.subflowId !== undefined && { subflowId: node.data.subflowId }),\n ...(node.data.isLazy === true && { isLazy: true }),\n ...(dimmed && { dimmed: true }),\n ...(stepNumbers && { stepNumbers }),\n ...(errorMessage && { errorMessage }),\n } as StageNodeData;\n\n return {\n ...node,\n type: \"stageNode\",\n data: stageData as unknown as Record<string, unknown>,\n ...(dimmed && { style: { opacity: 0.35 } }),\n };\n}\n\nfunction styleEdgeWithOverlay(\n edge: TraceEdge,\n doneStageIds: ReadonlySet<string>,\n activeStageId: string | null,\n colors: TracedFlowColors,\n): Edge {\n const kind = edge.data?.kind ?? \"next\";\n const sourceExecuted = doneStageIds.has(edge.source) || activeStageId === edge.source;\n const targetExecuted = doneStageIds.has(edge.target) || activeStageId === edge.target;\n const traversed = sourceExecuted && targetExecuted;\n const isLeadingEdge = activeStageId === edge.source && !doneStageIds.has(edge.target);\n\n let color: string = colors.default;\n if (kind === \"loop\") color = colors.loop;\n else if (isLeadingEdge) color = colors.active;\n else if (traversed) color = colors.done;\n\n const styled: Edge = {\n ...edge,\n type: \"smoothstep\",\n animated: isLeadingEdge,\n style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },\n markerEnd: { type: MarkerType.ArrowClosed, color, width: 16, height: 16 },\n };\n if (kind === \"loop\") {\n // Route loop-back edges AROUND the chart via the StageNode's\n // dedicated loop-source / loop-target handles + offset path.\n styled.style = { ...styled.style, strokeDasharray: \"4 3\" };\n (styled.data as any) = {\n ...(styled.data ?? {}),\n pathOptions: { borderRadius: 14, offset: 36 },\n };\n styled.sourceHandle = \"loop-source\";\n styled.targetHandle = \"loop-target\";\n }\n return styled;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TracedFlowProps extends BaseComponentProps {\n /** Build-time graph from `createTraceStructureRecorder().getGraph()`. */\n graph: TraceGraph;\n /** Runtime overlay from `createTraceRuntimeOverlay().getOverlay()`. */\n overlay?: RuntimeOverlay;\n /** Time-travel scrub index. Defaults to the last step (latest state). */\n scrubIndex?: number;\n /** Layout function. Default: BFS tree walk over the recorder graph. */\n layout?: TraceFlowLayout | \"passthrough\";\n /** Color overrides. */\n colors?: Partial<TracedFlowColors>;\n /** Node click handler — receives stage id. */\n onNodeClick?: (stageId: string) => void;\n /**\n * Fires when the chart drills into or out of a subflow (explicit\n * user click on a mount node). Receives the mount stage id (drill\n * in) or `null` (pop back). Container shells use this to keep\n * their data panels in lock-step with the chart's drill state.\n */\n onSubflowChange?: (mountStageId: string | null) => void;\n /**\n * Consumer-supplied xyflow node types. Merged with the built-in\n * `{ stageNode: StageNode }` registry — keys you supply OVERRIDE\n * the default for that node type. Pass `{ stageNode: MyNode }` to\n * replace the default stage renderer entirely, or add new keys\n * for custom node components you push into the graph.\n */\n nodeTypes?: NodeTypes;\n /**\n * Consumer-supplied xyflow edge types. Merged with no built-in\n * defaults — pass `{ myEdge: MyEdge }` to register custom edge\n * components for edges you push into the graph with `type: 'myEdge'`.\n */\n edgeTypes?: EdgeTypes;\n /**\n * Children rendered INSIDE the `<ReactFlow>` element, after the\n * built-in `<Background>`. Use this slot to mount xyflow\n * accessory components like `<Controls />`, `<MiniMap />`, or a\n * custom legend. If unset, only the default Background is rendered.\n */\n children?: React.ReactNode;\n}\n\nconst DEFAULT_NODE_TYPES: NodeTypes = { stageNode: StageNode };\n\nexport function TracedFlow({\n graph,\n overlay,\n scrubIndex,\n layout: layoutProp,\n colors: colorOverrides,\n onNodeClick,\n onSubflowChange,\n nodeTypes: userNodeTypes,\n edgeTypes: userEdgeTypes,\n children,\n className,\n style,\n}: TracedFlowProps) {\n const layout = layoutProp ?? defaultTraceFlowLayout;\n const colors = useMemo<TracedFlowColors>(\n () => ({ ...DEFAULT_COLORS, ...(colorOverrides ?? {}) }),\n [colorOverrides],\n );\n const mergedNodeTypes = useMemo<NodeTypes>(\n () => (userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES),\n [userNodeTypes],\n );\n\n // ── Drill state + visibility derivations ──────────────────────────\n const drill = useSubflowDrill(graph, onSubflowChange);\n const filteredGraph = useMemo(\n () => filterGraphForDrill(graph, drill.currentSubflowId),\n [graph, drill.currentSubflowId],\n );\n const breadcrumb = useMemo(\n () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),\n [graph, drill.currentSubflowId],\n );\n const positioned = useMemo<TraceGraph>(\n () => (layout === \"passthrough\" ? filteredGraph : layout(filteredGraph)),\n [filteredGraph, layout],\n );\n\n // ── Runtime overlay slice → leaf-normalize + mount aggregation ────\n const slice = useMemo(() => {\n const empty = {\n doneStageIds: new Set<string>(),\n activeStageId: null as string | null,\n executedStageIds: new Set<string>(),\n executedOrderIds: [] as string[],\n errors: new Map<string, string>(),\n };\n if (!overlay) return empty;\n const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);\n const normalized = normalizeSliceLeafIds(sliceOverlay(overlay, idx));\n return aggregateMountStatus(normalized, graph, drill.currentSubflowId);\n }, [overlay, scrubIndex, graph, drill.currentSubflowId]);\n\n // ── xyflow nodes + edges (re-run per scrub tick) ──────────────────\n const reactFlowNodes = useMemo<Node[]>(\n () =>\n positioned.nodes.map((n) =>\n toStageNodeWithOverlay(\n n,\n slice.doneStageIds,\n slice.activeStageId,\n slice.errors.get(n.id),\n slice.executedOrderIds,\n ),\n ),\n [positioned.nodes, slice],\n );\n const reactFlowEdges = useMemo<Edge[]>(\n () =>\n positioned.edges.map((e) =>\n styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors),\n ),\n [positioned.edges, slice, colors],\n );\n\n // ── Click handling: drill on subflow mount click, propagate click ─\n const handleNodeClick = useCallback(\n (_: unknown, node: Node) => {\n const data = (node.data ?? {}) as StageNodeData;\n if (data.isSubflow && data.subflowId) {\n drill.drillInto(data.subflowId);\n }\n onNodeClick?.(node.id);\n },\n [drill, onNodeClick],\n );\n\n // ── Container auto-refit (xyflow's fitView is mount-only) ─────────\n const wrapperRef = useRef<HTMLDivElement>(null);\n const [rfInstance, setRfInstance] = useState<ReactFlowInstance | null>(null);\n useChartAutoRefit(wrapperRef, rfInstance);\n\n return (\n <div\n ref={wrapperRef}\n className={className}\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 300,\n display: \"flex\",\n flexDirection: \"column\",\n ...style,\n }}\n >\n {breadcrumb.length > 1 && (\n <SubflowBreadcrumbBar\n entries={breadcrumb}\n onNavigate={drill.setCurrentSubflowId}\n />\n )}\n <div style={{ flex: 1, minHeight: 0 }}>\n <ReactFlow\n nodes={reactFlowNodes}\n edges={reactFlowEdges}\n nodeTypes={mergedNodeTypes}\n {...(userEdgeTypes && { edgeTypes: userEdgeTypes })}\n onNodeClick={handleNodeClick}\n onInit={setRfInstance}\n fitView\n proOptions={{ hideAttribution: true }}\n >\n <Background variant={BackgroundVariant.Dots} gap={20} size={1} />\n {children}\n </ReactFlow>\n </div>\n </div>\n );\n}\n","/**\n * Dev-mode detection without depending on `@types/node`.\n *\n * Returns `true` when running outside an explicitly production env.\n * Browser builds (no `process` global) treat as dev — acceptable for\n * a debugging library: a user-visible warning in a browser is a\n * debugging signal anyway.\n *\n * Shared by every translator's notify path + orphan-event warnings.\n */\nexport function isDevModeEnv(): boolean {\n const proc = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n return proc?.env?.NODE_ENV !== \"production\";\n}\n\n/**\n * Dev-mode `console.warn` shim. No-op in production. Lazy message\n * construction (`messageFn`) — avoids string-concat cost when prod.\n */\nexport function devWarn(messageFn: () => string, ...extras: unknown[]): void {\n if (!isDevModeEnv()) return;\n // eslint-disable-next-line no-console\n console.warn(messageFn(), ...extras);\n}\n","/**\n * `createNotifier` — shared pub-sub + monotonic version + microtask\n * batching, extracted from `traceStructureRecorder` and\n * `createTraceRuntimeOverlay` (which duplicated this pattern).\n *\n * Every translator needs the same shape to integrate with React's\n * `useSyncExternalStore`:\n * - `subscribe(listener)` returns unsubscribe\n * - `version()` returns monotonic int (snapshot identity)\n * - `notify()` bumps version + fires listeners (error-isolated)\n *\n * Microtask batching\n * ──────────────────\n * A single stage execution fires multiple recorder events (Structure\n * `onStageAdded` + `onEdgeAdded` for each edge; Flow `onStageExecuted`;\n * Scope `onCommit`). With 3+ translators subscribed, that's 6+ React\n * re-renders per stage. The batcher coalesces all `notify()` calls\n * within one microtask into a SINGLE listener fire — version still\n * bumps per event (so consumers that poll `version()` from outside\n * React see every change), but listener invocations are deduplicated.\n *\n * Trade-off: listeners observe the FINAL state after a microtask\n * batch, not every intermediate state. Acceptable for UI consumers\n * (React renders the final state anyway). Non-React consumers that\n * need every event should call `getSnapshot()` from inside event\n * handlers, not rely on the listener for granularity.\n *\n * Error isolation\n * ───────────────\n * A throwing listener is caught + warned in dev. Other listeners\n * still fire. Mirrors footprintjs's recorder dispatcher pattern.\n */\n\nimport { devWarn } from \"./devWarn\";\n\nexport interface Notifier {\n /** Subscribe a listener; returns unsubscribe. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps once per `notify()` call. */\n version(): number;\n /** Bump version + schedule a listener flush (coalesced via microtask). */\n notify(): void;\n /** Force-flush any pending coalesced notification immediately. Used\n * by tests that need synchronous observation. */\n flushPending(): void;\n /** Reset the notifier — clears listeners is NOT done (consumers\n * manage their own subscriptions). Only the pending-flush flag\n * and version stay as-is (no consumer should observe a version\n * rollback). */\n // (intentionally no reset for version — monotonicity is load-bearing\n // for useSyncExternalStore snapshot equality)\n}\n\nexport function createNotifier(label = \"notifier\"): Notifier {\n const listeners = new Set<() => void>();\n let v = 0;\n let pending = false;\n\n function flush(): void {\n if (!pending) return;\n pending = false;\n // Snapshot listeners into an array BEFORE iteration. A listener\n // that synchronously subscribes/unsubscribes another listener\n // would otherwise leave Set-iteration semantics implementation-\n // defined. Array snapshot guarantees: every listener registered\n // AT THIS FLUSH-START fires exactly once; listeners added during\n // a callback wait for the next notify cycle.\n const snapshot = Array.from(listeners);\n for (const l of snapshot) {\n try {\n l();\n } catch (err) {\n devWarn(\n () =>\n `[${label}] subscribe() listener threw — isolated; other subscribers continue.`,\n err,\n );\n }\n }\n }\n\n return {\n subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n version(): number {\n return v;\n },\n notify(): void {\n v += 1;\n if (pending) return;\n pending = true;\n // Coalesce within a single microtask. `queueMicrotask` is\n // available in every supported runtime (Node 11+, all browsers).\n queueMicrotask(flush);\n },\n flushPending(): void {\n flush();\n },\n };\n}\n","/**\n * createTraceRuntimeOverlay — event-driven runtime overlay for `<TracedFlow>`.\n *\n * The runtime twin of `createTraceStructureRecorder` (L7.7). Where the\n * structure recorder accumulates the build-time graph SHAPE from\n * `StructureRecorder` events, this recorder accumulates the runtime\n * EXECUTION STATE (which nodes ran, current active, errors) from\n * `FlowRecorder` events. The two compose into the full time-travel\n * trace UI:\n *\n * StructureRecorder events → TraceGraph (nodes + edges, id-keyed)\n * FlowRecorder events → RuntimeOverlay (per-node state, id-keyed)\n * │\n * ▼\n * <TracedFlow graph={...} overlay={...} scrubIndex={i} />\n *\n * **Universal key**: `runtimeStageId = [subflowPath/]stageId#executionIndex`.\n * Loops re-execute the same stageId with bumping executionIndex — the\n * overlay records each execution as a distinct step in `executionOrder`\n * but updates the SAME node-by-id in `doneStageIds` (because the build-\n * time graph has one node per spec — loops re-visit it).\n *\n * Per L7.7 panel guidance: the consumer pattern mirrors recorder error\n * isolation, exposes a pub-sub `subscribe(listener)` + monotonic\n * `version()` for `useSyncExternalStore` integration, and accumulates\n * pure data with zero React coupling.\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local type aliases mirroring footprintjs FlowRecorder\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Same rationale as traceStructureRecorder.ts: explainable-ui has no\n// `footprintjs` dep declared (consumer wires it). We mirror the\n// subset of `FlowRecorder` we consume. If footprintjs changes the\n// interface, this module's types update in lockstep.\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface RuntimeStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n /** Discriminator for which kind of stage completed. footprintjs v6+\n * fires this event uniformly for every stage kind (proposal #003);\n * consumers route by `stageType` without a chart-spec lookup. */\n readonly stageType: 'linear' | 'decider' | 'fork' | 'selector' | 'subflow-mount';\n readonly traversalContext: TraversalContext;\n}\n\ninterface RuntimeErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface RuntimeRunStartEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface RuntimeRunEndEvent {\n readonly traversalContext?: TraversalContext;\n}\n\n/** Minimal FlowRecorder interface mirror — see top-of-file rationale.\n *\n * As of footprintjs v6 (proposal #003), `onStageExecuted` fires\n * uniformly for ALL stage kinds — linear / decider / fork / selector\n * / subflow-mount. The event payload carries a `stageType` field for\n * consumers that need to route by kind. We no longer need separate\n * `onDecision` / `onFork` / `onSelected` handlers to track \"did this\n * stage run\" — a single `onStageExecuted` handler suffices. */\nexport interface MinimalFlowRecorder {\n readonly id: string;\n onStageExecuted?(event: RuntimeStageExecutedEvent): void;\n onError?(event: RuntimeErrorEvent): void;\n onRunStart?(event: RuntimeRunStartEvent): void;\n onRunEnd?(event: RuntimeRunEndEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Runtime overlay shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * One entry in the execution timeline. `<TracedFlow>` keys time-travel\n * scrubbing on the index into this array — at index `i`, all entries\n * `0..i-1` are \"done\", entry `i` is \"active\".\n */\nexport interface RuntimeExecutionStep {\n /** `[subflowPath/]stageId#executionIndex` — universal key. */\n readonly runtimeStageId: string;\n /** Base stage id (without `#N`) — matches the `TraceGraph` node id. */\n readonly stageId: string;\n /** Human-readable label (from event.stageName). */\n readonly stageName: string;\n /** When this step recorded, in ms since recorder start. */\n readonly timestampMs: number;\n}\n\nexport interface RuntimeOverlay {\n /** Ordered execution history — drives time-travel scrubbing. */\n readonly executionOrder: readonly RuntimeExecutionStep[];\n /** Per-base-stageId error message (most-recent wins). */\n readonly errors: ReadonlyMap<string, string>;\n /** True after `onRunStart` until `onRunEnd` — useful for \"still running\" indicators. */\n readonly running: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceRuntimeOverlayHandle {\n /** The recorder to attach via `executor.attachFlowRecorder(handle.recorder)`. */\n recorder: MinimalFlowRecorder;\n /** Returns a defensive copy of the current overlay state. */\n getOverlay(): RuntimeOverlay;\n /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps once per overlay-mutating event. */\n version(): number;\n /** Reset for reuse across runs. Does NOT bump version or notify (matches\n * traceStructureRecorder's reset contract). */\n reset(): void;\n}\n\nexport interface CreateTraceRuntimeOverlayOptions {\n id?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport { createNotifier } from \"./_internal/notifyChange\";\n\n/**\n * Strip `#executionIndex` suffix to get the base stage id.\n *\n * **WARNING (invariant I3)**: use ONLY for DISPLAY. NEVER for matching\n * commitLog stageIds — those use the full path-prefixed id (e.g.,\n * `'sf-a/sf-b/inner'`) as emitted by the engine. Parsing back to the\n * unqualified inner name loses uniqueness across subflow instances.\n */\nfunction parseStageIdFromRuntimeStageId(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createTraceRuntimeOverlay(\n options: CreateTraceRuntimeOverlayOptions = {},\n): TraceRuntimeOverlayHandle {\n const id = options.id ?? \"trace-runtime-overlay\";\n const startTime = performance.now();\n\n let executionOrder: RuntimeExecutionStep[] = [];\n // Defensive dedupe by runtimeStageId — should be moot post-#003\n // since the engine fires `onStageExecuted` exactly once per stage\n // execution, but a future change or a misbehaving recorder upstream\n // could still produce duplicates; keep the set as belt-and-suspenders.\n const recordedRuntimeStageIds = new Set<string>();\n const errors = new Map<string, string>();\n let running = false;\n const notifier = createNotifier(\"traceRuntimeOverlay\");\n const notifyChange = notifier.notify;\n\n function pushStep(runtimeStageId: string, stageId: string, stageName: string): void {\n if (recordedRuntimeStageIds.has(runtimeStageId)) return;\n recordedRuntimeStageIds.add(runtimeStageId);\n executionOrder.push({\n runtimeStageId,\n stageId,\n stageName,\n timestampMs: performance.now() - startTime,\n });\n notifyChange();\n }\n\n const recorder: MinimalFlowRecorder = {\n id,\n onRunStart() {\n running = true;\n notifyChange();\n },\n onRunEnd() {\n running = false;\n notifyChange();\n },\n onStageExecuted(event) {\n // footprintjs v6 (#003) fires this for EVERY stage kind —\n // linear / decider / fork / selector / subflow-mount — so\n // we no longer need separate handlers for the branching events.\n const runtimeStageId = event.traversalContext.runtimeStageId;\n const baseStageId = parseStageIdFromRuntimeStageId(runtimeStageId);\n pushStep(runtimeStageId, baseStageId, event.stageName);\n },\n onError(event) {\n const fallbackId =\n event.stageId ??\n (event.traversalContext\n ? parseStageIdFromRuntimeStageId(event.traversalContext.runtimeStageId)\n : event.stageName);\n errors.set(fallbackId, event.message ?? \"error\");\n notifyChange();\n },\n };\n\n return {\n recorder,\n getOverlay(): RuntimeOverlay {\n return {\n executionOrder: executionOrder.map((s) => ({ ...s })),\n errors: new Map(errors),\n running,\n };\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n executionOrder = [];\n recordedRuntimeStageIds.clear();\n errors.clear();\n running = false;\n // Note: reset does NOT bump version or notify (matches\n // traceStructureRecorder contract — see its `reset()` JSDoc\n // for the consumer-facing recipe).\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Overlay slicing for time-travel\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Snapshot of overlay state AT a specific scrub index. Drives node\n * coloring in `<TracedFlow>`.\n */\nexport interface RuntimeOverlaySlice {\n /** Base stage ids that completed before the active scrub position. */\n readonly doneStageIds: ReadonlySet<string>;\n /** The currently-active stage id (or `null` when scrub is at 0 with no exec yet). */\n readonly activeStageId: string | null;\n /** Union of done + active — convenient for \"executed at all\" checks. */\n readonly executedStageIds: ReadonlySet<string>;\n /** The full ordered list of base stage ids up through the active position —\n * used by renderers that want to number stages by occurrence (e.g.,\n * show \"3rd loop iteration\" badges). */\n readonly executedOrderIds: readonly string[];\n /** Pass-through errors map for the renderer. */\n readonly errors: ReadonlyMap<string, string>;\n}\n\n/**\n * Slice `overlay.executionOrder` at the given index:\n *\n * - `executionOrder[0..index-1]` → \"done\"\n * - `executionOrder[index]` → \"active\"\n * - `index >= executionOrder.length` → all done, no active\n *\n * Returns an empty slice when overlay has no execution history.\n */\nexport function sliceOverlay(\n overlay: RuntimeOverlay,\n index: number,\n): RuntimeOverlaySlice {\n const order = overlay.executionOrder;\n if (order.length === 0) {\n return {\n doneStageIds: new Set(),\n activeStageId: null,\n executedStageIds: new Set(),\n executedOrderIds: [],\n errors: overlay.errors,\n };\n }\n const clampedIndex = Math.max(0, Math.min(index, order.length - 1));\n const doneStageIds = new Set<string>();\n for (let i = 0; i < clampedIndex; i++) {\n doneStageIds.add(order[i]!.stageId);\n }\n const activeStep = order[clampedIndex];\n const activeStageId = activeStep ? activeStep.stageId : null;\n const executedStageIds = new Set(doneStageIds);\n if (activeStageId) executedStageIds.add(activeStageId);\n const executedOrderIds = order.slice(0, clampedIndex + 1).map((s) => s.stageId);\n return {\n doneStageIds,\n activeStageId,\n executedStageIds,\n executedOrderIds,\n errors: overlay.errors,\n };\n}\n","/**\n * Pure helpers for subflow drill-down on a `TraceGraph`.\n *\n * Filtering and breadcrumb computation are derived from the\n * `TraceNodeData.subflowOf` field that the structure recorder sets\n * at `onSubflowMounted` time. Both functions are pure (no I/O, no\n * React) so they can be unit-tested in isolation and reused by any\n * renderer.\n */\n\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\n/**\n * Filter the trace graph by drill-down scope.\n *\n * - `currentSubflowId === null` → show top-level (nodes with no\n * `subflowOf`). Subflow internals are hidden; their mount node\n * stays visible as a single clickable card.\n * - `currentSubflowId === 'X'` → show only nodes where\n * `subflowOf === 'X'` (the drilled-in subflow's internals).\n *\n * Edges follow the same filter — only edges where both endpoints\n * are in the visible set survive. When nothing would be filtered\n * out, returns the original graph reference (preserves upstream\n * memoization).\n */\nexport function filterGraphForDrill(\n graph: TraceGraph,\n currentSubflowId: string | null,\n): TraceGraph {\n if (graph.nodes.length === 0) return graph;\n const matchesScope = (subflowOf: string | undefined): boolean =>\n currentSubflowId === null ? subflowOf === undefined : subflowOf === currentSubflowId;\n const visibleIds = new Set<string>();\n for (const n of graph.nodes) {\n if (matchesScope(n.data?.subflowOf)) visibleIds.add(n.id);\n }\n if (visibleIds.size === graph.nodes.length) return graph;\n return {\n nodes: graph.nodes.filter((n) => visibleIds.has(n.id)),\n edges: graph.edges.filter((e) => visibleIds.has(e.source) && visibleIds.has(e.target)),\n };\n}\n\n/** Entry in the breadcrumb path. `subflowId === null` is the root. */\nexport interface BreadcrumbEntry {\n subflowId: string | null;\n label: string;\n}\n\n/**\n * Build the breadcrumb path for the current drill level.\n *\n * Always starts with the root `{ subflowId: null, label: 'Chart' }`.\n * When drilled into a subflow, appends one entry with the mount\n * node's display label (falling back to the subflow id). Multi-level\n * drill chains are NOT supported by the current chart UX (drill is\n * always from root or sibling — clicking a deeper subflow's mount\n * replaces the current scope), so the path has at most 2 entries.\n */\nexport function buildSubflowBreadcrumb(\n graph: TraceGraph,\n currentSubflowId: string | null,\n): BreadcrumbEntry[] {\n const out: BreadcrumbEntry[] = [{ subflowId: null, label: \"Chart\" }];\n if (currentSubflowId !== null) {\n const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);\n out.push({\n subflowId: currentSubflowId,\n label: mount?.data?.label ?? currentSubflowId,\n });\n }\n return out;\n}\n","/**\n * Pure helpers for projecting a raw `RuntimeOverlaySlice` into the\n * shape `<TracedFlow>` needs for per-node coloring:\n *\n * 1. `normalizeSliceLeafIds` — strips subflow path prefixes from\n * stage ids so they match `TraceNode.id` (graph stores LEAF ids\n * like `charge-card`; overlay records path-prefixed ids like\n * `payment/charge-card`).\n * 2. `aggregateMountStatus` — when execution is INSIDE a subflow,\n * light up the mount node in the parent view as\n * done/active based on its internals' statuses.\n *\n * Both are pure (no I/O, no React). Composed in TracedFlow as\n * `aggregate(normalize(raw))`.\n */\n\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\nexport interface OverlaySlice {\n doneStageIds: ReadonlySet<string>;\n activeStageId: string | null;\n executedStageIds: ReadonlySet<string>;\n executedOrderIds: readonly string[];\n errors: ReadonlyMap<string, string>;\n}\n\n/** Strip everything before the last `/` — `'payment/charge-card'` → `'charge-card'`. */\nfunction leafId(id: string): string {\n const i = id.lastIndexOf(\"/\");\n return i >= 0 ? id.slice(i + 1) : id;\n}\n\n/**\n * Normalize all stage ids in a slice to LEAF ids so they line up\n * with `TraceNode.id` keys for coloring lookups.\n */\nexport function normalizeSliceLeafIds(slice: OverlaySlice): OverlaySlice {\n return {\n doneStageIds: new Set(Array.from(slice.doneStageIds).map(leafId)),\n activeStageId: slice.activeStageId ? leafId(slice.activeStageId) : null,\n executedStageIds: new Set(Array.from(slice.executedStageIds).map(leafId)),\n executedOrderIds: slice.executedOrderIds.map(leafId),\n errors: new Map(Array.from(slice.errors).map(([k, v]) => [leafId(k), v])),\n };\n}\n\n/**\n * Aggregate subflow internals' status onto their mount nodes.\n *\n * - Mount is DONE when EVERY internal stage is done.\n * - Mount is ACTIVE when ANY internal is active or done — but only\n * when we're viewing the TOP-LEVEL chart (`currentSubflowId ===\n * null`). When drilled INTO a subflow, the active highlight goes\n * on the actual subflow stage, not on the parent's mount.\n *\n * Pre-condition: slice has already been leaf-normalized so its\n * stage ids match `graph.nodes[].id`.\n */\nexport function aggregateMountStatus(\n slice: OverlaySlice,\n graph: TraceGraph,\n currentSubflowId: string | null,\n): OverlaySlice {\n if (graph.nodes.length === 0) return slice;\n const mounts = graph.nodes.filter((n) => n.data?.isSubflow && n.data?.subflowId);\n if (mounts.length === 0) return slice;\n const doneIds = new Set(slice.doneStageIds);\n let activeId = slice.activeStageId;\n for (const mount of mounts) {\n const sfId = mount.data!.subflowId as string;\n const members = graph.nodes.filter((n) => n.data?.subflowOf === sfId);\n if (members.length === 0) continue;\n const anyActive = members.some((m) => m.id === slice.activeStageId);\n const anyDone = members.some((m) => slice.doneStageIds.has(m.id));\n const allDone = members.every((m) => slice.doneStageIds.has(m.id));\n if (allDone) doneIds.add(mount.id);\n else if ((anyActive || anyDone) && currentSubflowId === null) {\n activeId = mount.id;\n }\n }\n return { ...slice, doneStageIds: doneIds, activeStageId: activeId };\n}\n","/**\n * useSubflowDrill — drill state for the chart's view scope.\n *\n * - Owns `currentSubflowId: string | null` (null = top-level)\n * - Exposes `drillInto(subflowId)` and `drillUp()` for navigation\n * - Notifies the host via `onSubflowChange(mountStageId | null)`\n * whenever the drill state changes — host wires this to its own\n * drill-stack so data panels follow\n *\n * Drill changes are EXPLICIT — there's no auto-drill on scrub. The\n * mount node's status reflects \"execution is inside\" via\n * `aggregateMountStatus` (see overlayProjection.ts).\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\nexport interface SubflowDrillHandle {\n /** Current drill scope. `null` = top-level. */\n currentSubflowId: string | null;\n /** Navigate INTO the given subflow (by `subflowId`). */\n drillInto: (subflowId: string) => void;\n /** Pop back up to the parent / top-level. */\n drillUp: () => void;\n /** Direct setter for breadcrumb navigation (any target including `null`). */\n setCurrentSubflowId: (id: string | null) => void;\n}\n\nexport function useSubflowDrill(\n graph: TraceGraph,\n onSubflowChange?: (mountStageId: string | null) => void,\n): SubflowDrillHandle {\n const [currentSubflowId, setCurrentSubflowId] = useState<string | null>(null);\n\n // Reset drill state when the graph IDENTITY changes (e.g., the\n // user switched to a different sample in the playground sidebar).\n // Without this, the drill state from sample A persists into\n // sample B's rendering — `currentSubflowId='payment'` survives the\n // chart swap, but sample B has no 'payment' subflow, so the filter\n // returns no visible nodes (blank chart).\n //\n // Also reset when the currently-drilled subflow no longer exists\n // in the new graph (defensive — graph mutations could remove a\n // subflow without changing the wrapper reference).\n const lastGraphRef = useRef<TraceGraph | null>(null);\n if (lastGraphRef.current !== graph) {\n lastGraphRef.current = graph;\n if (\n currentSubflowId !== null &&\n !graph.nodes.some((n) => n.data?.subflowId === currentSubflowId)\n ) {\n // Schedule reset for next render (can't setState during render).\n queueMicrotask(() => setCurrentSubflowId(null));\n }\n }\n\n // Notify the host when drill changes. Resolve the mount stage id\n // from the graph (the parent-chart node whose `subflowId` matches).\n const lastNotifiedRef = useRef<string | null | undefined>(undefined);\n useEffect(() => {\n if (lastNotifiedRef.current === currentSubflowId) return;\n lastNotifiedRef.current = currentSubflowId;\n if (currentSubflowId === null) {\n onSubflowChange?.(null);\n } else {\n const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);\n if (mount) onSubflowChange?.(mount.id);\n }\n }, [currentSubflowId, graph, onSubflowChange]);\n\n const drillInto = useCallback((subflowId: string) => {\n setCurrentSubflowId(subflowId);\n }, []);\n const drillUp = useCallback(() => {\n setCurrentSubflowId(null);\n }, []);\n\n return { currentSubflowId, drillInto, drillUp, setCurrentSubflowId };\n}\n","/**\n * useChartAutoRefit — keep an xyflow chart fitted to its container.\n *\n * xyflow's `fitView` prop only runs on mount; it does NOT re-fit\n * when the container resizes. This hook closes that gap by:\n *\n * 1. Observing the wrapper element via `ResizeObserver` →\n * `instance.fitView({ duration, padding })` on the next animation\n * frame (so the new container size is measured first).\n * 2. Also listening to `window resize` events — `ExplainableShell`\n * dispatches synthetic resize events when its detail panels\n * toggle (those size changes may be animated and not yet\n * measurable by ResizeObserver on the first tick).\n *\n * Without this hook the chart shrinks once on Details-open and\n * never grows back when Details closes.\n */\n\nimport { useEffect } from \"react\";\nimport type { RefObject } from \"react\";\nimport type { ReactFlowInstance } from \"@xyflow/react\";\n\nexport function useChartAutoRefit(\n wrapperRef: RefObject<HTMLElement | null>,\n rfInstance: ReactFlowInstance | null,\n options: { duration?: number; padding?: number } = {},\n): void {\n const duration = options.duration ?? 200;\n const padding = options.padding ?? 0.1;\n\n useEffect(() => {\n const el = wrapperRef.current;\n if (!el || !rfInstance) return;\n let raf = 0;\n const refit = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() => {\n rfInstance.fitView({ duration, padding });\n });\n };\n const ro = new ResizeObserver(refit);\n ro.observe(el);\n window.addEventListener(\"resize\", refit);\n return () => {\n ro.disconnect();\n window.removeEventListener(\"resize\", refit);\n cancelAnimationFrame(raf);\n };\n }, [rfInstance, wrapperRef, duration, padding]);\n}\n","/**\n * SubflowBreadcrumbBar — clickable trail of subflow drill levels.\n *\n * Chart › Outer Subflow › Inner Subflow\n *\n * The last entry renders disabled (you're already here). Earlier\n * entries are clickable — fire `onNavigate(subflowId)` (null = root).\n *\n * Pure presentation: takes the precomputed `entries` array (built by\n * `buildSubflowBreadcrumb` in `_internal/subflowDrill.ts`). No drill\n * state lives here.\n */\n\nimport type { BreadcrumbEntry } from \"./_internal/subflowDrill\";\nimport { rawDefaults } from \"../../theme/tokens\";\n\nexport interface SubflowBreadcrumbBarProps {\n entries: BreadcrumbEntry[];\n onNavigate: (subflowId: string | null) => void;\n}\n\nexport function SubflowBreadcrumbBar({ entries, onNavigate }: SubflowBreadcrumbBarProps) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"6px 12px\",\n fontSize: 11,\n background: rawDefaults.colors.bgSecondary,\n borderBottom: `1px solid ${rawDefaults.colors.border}`,\n flexShrink: 0,\n }}\n aria-label=\"Subflow breadcrumb\"\n >\n {entries.map((entry, i) => {\n const isLast = i === entries.length - 1;\n return (\n <span\n key={entry.subflowId ?? \"__top__\"}\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n >\n <button\n type=\"button\"\n onClick={() => onNavigate(entry.subflowId)}\n disabled={isLast}\n style={{\n background: \"transparent\",\n border: \"none\",\n padding: 0,\n fontSize: 11,\n fontWeight: isLast ? 600 : 500,\n color: isLast ? rawDefaults.colors.textPrimary : rawDefaults.colors.primary,\n cursor: isLast ? \"default\" : \"pointer\",\n textDecoration: isLast ? \"none\" : \"underline\",\n fontFamily: \"inherit\",\n }}\n >\n {entry.label}\n </button>\n {!isLast && <span style={{ color: rawDefaults.colors.textMuted }}>›</span>}\n </span>\n );\n })}\n </div>\n );\n}\n","import { memo } from \"react\";\nimport { theme } from \"../../theme\";\nimport type { BreadcrumbEntry } from \"./useSubflowNavigation\";\n\nexport interface SubflowBreadcrumbProps {\n breadcrumbs: BreadcrumbEntry[];\n onNavigate: (level: number) => void;\n}\n\n/**\n * Breadcrumb bar for subflow drill-down navigation.\n * Shows: Root > SubflowA > SubflowB — clicking any crumb navigates back.\n */\nexport const SubflowBreadcrumb = memo(function SubflowBreadcrumb({\n breadcrumbs,\n onNavigate,\n}: SubflowBreadcrumbProps) {\n if (breadcrumbs.length <= 1) return null;\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n padding: \"6px 12px\",\n background: theme.bgSecondary,\n borderBottom: `1px solid ${theme.border}`,\n fontSize: 12,\n fontFamily: theme.fontSans,\n flexShrink: 0,\n overflowX: \"auto\",\n }}\n >\n {breadcrumbs.map((crumb, i) => {\n const isLast = i === breadcrumbs.length - 1;\n return (\n <span key={`${crumb.label}-${i}`} style={{ display: \"flex\", alignItems: \"center\", gap: 4 }}>\n {i > 0 && (\n <span style={{ color: theme.textMuted, fontSize: 10 }}>\n ›\n </span>\n )}\n {isLast ? (\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <span\n style={{\n color: theme.primary,\n fontWeight: 600,\n }}\n >\n {crumb.label}\n </span>\n {crumb.description && (\n <span\n style={{\n color: theme.textMuted,\n fontWeight: 400,\n fontSize: 11,\n }}\n >\n — {crumb.description}\n </span>\n )}\n </span>\n ) : (\n <button\n onClick={() => onNavigate(i)}\n style={{\n background: \"none\",\n border: \"none\",\n color: theme.textSecondary,\n cursor: \"pointer\",\n padding: \"2px 4px\",\n borderRadius: 4,\n fontSize: 12,\n fontFamily: \"inherit\",\n fontWeight: 500,\n transition: \"color 0.15s\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.color = `${theme.primary}`;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.color = `${theme.textSecondary}`;\n }}\n >\n {crumb.label}\n </button>\n )}\n </span>\n );\n })}\n </div>\n );\n});\n","/**\n * useSubflowNavigation — drill-down breadcrumb tracker for recorder-driven charts.\n *\n * Recorder-driven (v6+): replaces the legacy SpecNode-walk path. Accepts\n * a `TraceGraph` (from `createTraceStructureRecorder`) and tracks WHICH\n * subflow the user has drilled into.\n *\n * Limitation (intentional — recorder graph is flat / mount-only):\n * The StructureRecorder records the MOUNT of each subflow in the\n * parent chart, not the inner structure of each child chart. So\n * \"drill into a subflow\" today returns the SAME graph with the\n * `currentSubflowId` marker advanced — there is no separate\n * child-graph to swap in. Filtering nodes by\n * `data.subflowId === <selected>` would only surface mount nodes,\n * not the child chart's stages.\n *\n * TODO(recorder-driven-nesting): when child charts attach their own\n * `traceStructureRecorder` and surface those graphs via a registry,\n * accept `Map<subflowId, TraceGraph>` and swap `currentGraph` to the\n * child's graph on drill-down. Consumers can then render\n * `<TraceFlow graph={currentGraph} />` per level.\n */\n\nimport { useState, useCallback, useMemo } from \"react\";\nimport type { TraceGraph } from \"./traceStructureRecorder\";\n\nexport interface BreadcrumbEntry {\n /** Display name for this level */\n label: string;\n /** The subflow id that was drilled into to reach this level\n * (undefined for root). */\n subflowId?: string;\n /** Human-readable description of this subflow */\n description?: string;\n}\n\nexport interface SubflowNavigation {\n /** Current breadcrumb path (root → ... → current) */\n breadcrumbs: BreadcrumbEntry[];\n /** Current graph — today identical to the root graph (see file-level\n * TODO). Consumers should still treat this as the source of truth so\n * they remain forward-compatible once per-subflow graphs are wired in. */\n currentGraph: TraceGraph;\n /** Subflow id of the level the user is currently inside (null at root). */\n currentSubflowId: string | null;\n /** Display name of the subflow node we drilled into (null at root). */\n currentSubflowNodeName: string | null;\n /** Call when a node is clicked — drills in if it's a subflow.\n * Returns true when the click pushed a new level. */\n handleNodeClick: (nodeId: string) => boolean;\n /** Navigate to a specific breadcrumb level (0 = root) */\n navigateTo: (level: number) => void;\n /** Whether we're currently inside a subflow (not at root) */\n isInSubflow: boolean;\n}\n\nconst EMPTY_GRAPH: TraceGraph = { nodes: [], edges: [] };\n\n/**\n * Hook that tracks subflow drill-down state for a recorder-driven chart.\n *\n * Maintains a breadcrumb stack. When a subflow node is clicked the\n * stack pushes a new entry; breadcrumb clicks pop back to that level.\n * See file-level docs for the deferred per-subflow graph swap.\n */\nexport function useSubflowNavigation(\n rootGraph: TraceGraph | null,\n): SubflowNavigation {\n const [stack, setStack] = useState<BreadcrumbEntry[]>([]);\n\n const safeRootGraph = rootGraph ?? EMPTY_GRAPH;\n\n // Lookup: subflow id → mount node display name. Populated from the\n // recorder graph so click handlers can resolve the node-id the\n // consumer passes.\n const subflowMounts = useMemo(() => {\n const map = new Map<\n string,\n { subflowId: string; label: string; description?: string }\n >();\n for (const node of safeRootGraph.nodes) {\n if (!node.data?.isSubflow) continue;\n const subflowId =\n typeof node.data.subflowId === \"string\" ? node.data.subflowId : node.id;\n const label =\n typeof node.data.label === \"string\" ? node.data.label : node.id;\n const entry: { subflowId: string; label: string; description?: string } = {\n subflowId,\n label,\n };\n if (typeof node.data.description === \"string\") {\n entry.description = node.data.description;\n }\n // Key by stable id AND by the node id callers usually pass.\n map.set(node.id, entry);\n map.set(subflowId, entry);\n }\n return map;\n }, [safeRootGraph]);\n\n const breadcrumbs: BreadcrumbEntry[] = useMemo(() => {\n const rootLabel = \"Flowchart\";\n const root: BreadcrumbEntry = { label: rootLabel };\n return [root, ...stack];\n }, [stack]);\n\n const handleNodeClick = useCallback(\n (nodeId: string): boolean => {\n const mount = subflowMounts.get(nodeId);\n if (!mount) return false;\n setStack((prev) => {\n const entry: BreadcrumbEntry = {\n label: mount.label,\n subflowId: mount.subflowId,\n };\n if (mount.description !== undefined) entry.description = mount.description;\n return [...prev, entry];\n });\n return true;\n },\n [subflowMounts],\n );\n\n const navigateTo = useCallback((level: number) => {\n if (level === 0) {\n setStack([]);\n } else {\n setStack((prev) => prev.slice(0, level));\n }\n }, []);\n\n const top = stack[stack.length - 1];\n return {\n breadcrumbs,\n // TODO(recorder-driven-nesting): swap to per-subflow graph when\n // child charts attach their own recorders.\n currentGraph: safeRootGraph,\n currentSubflowId: top?.subflowId ?? null,\n currentSubflowNodeName: top?.label ?? null,\n handleNodeClick,\n navigateTo,\n isInSubflow: stack.length > 0,\n };\n}\n","/**\n * SubflowTree — collapsible sidebar listing mounted subflows.\n *\n * Recorder-driven (v6+): derives the tree from a `TraceGraph` produced\n * by `createTraceStructureRecorder`. Filters nodes by\n * `data.isSubflow === true` and lists them as `SubflowTreeEntry[]`\n * keyed by `subflowId`.\n *\n * Limitation (intentional — recorder graph is flat / mount-only):\n * Subflow-within-subflow nesting is NOT represented. The\n * StructureRecorder records the MOUNT of each subflow in the parent\n * chart, not the inner structure of each child chart. Rendering the\n * nested tree requires a separate recorder attached to each child\n * chart instance (deferred — see TODO below).\n *\n * Shared navigation layer — humans click through the tree just like\n * LLMs call getSubflowManifest() / getSubflowSpec().\n *\n * TODO(recorder-driven-nesting): when child charts attach their own\n * `traceStructureRecorder` and surface those graphs via a parent\n * registry, accept `Map<subflowId, TraceGraph>` and recurse to\n * restore the nested rendering the legacy SpecNode-walk supported.\n *\n * All colors come from `--fp-*` CSS variables set by the consumer.\n */\nimport { memo, useState, useCallback, useMemo } from \"react\";\nimport { theme } from \"../../theme\";\nimport type { TraceGraph } from \"./traceStructureRecorder\";\nimport type { BaseComponentProps } from \"../../types\";\n\nexport interface SubflowTreeEntry {\n /** Node name / identifier */\n name: string;\n /** Human-readable description */\n description?: string;\n /** Subflow ID (when this node represents a subflow) */\n subflowId?: string;\n /** Whether this node is a subflow root (has nested structure) */\n isSubflow?: boolean;\n /** Nested children (subflow stages) — always undefined in the\n * current recorder-driven implementation; see file-level TODO. */\n children?: SubflowTreeEntry[];\n}\n\nexport interface SubflowTreeProps extends BaseComponentProps {\n /** Recorder-captured graph from `createTraceStructureRecorder().getGraph()`. */\n graph: TraceGraph;\n /** Currently active stage name (highlights in tree) */\n activeStage?: string | null;\n /** Set of completed stage names */\n doneStages?: Set<string>;\n /** Called when a tree node is clicked */\n onNodeSelect?: (name: string, isSubflow: boolean) => void;\n}\n\n/** Extracts subflow entries from a recorder graph. Insertion-order preserving. */\nexport function graphToSubflowEntries(graph: TraceGraph): SubflowTreeEntry[] {\n if (!graph?.nodes?.length) return [];\n const entries: SubflowTreeEntry[] = [];\n for (const node of graph.nodes) {\n if (!node.data?.isSubflow) continue;\n const entry: SubflowTreeEntry = {\n name: typeof node.data.label === \"string\" ? node.data.label : node.id,\n isSubflow: true,\n };\n if (typeof node.data.description === \"string\") entry.description = node.data.description;\n if (typeof node.data.subflowId === \"string\") entry.subflowId = node.data.subflowId;\n entries.push(entry);\n }\n return entries;\n}\n\n/** Single tree node row */\nconst TreeNode = memo(function TreeNode({\n entry,\n depth,\n activeStage,\n doneStages,\n onNodeSelect,\n}: {\n entry: SubflowTreeEntry;\n depth: number;\n activeStage?: string | null;\n doneStages?: Set<string>;\n onNodeSelect?: (name: string, isSubflow: boolean) => void;\n}) {\n const [expanded, setExpanded] = useState(true);\n const hasChildren = entry.children && entry.children.length > 0;\n const isActive = activeStage === entry.name;\n const isDone = doneStages?.has(entry.name);\n\n const handleClick = useCallback(() => {\n if (hasChildren) {\n setExpanded((prev) => !prev);\n }\n onNodeSelect?.(entry.name, !!entry.isSubflow);\n }, [hasChildren, onNodeSelect, entry.name, entry.isSubflow]);\n\n return (\n <>\n <button\n onClick={handleClick}\n data-fp=\"subflow-tree-node\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n width: \"100%\",\n border: \"none\",\n background: isActive\n ? `color-mix(in srgb, ${theme.primary} 15%, transparent)`\n : \"transparent\",\n cursor: \"pointer\",\n padding: `4px 8px 4px ${8 + depth * 16}px`,\n fontFamily: theme.fontSans,\n fontSize: 12,\n textAlign: \"left\",\n borderRadius: 4,\n transition: \"background 0.15s\",\n }}\n onMouseEnter={(e) => {\n if (!isActive) {\n e.currentTarget.style.background = `color-mix(in srgb, ${theme.textMuted} 10%, transparent)`;\n }\n }}\n onMouseLeave={(e) => {\n if (!isActive) {\n e.currentTarget.style.background = \"transparent\";\n }\n }}\n >\n {/* Expand/collapse chevron for subflows */}\n {hasChildren ? (\n <span\n style={{\n fontSize: 10,\n color: theme.textMuted,\n width: 12,\n textAlign: \"center\",\n flexShrink: 0,\n transition: \"transform 0.15s\",\n transform: expanded ? \"rotate(90deg)\" : \"rotate(0deg)\",\n display: \"inline-block\",\n }}\n >\n ▶\n </span>\n ) : (\n <span style={{ width: 12, flexShrink: 0 }} />\n )}\n\n {/* Status dot */}\n <span\n style={{\n width: 6,\n height: 6,\n borderRadius: \"50%\",\n flexShrink: 0,\n background: isActive\n ? theme.primary\n : isDone\n ? theme.success\n : theme.border,\n }}\n />\n\n {/* Label + description */}\n <span style={{ display: \"flex\", flexDirection: \"column\", minWidth: 0 }}>\n <span\n style={{\n color: isActive\n ? theme.primary\n : isDone\n ? theme.textPrimary\n : theme.textSecondary,\n fontWeight: isActive ? 600 : entry.isSubflow ? 500 : 400,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {entry.name}\n {entry.isSubflow && (\n <span style={{ opacity: 0.5, marginLeft: 4, fontSize: 10 }}>⊞</span>\n )}\n </span>\n {entry.description && (\n <span\n style={{\n color: theme.textMuted,\n fontSize: 10,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {entry.description}\n </span>\n )}\n </span>\n </button>\n\n {/* Children */}\n {hasChildren && expanded && (\n <div>\n {entry.children!.map((child, i) => (\n <TreeNode\n key={child.subflowId ?? `${child.name}-${i}`}\n entry={child}\n depth={depth + 1}\n activeStage={activeStage}\n doneStages={doneStages}\n onNodeSelect={onNodeSelect}\n />\n ))}\n </div>\n )}\n </>\n );\n});\n\n/** Section label used for \"Flowchart\" and \"Subflows\" headings. */\nconst SectionLabel = memo(function SectionLabel({ children }: { children: string }) {\n return (\n <div\n style={{\n padding: \"4px 12px 8px\",\n fontSize: 10,\n fontWeight: 600,\n textTransform: \"uppercase\",\n letterSpacing: \"0.05em\",\n color: theme.textMuted,\n }}\n >\n {children}\n </div>\n );\n});\n\nexport const SubflowTree = memo(function SubflowTree({\n graph,\n activeStage,\n doneStages,\n onNodeSelect,\n unstyled = false,\n className,\n style,\n}: SubflowTreeProps) {\n const subflowStages = useMemo(() => graphToSubflowEntries(graph), [graph]);\n\n // Don't render anything if there are no subflows\n if (subflowStages.length === 0) return null;\n\n return (\n <div\n className={className}\n data-fp=\"subflow-tree\"\n style={{\n ...(unstyled\n ? {}\n : {\n fontFamily: theme.fontSans,\n fontSize: 12,\n background: theme.bgPrimary,\n borderRight: `1px solid ${theme.border}`,\n overflowY: \"auto\",\n overflowX: \"hidden\",\n padding: \"8px 0\",\n }),\n ...style,\n }}\n >\n {!unstyled && <SectionLabel>Subflows</SectionLabel>}\n {subflowStages.map((entry, i) => (\n <TreeNode\n key={entry.subflowId ?? `${entry.name}-${i}`}\n entry={entry}\n depth={0}\n activeStage={activeStage}\n doneStages={doneStages}\n onNodeSelect={onNodeSelect}\n />\n ))}\n </div>\n );\n});\n","/**\n * Branded types for translator key discipline.\n *\n * The footprintjs/trace contract uses two distinct identity strings:\n *\n * - **StageId**: the stable identifier the user picks at build time\n * (e.g. `'load-order'`, `'check-inventory'`). Identity per chart spec.\n *\n * - **RuntimeStageId**: `[subflowPath/]stageId#executionIndex` — the\n * per-execution identity. A loop visiting the same stage 3 times\n * produces 3 distinct RuntimeStageIds with the same StageId base.\n *\n * Translator outputs index per-stage data by StageId (`Map<StageId, ...>`)\n * AND per-execution data by RuntimeStageId (`Map<RuntimeStageId, ...>`).\n * Both are `string` at runtime — TypeScript can't distinguish them\n * without help. Branded types make `byStageId.get(runtimeStageId)` a\n * **compile-time error** instead of a silent `undefined` at runtime.\n *\n * Why branded types over wrapper classes\n * ──────────────────────────────────────\n * - Zero runtime cost (the brand exists only at the type level)\n * - JSON-serializable as-is (no `toJSON` glue needed)\n * - Interop with consumer code that uses raw `string` is one cast\n * (`stageId as StageId`) when the consumer is sure of the source.\n *\n * Usage pattern\n * ─────────────\n * ```ts\n * import type { StageId, RuntimeStageId } from './_internal/keys';\n *\n * // In a translator, when accepting input from a footprintjs event:\n * const sid = event.stageId as StageId;\n * const rsid = event.traversalContext.runtimeStageId as RuntimeStageId;\n *\n * // In a consumer reading from the index:\n * const node = index.byStageId.get(stageId); // typechecks\n * const node = index.byStageId.get(runtimeStageId); // TS ERROR ✓\n * ```\n *\n * Helper to derive a StageId from a RuntimeStageId — strips `#N` suffix\n * and optional subflow path. **Use only for DISPLAY**, NEVER for matching\n * commitLog stageIds (see invariant I3 in `traceStructureRecorder.ts`).\n */\n\n// String-literal brands (NOT `unique symbol`) — survive `.d.ts` emit\n// across module boundaries. Unique-symbol brands get serialized as\n// new local symbols when consumers compile their own .d.ts, causing\n// \"missing property [unique symbol]\" errors. String literals stay\n// nominal because the literal value is identical across builds.\n\n/** Stable per-spec identifier (e.g. `'load-order'`). */\nexport type StageId = string & { readonly __brand: \"StageId\" };\n\n/** Per-execution identifier (e.g. `'load-order#0'` or `'sf-foo/inner#3'`). */\nexport type RuntimeStageId = string & { readonly __brand: \"RuntimeStageId\" };\n\n/**\n * Tag a raw string as a `StageId`. Use at translator boundaries when\n * ingesting from a footprintjs event payload (the source guarantees\n * the string IS a stage id). Zero runtime cost.\n */\nexport function asStageId(s: string): StageId {\n return s as StageId;\n}\n\n/**\n * Tag a raw string as a `RuntimeStageId`. Use at translator boundaries\n * when ingesting from a `traversalContext.runtimeStageId`. Zero\n * runtime cost.\n */\nexport function asRuntimeStageId(s: string): RuntimeStageId {\n return s as RuntimeStageId;\n}\n","/**\n * walkSubflowSpecInto — walks a footprintjs v6.0+ `subflowSpec` payload\n * from `StructureSubflowMountedEvent` and emits nodes + edges into the\n * trace recorder's existing upsert helpers.\n *\n * This is the local mirror of `walkSubflowSpec` from `footprintjs/trace`\n * — kept local to preserve explainable-ui's zero-`footprintjs`-dep\n * boundary (see traceStructureRecorder.ts top-of-file rationale).\n *\n * Stage IDs come pre-prefixed from footprintjs's `_prefixNodeTree`\n * (e.g. `'sf-tools/execute-tool-calls'`), so we use them as-is for\n * node ids. The `subflowPath` is set on `data.subflowOf` to mark which\n * subflow each inner stage belongs to.\n */\n\nimport type { Node, Edge } from \"@xyflow/react\";\nimport { asStageId } from \"./keys\";\nimport type { TraceEdgeData, TraceNodeData } from \"../traceStructureRecorder\";\n\n/** Minimal duck-typed spec shape — mirrors the slice of\n * `SerializedPipelineStructure` we need. */\ninterface SpecNode {\n readonly id: string;\n readonly name: string;\n readonly type?: \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n readonly icon?: string;\n readonly description?: string;\n readonly children?: readonly SpecNode[];\n readonly next?: SpecNode;\n readonly loopTarget?: string;\n readonly isLoopReference?: boolean;\n readonly isSubflowRoot?: boolean;\n readonly subflowId?: string;\n readonly subflowName?: string;\n readonly subflowStructure?: SpecNode;\n readonly isPausable?: boolean;\n readonly isLazy?: boolean;\n}\n\ninterface WalkSink {\n upsertNode(node: Node<TraceNodeData>): void;\n pushEdge(edge: Edge<TraceEdgeData>): void;\n}\n\nexport function walkSubflowSpecInto(\n spec: SpecNode,\n subflowPath: string,\n sink: WalkSink,\n): void {\n walkNode(spec, subflowPath, sink, new Set<string>());\n}\n\nfunction walkNode(\n node: SpecNode,\n subflowPath: string,\n sink: WalkSink,\n visited: Set<string>,\n): void {\n if (visited.has(node.id)) return;\n visited.add(node.id);\n if (node.isLoopReference) return;\n\n // Nested subflow mount — recurse into its structure with composed path.\n if (node.isSubflowRoot && node.subflowId !== undefined && node.subflowStructure) {\n const nestedPath = `${subflowPath}/${node.subflowId}`;\n walkNode(node.subflowStructure, nestedPath, sink, visited);\n // Fall through so the mount node itself is emitted in the parent\n // subflow's scope below.\n }\n\n // Emit the stage node, tagged with subflowOf.\n const type = node.type ?? \"stage\";\n const isDecider = type === \"decider\" || type === \"selector\";\n const isFork = type === \"fork\";\n const isStreaming = type === \"streaming\";\n const isSubflow = !!node.isSubflowRoot;\n\n const stageId = asStageId(node.id);\n const data: TraceNodeData = {\n label: node.name,\n isDecider,\n isFork,\n isStreaming,\n isSubflow,\n subflowOf: subflowPath,\n prevIds: [],\n nextIds: [],\n };\n if (node.description !== undefined) data.description = node.description;\n if (node.icon !== undefined) data.icon = node.icon;\n if (node.subflowId !== undefined) data.subflowId = node.subflowId;\n if (node.isLazy === true) data.isLazy = true;\n if (node.isPausable === true) data.isPausable = true;\n\n sink.upsertNode({\n id: node.id,\n type: \"stage\",\n position: { x: 0, y: 0 },\n data,\n });\n\n // Children (decider/selector/fork branches).\n if (node.children && node.children.length > 0) {\n const edgeKind: \"fork-branch\" | \"decision-branch\" = type === \"fork\" ? \"fork-branch\" : \"decision-branch\";\n for (const child of node.children) {\n const edgeId = `${node.id}->${child.id}:${edgeKind}${edgeKind === \"decision-branch\" ? `:${child.id}` : \"\"}`;\n const edgeData: TraceEdgeData = { kind: edgeKind };\n if (edgeKind === \"decision-branch\") edgeData.label = child.id;\n const edge: Edge<TraceEdgeData> = {\n id: edgeId,\n source: node.id,\n target: child.id,\n data: edgeData,\n };\n if (edgeKind === \"decision-branch\") edge.label = child.id;\n sink.pushEdge(edge);\n walkNode(child, subflowPath, sink, visited);\n }\n }\n\n // Linear next or loop back-edge.\n if (node.next) {\n if (node.next.isLoopReference && node.loopTarget) {\n sink.pushEdge({\n id: `${node.id}->${node.loopTarget}:loop`,\n source: node.id,\n target: node.loopTarget,\n data: { kind: \"loop\" },\n });\n } else {\n const edgeId = `${node.id}->${node.next.id}:next`;\n sink.pushEdge({\n id: edgeId,\n source: node.id,\n target: node.next.id,\n data: { kind: \"next\" },\n });\n walkNode(node.next, subflowPath, sink, visited);\n }\n }\n // Suppress unused-binding warning for stageId (kept for parity with\n // recorder upsertNode signature; xyflow node `id` is the string form).\n void stageId;\n}\n","/**\n * traceStructureRecorder — event-driven xyflow Node[] + Edge[] collector.\n *\n * Implements footprintjs v6.0+ `StructureRecorder` interface. Accumulates\n * an unpositioned graph (xyflow node + edge shape) as the chart is being\n * built — no spec tree walk required.\n *\n * Why event-driven\n * ────────────────\n * The recorder fires SYNCHRONOUSLY at every spec-mutation moment during\n * construction. By the time `.build()` returns, the recorder's\n * `getGraph()` returns the complete graph — zero extra walking\n * (the \"collect during traversal, never post-process\" rule footprintjs\n * documents in its core principle).\n *\n * Bonus: the same recorder shape can drive incremental UI updates if\n * the builder is constructed asynchronously (e.g., a UI builder where\n * each \"add stage\" click re-renders the live graph).\n *\n * Layout is a separate concern\n * ────────────────────────────\n * This module produces UNPOSITIONED nodes (no `position` field set;\n * xyflow defaults to `{x: 0, y: 0}`). Apply a layout algorithm\n * downstream — either:\n *\n * - a graph algorithm (dagre / elk / d3-force)\n * - manual positioning via your own walk over `recorder.getGraph()`\n *\n * The `<TraceFlow>` component wires a default BFS layout.\n *\n * @example\n * ```ts\n * import { flowChart } from 'footprintjs';\n * import { createTraceStructureRecorder } from 'footprint-explainable-ui/flowchart';\n *\n * const trace = createTraceStructureRecorder();\n * const chart = flowChart('seed', fn, 'seed', {\n * structureRecorders: [trace.recorder],\n * })\n * .addFunction('a', fnA, 'a')\n * .build();\n *\n * const { nodes, edges } = trace.getGraph();\n * // → nodes: [{ id: 'seed', data: { label: 'seed', ... } }, { id: 'a', ... }]\n * // → edges: [{ id: 'seed->a', source: 'seed', target: 'a', data: { kind: 'next' } }]\n *\n * <ReactFlow nodes={layout(nodes)} edges={edges} />\n * ```\n */\n\nimport type { Node, Edge } from \"@xyflow/react\";\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport type { StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { walkSubflowSpecInto } from \"./_internal/walkSubflowSpecInto\";\n\nexport type { StageId, RuntimeStageId } from \"./_internal/keys\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local type aliases mirroring footprintjs/StructureRecorder\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Rationale for redefining these here instead of `import type` from\n// 'footprintjs': footprint-explainable-ui has no `footprintjs` dependency\n// declared in package.json (intentional — consumers wire it). So we mirror\n// the public interface shape. If footprintjs changes the StructureRecorder\n// interface, this module's types must update in lockstep — tracked by the\n// type-conformance test in `test/unit/traceStructureRecorder.test.ts`.\n\ntype StructureNodeType = \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n\ninterface StructureSpecRef {\n readonly id: string;\n readonly name: string;\n readonly type?: StructureNodeType;\n readonly description?: string;\n readonly icon?: string;\n readonly isSubflowRoot?: boolean;\n readonly subflowId?: string;\n readonly isLazy?: boolean;\n readonly [key: string]: unknown;\n}\n\ninterface StageAddedEvent {\n readonly stageId: string;\n readonly name: string;\n readonly type: StructureNodeType;\n readonly isPausable?: boolean;\n readonly spec: StructureSpecRef;\n}\n\ntype EdgeKind = \"next\" | \"fork-branch\" | \"decision-branch\";\n\ninterface EdgeAddedEvent {\n readonly from: string;\n readonly to: string;\n readonly kind: EdgeKind;\n readonly label?: string;\n}\n\ninterface LoopEdgeAddedEvent {\n readonly from: string;\n readonly to: string;\n}\n\ninterface DeciderCompleteEvent {\n readonly decider: string;\n readonly type: \"decider\" | \"selector\";\n readonly branchIds: readonly string[];\n readonly defaultBranch?: string;\n}\n\ninterface SubflowMountedEvent {\n readonly subflowId: string;\n readonly subflowName: string;\n readonly rootStageId: string;\n readonly isLazy?: boolean;\n /**\n * The mounted subflow's complete spec — added in footprintjs v6.0\n * (proposal #001). Present for eager mounts, UNDEFINED for lazy\n * mounts (the subflow isn't resolved yet at mount-event-fire-time).\n * When present, the consumer walks it to materialize inner nodes +\n * edges directly with `subflowOf` set — no retroactive tagging\n * needed.\n *\n * Typed as `unknown` because the upstream `SerializedPipelineStructure`\n * shape has no index signature and we want to stay loosely-coupled\n * (see top-of-file rationale for the no-`footprintjs`-dep boundary).\n * `walkSubflowSpecInto` accepts the duck-typed shape it actually\n * walks.\n */\n readonly subflowSpec?: unknown;\n /**\n * Local mount id within the parent (matches `subflowId` for top-level\n * mounts; composed `'parent/child'` for nested). Tagged onto every\n * inner stage's `data.subflowOf` during the walk.\n */\n readonly subflowPath?: string;\n}\n\n/**\n * Minimal StructureRecorder interface — mirrors footprintjs v6.0+.\n *\n * Named with the `Minimal` prefix to make the local-mirror nature\n * explicit at consumer call sites — a consumer importing both this\n * type and the upstream `StructureRecorder` from `footprintjs` won't\n * collide, and code reviewers see at a glance which boundary the type\n * crosses.\n *\n * The upstream `footprintjs.StructureRecorder` is structurally\n * compatible (this type's shape is a subset of upstream's), so passing\n * an instance of this to `flowChart(..., { structureRecorders: [...] })`\n * typechecks cleanly.\n */\nexport interface MinimalStructureRecorder {\n readonly id: string;\n onStageAdded?(event: StageAddedEvent): void;\n onEdgeAdded?(event: EdgeAddedEvent): void;\n onLoopEdgeAdded?(event: LoopEdgeAddedEvent): void;\n onDeciderComplete?(event: DeciderCompleteEvent): void;\n onSubflowMounted?(event: SubflowMountedEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// xyflow node + edge data shapes\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Per-node data attached to the xyflow `Node`. The built-in `StageNode`\n * renderer reads the named fields below.\n *\n * Consumer extension: this type EXTENDS `Record<string, unknown>` so\n * you can attach custom fields without TypeScript fighting you. Pair\n * this with `<TraceFlow nodeTypes={{ stageNode: MyNode }} />` (or push\n * nodes with `type: 'myCustomKind'`) to render those custom fields\n * however you want. The built-in `StageNode` ignores fields it doesn't\n * recognize, so adding consumer fields is non-breaking even if you\n * keep the default renderer.\n */\nexport interface TraceNodeData extends Record<string, unknown> {\n label: string;\n isDecider: boolean;\n isFork: boolean;\n isSubflow: boolean;\n /** True when the event carried `type: 'streaming'` (the spec was added\n * via `addStreamingFunction`). Renderers that style streaming stages\n * distinctly key on this flag. */\n isStreaming: boolean;\n description?: string;\n icon?: string;\n subflowId?: string;\n isLazy?: boolean;\n isPausable?: boolean;\n /** Set later by `onDeciderComplete` when the decider's branch list is\n * sealed. Useful for renderers that want to render decider with a\n * branch-count badge. */\n branchIds?: readonly string[];\n defaultBranch?: string;\n /**\n * The subflow this node belongs to, OR `undefined` for top-level\n * parent-chart stages. Tracked via a stack-based heuristic during\n * event ingestion:\n *\n * - Push on `onSubflowMounted({subflowId, rootStageId})` →\n * top-of-stack = `{subflowId, mountStageId}`\n * - `onStageAdded` tags new nodes with the top-of-stack `subflowId`\n * (the mount node itself stays UNtagged — it's part of the parent\n * chain)\n * - Pop on `onEdgeAdded` where `from === mount.id` (a mount's\n * outgoing edge to a sibling means the parent chain has resumed);\n * the wrongly-tagged target node is re-tagged to the parent scope\n *\n * Mount nodes (where `isSubflow=true`) have `subflowOf` reflecting\n * their OWN parent context, NOT the subflow they mount. So a parent's\n * mount node has `subflowOf=undefined` (top-level parent), and the\n * subflow's INTERNAL stages have `subflowOf=<mount.subflowId>`.\n *\n * Renderers use this to filter the chart by drill-down level: show\n * only nodes where `subflowOf === currentDrillSubflowId` (undefined\n * for top-level view, mount.subflowId after drilling in).\n */\n subflowOf?: string;\n /**\n * **L8.0 — STRUCTURAL prev/next**: stage ids that lead into / out of\n * this node, derived live from incoming/outgoing edges. Excludes\n * `loop` back-edges (visual only — per invariant I1).\n *\n * Convergence-correct: a fork-join node carries an ENTRY per branch\n * child (e.g., `FinalizeOrder.prevIds = ['CheckInventory', 'RunFraudCheck']`).\n *\n * \"Structural\" qualifier: this is the chart-SHAPE prev/next, not\n * runtime execution order. For runtime ancestry use `CommitView`\n * fields on `CommitFlowIndex` (L8.2).\n */\n prevIds: StageId[];\n nextIds: StageId[];\n}\n\n/**\n * Per-edge data attached to the xyflow `Edge`. The default edge\n * renderer reads `kind` (and `label`).\n *\n * Consumer extension: same pattern as `TraceNodeData` — extra fields\n * pass through unchanged. Pair with `<TraceFlow edgeTypes={...} />`\n * to render custom edges (e.g., a \"retried\" edge with a count badge).\n */\nexport interface TraceEdgeData extends Record<string, unknown> {\n kind: EdgeKind | \"loop\";\n label?: string;\n}\n\nexport type TraceNode = Node<TraceNodeData>;\nexport type TraceEdge = Edge<TraceEdgeData>;\n\nexport interface TraceGraph {\n nodes: TraceNode[];\n edges: TraceEdge[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceStructureRecorderHandle {\n /** The recorder to register via `flowChart(..., { structureRecorders: [handle.recorder] })`\n * or `.attachStructureRecorder(handle.recorder)`. */\n recorder: MinimalStructureRecorder;\n /** Returns a defensive copy of the current graph state. Safe to call\n * multiple times; safe to mutate the returned arrays without affecting\n * the recorder's internal state. */\n getGraph(): TraceGraph;\n /** Direct read-only access for hot-path consumers (Lens slider scrubbing).\n * Returns the LIVE internal arrays — do NOT mutate. Prefer `getGraph()`\n * unless you measure a performance cost. */\n getGraphRef(): Readonly<TraceGraph>;\n /**\n * Subscribe to graph-change notifications. Pub-sub model — multiple\n * listeners can subscribe; each fires after every event that mutates\n * the graph (per-event, NOT batched). Returns an unsubscribe function.\n * Designed for React's `useSyncExternalStore` consumption.\n *\n * Listeners are NOT invoked during `reset()`. **Consumer guidance**:\n * if you need to clear a live `<TraceFlow recorder={handle} />`\n * mid-mount, either (a) unmount the component before calling\n * `reset()` and re-mount after, OR (b) drive a fresh recorder\n * instance via state. See `reset()` JSDoc for the rationale.\n */\n subscribe(listener: () => void): () => void;\n /**\n * Monotonically-increasing version counter — bumps once per\n * graph-mutating event. Pair with `getGraph()` in\n * `useSyncExternalStore` snapshot equality:\n * ```ts\n * const version = useSyncExternalStore(handle.subscribe, () => handle.version());\n * const graph = useMemo(() => handle.getGraph(), [version]);\n * ```\n * Avoids defensive-copy allocation on every render while keeping\n * React's identity-check happy.\n */\n version(): number;\n /** Reset the recorder for reuse across multiple builds. After this,\n * the recorder behaves like a freshly-constructed instance. */\n reset(): void;\n}\n\nexport interface CreateTraceStructureRecorderOptions {\n /** Recorder id — surfaces in `StructureBuildError.recorderId` when\n * the recorder throws. Defaults to `'trace-structure'`. Use distinct\n * ids if you attach multiple instances. */\n id?: string;\n /** Optional callback fired after each event mutates the graph. Useful\n * for incremental-render UIs (Lens) that want to re-render between\n * builder operations. NOT invoked during the initial `attachStructureRecorder`\n * seed replay; consumers can call `getGraph()` directly after attach. */\n onChange?: (graph: Readonly<TraceGraph>) => void;\n}\n\nexport function createTraceStructureRecorder(\n options: CreateTraceStructureRecorderOptions = {},\n): TraceStructureRecorderHandle {\n const id = options.id ?? \"trace-structure\";\n const onChange = options.onChange;\n\n let nodes: TraceNode[] = [];\n let edges: TraceEdge[] = [];\n // Indexes — O(1) lookup for decider-completion + subflow-mounted updates.\n const nodeIndex = new Map<string, number>();\n const seenEdgeIds = new Set<string>();\n // L8.0 — per-node prev/next indexes maintained as edges arrive. The\n // arrays land on `TraceNode.data.prevIds` / `data.nextIds` so basic\n // TraceGraph consumers get convergence-correct neighbor info \"for\n // free\" (no separate NodeView translator needed for chart rendering).\n const prevIdsOf = new Map<string, StageId[]>();\n const nextIdsOf = new Map<string, StageId[]>();\n // Pub-sub + version via shared infra (microtask-batched listener fan-out).\n const notifier = createNotifier(\"traceStructureRecorder\");\n\n function notifyChange(): void {\n if (onChange) {\n try {\n onChange({ nodes, edges });\n } catch (err) {\n devWarn(\n () => \"[traceStructureRecorder] onChange callback threw — isolated.\",\n err,\n );\n }\n }\n notifier.notify();\n }\n\n function upsertNode(node: TraceNode): void {\n const existing = nodeIndex.get(node.id);\n if (existing !== undefined) {\n // Merge: later events may carry richer data (e.g., onDeciderComplete\n // → branchIds). Preserve any fields the new event didn't set.\n nodes[existing] = {\n ...nodes[existing],\n ...node,\n data: { ...nodes[existing]!.data, ...node.data },\n };\n } else {\n nodeIndex.set(node.id, nodes.length);\n nodes.push(node);\n }\n }\n\n function pushEdge(edge: TraceEdge): void {\n // Dedupe by id — the seed replay path could otherwise double-add\n // if a consumer attaches the same recorder twice (allowed by design,\n // but the graph should still be sane).\n if (seenEdgeIds.has(edge.id)) return;\n seenEdgeIds.add(edge.id);\n edges.push(edge);\n\n // L8.0 — maintain prev/next indexes. Loop back-edges do NOT\n // contribute (invariant I1: loops are visual annotations only).\n const kind = edge.data?.kind;\n if (kind === \"loop\") return;\n const source = asStageId(edge.source);\n const target = asStageId(edge.target);\n const nextArr = nextIdsOf.get(source) ?? [];\n nextArr.push(target);\n nextIdsOf.set(source, nextArr);\n const prevArr = prevIdsOf.get(target) ?? [];\n prevArr.push(source);\n prevIdsOf.set(target, prevArr);\n\n // Sync the index changes onto the LIVE node-data arrays so\n // consumers reading `node.data.prevIds`/`nextIds` see fresh values\n // after each edge event. We mutate in place rather than re-cloning\n // the node — `getGraph()` returns defensive copies anyway.\n syncNeighborsOnto(source);\n syncNeighborsOnto(target);\n }\n\n function syncNeighborsOnto(stageId: StageId): void {\n const idx = nodeIndex.get(stageId);\n if (idx === undefined) return; // node not yet announced — will sync at onStageAdded\n const node = nodes[idx]!;\n // L8.0 panel must-fix: ATOMIC REPLACE — copy the arrays from the\n // index, don't share the map's array refs. A consumer using\n // `getGraphRef()` who caches `node.data.prevIds` would otherwise\n // see their cached array silently grow when a new edge fires.\n // The slice() cost is one allocation per edge per touched node —\n // negligible vs. the consumer-safety win.\n const prevs = prevIdsOf.get(stageId);\n const nexts = nextIdsOf.get(stageId);\n node.data.prevIds = prevs ? prevs.slice() : [];\n node.data.nextIds = nexts ? nexts.slice() : [];\n }\n\n const recorder: MinimalStructureRecorder = {\n id,\n onStageAdded(event) {\n const spec = event.spec;\n const type = event.type;\n const isDecider = type === \"decider\" || type === \"selector\";\n const isFork = type === \"fork\";\n const isStreaming = type === \"streaming\";\n const isSubflow = !!spec.isSubflowRoot;\n\n const stageId = asStageId(event.stageId);\n const data: TraceNodeData = {\n label: event.name,\n isDecider,\n isFork,\n isStreaming,\n isSubflow,\n // L8.0 — seed prev/next from any edges that already fired\n // pointing AT this node. Convergence case: a fork-branch edge\n // from LoadOrder fires BEFORE the child's onStageAdded; this\n // line ensures the child's prevIds picks up the back-pointer.\n // Atomic copy (not shared ref) — see `syncNeighborsOnto` for\n // the panel-flagged consumer-safety rationale.\n prevIds: (prevIdsOf.get(stageId) ?? []).slice(),\n nextIds: (nextIdsOf.get(stageId) ?? []).slice(),\n };\n if (spec.description !== undefined) data.description = spec.description;\n if (spec.icon !== undefined) data.icon = spec.icon;\n if (spec.subflowId !== undefined) data.subflowId = spec.subflowId;\n if (spec.isLazy === true) data.isLazy = true;\n if (event.isPausable === true) data.isPausable = true;\n // subflowOf gets set RETROACTIVELY in onSubflowMounted (the\n // builder fires inner-stage events BEFORE the mount event, so\n // we can't tag at stage-add time — we tag at mount time by\n // identifying untagged disconnected subgraphs).\n\n upsertNode({\n id: event.stageId,\n type: \"stage\",\n // No layout here — downstream consumer applies positions.\n position: { x: 0, y: 0 },\n data,\n });\n notifyChange();\n },\n\n onEdgeAdded(event) {\n const edgeId = `${event.from}->${event.to}:${event.kind}${event.label ? `:${event.label}` : \"\"}`;\n const data: TraceEdgeData = { kind: event.kind };\n if (event.label !== undefined) data.label = event.label;\n const edge: TraceEdge = {\n id: edgeId,\n source: event.from,\n target: event.to,\n data,\n };\n if (event.label !== undefined) edge.label = event.label;\n pushEdge(edge);\n notifyChange();\n },\n\n onLoopEdgeAdded(event) {\n const edgeId = `${event.from}->${event.to}:loop`;\n pushEdge({\n id: edgeId,\n source: event.from,\n target: event.to,\n data: { kind: \"loop\" },\n });\n notifyChange();\n },\n\n onDeciderComplete(event) {\n // Patch the already-added decider node with its sealed branch info.\n const existing = nodeIndex.get(event.decider);\n if (existing === undefined) {\n // The decider node SHOULD have been added via onStageAdded\n // before its branches were declared. If this fires for an\n // unknown id, the upstream builder reordered events —\n // visualisation will silently degrade. Warn in dev so the bug\n // is visible at its source.\n devWarn(\n () =>\n `[traceStructureRecorder] onDeciderComplete fired for unknown stageId \"${event.decider}\" — branch metadata dropped. Did the upstream fire onStageAdded for this id first?`,\n );\n return;\n }\n const node = nodes[existing]!;\n const data: TraceNodeData = {\n ...node.data,\n branchIds: event.branchIds,\n };\n if (event.defaultBranch !== undefined) data.defaultBranch = event.defaultBranch;\n nodes[existing] = { ...node, data };\n notifyChange();\n },\n\n onSubflowMounted(event) {\n // The mount node was already announced via `onStageAdded`; here\n // we patch in the subflow-specific data fields, then materialize\n // the subflow's inner structure.\n const existing = nodeIndex.get(event.rootStageId);\n if (existing === undefined) {\n devWarn(\n () =>\n `[traceStructureRecorder] onSubflowMounted fired for unknown rootStageId \"${event.rootStageId}\" (subflowId=\"${event.subflowId}\") — subflow metadata dropped. Did the upstream fire onStageAdded for the mount node first?`,\n );\n return;\n }\n const node = nodes[existing]!;\n const data: TraceNodeData = {\n ...node.data,\n isSubflow: true,\n subflowId: event.subflowId,\n };\n if (event.isLazy === true) data.isLazy = true;\n nodes[existing] = { ...node, data };\n\n // Eager mounts (footprintjs v6.0+): walk the full subflow spec\n // delivered on the event to emit inner nodes + edges with\n // `subflowOf` set directly. Lazy mounts arrive with no spec —\n // their internal structure isn't known until the resolver runs\n // at runtime; the mount node alone is rendered (consumer apps\n // can subscribe to runtime events to fill in detail if desired).\n const subflowPath = event.subflowPath ?? event.subflowId;\n if (event.subflowSpec) {\n // Cast: type is `unknown` at the event boundary (see\n // SubflowMountedEvent JSDoc); walkSubflowSpecInto accepts\n // the duck-typed structural shape it actually traverses.\n walkSubflowSpecInto(event.subflowSpec as Parameters<typeof walkSubflowSpecInto>[0], subflowPath, {\n upsertNode,\n pushEdge,\n });\n }\n notifyChange();\n },\n };\n\n return {\n recorder,\n getGraph(): TraceGraph {\n return {\n nodes: nodes.map((n) => ({ ...n, data: { ...n.data } })),\n edges: edges.map((e) => ({ ...e, data: e.data ? { ...e.data } : undefined })),\n };\n },\n getGraphRef(): Readonly<TraceGraph> {\n return { nodes, edges };\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n nodes = [];\n edges = [];\n nodeIndex.clear();\n seenEdgeIds.clear();\n prevIdsOf.clear();\n nextIdsOf.clear();\n // Why `reset()` does NOT bump version or notify listeners:\n // a notify here would cause `<TraceFlow recorder={handle} />`\n // to re-render with an empty graph for one frame, then re-render\n // again when the next builder event fires — visible flicker for\n // users who reset between builds. The recommended pattern is to\n // recycle the recorder OUTSIDE the React tree (e.g., via a\n // factory hook keyed on a \"build epoch\" so React unmounts and\n // re-mounts <TraceFlow> across builds). See `subscribe()` JSDoc\n // for the consumer-facing recipe.\n },\n };\n}\n","/**\n * createNodeViewRecorder — per-stage summary translator.\n *\n * Implements footprintjs v6.0+ `CombinedRecorder` (Flow + Scope) and\n * produces a `NodeViewIndex` — per-stage data keyed by both `StageId`\n * (chart-shape lookup) and `RuntimeStageId` (per-execution lookup).\n *\n * Composition (panel guidance, L8.0 review)\n * ─────────────────────────────────────────\n * NodeView does NOT duplicate the structural prev/next index — it\n * READS those fields from the structure translator's\n * `node.data.prevIds`/`nextIds`. The structure translator already\n * maintains convergence-correct, loop-excluded neighbors. Duplicating\n * the index here would re-introduce edge-ordering bugs we just\n * solved.\n *\n * The NodeView translator owns ONLY runtime-derived per-stage state:\n * - `executions[]` — every FlowRecorder.onStageExecuted event for\n * this stage (loop-friendly: N executions of one stage produce\n * N entries, each with its own runtimeStageId).\n * - `commitRuntimeStageIds[]` — refs to commits made by this stage\n * (the canonical CommitView lives in CommitFlowIndex from L8.2;\n * NodeView stores only the join key).\n *\n * Plus derived convenience fields: `visitedInRun`, `executionCount`,\n * `firstExecutedAt`, `lastExecutedAt`, `totalDurationMs`, `errorCount`.\n *\n * Version bumping\n * ───────────────\n * NodeView bumps its own version on EITHER:\n * (a) a Flow/Scope event arrives (own state mutates), OR\n * (b) the structure translator's version bumps (structural data\n * the index projects from changed).\n *\n * So `useTranslator(nodeView, ...)` re-renders when EITHER changes —\n * one subscription, full reactive coverage.\n *\n * @example\n * ```tsx\n * import { createTraceStructureRecorder, createNodeViewRecorder, useTranslator } from 'footprint-explainable-ui/flowchart';\n *\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const nodeView = useMemo(() => createNodeViewRecorder({ structure: trace }), [trace]);\n *\n * useEffect(() => {\n * executor.attachFlowRecorder(nodeView.recorder);\n * executor.attachScopeRecorder(nodeView.recorder);\n * }, [nodeView]);\n *\n * const index = useTranslator(nodeView, () => nodeView.getIndex());\n * const finalize = index.byStageId.get(asStageId('FinalizeOrder'));\n * // finalize.prevIds → ['CheckInventory', 'RunFraudCheck'] (from structure)\n * // finalize.executions → [{ runtimeStageId, iteration, startMs, endMs, ... }]\n * // finalize.visitedInRun → true\n * // finalize.commitRuntimeStageIds → ['finalize-order#3', ...]\n * ```\n */\n\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport { asStageId, asRuntimeStageId } from \"./_internal/keys\";\nimport type { StageId, RuntimeStageId } from \"./_internal/keys\";\nimport type { TraceStructureRecorderHandle, TraceNode } from \"./traceStructureRecorder\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local mirrors of footprintjs runtime recorder interfaces\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Same rationale as other translators: explainable-ui has no\n// `footprintjs` dep — we mirror the subset we consume. Structural\n// compatibility means our `recorder` passes through to\n// `executor.attachFlowRecorder()` / `attachScopeRecorder()` cleanly.\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface FlowStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly traversalContext: TraversalContext;\n readonly startTime?: number;\n readonly endTime?: number;\n}\n\ninterface FlowErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface FlowRunLifecycleEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface ScopeCommitEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly updates?: Record<string, unknown>;\n readonly reads?: readonly string[];\n}\n\n/**\n * Minimal CombinedRecorder interface mirror — subset of footprintjs's\n * Flow + Scope recorder interfaces NodeView consumes. Implements both\n * channels in one object; consumer attaches via\n * `executor.attachFlowRecorder()` AND `executor.attachScopeRecorder()`\n * (or `executor.attachCombinedRecorder()` if available).\n */\nexport interface MinimalNodeViewRecorder {\n readonly id: string;\n // Flow channel\n onStageExecuted?(event: FlowStageExecutedEvent): void;\n onError?(event: FlowErrorEvent): void;\n onRunStart?(event: FlowRunLifecycleEvent): void;\n onRunEnd?(event: FlowRunLifecycleEvent): void;\n // Scope channel\n onCommit?(event: ScopeCommitEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** One execution of a stage. A stage that runs N times in a loop\n * produces N `ExecutionRecord` entries on the NodeView.executions[]. */\nexport interface ExecutionRecord {\n /** `[subflowPath/]stageId#executionIndex` — universal join key. */\n readonly runtimeStageId: RuntimeStageId;\n /** Loop iteration (0-indexed). undefined when the engine didn't\n * populate it (rare). */\n readonly iteration?: number;\n /** ms since executor start. */\n readonly startMs?: number;\n /** ms since executor start. */\n readonly endMs?: number;\n /** Set when `onError` fired for this execution. */\n readonly errorMessage?: string;\n}\n\n/**\n * Per-stage summary. Joins STRUCTURAL data (from the structure\n * translator's TraceNode.data) with RUNTIME data (executions + commit\n * refs accumulated by this translator).\n */\nexport interface NodeView {\n // ── Identity ────────────────────────────────────────────────────\n readonly stageId: StageId;\n readonly label: string;\n\n // ── Structural (read-through from structure translator) ─────────\n readonly type: \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n readonly isDecider: boolean;\n readonly isFork: boolean;\n readonly isSubflow: boolean;\n readonly isStreaming: boolean;\n readonly isPausable: boolean;\n readonly description?: string;\n readonly icon?: string;\n readonly subflowId?: string;\n readonly branchIds?: readonly string[];\n readonly defaultBranch?: string;\n /** From the structure translator (loop-excluded, convergence-correct). */\n readonly prevIds: StageId[];\n readonly nextIds: StageId[];\n\n // ── Visit data (runtime) ────────────────────────────────────────\n readonly executions: ExecutionRecord[];\n /** Derived: `executions.length > 0`. */\n readonly visitedInRun: boolean;\n /** Derived: `executions.length` (loop iteration count). */\n readonly executionCount: number;\n /** Derived: first execution `startMs`, or `null` if not yet executed. */\n readonly firstExecutedAt: number | null;\n /** Derived: last execution `endMs`, or `null`. */\n readonly lastExecutedAt: number | null;\n /** Derived: sum of `endMs - startMs` across executions. */\n readonly totalDurationMs: number;\n /** Derived: count of executions with an errorMessage. */\n readonly errorCount: number;\n\n // ── Commit refs (join key into CommitFlowIndex from L8.2) ───────\n /** Run-time stage ids of commits made by this stage. Look up the\n * canonical CommitView via `commitFlow.byRuntimeStageId.get(id)`. */\n readonly commitRuntimeStageIds: RuntimeStageId[];\n}\n\n/** Index of NodeView keyed by both StageId and RuntimeStageId. The\n * branded types prevent `byStageId.get(runtimeStageId)` silent-undefined. */\nexport interface NodeViewIndex {\n readonly byStageId: ReadonlyMap<StageId, NodeView>;\n readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, NodeView>;\n /** All NodeViews — insertion order matches structure translator. */\n readonly all: readonly NodeView[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface NodeViewRecorderHandle {\n /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`\n * AND `executor.attachScopeRecorder()` (footprintjs routes by\n * method-shape detection). */\n recorder: MinimalNodeViewRecorder;\n /** Returns a defensive copy of the current index state. */\n getIndex(): NodeViewIndex;\n /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps on Flow/Scope event OR when\n * the structure translator's version bumps (since NodeView projects\n * from its data). */\n version(): number;\n /** Reset runtime state. Does NOT bump version or notify (consistent\n * with traceStructureRecorder + createTraceRuntimeOverlay). */\n reset(): void;\n}\n\nexport interface CreateNodeViewRecorderOptions {\n /** Recorder id (surfaces in error attribution). */\n id?: string;\n /** REQUIRED — the structure translator handle. NodeView projects\n * structural fields (`prevIds`, `nextIds`, `label`, etc.) from\n * this on every `getIndex()` call. */\n structure: TraceStructureRecorderHandle;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Strip `#executionIndex` from runtimeStageId to recover the base\n * stageId. **Use only for in-translator matching where both sides\n * use full-path-prefixed stageIds consistently** (invariant I3 — do\n * NOT use this to match commitLog stageIds across subflow boundaries). */\nfunction baseStageIdOf(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createNodeViewRecorder(\n options: CreateNodeViewRecorderOptions,\n): NodeViewRecorderHandle {\n const id = options.id ?? \"node-view\";\n const structure = options.structure;\n if (!structure) {\n throw new Error(\n \"[createNodeViewRecorder] `structure` option is required. \" +\n \"Pass the handle returned by `createTraceStructureRecorder()`.\",\n );\n }\n\n // Per-stage execution + commit-ref state. Keyed by base stageId.\n // Loops produce multiple entries with the same stageId / different\n // runtimeStageIds.\n let executionsOf: Map<StageId, ExecutionRecord[]> = new Map();\n let commitRefsOf: Map<StageId, RuntimeStageId[]> = new Map();\n // Reverse lookup: runtimeStageId → its base stageId. Lets\n // `byRuntimeStageId` map directly to a NodeView without\n // re-parsing.\n let stageIdOfRuntimeStageId: Map<RuntimeStageId, StageId> = new Map();\n\n const notifier = createNotifier(\"node-view\");\n\n // Subscribe to structure translator — when its graph changes\n // (e.g., new stage announced during incremental build), bump our\n // version so consumers re-derive the projection.\n const unsubStructure = structure.subscribe(() => notifier.notify());\n\n function recordExecution(event: FlowStageExecutedEvent): void {\n // L8.1 Panel 2 must-fix: guard against malformed event payloads\n // (asymmetric with recordError's existing guard). Upstream MAY\n // fire with traversalContext absent if the engine's runtime\n // observer chain is reorganised — fail soft, not hard.\n const rsid = event.traversalContext?.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onStageExecuted event without traversalContext.runtimeStageId — execution attribution dropped (stage=${event.stageName}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const runtimeStageId = asRuntimeStageId(rsid);\n const execList = executionsOf.get(stageId) ?? [];\n const record: ExecutionRecord = {\n runtimeStageId,\n ...(event.traversalContext.iteration !== undefined && {\n iteration: event.traversalContext.iteration,\n }),\n ...(event.startTime !== undefined && { startMs: event.startTime }),\n ...(event.endTime !== undefined && { endMs: event.endTime }),\n };\n execList.push(record);\n executionsOf.set(stageId, execList);\n stageIdOfRuntimeStageId.set(runtimeStageId, stageId);\n notifier.notify();\n }\n\n function recordError(event: FlowErrorEvent): void {\n const rsid = event.traversalContext?.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onError event without traversalContext.runtimeStageId — error attribution dropped (stage=${event.stageName}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const runtimeStageId = asRuntimeStageId(rsid);\n const execList = executionsOf.get(stageId);\n // L8.1 Panel 1 must-fix: match by runtimeStageId equality (NOT\n // array position). With interleaved-stage events under footprintjs's\n // FlowRecorder dispatcher, \"most-recent execution by array index\"\n // can attach an error to the wrong execution. Looking up by\n // runtimeStageId is the correct join key.\n const matchIdx = execList\n ? execList.findIndex((e) => e.runtimeStageId === runtimeStageId)\n : -1;\n if (!execList || matchIdx === -1) {\n // Error before onStageExecuted? Synthesize a minimal execution\n // record so consumers see the error.\n const synth: ExecutionRecord = {\n runtimeStageId,\n errorMessage: event.message ?? \"error\",\n };\n if (execList) {\n execList.push(synth);\n } else {\n executionsOf.set(stageId, [synth]);\n }\n } else {\n const match = execList[matchIdx]!;\n execList[matchIdx] = { ...match, errorMessage: event.message ?? \"error\" };\n }\n stageIdOfRuntimeStageId.set(runtimeStageId, stageId);\n notifier.notify();\n }\n\n function recordCommit(event: ScopeCommitEvent): void {\n // Read runtimeStageId directly from the onCommit payload\n // (panel L8.0 ordering invariant: Scope.onCommit fires BEFORE\n // Flow.onStageExecuted; don't rely on Flow event arriving first).\n const rsid = event.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onCommit event without runtimeStageId — commit attribution dropped (stage=${event.stage ?? event.stageId ?? \"?\"}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const refs = commitRefsOf.get(stageId) ?? [];\n refs.push(asRuntimeStageId(rsid));\n commitRefsOf.set(stageId, refs);\n stageIdOfRuntimeStageId.set(asRuntimeStageId(rsid), stageId);\n notifier.notify();\n }\n\n const recorder: MinimalNodeViewRecorder = {\n id,\n onStageExecuted: recordExecution,\n onError: recordError,\n onCommit: recordCommit,\n // onRunStart / onRunEnd — no-op for now (state stays alive across\n // runs; consumers call .reset() between runs if they want fresh\n // state). Listed for shape conformance with FlowRecorder.\n onRunStart() {\n /* no-op */\n },\n onRunEnd() {\n /* no-op */\n },\n };\n\n function buildView(structNode: TraceNode): NodeView {\n const stageId = asStageId(structNode.id);\n const execs = executionsOf.get(stageId) ?? [];\n const commitRefs = commitRefsOf.get(stageId) ?? [];\n\n // Derived visit-data fields\n const visitedInRun = execs.length > 0;\n const executionCount = execs.length;\n const firstExecutedAt = execs.length > 0 && execs[0]!.startMs !== undefined\n ? execs[0]!.startMs!\n : null;\n const lastExecutedAt = execs.length > 0 && execs[execs.length - 1]!.endMs !== undefined\n ? execs[execs.length - 1]!.endMs!\n : null;\n let totalDurationMs = 0;\n let errorCount = 0;\n for (const e of execs) {\n if (e.startMs !== undefined && e.endMs !== undefined) {\n totalDurationMs += e.endMs - e.startMs;\n }\n if (e.errorMessage) errorCount++;\n }\n\n const d = structNode.data;\n return {\n stageId,\n label: d.label,\n type: (structNode.type as NodeView[\"type\"]) ?? \"stage\",\n isDecider: d.isDecider,\n isFork: d.isFork,\n isSubflow: d.isSubflow,\n isStreaming: d.isStreaming,\n isPausable: d.isPausable === true,\n ...(d.description !== undefined && { description: d.description }),\n ...(d.icon !== undefined && { icon: d.icon }),\n ...(d.subflowId !== undefined && { subflowId: d.subflowId }),\n // L8.1 Panel 2 must-fix: branchIds is a live ref from the\n // structure translator's internal graph — defensive copy via\n // slice() prevents consumer mutation from corrupting it.\n ...(d.branchIds !== undefined && { branchIds: d.branchIds.slice() }),\n ...(d.defaultBranch !== undefined && { defaultBranch: d.defaultBranch }),\n // Note: structure translator always sets prevIds/nextIds (never\n // undefined). The slice() copies defend against consumer mutation.\n prevIds: d.prevIds.slice(),\n nextIds: d.nextIds.slice(),\n executions: execs.map((e) => ({ ...e })),\n visitedInRun,\n executionCount,\n firstExecutedAt,\n lastExecutedAt,\n totalDurationMs,\n errorCount,\n commitRuntimeStageIds: commitRefs.slice(),\n };\n }\n\n // L8.1 Panel 5 optimization: version-keyed cache. `getIndex()` is\n // called per React render that observes a version bump; with N\n // translators subscribed + StrictMode double-invoke, a single\n // stage event can produce 6+ full rebuilds. Cache the last index\n // keyed on `(ownVersion, structureVersion)` — return the cached\n // index when neither has changed since the previous build.\n let cachedIndex: NodeViewIndex | null = null;\n let cachedOwnVersion = -1;\n let cachedStructureVersion = -1;\n\n return {\n recorder,\n getIndex(): NodeViewIndex {\n const own = notifier.version();\n const struct = structure.version();\n if (\n cachedIndex !== null &&\n cachedOwnVersion === own &&\n cachedStructureVersion === struct\n ) {\n return cachedIndex;\n }\n // Read structure live — we project from its current graph each\n // call. Defensive-copy via getGraph() would over-allocate; we\n // use getGraphRef() and tolerate the read-only contract (we\n // don't mutate structure data).\n const graphRef = structure.getGraphRef();\n const byStageId = new Map<StageId, NodeView>();\n const byRuntimeStageId = new Map<RuntimeStageId, NodeView>();\n const all: NodeView[] = [];\n for (const structNode of graphRef.nodes) {\n const view = buildView(structNode);\n byStageId.set(view.stageId, view);\n all.push(view);\n // Reverse map: every execution's runtimeStageId → this view.\n for (const exec of view.executions) {\n byRuntimeStageId.set(exec.runtimeStageId, view);\n }\n // Commit refs also point back to this view (a stage's\n // runtimeStageId for its execution is the same key its\n // commit carries).\n for (const rsid of view.commitRuntimeStageIds) {\n byRuntimeStageId.set(rsid, view);\n }\n }\n cachedIndex = { byStageId, byRuntimeStageId, all };\n cachedOwnVersion = own;\n cachedStructureVersion = struct;\n return cachedIndex;\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n executionsOf = new Map();\n commitRefsOf = new Map();\n stageIdOfRuntimeStageId = new Map();\n // L8.1 — invalidate the version-keyed cache. We do NOT bump\n // version (matches the other translators' reset contract — see\n // traceStructureRecorder's `reset()` JSDoc for the consumer\n // recipe), but the cache MUST be cleared so the next\n // `getIndex()` rebuilds from the freshly-empty state instead\n // of returning a stale snapshot.\n cachedIndex = null;\n cachedOwnVersion = -1;\n cachedStructureVersion = -1;\n // We intentionally do NOT unsubscribe from structure here; the\n // handle is still alive across resets.\n void unsubStructure;\n },\n };\n}\n","/**\n * createCommitFlowRecorder — per-commit summary translator.\n *\n * Owns the canonical `CommitView[]` — captured from Scope `onCommit`\n * events as the chart runs. Each CommitView joins:\n *\n * - **Identity**: runtimeStageId, stageId, commitIdx\n * - **Structural**: prev/next stage ids (read from structure\n * translator's `TraceNode.data.prevIds`/`nextIds`)\n * - **Runtime prev/next**: derived via \"most-recent-per-structural-\n * prev\" rule over the commitLog (loop-safe, convergence-aware)\n * - **Data dependencies**: per-read-key lineage via\n * `findLastWriter` over the commitLog\n * - **Payload**: updates + reads\n *\n * Composition (panel guidance, L8.1 review)\n * ─────────────────────────────────────────\n * Per Panel 1 rule \"translators MUST subscribe to structure\n * directly, never to peer translators\", CommitFlow subscribes to\n * the structure handle (NOT to NodeView). Linear dependency tree\n * keeps notify cascades O(depth) instead of O(N²).\n *\n * NodeView (L8.1) stores `commitRuntimeStageIds[]` — refs only —\n * pointing into CommitFlow's `byRuntimeStageId`. The canonical\n * payload lives HERE; NodeView is the per-stage projection.\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const commitFlow = useMemo(\n * () => createCommitFlowRecorder({ structure: trace }),\n * [trace],\n * );\n * useEffect(() => {\n * executor.attachFlowRecorder(commitFlow.recorder);\n * executor.attachScopeRecorder(commitFlow.recorder);\n * }, [commitFlow]);\n *\n * const index = useTranslator(commitFlow, () => commitFlow.getIndex());\n * const c = index.byRuntimeStageId.get(asRuntimeStageId('finalize-order#3'));\n * c.structuralPrevIds // ['CheckInventory', 'RunFraudCheck']\n * c.runtimePrevIds // ['check-inventory#1', 'run-fraud-check#2']\n * c.dataDependencies // [{ key:'inStock', sourceRuntimeStageId:'check-inventory#1', sourceCommitIdx:1 }, ...]\n *\n * const lineage = backtraceDataFlow(index, asRuntimeStageId('finalize-order#3'));\n * // → ancestry chain of commits whose writes contributed to this commit's reads\n * ```\n */\n\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport { asStageId, asRuntimeStageId } from \"./_internal/keys\";\nimport type { StageId, RuntimeStageId } from \"./_internal/keys\";\nimport type { TraceStructureRecorderHandle } from \"./traceStructureRecorder\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local mirrors of footprintjs runtime recorder interfaces\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface FlowStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly traversalContext: TraversalContext;\n}\n\ninterface FlowErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface FlowRunLifecycleEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface ScopeReadEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly key?: string;\n}\n\ninterface ScopeCommitEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly updates?: Record<string, unknown>;\n readonly reads?: readonly string[];\n}\n\n/**\n * Minimal CombinedRecorder mirror — subset of footprintjs's Flow +\n * Scope channels CommitFlow consumes.\n */\nexport interface MinimalCommitFlowRecorder {\n readonly id: string;\n // Flow channel — for runtimeStageId enrichment + error attribution\n onStageExecuted?(event: FlowStageExecutedEvent): void;\n onError?(event: FlowErrorEvent): void;\n onRunStart?(event: FlowRunLifecycleEvent): void;\n onRunEnd?(event: FlowRunLifecycleEvent): void;\n // Scope channel — the canonical commit + read data source\n onRead?(event: ScopeReadEvent): void;\n onCommit?(event: ScopeCommitEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * One data-dependency edge — a read key in this commit AND the commit\n * whose `updates` last wrote that key before this commit's index.\n *\n * `sourceRuntimeStageId` and `sourceCommitIdx` are BOTH `null` when no\n * prior commit wrote the key (panel-flagged: NEVER `undefined` — forces\n * consumers to handle absence as load-bearing).\n */\nexport interface DataDependency {\n readonly key: string;\n readonly sourceRuntimeStageId: RuntimeStageId | null;\n readonly sourceCommitIdx: number | null;\n}\n\n/**\n * Per-commit summary. Joins structural data (from the structure\n * translator) with runtime data (commitLog timeline) into a single\n * consumer-friendly shape.\n *\n * Three \"prev\" views — pick the right one for your UI:\n * ─────────────────────────────────────────────────────\n * | Field | Answers |\n * |----------------------|--------------------------------------------|\n * | `structuralPrevIds` | \"what COULD flow in\" (chart shape) |\n * | `runtimePrevIds` | \"what DID flow in by stage\" (execution |\n * | | timeline; loop-aware) |\n * | `dataDependencies` | \"which commit wrote the bytes I read\" |\n * | | (causal data lineage; per-key) |\n *\n * The three answers usually align on simple charts (linear; single\n * fork-merge). They DIVERGE in interesting ways under loops (runtime\n * differs by iteration; data-deps may skip uninvolved stages) and\n * conditional branches (structural sees all options; runtime + data\n * see only the chosen path).\n */\nexport interface CommitView {\n // ── Identity ────────────────────────────────────────────────────\n readonly runtimeStageId: RuntimeStageId;\n readonly stageId: StageId;\n /** Position in the chronologically-ordered commitLog. */\n readonly commitIdx: number;\n\n // ── Structural (from structure translator) ──────────────────────\n /** Stage ids that lead into this stage in the chart (loop-excluded). */\n readonly structuralPrevIds: StageId[];\n readonly structuralNextIds: StageId[];\n\n // ── Runtime (derived: structural prev ∩ commitLog up-to-here) ──\n /**\n * For each structural prev stage that EXECUTED IN THIS RUN before\n * this commit, the most-recent runtimeStageId of that prev's commit.\n * Loop-safe: in iteration 2, runtime prev points at iteration 2's\n * commits (not iteration 1's).\n */\n readonly runtimePrevIds: RuntimeStageId[];\n /**\n * For each structural next stage that EXECUTED IN THIS RUN after\n * this commit, the soonest runtimeStageId. Symmetric to prev.\n */\n readonly runtimeNextIds: RuntimeStageId[];\n\n // ── Data flow (per-key lineage via findLastWriter) ──────────────\n /**\n * One entry per key in `reads`. `sourceRuntimeStageId` points at the\n * commit whose `updates` last set this key BEFORE this commit's\n * index; `null` when no prior writer (typically: read of a key\n * declared as default but never written by another stage).\n */\n readonly dataDependencies: DataDependency[];\n\n // ── Payload ─────────────────────────────────────────────────────\n /**\n * The commit's writes. **Shallow-copied** at intake — top-level\n * keys are owned, but nested object values are SHARED references\n * to whatever the upstream `onCommit` payload carried. Consumers\n * MUST NOT mutate nested values; doing so corrupts the recorder's\n * internal state and propagates through `findLastWriter` to every\n * subsequent `getIndex()` call.\n */\n readonly updates: Record<string, unknown>;\n readonly reads: string[];\n}\n\n/** Indexed CommitView access. */\nexport interface CommitFlowIndex {\n /** Ordered list — index === commitIdx. */\n readonly commits: readonly CommitView[];\n /** Lookup by runtimeStageId (the universal join key). */\n readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, CommitView>;\n /**\n * Data-dependency edges — `from` and `to` are commitIdx ints; `key`\n * is the data key that flowed from one commit to the other. Same\n * data as walking each CommitView's `dataDependencies` — exposed as\n * a flat edge list for graph algorithms and rendering.\n *\n * **When to use which**:\n * - `view.dataDependencies` — render ONE commit's inputs in a\n * detail panel (e.g., `<CommitInspector>`).\n * - `index.dataEdges` — draw the FULL data-flow DAG (React Flow\n * edges, GraphViz, dependency matrix, etc.). One pass over the\n * flat list = the whole graph.\n *\n * Edges are `Object.freeze()`d at construction — type `readonly` is\n * compile-time; freeze is the runtime enforcement.\n */\n readonly dataEdges: readonly { readonly from: number; readonly to: number; readonly key: string }[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CommitFlowRecorderHandle {\n /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`\n * AND `executor.attachScopeRecorder()`. */\n recorder: MinimalCommitFlowRecorder;\n /** Returns a defensive copy of the current index state. */\n getIndex(): CommitFlowIndex;\n /** Pub-sub: returns unsubscribe. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps on Scope/Flow event OR when\n * the structure translator's version bumps. */\n version(): number;\n /** Reset runtime state. Does NOT bump version or notify (consistent\n * with other translators' reset contracts). */\n reset(): void;\n}\n\nexport interface CreateCommitFlowRecorderOptions {\n /** Recorder id (surfaces in error attribution). */\n id?: string;\n /** REQUIRED — structure translator handle for structural prev/next\n * projection. CommitFlow subscribes to its version. */\n structure: TraceStructureRecorderHandle;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Strip `#executionIndex` from a runtimeStageId to recover the base\n * stageId. **Invariant I3**: matches commitLog stageIds when the\n * runtimeStageId already carries the full subflow path prefix the\n * engine emits. Do NOT manually re-parse subflow paths. */\nfunction baseStageIdOf(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createCommitFlowRecorder(\n options: CreateCommitFlowRecorderOptions,\n): CommitFlowRecorderHandle {\n const id = options.id ?? \"commit-flow\";\n const structure = options.structure;\n if (!structure) {\n throw new Error(\n \"[createCommitFlowRecorder] `structure` option is required. \" +\n \"Pass the handle returned by `createTraceStructureRecorder()`.\",\n );\n }\n\n // Internal raw commit storage — `RawCommit` is the un-projected\n // version (no structural/runtime joins yet). The full `CommitView`\n // gets computed on `getIndex()` (cached by version key).\n interface RawCommit {\n runtimeStageId: RuntimeStageId;\n stageId: StageId;\n commitIdx: number;\n updates: Record<string, unknown>;\n reads: string[];\n }\n let rawCommits: RawCommit[] = [];\n\n const notifier = createNotifier(\"commit-flow\");\n const unsubStructure = structure.subscribe(() => notifier.notify());\n\n function recordCommit(event: ScopeCommitEvent): void {\n // L8.0 ordering invariant — Scope.onCommit fires BEFORE Flow's\n // onStageExecuted. We read runtimeStageId directly from the\n // onCommit payload, NEVER waiting for a Flow event to enrich.\n const rsid = event.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createCommitFlowRecorder] onCommit without runtimeStageId — commit dropped (stage=${event.stage ?? event.stageId ?? \"?\"}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n rawCommits.push({\n runtimeStageId: asRuntimeStageId(rsid),\n stageId,\n commitIdx: rawCommits.length,\n updates: event.updates ? { ...event.updates } : {},\n reads: event.reads ? [...event.reads] : [],\n });\n notifier.notify();\n }\n\n // Flow channel handlers — no-ops for the canonical commit-data\n // capture (Scope.onCommit already carries runtimeStageId). Listed\n // so the recorder shape matches FlowRecorder and `attachTo()` can\n // attach via attachFlowRecorder for parity with other translators.\n // onError doesn't influence CommitView state today — errors belong\n // to NodeView's per-stage projection.\n const recorder: MinimalCommitFlowRecorder = {\n id,\n onCommit: recordCommit,\n onStageExecuted() {\n /* no-op — CommitFlow is commit-centric, not execution-centric */\n },\n onError() {\n /* no-op */\n },\n onRunStart() {\n /* no-op */\n },\n onRunEnd() {\n /* no-op */\n },\n };\n\n function buildIndex(): CommitFlowIndex {\n // Snapshot structure once — `getGraphRef()` returns live refs;\n // we only read from `node.data.prevIds`/`nextIds` (read-only).\n const graphRef = structure.getGraphRef();\n const nodeByStageId = new Map<string, (typeof graphRef.nodes)[number]>();\n for (const n of graphRef.nodes) nodeByStageId.set(n.id, n);\n\n // Precompute per-key writer index for findLastWriter (linear-time\n // build, O(1) lookup per read in the per-commit loop below).\n // Maps key → ordered list of {commitIdx, runtimeStageId} for\n // commits that wrote this key.\n interface KeyWriter {\n commitIdx: number;\n runtimeStageId: RuntimeStageId;\n }\n const writersOf = new Map<string, KeyWriter[]>();\n for (const rc of rawCommits) {\n for (const k of Object.keys(rc.updates)) {\n const list = writersOf.get(k) ?? [];\n list.push({ commitIdx: rc.commitIdx, runtimeStageId: rc.runtimeStageId });\n writersOf.set(k, list);\n }\n }\n\n // Precompute per-stage commit-index lists for runtimePrev/Next\n // derivation. Each stageId → ordered list of commitIdx where that\n // stage committed.\n const commitsOfStage = new Map<string, number[]>();\n for (const rc of rawCommits) {\n const list = commitsOfStage.get(rc.stageId) ?? [];\n list.push(rc.commitIdx);\n commitsOfStage.set(rc.stageId, list);\n }\n\n const commits: CommitView[] = [];\n const byRuntimeStageId = new Map<RuntimeStageId, CommitView>();\n const dataEdges: { from: number; to: number; key: string }[] = [];\n\n for (const rc of rawCommits) {\n const structNode = nodeByStageId.get(rc.stageId);\n const structuralPrevIds = (structNode?.data.prevIds ?? []).slice();\n const structuralNextIds = (structNode?.data.nextIds ?? []).slice();\n\n // runtimePrevIds — for each structural prev, the most-recent\n // commit with that stageId BEFORE rc.commitIdx.\n const runtimePrevIds: RuntimeStageId[] = [];\n for (const pStageId of structuralPrevIds) {\n const list = commitsOfStage.get(pStageId);\n if (!list) continue;\n // Walk backwards to find the highest commitIdx strictly less\n // than rc.commitIdx (invariant I2: strict `<`, not `<=`).\n let chosenIdx: number | null = null;\n for (let i = list.length - 1; i >= 0; i--) {\n if (list[i]! < rc.commitIdx) {\n chosenIdx = list[i]!;\n break;\n }\n }\n if (chosenIdx !== null) {\n runtimePrevIds.push(rawCommits[chosenIdx]!.runtimeStageId);\n }\n }\n\n // runtimeNextIds — for each structural next, the soonest commit\n // with that stageId AFTER rc.commitIdx.\n const runtimeNextIds: RuntimeStageId[] = [];\n for (const nStageId of structuralNextIds) {\n const list = commitsOfStage.get(nStageId);\n if (!list) continue;\n let chosenIdx: number | null = null;\n for (let i = 0; i < list.length; i++) {\n if (list[i]! > rc.commitIdx) {\n chosenIdx = list[i]!;\n break;\n }\n }\n if (chosenIdx !== null) {\n runtimeNextIds.push(rawCommits[chosenIdx]!.runtimeStageId);\n }\n }\n\n // Data dependencies — per-read-key findLastWriter.\n const dataDependencies: DataDependency[] = [];\n for (const key of rc.reads) {\n const writers = writersOf.get(key);\n let source: KeyWriter | null = null;\n if (writers) {\n for (let i = writers.length - 1; i >= 0; i--) {\n if (writers[i]!.commitIdx < rc.commitIdx) {\n source = writers[i]!;\n break;\n }\n }\n }\n if (source) {\n dataDependencies.push({\n key,\n sourceRuntimeStageId: source.runtimeStageId,\n sourceCommitIdx: source.commitIdx,\n });\n // L8.2 Panel 2 must-fix: freeze each edge so consumers can't\n // mutate the exposed objects. `readonly` is type-only; this\n // is the runtime enforcement.\n dataEdges.push(\n Object.freeze({ from: source.commitIdx, to: rc.commitIdx, key }),\n );\n } else {\n // Panel must-fix: use `null` (not `undefined`) for missing\n // source — forces consumers to handle absence load-bearingly.\n dataDependencies.push({\n key,\n sourceRuntimeStageId: null,\n sourceCommitIdx: null,\n });\n }\n }\n\n const view: CommitView = {\n runtimeStageId: rc.runtimeStageId,\n stageId: rc.stageId,\n commitIdx: rc.commitIdx,\n structuralPrevIds,\n structuralNextIds,\n runtimePrevIds,\n runtimeNextIds,\n dataDependencies,\n updates: { ...rc.updates },\n reads: rc.reads.slice(),\n };\n commits.push(view);\n byRuntimeStageId.set(view.runtimeStageId, view);\n }\n\n return { commits, byRuntimeStageId, dataEdges };\n }\n\n // L8.1 Panel 5 optimization: version-keyed cache. Same pattern as\n // NodeView — rebuild on (ownVersion, structureVersion) change.\n let cachedIndex: CommitFlowIndex | null = null;\n let cachedOwnVersion = -1;\n let cachedStructureVersion = -1;\n\n return {\n recorder,\n getIndex(): CommitFlowIndex {\n const own = notifier.version();\n const struct = structure.version();\n if (\n cachedIndex !== null &&\n cachedOwnVersion === own &&\n cachedStructureVersion === struct\n ) {\n return cachedIndex;\n }\n cachedIndex = buildIndex();\n cachedOwnVersion = own;\n cachedStructureVersion = struct;\n return cachedIndex;\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n rawCommits = [];\n // Cache invalidation — version doesn't bump (panel reset contract),\n // but next getIndex() must rebuild from the freshly-empty state.\n cachedIndex = null;\n cachedOwnVersion = -1;\n cachedStructureVersion = -1;\n // Subscription to structure is INTENTIONALLY kept across resets\n // (matches NodeView's reset contract). The handle is alive for\n // the recorder's full lifetime; consumer that wants full\n // disposal should drop the handle reference + let GC reclaim.\n // Referenced here purely to keep the closure alive for the\n // unsub's lexical scope.\n void unsubStructure;\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Data-flow backtrace helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Walk data-dependency edges BACKWARD from a starting commit. Returns\n * the lineage chain — every ancestor commit whose writes transitively\n * contributed to the starting commit's reads.\n *\n * BFS order, commitIdx-ascending (oldest first). Includes the starting\n * commit at the END of the returned array.\n *\n * Cycle defense: visited set + recursion cap at `index.commits.length`\n * (per L8 panel must-fix — defends against future malformed graphs).\n *\n * @example\n * ```ts\n * const lineage = backtraceDataFlow(commitIndex, asRuntimeStageId('finalize-order#3'));\n * // → [load-order#0, check-inventory#1, run-fraud-check#2, finalize-order#3]\n * // (the commits whose updates fed FinalizeOrder's reads)\n * ```\n */\nexport function backtraceDataFlow(\n index: CommitFlowIndex,\n startRuntimeStageId: RuntimeStageId,\n): CommitView[] {\n const start = index.byRuntimeStageId.get(startRuntimeStageId);\n if (!start) return [];\n // L8.2 Panel 1 must-fix: dropped the `hops < cap` counter. The\n // visited-set IS the real cycle defense — it guarantees each\n // commitIdx is dequeued AT MOST ONCE, so the loop body executes\n // ≤ `index.commits.length` times by construction. The old `hops`\n // counter could short-circuit BEFORE the visited-set saturated in\n // dense-data graphs (every commit reads from every prior), dropping\n // legitimate work. Visited-set + head-index queue is sufficient and\n // correct.\n const visitedIdx = new Set<number>([start.commitIdx]);\n const queue: number[] = [start.commitIdx];\n const collectedIdxs = new Set<number>([start.commitIdx]);\n let head = 0;\n while (head < queue.length) {\n const cur = index.commits[queue[head++]!];\n if (!cur) continue;\n for (const dep of cur.dataDependencies) {\n if (dep.sourceCommitIdx === null) continue;\n if (visitedIdx.has(dep.sourceCommitIdx)) continue;\n visitedIdx.add(dep.sourceCommitIdx);\n collectedIdxs.add(dep.sourceCommitIdx);\n queue.push(dep.sourceCommitIdx);\n }\n }\n // Return commits ordered by commitIdx ascending (chronological).\n return Array.from(collectedIdxs)\n .sort((a, b) => a - b)\n .map((idx) => index.commits[idx]!)\n .filter((c): c is CommitView => c !== undefined);\n}\n","/**\n * `createTraceBundle` — one factory wires every shipped translator\n * + provides a single `attachTo(executor)` call that registers all\n * runtime recorders.\n *\n * Bundle shape (as of L8.2)\n * ─────────────────────────\n * - `structure` — build-time `TraceGraph` (StructureRecorder).\n * - `runtimeOverlay` — execution overlay for time-travel (FlowRecorder).\n * - `nodeView` — per-stage summary index, CombinedRecorder\n * (FlowRecorder + ScopeRecorder).\n * - `commitFlow` — per-commit summary + data-lineage,\n * CombinedRecorder (ScopeRecorder + FlowRecorder).\n *\n * Goal: collapse the 5-line \"create + attach + subscribe\" boilerplate\n * into one call for the common case. Consumers that want à-la-carte\n * setup can still construct each translator directly (the underlying\n * factories are unchanged).\n *\n * Independence: each translator subscribes ONLY to `structure` (per\n * L8.1 Panel 1 rule — translators must never subscribe to peers).\n * Linear dependency tree keeps notify cascades O(depth), not O(N²).\n *\n * @example\n * ```tsx\n * import { createTraceBundle } from 'footprint-explainable-ui/flowchart';\n *\n * function MyTraceUI() {\n * const bundle = useMemo(() => createTraceBundle(), []);\n * useEffect(() => {\n * const chart = flowChart('seed', fn, 'seed', {\n * structureRecorders: [bundle.structure.recorder],\n * }).addFunction('a', fnA, 'a').build();\n * const executor = new FlowChartExecutor(chart);\n * bundle.attachTo(executor);\n * executor.run({ input });\n * }, [bundle]);\n *\n * return <TracedFlow recorder={bundle.structure} overlay={bundle.runtimeOverlay} />;\n * }\n * ```\n *\n * **Recorder-attach lifecycle**: `attachTo(executor)` attaches THREE\n * FlowRecorders (`runtimeOverlay`, `nodeView`, `commitFlow`) and TWO\n * ScopeRecorders (`nodeView`, `commitFlow`). Each translator has a\n * distinct `recorder.id`, so footprintjs's id-idempotency rule\n * doesn't collide. The build-time `structure.recorder` is NOT\n * auto-attached — it must be passed to `flowChart(..., {\n * structureRecorders: [...] })` because builder recorders register\n * BEFORE `executor` exists. Consumers wire that one explicitly (see\n * example above). This matches footprintjs's two-phase recorder\n * model (build vs runtime).\n */\n\nimport { devWarn } from \"./_internal/devWarn\";\nimport {\n createTraceStructureRecorder,\n type TraceStructureRecorderHandle,\n type CreateTraceStructureRecorderOptions,\n} from \"./traceStructureRecorder\";\nimport {\n createTraceRuntimeOverlay,\n type TraceRuntimeOverlayHandle,\n type CreateTraceRuntimeOverlayOptions,\n} from \"./createTraceRuntimeOverlay\";\nimport {\n createNodeViewRecorder,\n type NodeViewRecorderHandle,\n type CreateNodeViewRecorderOptions,\n} from \"./createNodeViewRecorder\";\nimport {\n createCommitFlowRecorder,\n type CommitFlowRecorderHandle,\n type CreateCommitFlowRecorderOptions,\n} from \"./createCommitFlowRecorder\";\n\n/** Minimal executor surface — mirrors the bits of footprintjs's\n * `FlowChartExecutor` the bundle calls into. Local to keep\n * explainable-ui dep-free from footprintjs. */\ninterface MinimalExecutor {\n attachFlowRecorder(recorder: unknown): void;\n attachScopeRecorder?(recorder: unknown): void;\n}\n\nexport interface TraceBundle {\n structure: TraceStructureRecorderHandle;\n runtimeOverlay: TraceRuntimeOverlayHandle;\n /** L8.1 — per-stage summary translator. Reads `prevIds`/`nextIds`\n * from `structure` (no duplication), accumulates `executions[]`\n * + commit refs from Flow + Scope events. */\n nodeView: NodeViewRecorderHandle;\n /** L8.2 — per-commit summary translator. Owns canonical CommitView[].\n * Derives structural prev/next from `structure`, runtimePrev/Next\n * from \"most-recent-per-prev\" over commitLog, and dataDependencies\n * via findLastWriter per read key. */\n commitFlow: CommitFlowRecorderHandle;\n /**\n * Attach RUNTIME recorders (FlowRecorder, ScopeRecorder) to a\n * footprintjs executor. The build-time `structure.recorder` is NOT\n * covered — pass it to `flowChart(..., { structureRecorders: [...] })`\n * at construction time instead (see file header example).\n */\n attachTo(executor: MinimalExecutor): void;\n}\n\nexport interface CreateTraceBundleOptions {\n /** Per-translator options. All optional. */\n structure?: CreateTraceStructureRecorderOptions;\n runtimeOverlay?: CreateTraceRuntimeOverlayOptions;\n nodeView?: Omit<CreateNodeViewRecorderOptions, \"structure\">;\n commitFlow?: Omit<CreateCommitFlowRecorderOptions, \"structure\">;\n}\n\nexport function createTraceBundle(\n options: CreateTraceBundleOptions = {},\n): TraceBundle {\n const structure = createTraceStructureRecorder(options.structure);\n const runtimeOverlay = createTraceRuntimeOverlay(options.runtimeOverlay);\n // NodeView needs the structure handle — wired internally so the\n // consumer doesn't have to pass it. The bundle is the consumer-\n // ergonomics layer; à-la-carte consumers can construct\n // createNodeViewRecorder directly with their own structure handle.\n const nodeView = createNodeViewRecorder({\n ...(options.nodeView ?? {}),\n structure,\n });\n const commitFlow = createCommitFlowRecorder({\n ...(options.commitFlow ?? {}),\n structure,\n });\n\n return {\n structure,\n runtimeOverlay,\n nodeView,\n commitFlow,\n attachTo(executor: MinimalExecutor): void {\n // All three runtime translators attach as FlowRecorders (each\n // has its own distinct `recorder.id`, so the dispatcher's\n // id-idempotency rule doesn't collide). NodeView + CommitFlow\n // ALSO implement ScopeRecorder (onCommit) — attached via\n // attachScopeRecorder when the executor exposes it.\n //\n // Footprintjs v6.0+ exposes both methods; older executors\n // gracefully degrade (commit-side data drops with a dev-warn).\n executor.attachFlowRecorder(runtimeOverlay.recorder);\n executor.attachFlowRecorder(nodeView.recorder);\n executor.attachFlowRecorder(commitFlow.recorder);\n if (typeof executor.attachScopeRecorder === \"function\") {\n executor.attachScopeRecorder(nodeView.recorder);\n executor.attachScopeRecorder(commitFlow.recorder);\n } else {\n // Old/partial executor without ScopeRecorder support. NodeView\n // + CommitFlow will silently miss commit events — surface this\n // to consumers debugging \"why are commitRuntimeStageIds empty?\".\n devWarn(\n () =>\n \"[createTraceBundle] executor.attachScopeRecorder is missing — NodeView.commitRuntimeStageIds[] AND CommitFlow.commits[] will be empty. Upgrade to footprintjs v6.0+.\",\n );\n }\n },\n };\n}\n","/**\n * `useTranslator(handle, getSnapshot)` — React adapter for any translator\n * exposing the standard `subscribe()` + `version()` shape.\n *\n * Wraps `useSyncExternalStore` so consumers don't repeat the boilerplate\n * for every translator. The `version` is the snapshot identity — when it\n * changes, React re-renders; `getSnapshot` then returns the consumer-\n * chosen view (full graph, slice, etc.).\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const graph = useTranslator(trace, () => trace.getGraph());\n * return <TraceFlow graph={graph} />;\n * ```\n *\n * **Why a hook (vs each component wiring `useSyncExternalStore` itself)**:\n * three reasons. (1) Reduces 4 lines of `useSyncExternalStore + useMemo`\n * boilerplate to one line. (2) Standardises the snapshot-identity\n * convention (version int) — consumers can't accidentally pass a getter\n * whose return identity changes every call (which would re-render\n * forever). (3) Stable subscribe/getVersion refs via memoization on the\n * handle identity — no re-subscribe on parent re-renders.\n */\n\nimport { useMemo, useSyncExternalStore } from \"react\";\n\nexport interface TranslatorHandleLike {\n subscribe(listener: () => void): () => void;\n version(): number;\n}\n\n/**\n * Subscribe to a translator + return a typed snapshot computed by the\n * caller. The snapshot recomputes whenever `version()` changes.\n *\n * `getSnapshot` is called inside a `useMemo` keyed on the version\n * integer — so consumers can return fresh objects from `getSnapshot`\n * (e.g., `handle.getGraph()` returns a defensive copy) without\n * triggering infinite re-renders.\n */\nexport function useTranslator<T>(\n handle: TranslatorHandleLike,\n getSnapshot: () => T,\n): T {\n const subscribe = useMemo(() => handle.subscribe.bind(handle), [handle]);\n const getVersion = useMemo(() => handle.version.bind(handle), [handle]);\n const version = useSyncExternalStore(subscribe, getVersion, getVersion);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => getSnapshot(), [version, getSnapshot]);\n}\n","/**\n * Graph traversal helpers — pure functions over a `NodeViewIndex`.\n *\n * Bi-directional structural walks (`walkForward` / `walkBackward`) plus\n * convenience wrappers (`backtraceStructural` / `forwardtraceStructural`).\n *\n * Cycle defense (panel L8 must-fix)\n * ──────────────────────────────────\n * Every traversal carries a `visited: Set<StageId>` and caps recursion\n * at `index.all.length` (the total node count). Defends against:\n * - Future bugs where a malformed graph includes a non-loop cycle\n * - Manual edge injection bypassing the structure-recorder fix\n * - Duplicate edges that survive dedupe due to source/target\n * collisions\n * Loop back-edges (`data.kind === 'loop'`) already excluded at the\n * structure-recorder layer (invariant I1), so they never enter\n * `prevIds`/`nextIds` — no extra filtering here.\n *\n * BFS order\n * ─────────\n * Walks return nodes in BFS order — root first, then immediate\n * neighbors, then their neighbors. Matches breadcrumb-friendly\n * \"closest-first\" display order.\n *\n * Always-arrays returns\n * ─────────────────────\n * All helpers return `NodeView[]`. Empty array (NOT null/undefined)\n * means \"no path\" or \"node not found\". Consumers `.map()` /\n * `.length`-check without null-handling boilerplate.\n */\n\nimport type { NodeView, NodeViewIndex } from \"./createNodeViewRecorder\";\nimport type { StageId } from \"./_internal/keys\";\n\nexport interface WalkOptions {\n /** Hard cap on hops. Default: `index.all.length` (one full traversal). */\n maxDepth?: number;\n /** When true, only return nodes that have `visitedInRun === true`.\n * Useful for \"in THIS run, what fed me?\" queries (runtime-aware walk). */\n onlyVisited?: boolean;\n /** When true, INCLUDE the start node in the returned array. Default:\n * false (caller already has the start node; the walk returns its\n * ancestors/descendants). */\n includeStart?: boolean;\n}\n\n/**\n * Walk forward (`nextIds`) from `startId`. BFS order. Cycle-safe.\n * Returns `[]` if `startId` is unknown.\n *\n * Convergence semantics: a node reachable via multiple paths appears\n * ONCE in the result (visited-set dedupes).\n */\nexport function walkForward(\n index: NodeViewIndex,\n startId: StageId,\n options: WalkOptions = {},\n): NodeView[] {\n return bfsWalk(index, startId, (n) => n.nextIds, options);\n}\n\n/**\n * Walk backward (`prevIds`) from `startId`. BFS order. Cycle-safe.\n * Returns `[]` if `startId` is unknown.\n *\n * Convergence semantics: a fork-join's `walkBackward` returns BOTH\n * branch parents (and their ancestors), each once.\n */\nexport function walkBackward(\n index: NodeViewIndex,\n startId: StageId,\n options: WalkOptions = {},\n): NodeView[] {\n return bfsWalk(index, startId, (n) => n.prevIds, options);\n}\n\n/**\n * Backtrace from `stageId` to a structural root (no prev) OR a split\n * point (multiple prevs). Returns the chain from `stageId` BACK to\n * the root, root-first. Includes `stageId` at the END.\n *\n * Defines \"split\" as `prevIds.length > 1 OR prevIds.length === 0`\n * (per L8 panel recommendation) — stops at convergence points AND at\n * the seed. Useful for breadcrumb display where \"innermost serial\n * run\" is the meaningful path.\n */\nexport function backtraceStructural(\n index: NodeViewIndex,\n stageId: StageId,\n options: Pick<WalkOptions, \"maxDepth\" | \"onlyVisited\"> = {},\n): NodeView[] {\n const start = index.byStageId.get(stageId);\n if (!start) return [];\n const chain: NodeView[] = [start];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>([stageId]);\n let cur: NodeView | undefined = start;\n let hops = 0;\n while (cur && hops < cap) {\n if (cur.prevIds.length === 0 || cur.prevIds.length > 1) {\n // Reached seed (no prevs) or split (multi-prev convergence).\n break;\n }\n const nextId = cur.prevIds[0]!;\n if (visited.has(nextId)) break; // cycle guard\n visited.add(nextId);\n const next: NodeView | undefined = index.byStageId.get(nextId);\n if (!next) break;\n if (options.onlyVisited && !next.visitedInRun) break;\n chain.unshift(next);\n cur = next;\n hops++;\n }\n return chain;\n}\n\n/**\n * Forward-trace from `stageId` to a structural leaf (no next) OR a\n * fork point (multiple nexts). Returns the chain from `stageId`\n * FORWARD to the leaf/fork, with `stageId` at the START.\n */\nexport function forwardtraceStructural(\n index: NodeViewIndex,\n stageId: StageId,\n options: Pick<WalkOptions, \"maxDepth\" | \"onlyVisited\"> = {},\n): NodeView[] {\n const start = index.byStageId.get(stageId);\n if (!start) return [];\n const chain: NodeView[] = [start];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>([stageId]);\n let cur: NodeView | undefined = start;\n let hops = 0;\n while (cur && hops < cap) {\n if (cur.nextIds.length === 0 || cur.nextIds.length > 1) break;\n const nextId = cur.nextIds[0]!;\n if (visited.has(nextId)) break;\n visited.add(nextId);\n const next: NodeView | undefined = index.byStageId.get(nextId);\n if (!next) break;\n if (options.onlyVisited && !next.visitedInRun) break;\n chain.push(next);\n cur = next;\n hops++;\n }\n return chain;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction bfsWalk(\n index: NodeViewIndex,\n startId: StageId,\n neighborsOf: (n: NodeView) => StageId[],\n options: WalkOptions,\n): NodeView[] {\n const start = index.byStageId.get(startId);\n if (!start) return [];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>();\n visited.add(startId);\n const out: NodeView[] = [];\n if (options.includeStart) out.push(start);\n // Queue holds [node, depthFromStart]. depthFromStart = 0 for the\n // start node; neighbors are depth 1; etc. We bail when depth > cap.\n //\n // L8.1 Panel 5 optimization: use a head-index pointer instead of\n // `queue.shift()`. shift() is O(n) (re-indexes the array on every\n // pop) → BFS over 50+ nodes degrades to O(n²). The head-index\n // pattern is O(1) per pop, O(n) total — standard interview answer.\n const queue: Array<[NodeView, number]> = [[start, 0]];\n let head = 0;\n while (head < queue.length) {\n const [node, depth] = queue[head++]!;\n if (depth >= cap) continue;\n for (const neighborId of neighborsOf(node)) {\n if (visited.has(neighborId)) continue;\n visited.add(neighborId);\n const neighbor = index.byStageId.get(neighborId);\n if (!neighbor) continue;\n if (options.onlyVisited && !neighbor.visitedInRun) continue;\n out.push(neighbor);\n queue.push([neighbor, depth + 1]);\n }\n }\n return out;\n}\n","/**\n * NodeInspector — debug/teaching panel for a single stage's\n * per-node summary from a `NodeViewIndex`.\n *\n * Demonstrates the canonical L8.1 consumer pattern:\n * 1. Read the `NodeView` for `selectedId` from the index\n * 2. Use `backtraceStructural` / `forwardtraceStructural` for the\n * prev/next chains\n * 3. Render: identity, structural neighbors (clickable to navigate),\n * visit data (count + duration + error state), commit refs.\n *\n * Composable: this is a small demo renderer. Real consumers wire\n * their own layout — the data shape is the contract.\n */\n\nimport { useMemo } from \"react\";\nimport type { NodeViewIndex, NodeView } from \"./createNodeViewRecorder\";\nimport type { StageId } from \"./_internal/keys\";\nimport { backtraceStructural, forwardtraceStructural } from \"./walkHelpers\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface NodeInspectorProps extends BaseComponentProps {\n /** The NodeView index (from `nodeView.getIndex()` or `useTranslator`).\n *\n * **Pure data prop** (NOT the recorder handle) — by design. Lets\n * consumers wrap in `useTranslator(nodeView, () => nodeView.getIndex())`\n * at the parent, or pass a static index from tests / Storybook /\n * SSR. Mirrors `<CommitInspector index={...}>` for consistency. */\n index: NodeViewIndex;\n /** Which stage to inspect. When `null`, renders the placeholder. */\n selectedId: StageId | null;\n /** Click handler — receives a stageId for breadcrumb navigation. */\n onNavigate?: (stageId: StageId) => void;\n /** When true, the prev/next chains include only `visitedInRun` nodes\n * (runtime-filtered view). */\n onlyVisited?: boolean;\n}\n\nexport function NodeInspector({\n index,\n selectedId,\n onNavigate,\n onlyVisited = false,\n className,\n style,\n}: NodeInspectorProps) {\n const view = selectedId ? index.byStageId.get(selectedId) ?? null : null;\n\n // Backtrace (root-first chain ending at this stage) — recomputes\n // when index version OR selectedId OR onlyVisited changes.\n const prevChain = useMemo(\n () => (view ? backtraceStructural(index, view.stageId, { onlyVisited }) : []),\n [index, view, onlyVisited],\n );\n // Forward-trace (this stage → leaf or fork).\n const nextChain = useMemo(\n () => (view ? forwardtraceStructural(index, view.stageId, { onlyVisited }) : []),\n [index, view, onlyVisited],\n );\n\n if (!view) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n Select a stage to inspect.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 14,\n color: theme.textPrimary,\n fontSize: 13,\n overflow: \"auto\",\n ...style,\n }}\n >\n {/* ── Identity ──────────────────────────────────────────── */}\n <div style={{ marginBottom: 16 }}>\n <div style={{ fontSize: 16, fontWeight: 700, color: theme.textPrimary }}>\n {view.label}\n </div>\n <div style={{ fontSize: 11, fontFamily: \"monospace\", color: theme.textMuted, marginTop: 2 }}>\n {view.stageId} · {view.type}\n {view.isDecider && \" · decider\"}\n {view.isFork && \" · fork\"}\n {view.isSubflow && \" · subflow\"}\n {view.isStreaming && \" · streaming\"}\n {view.isPausable && \" · pausable\"}\n </div>\n {view.description && (\n <div style={{ fontSize: 12, color: theme.textSecondary, marginTop: 6 }}>\n {view.description}\n </div>\n )}\n </div>\n\n {/* ── Visit data ────────────────────────────────────────── */}\n <Section title=\"Runtime\">\n <Row label=\"Visited\" value={view.visitedInRun ? \"yes\" : \"no\"} />\n {view.visitedInRun && (\n <>\n <Row label=\"Executions\" value={String(view.executionCount)} />\n {view.firstExecutedAt !== null && (\n <Row label=\"First at\" value={`${view.firstExecutedAt.toFixed(1)}ms`} />\n )}\n {view.lastExecutedAt !== null && (\n <Row label=\"Last at\" value={`${view.lastExecutedAt.toFixed(1)}ms`} />\n )}\n {view.totalDurationMs > 0 && (\n <Row label=\"Total\" value={`${view.totalDurationMs.toFixed(1)}ms`} />\n )}\n {view.errorCount > 0 && (\n <Row label=\"Errors\" value={String(view.errorCount)} valueColor={theme.error} />\n )}\n </>\n )}\n </Section>\n\n {/* ── Structural prev chain (clickable breadcrumb) ──────── */}\n {prevChain.length > 1 && (\n <Section title={`Prev chain (${prevChain.length - 1} hops)`}>\n <Crumbs nodes={prevChain.slice(0, -1)} onClick={onNavigate} />\n </Section>\n )}\n {view.prevIds.length > 1 && (\n <Section title=\"Multiple prev (convergence)\">\n <Crumbs\n nodes={view.prevIds\n .map((id) => index.byStageId.get(id))\n .filter((n): n is NodeView => n !== undefined)}\n onClick={onNavigate}\n />\n </Section>\n )}\n\n {/* ── Structural next chain ─────────────────────────────── */}\n {nextChain.length > 1 && (\n <Section title={`Next chain (${nextChain.length - 1} hops)`}>\n <Crumbs nodes={nextChain.slice(1)} onClick={onNavigate} />\n </Section>\n )}\n {view.nextIds.length > 1 && (\n <Section title=\"Multiple next (fork/decider)\">\n <Crumbs\n nodes={view.nextIds\n .map((id) => index.byStageId.get(id))\n .filter((n): n is NodeView => n !== undefined)}\n onClick={onNavigate}\n />\n </Section>\n )}\n\n {/* ── Commit refs (join key into CommitFlowIndex from L8.2) ── */}\n {view.commitRuntimeStageIds.length > 0 && (\n <Section title={`Commits (${view.commitRuntimeStageIds.length})`}>\n <div style={{ fontFamily: \"monospace\", fontSize: 11, color: theme.textSecondary }}>\n {view.commitRuntimeStageIds.map((rsid) => (\n <div key={rsid}>{rsid}</div>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n\n// ── Sub-components ─────────────────────────────────────────────────\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div style={{ marginBottom: 14 }}>\n <div\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n marginBottom: 6,\n }}\n >\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nfunction Row({ label, value, valueColor }: { label: string; value: string; valueColor?: string }) {\n return (\n <div style={{ display: \"flex\", justifyContent: \"space-between\", fontSize: 12, padding: \"2px 0\" }}>\n <span style={{ color: theme.textMuted }}>{label}</span>\n <span style={{ color: valueColor ?? theme.textSecondary, fontFamily: \"monospace\" }}>{value}</span>\n </div>\n );\n}\n\nfunction Crumbs({ nodes, onClick }: { nodes: NodeView[]; onClick?: (id: StageId) => void }) {\n if (nodes.length === 0) return null;\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {nodes.map((n, i) => (\n <span key={n.stageId} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n <button\n onClick={onClick ? () => onClick(n.stageId) : undefined}\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"3px 8px\",\n borderRadius: 4,\n border: `1px solid ${theme.border}`,\n background: \"transparent\",\n color: n.visitedInRun ? theme.success : theme.textSecondary,\n cursor: onClick ? \"pointer\" : \"default\",\n }}\n >\n {n.label}\n </button>\n {i < nodes.length - 1 && <span style={{ color: theme.textMuted, fontSize: 10 }}>›</span>}\n </span>\n ))}\n </div>\n );\n}\n","/**\n * CommitInspector — demo renderer for a single CommitView from a\n * `CommitFlowIndex`. Mirrors `<NodeInspector>` but commit-centric:\n *\n * - Identity: runtimeStageId + stageId + commitIdx\n * - Structural: prev/next stage ids (the chart-shape neighbors)\n * - Runtime: runtimePrev/Next commit refs (the actual prev/next\n * executions in this run — useful for time-travel breadcrumbs)\n * - Data lineage: `dataDependencies[]` per read key + a one-click\n * `backtraceDataFlow` walk showing the full ancestry chain\n * - Payload: updates + reads\n */\n\nimport { useMemo } from \"react\";\nimport type {\n CommitFlowIndex,\n CommitView,\n} from \"./createCommitFlowRecorder\";\nimport { backtraceDataFlow } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface CommitInspectorProps extends BaseComponentProps {\n /** The CommitFlow index (from `commitFlow.getIndex()` or `useTranslator`).\n *\n * **Pure data prop** (NOT the recorder handle) — by design. Lets\n * consumers wrap in `useTranslator(commitFlow, () => commitFlow.getIndex())`\n * at the parent, or pass a static index from tests / Storybook /\n * SSR. Mirrors `<NodeInspector index={...}>` for consistency. */\n index: CommitFlowIndex;\n /** Which commit to inspect (by runtimeStageId). null → placeholder. */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Click handler — receives a runtimeStageId for time-travel\n * navigation. Used by all clickable references (runtime prev/next,\n * data-dep sources, lineage chain). */\n onNavigate?: (runtimeStageId: RuntimeStageId) => void;\n}\n\nexport function CommitInspector({\n index,\n selectedRuntimeStageId,\n onNavigate,\n className,\n style,\n}: CommitInspectorProps) {\n const view = selectedRuntimeStageId\n ? index.byRuntimeStageId.get(selectedRuntimeStageId) ?? null\n : null;\n\n // Backtrace ancestry chain — recomputes when index version OR\n // selectedRuntimeStageId changes.\n const lineage = useMemo(\n () =>\n view ? backtraceDataFlow(index, view.runtimeStageId) : [],\n [index, view],\n );\n\n if (!view) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n Select a commit to inspect.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 14,\n color: theme.textPrimary,\n fontSize: 13,\n overflow: \"auto\",\n ...style,\n }}\n >\n {/* ── Identity ──────────────────────────────────────────── */}\n <div style={{ marginBottom: 16 }}>\n <div style={{ fontSize: 16, fontWeight: 700, color: theme.textPrimary }}>\n {view.stageId}\n </div>\n <div\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n color: theme.textMuted,\n marginTop: 2,\n }}\n >\n {view.runtimeStageId} · commitIdx {view.commitIdx}\n </div>\n </div>\n\n {/* ── Structural neighbors ──────────────────────────────── */}\n {view.structuralPrevIds.length > 0 && (\n <Section title=\"Structural prev (chart shape)\">\n <PlainTags labels={view.structuralPrevIds} />\n </Section>\n )}\n {view.structuralNextIds.length > 0 && (\n <Section title=\"Structural next (chart shape)\">\n <PlainTags labels={view.structuralNextIds} />\n </Section>\n )}\n\n {/* ── Runtime neighbors (clickable for time-travel) ─────── */}\n {view.runtimePrevIds.length > 0 && (\n <Section title=\"Runtime prev (this execution)\">\n <RuntimeRefs refs={view.runtimePrevIds} onClick={onNavigate} />\n </Section>\n )}\n {view.runtimeNextIds.length > 0 && (\n <Section title=\"Runtime next (this execution)\">\n <RuntimeRefs refs={view.runtimeNextIds} onClick={onNavigate} />\n </Section>\n )}\n\n {/* ── Payload ───────────────────────────────────────────── */}\n {Object.keys(view.updates).length > 0 && (\n <Section title={`Updates (${Object.keys(view.updates).length})`}>\n <KeyValueGrid entries={Object.entries(view.updates)} />\n </Section>\n )}\n {view.reads.length > 0 && (\n <Section title={`Reads (${view.reads.length})`}>\n <PlainTags labels={view.reads} />\n </Section>\n )}\n\n {/* ── Data dependencies (per-key lineage) ───────────────── */}\n {view.dataDependencies.length > 0 && (\n <Section title={`Data dependencies (${view.dataDependencies.length})`}>\n <table style={{ fontSize: 11, fontFamily: \"monospace\", width: \"100%\", borderCollapse: \"collapse\" }}>\n <tbody>\n {view.dataDependencies.map((dep) => (\n <tr key={dep.key}>\n <td style={{ color: theme.textSecondary, padding: \"2px 8px 2px 0\" }}>\n {dep.key}\n </td>\n <td style={{ color: dep.sourceRuntimeStageId ? theme.textPrimary : theme.textMuted }}>\n {dep.sourceRuntimeStageId ? (\n <button\n onClick={onNavigate ? () => onNavigate(dep.sourceRuntimeStageId!) : undefined}\n style={crumbButtonStyle(onNavigate !== undefined)}\n >\n ← {dep.sourceRuntimeStageId}\n </button>\n ) : (\n <em>(no prior writer — default or external)</em>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </Section>\n )}\n\n {/* ── Lineage chain (full data-flow backtrace) ──────────── */}\n {lineage.length > 1 && (\n <Section title={`Lineage chain (${lineage.length - 1} ancestor commits)`}>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {lineage.slice(0, -1).map((c, i) => (\n <span key={c.runtimeStageId} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n <button\n onClick={onNavigate ? () => onNavigate(c.runtimeStageId) : undefined}\n style={crumbButtonStyle(onNavigate !== undefined)}\n >\n {c.runtimeStageId}\n </button>\n {i < lineage.length - 2 && (\n <span style={{ color: theme.textMuted, fontSize: 10 }}>→</span>\n )}\n </span>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n\n// ── Sub-components ─────────────────────────────────────────────────\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div style={{ marginBottom: 14 }}>\n <div\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n marginBottom: 6,\n }}\n >\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nfunction PlainTags({ labels }: { labels: readonly string[] }) {\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 4 }}>\n {labels.map((l) => (\n <span\n key={l}\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"2px 6px\",\n borderRadius: 3,\n background: \"var(--fp-bg-secondary, transparent)\",\n color: theme.textSecondary,\n }}\n >\n {l}\n </span>\n ))}\n </div>\n );\n}\n\nfunction RuntimeRefs({\n refs,\n onClick,\n}: {\n refs: readonly RuntimeStageId[];\n onClick?: (rsid: RuntimeStageId) => void;\n}) {\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {refs.map((r) => (\n <button\n key={r}\n onClick={onClick ? () => onClick(r) : undefined}\n style={crumbButtonStyle(onClick !== undefined)}\n >\n {r}\n </button>\n ))}\n </div>\n );\n}\n\nfunction KeyValueGrid({ entries }: { entries: ReadonlyArray<[string, unknown]> }) {\n return (\n <table style={{ fontSize: 11, fontFamily: \"monospace\", width: \"100%\", borderCollapse: \"collapse\" }}>\n <tbody>\n {entries.map(([k, v]) => (\n <tr key={k}>\n <td style={{ color: theme.textSecondary, padding: \"2px 8px 2px 0\", verticalAlign: \"top\" }}>\n {k}\n </td>\n <td style={{ color: theme.textPrimary, wordBreak: \"break-word\" }}>\n {typeof v === \"object\" ? JSON.stringify(v) : String(v)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n\nfunction crumbButtonStyle(clickable: boolean): React.CSSProperties {\n return {\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"3px 8px\",\n borderRadius: 4,\n border: `1px solid ${theme.border}`,\n background: \"transparent\",\n color: theme.textSecondary,\n cursor: clickable ? \"pointer\" : \"default\",\n };\n}\n","/**\n * Series-parallel chain tree builders — pure functions over `TraceGraph`\n * (structural) + `CommitFlowIndex` (runtime).\n *\n * When to reach for this vs. flat commitLog\n * ─────────────────────────────────────────\n * Use `commitLog` when you want chronological replay / slider scrubbing\n * (\"what happened in order\"). Use the chain tree when you want to\n * render parallel structure visually or answer \"which branch ran?\"\n * questions — flat `commitLog[idx-1]` loses the fork shape.\n *\n * Pairs with `<CommitInspector>` for git-log-style master/detail —\n * `<CommitChainView>` picks, `<CommitInspector>` inspects.\n * Complements the per-stage view from `createNodeViewRecorder`.\n *\n * Why a chain tree\n * ────────────────\n * Footprintjs charts are **series-parallel DAGs by construction** —\n * the builder primitives compose serially (`addFunction`) or in\n * parallel (`addListOfFunction` / `addDeciderFunction`). Series-\n * parallel DAGs are provably representable as expression trees,\n * so we can decompose any footprintjs chart into a nested\n * `(serial | parallel | leaf)` shape that renders cleanly as\n * swim lanes.\n *\n * Two builders, one tree shape\n * ────────────────────────────\n * - `structureAsChainTree(graph, options?)` — STRUCTURAL view.\n * No commitLog. Decomposes the chart shape into S-P primitives.\n * Renders the full chart (all branches of a decider, etc.) even\n * before running.\n *\n * - `buildCommitChainTree(graph, commitFlow, options?)` — RUNTIME\n * view. Each leaf carries the commits[] that fired for that stage\n * in this run. Loops produce a leaf with N commits. Branches that\n * never executed in this run appear as empty `commits[]` leaves\n * (consumer can filter).\n *\n * Algorithm scope (correctness contract)\n * ──────────────────────────────────────\n * These builders are tuned for **series-parallel charts** — every\n * fork in footprintjs's builder has a matching merge point. For\n * non-S-P or malformed graphs the tree is still finite and stable\n * (cycle defense guarantees termination), but the shape may not\n * reflect a clean S-P decomposition.\n *\n * - Forks with **no common descendant** drop the outer-walk tail at\n * the fork node. Real footprintjs charts always re-merge.\n * - Edges with `data.kind === undefined` are treated as `'next'`.\n * Multiple linear-next edges from a single source follow only the\n * first (deterministic by insertion order); a dev-mode warning\n * fires when this is observed (`isDevMode()` from footprintjs).\n *\n * Cycle defense (L8 panel must-fix carried forward)\n * ─────────────────────────────────────────────────\n * Every recursive walk carries a `visited: Set<StageId>` to defend\n * against malformed graphs (manual edge injection, future builder\n * bugs). Loop edges (`kind === 'loop'`) are excluded at the\n * structure-recorder layer per invariant I1, so they never enter\n * prev/next — no extra filtering needed here. Convergence detection\n * uses BFS bounded by `graph.nodes.length`.\n *\n * @example\n * ```ts\n * const trace = createTraceStructureRecorder();\n * // ... build a fork chart ...\n *\n * const sChain = structureAsChainTree(trace.getGraph());\n * // → { kind: 'serial', items: [\n * // { kind: 'leaf', stageId: 'LoadOrder' },\n * // { kind: 'parallel', branches: [\n * // { kind: 'leaf', stageId: 'CheckInventory' },\n * // { kind: 'leaf', stageId: 'RunFraudCheck' },\n * // ]},\n * // { kind: 'leaf', stageId: 'FinalizeOrder' },\n * // ]}\n *\n * const commitFlow = createCommitFlowRecorder({ structure: trace });\n * // ... run chart ...\n * const cChain = buildCommitChainTree(trace.getGraph(), commitFlow.getIndex());\n * // → same shape, but each leaf carries `commits: CommitView[]`\n * ```\n */\n\nimport type { TraceGraph } from \"./traceStructureRecorder\";\nimport type { CommitFlowIndex, CommitView } from \"./createCommitFlowRecorder\";\nimport type { StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { devWarn } from \"./_internal/devWarn\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Structural chain tree leaf (no commits). */\nexport interface StructureChainLeaf {\n readonly kind: \"leaf\";\n readonly stageId: StageId;\n}\n\n/** Structural chain tree node — recursive S-P composition over stage ids. */\nexport type StructureChain =\n | StructureChainLeaf\n | { readonly kind: \"serial\"; readonly items: readonly StructureChain[] }\n | { readonly kind: \"parallel\"; readonly branches: readonly StructureChain[] };\n\n/** Commit chain tree leaf — carries all commits for the stage (loop-aware). */\nexport interface CommitChainLeaf {\n readonly kind: \"leaf\";\n readonly stageId: StageId;\n /** All commits that fired for this stage in this run, in commitIdx\n * ascending order. Loop iteration N has commits[N]. Empty array\n * when the stage never executed in this run.\n *\n * **Ownership**: references are shared with\n * `CommitFlowIndex.commits` (no deep copy). The same shallow-copy /\n * nested-shared-value contract documented on `CommitView.updates`\n * applies. Do not mutate. */\n readonly commits: readonly CommitView[];\n}\n\n/** Commit chain tree — recursive S-P composition with commit leaves. */\nexport type CommitChain =\n | CommitChainLeaf\n | { readonly kind: \"serial\"; readonly items: readonly CommitChain[] }\n | { readonly kind: \"parallel\"; readonly branches: readonly CommitChain[] };\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Per-stage indexes computed once per build call. */\ninterface GraphIndex {\n byStageId: Map<StageId, { branchChildren: StageId[]; linearNext: StageId[] }>;\n allNodeIds: StageId[];\n}\n\nfunction indexGraph(graph: TraceGraph): GraphIndex {\n const byStageId = new Map<\n StageId,\n { branchChildren: StageId[]; linearNext: StageId[] }\n >();\n const allNodeIds: StageId[] = [];\n\n for (const node of graph.nodes) {\n const stageId = asStageId(node.id);\n allNodeIds.push(stageId);\n // node.data already carries prevIds/nextIds (L8.0 enrichment), but\n // we split outgoing into branch vs linear based on edge kind below.\n byStageId.set(stageId, { branchChildren: [], linearNext: [] });\n }\n\n for (const edge of graph.edges) {\n const kind = edge.data?.kind;\n if (kind === \"loop\") continue;\n const sourceEntry = byStageId.get(asStageId(edge.source));\n if (!sourceEntry) continue;\n // Skip edges whose target is not in the node set (malformed graph\n // defense — walker would bail on entry === undefined anyway, but\n // pruning here keeps branchChildren/linearNext clean for the\n // ambiguity warning below).\n const target = asStageId(edge.target);\n if (!byStageId.has(target)) continue;\n if (kind === \"fork-branch\" || kind === \"decision-branch\") {\n sourceEntry.branchChildren.push(target);\n } else {\n // 'next' or any unspecified kind treated as linear.\n sourceEntry.linearNext.push(target);\n }\n }\n\n return { byStageId, allNodeIds };\n}\n\n/** Find the seed: first node with no incoming non-loop edge. Falls back\n * to the first node in insertion order. */\nfunction findSeed(graph: TraceGraph, fromStageId?: StageId): StageId | null {\n if (fromStageId) {\n const n = graph.nodes.find((n) => n.id === fromStageId);\n return n ? asStageId(n.id) : null;\n }\n const hasIncoming = new Set<string>();\n for (const e of graph.edges) {\n if (e.data?.kind !== \"loop\") hasIncoming.add(e.target);\n }\n const seed = graph.nodes.find((n) => !hasIncoming.has(n.id)) ?? graph.nodes[0];\n return seed ? asStageId(seed.id) : null;\n}\n\n/**\n * BFS forward from `startId`. Returns ordered visit list (BFS order)\n * + reachable set. Skips `loop`-kind edges per invariant I1.\n */\nfunction bfsReachable(\n startId: StageId,\n index: GraphIndex,\n): { order: StageId[]; reachable: Set<StageId> } {\n const reachable = new Set<StageId>([startId]);\n const order: StageId[] = [startId];\n const queue: StageId[] = [startId];\n let head = 0;\n while (head < queue.length) {\n const cur = queue[head++]!;\n const entry = index.byStageId.get(cur);\n if (!entry) continue;\n for (const next of [...entry.branchChildren, ...entry.linearNext]) {\n if (reachable.has(next)) continue;\n reachable.add(next);\n order.push(next);\n queue.push(next);\n }\n }\n return { order, reachable };\n}\n\n/**\n * Find the convergence point of a fork — the FIRST node (BFS order\n * from branch[0]) reachable from EVERY branch. Returns `null` if no\n * common descendant (branches diverge without re-merging — does not\n * happen in series-parallel footprintjs charts).\n *\n * For strict S-P charts, the first node in branch[0]'s BFS order that\n * sits in every reachable set IS the true convergence (dominator).\n * For non-S-P graphs this is a best-effort approximation.\n */\nfunction findConvergence(\n branches: readonly StageId[],\n index: GraphIndex,\n): StageId | null {\n if (branches.length < 2) return null;\n // Compute reachable + order for branch[0] once; reuse the same walk\n // for both ordering AND the first reachable set (panel 5 must-fix).\n const firstWalk = bfsReachable(branches[0]!, index);\n const reachableSets: Set<StageId>[] = [firstWalk.reachable];\n for (let i = 1; i < branches.length; i++) {\n reachableSets.push(bfsReachable(branches[i]!, index).reachable);\n }\n // Exclude the branch starting points themselves — they're not the\n // convergence of their own subtree.\n const startSet = new Set(branches);\n for (const candidate of firstWalk.order) {\n if (startSet.has(candidate)) continue;\n if (reachableSets.every((s) => s.has(candidate))) {\n return candidate;\n }\n }\n return null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Recursive walker — produces a StructureChain\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Walk forward from `startId`, stopping at `untilId` (exclusive). Returns\n * the chain for the [startId, untilId) segment. `untilId === null` means\n * walk to the end (terminal nodes).\n *\n * Cycle defense: passes a `visited: Set<StageId>` through recursion. A\n * node already in `visited` is skipped (returns null), so the same\n * StageId appears at most once in the resulting tree.\n */\nfunction walkChain(\n startId: StageId,\n untilId: StageId | null,\n index: GraphIndex,\n visited: Set<StageId>,\n): StructureChain | null {\n const items: StructureChain[] = [];\n let cur: StageId | null = startId;\n while (cur !== null && cur !== untilId) {\n if (visited.has(cur)) break;\n visited.add(cur);\n const entry = index.byStageId.get(cur);\n if (!entry) break;\n\n const branches = entry.branchChildren;\n const linearNexts = entry.linearNext;\n\n // Always emit the current node as a leaf — its OWN position in the\n // chain. Parallel/serial wrappers follow if applicable.\n items.push({ kind: \"leaf\", stageId: cur });\n\n if (branches.length >= 2) {\n // Fork — find convergence + recurse into each branch.\n const convergence = findConvergence(branches, index);\n const branchChains: StructureChain[] = [];\n for (const b of branches) {\n // Each branch walks with a per-branch clone of `visited` for\n // traversal isolation. After the branch returns, its markers\n // are unioned into the outer scope so the post-convergence\n // walk doesn't re-emit nodes that any branch already covered.\n // This is correct dedup for S-P graphs (branches don't share\n // pre-convergence nodes) and is what keeps the recursion\n // bounded for malformed graphs (cycle defense).\n const branchVisited = new Set(visited);\n const sub = walkChain(b, convergence, index, branchVisited);\n if (sub !== null) branchChains.push(sub);\n for (const v of branchVisited) visited.add(v);\n }\n if (branchChains.length > 0) {\n items.push({ kind: \"parallel\", branches: branchChains });\n }\n cur = convergence;\n } else if (branches.length === 1 && linearNexts.length === 0) {\n // Single branch — treat as linear continuation.\n cur = branches[0]!;\n } else if (linearNexts.length >= 1) {\n // Linear continuation. Multiple linearNexts is ambiguous for S-P\n // decomposition; we follow the first (deterministic per-recorder\n // insertion order) and warn in dev mode so consumers building\n // unusual graph shapes are alerted.\n if (linearNexts.length > 1) {\n devWarn(\n () =>\n `[buildCommitChainTree] stage '${cur}' has ${linearNexts.length} linear-next edges; chain decomposition follows only the first ('${linearNexts[0]}'). Use 'fork-branch' or 'decision-branch' edge kinds to express parallel/conditional splits.`,\n );\n }\n cur = linearNexts[0]!;\n } else {\n // Terminal node.\n cur = null;\n }\n }\n\n if (items.length === 0) return null;\n if (items.length === 1) return items[0]!;\n return { kind: \"serial\", items };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API: structureAsChainTree\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ChainTreeOptions {\n /** Stage id to start the walk from. Defaults to the chart's seed\n * (first node with no incoming non-loop edge). */\n rootStageId?: StageId;\n}\n\n/**\n * Build a structural chain tree for a chart. Pure function over\n * `TraceGraph` — no runtime data required. Useful for rendering the\n * chart shape before any execution (static documentation, etc.).\n */\nexport function structureAsChainTree(\n graph: TraceGraph,\n options: ChainTreeOptions = {},\n): StructureChain | null {\n if (graph.nodes.length === 0) return null;\n const index = indexGraph(graph);\n const seed = findSeed(graph, options.rootStageId);\n if (!seed) return null;\n const visited = new Set<StageId>();\n return walkChain(seed, null, index, visited);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API: buildCommitChainTree\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a commit-decorated chain tree. Same S-P shape as\n * `structureAsChainTree`, but each leaf carries the commits[] that\n * fired for that stage in this run (in commitIdx ascending order).\n *\n * Loop semantics: a stage that ran N times has a leaf with\n * `commits.length === N`. The consumer's renderer decides whether to\n * display them as a single \"ran 3×\" badge or unroll into N visible\n * boxes — both views are supported by the same data.\n *\n * Branches that never executed in this run appear with empty\n * `commits[]`. Consumers wanting \"runtime-only\" view can filter them\n * out.\n */\nexport function buildCommitChainTree(\n graph: TraceGraph,\n commitFlow: CommitFlowIndex,\n options: ChainTreeOptions = {},\n): CommitChain | null {\n const structural = structureAsChainTree(graph, options);\n if (!structural) return null;\n // Index commits by stageId for O(1) leaf decoration.\n const commitsByStageId = new Map<StageId, CommitView[]>();\n for (const c of commitFlow.commits) {\n const list = commitsByStageId.get(c.stageId) ?? [];\n list.push(c);\n commitsByStageId.set(c.stageId, list);\n }\n return decorate(structural, commitsByStageId);\n}\n\nfunction decorate(\n node: StructureChain,\n commitsByStageId: ReadonlyMap<StageId, readonly CommitView[]>,\n): CommitChain {\n if (node.kind === \"leaf\") {\n return {\n kind: \"leaf\",\n stageId: node.stageId,\n commits: commitsByStageId.get(node.stageId) ?? [],\n };\n }\n if (node.kind === \"serial\") {\n return {\n kind: \"serial\",\n items: node.items.map((n) => decorate(n, commitsByStageId)),\n };\n }\n return {\n kind: \"parallel\",\n branches: node.branches.map((b) => decorate(b, commitsByStageId)),\n };\n}\n","/**\n * CommitChainView — git-log-style swim-lane renderer for a\n * `CommitChain` or `StructureChain` (from `buildCommitChainTree` or\n * `structureAsChainTree`).\n *\n * Pair with `<CommitInspector>` for master/detail — this picks,\n * that inspects.\n *\n * Time-travel dimming (L8.5)\n * ──────────────────────────\n * Pass `revealedThroughCommitIdx={N}` (typically driven by\n * `<RunSlider>` via the ONE-CURSOR model) to dim commits with\n * `commitIdx > N`. Dimmed commits stay in the DOM (stable layout)\n * and stay CLICKABLE (clicking jumps the cursor forward to that\n * commit). Use `null` (default) to reveal all, `-1` to reveal none\n * (e.g., stale-cursor sentinel from `<TraceExplorerShell>`).\n *\n * Layout rules\n * ────────────\n * serial → vertical stack of children; subtle connector between them\n * parallel → horizontal row of branch columns (swim lanes), each\n * column is its own chain\n * leaf → one box per commit (loop unrolls into N boxes); empty\n * commits[] (or `StructureChain` leaf) renders a dashed\n * \"not executed in this run\" box\n *\n * Pure data prop: pass `chain` directly. For live updates, wrap with\n * `useTranslator(commitFlow, () => buildCommitChainTree(graph, commitFlow.getIndex()))`\n * at the parent. Mirrors the consumer pattern used by `<NodeInspector>`\n * and `<CommitInspector>`.\n *\n * Pre-execution rendering: pass a `StructureChain` directly (from\n * `structureAsChainTree(graph)`) — every leaf renders as the\n * \"not executed yet\" placeholder. No need to manufacture an empty\n * `CommitFlowIndex`.\n *\n * Selection: `selectedRuntimeStageId` highlights one commit box;\n * `onSelectCommit` fires when any commit box is clicked.\n *\n * Future extension: the recursive renderer is factored as\n * `<ChainShell renderLeaf={...}>` so a future `<StructureChainView>`\n * can reuse the same layout primitives with a different leaf renderer.\n *\n * @example\n * ```tsx\n * const chain = useTranslator(commitFlow, () =>\n * buildCommitChainTree(trace.getGraph(), commitFlow.getIndex()),\n * );\n * const [selected, setSelected] = useState<RuntimeStageId | null>(null);\n * return (\n * <div style={{ display: 'flex' }}>\n * <CommitChainView\n * chain={chain}\n * selectedRuntimeStageId={selected}\n * onSelectCommit={setSelected}\n * />\n * <CommitInspector index={commitFlow.getIndex()} selectedRuntimeStageId={selected} />\n * </div>\n * );\n * ```\n */\n\nimport type {\n CommitChain,\n CommitChainLeaf,\n StructureChain,\n StructureChainLeaf,\n} from \"./buildCommitChainTree\";\nimport type { CommitView } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId, StageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface CommitChainViewProps extends BaseComponentProps {\n /** The chain tree. Accepts BOTH `CommitChain` (from\n * `buildCommitChainTree`) and `StructureChain` (from\n * `structureAsChainTree` — pre-execution view). null → placeholder. */\n chain: CommitChain | StructureChain | null;\n /** Highlighted commit (by runtimeStageId). Only meaningful for\n * `CommitChain` input (StructureChain has no commits to select). */\n selectedRuntimeStageId?: RuntimeStageId | null;\n /** Fires when a commit box is clicked — pass to `<CommitInspector>`\n * for master/detail wiring. Not fired for \"not executed\" leaves. */\n onSelectCommit?: (runtimeStageId: RuntimeStageId) => void;\n /** Optional label resolver — default uses the bare stageId. Consumers\n * can map id → friendly name (e.g., from a NodeViewIndex). */\n resolveLabel?: (stageId: StageId) => string;\n /** Time-travel cursor: commits with `commitIdx > revealedThroughCommitIdx`\n * render dimmed (still visible — keeps layout stable). Pairs with\n * `<RunSlider>` in the ONE-CURSOR model.\n *\n * Semantics:\n * - `null` (default) — reveal ALL commits (no time-travel applied).\n * - `N >= 0` — reveal commits 0..N inclusive; dim commits with\n * `commitIdx > N`.\n * - `N < 0` (e.g., `-1`) — reveal NONE; all commits dim. Use this\n * sentinel for \"cursor is stale / unresolved\" so the chain doesn't\n * accidentally fall back to fully-revealed when the consumer wants\n * no-reveal. */\n revealedThroughCommitIdx?: number | null;\n}\n\nexport function CommitChainView({\n chain,\n selectedRuntimeStageId = null,\n onSelectCommit,\n resolveLabel,\n revealedThroughCommitIdx = null,\n className,\n style,\n}: CommitChainViewProps) {\n if (!chain) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n No chain to display.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 12,\n color: theme.textPrimary,\n fontSize: 12,\n overflow: \"auto\",\n ...style,\n }}\n >\n <ChainShell\n node={chain}\n renderLeaf={(leaf) => (\n <Leaf\n leaf={leaf}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={onSelectCommit}\n resolveLabel={resolveLabel}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n )}\n />\n </div>\n );\n}\n\n// ── Recursive layout shell (reusable by future StructureChainView) ──\n\ntype AnyChain = CommitChain | StructureChain;\ntype AnyLeaf = CommitChainLeaf | StructureChainLeaf;\n\ninterface ChainShellProps {\n node: AnyChain;\n renderLeaf: (leaf: AnyLeaf) => React.ReactNode;\n}\n\nfunction ChainShell({ node, renderLeaf }: ChainShellProps): React.ReactElement {\n if (node.kind === \"leaf\") {\n return <>{renderLeaf(node)}</>;\n }\n\n if (node.kind === \"serial\") {\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 0,\n }}\n >\n {node.items.map((child, i) => (\n <div\n key={chainKey(child, i)}\n style={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\" }}\n >\n <ChainShell node={child} renderLeaf={renderLeaf} />\n {i < node.items.length - 1 && <Connector orientation=\"vertical\" />}\n </div>\n ))}\n </div>\n );\n }\n\n // parallel → swim lanes\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 0,\n }}\n >\n <ForkMarker />\n <div\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n gap: 18,\n padding: \"4px 0\",\n borderLeft: `1px dashed ${theme.border}`,\n borderRight: `1px dashed ${theme.border}`,\n paddingLeft: 12,\n paddingRight: 12,\n }}\n >\n {node.branches.map((branch, i) => (\n <div\n key={chainKey(branch, i)}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n minWidth: 120,\n }}\n >\n <ChainShell node={branch} renderLeaf={renderLeaf} />\n </div>\n ))}\n </div>\n <ForkMarker />\n </div>\n );\n}\n\n/**\n * Stable React key for serial/parallel children — derived from the\n * subtree shape so a rerender with shifted branches doesn't mis-pair\n * subtree state. Falls back to `index` only when the leaf can't be\n * located (defensive — shouldn't happen).\n */\nfunction chainKey(node: AnyChain, fallbackIndex: number): string {\n const leaf = firstLeafOf(node);\n return leaf ? `${node.kind}:${leaf.stageId}` : `${node.kind}:idx${fallbackIndex}`;\n}\n\nfunction firstLeafOf(node: AnyChain): AnyLeaf | null {\n if (node.kind === \"leaf\") return node;\n if (node.kind === \"serial\") {\n for (const item of node.items) {\n const l = firstLeafOf(item);\n if (l) return l;\n }\n return null;\n }\n for (const branch of node.branches) {\n const l = firstLeafOf(branch);\n if (l) return l;\n }\n return null;\n}\n\n// ── Leaf (one or N commit boxes for loop iterations) ────────────────\n\nfunction Leaf({\n leaf,\n selectedRuntimeStageId,\n onSelectCommit,\n resolveLabel,\n revealedThroughCommitIdx,\n}: {\n leaf: AnyLeaf;\n selectedRuntimeStageId: RuntimeStageId | null;\n onSelectCommit?: (rsid: RuntimeStageId) => void;\n resolveLabel?: (stageId: StageId) => string;\n revealedThroughCommitIdx: number | null;\n}) {\n const label = resolveLabel ? resolveLabel(leaf.stageId) : leaf.stageId;\n const commits: readonly CommitView[] =\n \"commits\" in leaf ? leaf.commits : [];\n\n if (commits.length === 0) {\n return (\n <div\n style={{\n ...boxBaseStyle,\n borderStyle: \"dashed\",\n color: theme.textMuted,\n background: \"transparent\",\n }}\n title={`${leaf.stageId} — not executed in this run`}\n >\n <div style={{ fontWeight: 600 }}>{label}</div>\n <div style={{ fontSize: 10, fontStyle: \"italic\" }}>not executed</div>\n </div>\n );\n }\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\", gap: 4 }}>\n {commits.map((c, i) => {\n const isSelected = c.runtimeStageId === selectedRuntimeStageId;\n const clickable = onSelectCommit !== undefined;\n // Time-travel dimming: when revealedThroughCommitIdx is set,\n // commits BEYOND the cursor render dimmed (still in the DOM\n // so layout stays stable as the cursor slides). Commits are\n // STILL clickable (clicking jumps the time cursor forward).\n // We use aria-disabled (not aria-hidden) so screen-readers\n // perceive the element + state, per WAI-ARIA's \"MUST NOT use\n // aria-hidden on focusable elements\" rule.\n const isRevealed =\n revealedThroughCommitIdx === null ||\n c.commitIdx <= revealedThroughCommitIdx;\n return (\n <button\n key={c.commitIdx}\n type=\"button\"\n onClick={clickable ? () => onSelectCommit(c.runtimeStageId) : undefined}\n style={{\n ...boxBaseStyle,\n cursor: clickable ? \"pointer\" : \"default\",\n borderColor: isSelected ? theme.success : theme.border,\n borderWidth: isSelected ? 2 : 1,\n background: isSelected ? \"rgba(34,197,94,0.08)\" : \"transparent\",\n color: theme.textPrimary,\n textAlign: \"left\",\n fontFamily: \"inherit\",\n padding: \"6px 10px\",\n opacity: isRevealed ? 1 : 0.35,\n }}\n aria-disabled={!isRevealed}\n aria-current={isSelected ? \"true\" : undefined}\n title={c.runtimeStageId}\n >\n <div style={{ fontWeight: 600 }}>\n {label}\n {commits.length > 1 && (\n <span style={{ color: theme.textMuted, fontWeight: 400, marginLeft: 6 }}>\n iter {i + 1}/{commits.length}\n </span>\n )}\n </div>\n <div\n style={{\n fontSize: 10,\n fontFamily: \"monospace\",\n color: theme.textMuted,\n marginTop: 2,\n }}\n >\n #{c.commitIdx} · {c.runtimeStageId}\n </div>\n </button>\n );\n })}\n </div>\n );\n}\n\n// ── Decorations ─────────────────────────────────────────────────────\n\nfunction Connector({ orientation }: { orientation: \"vertical\" | \"horizontal\" }) {\n return orientation === \"vertical\" ? (\n <div\n aria-hidden\n style={{\n width: 1,\n height: 12,\n background: theme.border,\n }}\n />\n ) : (\n <div\n aria-hidden\n style={{\n height: 1,\n width: 12,\n background: theme.border,\n }}\n />\n );\n}\n\nfunction ForkMarker() {\n return (\n <div\n aria-hidden\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: theme.border,\n margin: \"2px 0\",\n }}\n />\n );\n}\n\nconst boxBaseStyle: React.CSSProperties = {\n display: \"inline-block\",\n minWidth: 110,\n padding: \"6px 10px\",\n border: `1px solid ${theme.border}`,\n borderRadius: 4,\n fontSize: 12,\n color: theme.textPrimary,\n background: \"transparent\",\n};\n","/**\n * TraceExplorerShell — composed master/detail layout that wires the\n * full L8 translator stack into a single drop-in component.\n *\n * **Composes**: [`<CommitChainView>`](./CommitChainView.tsx),\n * [`<CommitInspector>`](./CommitInspector.tsx),\n * [`<NodeInspector>`](./NodeInspector.tsx) over a [`TraceBundle`](./createTraceBundle.ts).\n *\n * The L8 stack is intentionally factored as independent pieces\n * (structure / runtimeOverlay / nodeView / commitFlow / chain\n * builder / inspectors). Consumers can wire à-la-carte for custom\n * layouts. `<TraceExplorerShell>` is the \"I want the canonical\n * trace-explorer UI without writing 50 lines of `useTranslator`\n * plumbing\" entry point — pass a `bundle`, get a master/detail UI.\n *\n * **Prerequisite**: call `bundle.attachTo(executor)` (see\n * `createTraceBundle` for the recorder-attach lifecycle) BEFORE\n * rendering this component. The shell only consumes events; it does\n * not trigger them. Without the attach step, every pane will show its\n * placeholder.\n *\n * Layout\n * ──────\n * ┌─────────────────────────────────────────────────┐\n * │ RunSlider (time-travel cursor) │\n * ├──────────────────────────┬──────────────────────┤\n * │ CommitChainView │ CommitInspector │\n * │ (master, click a box) │ (detail, selected) │\n * │ │ │\n * ├──────────────────────────┴──────────────────────┤\n * │ NodeInspector (resolved from selected stageId) │\n * └─────────────────────────────────────────────────┘\n *\n * The slider is the **ONE-CURSOR** affordance: dragging it moves\n * the same cursor that clicking a commit moves. Commits past the\n * cursor render dimmed in the chain view (`revealedThroughCommitIdx`\n * threaded through automatically). Pass `slots: { slider: null }`\n * to hide the slider (e.g., for static post-run views).\n *\n * Selection model\n * ───────────────\n * ONE cursor (`selectedRuntimeStageId`) drives both detail panes.\n * Clicking a commit in the chain view updates the cursor; the\n * `<CommitInspector>` shows that commit; the `<NodeInspector>`\n * shows the stage that commit belongs to (derived by stripping the\n * `#executionIndex` suffix from the runtimeStageId).\n *\n * Controlled mode: pass `selectedRuntimeStageId` + `onSelectionChange`\n * to drive selection from outside (URL hash, parent state, etc.).\n * Uncontrolled mode: omit both — the shell owns the cursor.\n * `onSelectionChange` also fires in uncontrolled mode for\n * observability (logging, analytics).\n *\n * Composition rule (L8 architecture, carried forward)\n * ───────────────────────────────────────────────────\n * This shell consumes ONLY the bundle's translator handles via\n * `useTranslator`. It NEVER subscribes to peer translators directly\n * (would violate the linear-dep-tree rule). It builds the chain\n * tree fresh on each commitFlow version bump — cheap, cache-friendly\n * (every input index is version-keyed-cached upstream, and\n * `commitFlow` transitively re-notifies on `structure` changes per\n * the L8.2 contract, so structure-only events also propagate).\n *\n * Customization\n * ─────────────\n * The default layout is a CSS grid. Override via `slots` to swap any\n * panel for a custom renderer. Slot props mirror the sibling-\n * inspector pattern — they receive PURE DATA (the typed index/chain),\n * NOT the bundle. This keeps slots usable from tests / Storybook /\n * SSR and means slot authors do not have to re-subscribe to\n * translators (the shell does that once).\n *\n * Stability note: `slots` should be stable across renders (define at\n * module scope or wrap with `useMemo`). The shell memoizes the\n * resolved component refs to defend against accidental remounts.\n *\n * @example Minimal\n * ```tsx\n * const bundle = useMemo(() => createTraceBundle(), []);\n * useEffect(() => {\n * const chart = flowChart('seed', fn, 'seed', undefined, undefined, {\n * structureRecorders: [bundle.structure.recorder],\n * }).build();\n * const executor = new FlowChartExecutor(chart);\n * bundle.attachTo(executor); // Prerequisite — see createTraceBundle.\n * executor.run({ input });\n * }, [bundle]);\n *\n * return <TraceExplorerShell bundle={bundle} />;\n * ```\n *\n * @example Controlled selection (sync to URL hash)\n * ```tsx\n * const [sel, setSel] = useState<RuntimeStageId | null>(null);\n * return (\n * <TraceExplorerShell\n * bundle={bundle}\n * selectedRuntimeStageId={sel}\n * onSelectionChange={setSel}\n * />\n * );\n * ```\n *\n * @example Custom chain pane (typed data slot)\n * ```tsx\n * const slots = useMemo(() => ({\n * chain: ({ chain, selectedRuntimeStageId, onSelectCommit }) => (\n * <MyCustomTimeline chain={chain} cursor={selectedRuntimeStageId} onPick={onSelectCommit} />\n * ),\n * }), []);\n * return <TraceExplorerShell bundle={bundle} slots={slots} />;\n * ```\n */\n\nimport { useMemo, useState, useCallback } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport type { TraceBundle } from \"./createTraceBundle\";\nimport type { RuntimeStageId, StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { useTranslator } from \"./_internal/useTranslator\";\nimport { buildCommitChainTree, type CommitChain } from \"./buildCommitChainTree\";\nimport { CommitChainView } from \"./CommitChainView\";\nimport { CommitInspector } from \"./CommitInspector\";\nimport { NodeInspector } from \"./NodeInspector\";\nimport { RunSlider } from \"./RunSlider\";\nimport type { CommitFlowIndex } from \"./createCommitFlowRecorder\";\nimport type { NodeViewIndex } from \"./createNodeViewRecorder\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\n/**\n * Slot prop bags — slots receive PURE DATA (chain/index), NOT the\n * bundle. Mirrors the sibling-inspector convention so slot bodies are\n * usable from tests / Storybook / SSR and avoid re-subscribing to\n * translators. Each callback is wired by the shell to the shared\n * selection cursor.\n */\nexport interface ChainSlotProps {\n /** Live chain tree, derived from the bundle. `null` before any\n * commits arrive. */\n chain: CommitChain | null;\n /** Currently selected commit (shared cursor). */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor. */\n onSelectCommit: (rsid: RuntimeStageId) => void;\n /** Time-travel reveal cursor (derived from selectedRuntimeStageId\n * via ONE-CURSOR model). Commits with commitIdx > this value\n * render dimmed. `null` reveals all, `-1` reveals none, `N >= 0`\n * reveals up to commit N. **Optional in custom slots** — slot\n * authors that don't implement time-travel dimming can ignore it\n * (matches the standalone `<CommitChainView>` prop optionality). */\n revealedThroughCommitIdx?: number | null;\n}\nexport interface CommitInspectorSlotProps {\n /** Live commitFlow index. */\n index: CommitFlowIndex;\n /** Currently selected commit (shared cursor). */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor (e.g., for clickable\n * data-dep / lineage breadcrumbs). */\n onNavigate: (rsid: RuntimeStageId) => void;\n}\nexport interface NodeInspectorSlotProps {\n /** Live nodeView index. */\n index: NodeViewIndex;\n /** StageId derived from `selectedRuntimeStageId`. */\n selectedStageId: StageId | null;\n /** Wire to the shared selection cursor (e.g., for prev/next chain\n * breadcrumbs). Resolves the stage to its first commit. */\n onNavigate: (stageId: StageId) => void;\n}\nexport interface SliderSlotProps {\n /** Live commitFlow index. */\n index: CommitFlowIndex;\n /** Currently selected commit — same cursor as the chain selection\n * per the ONE-CURSOR model. */\n cursorRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor. */\n onCursorChange: (rsid: RuntimeStageId | null) => void;\n}\n\nexport interface TraceExplorerSlots {\n /** Override the chain (master) pane. Use to swap the swim-lane\n * renderer for a timeline/Gantt/custom layout while keeping the\n * same selection contract. */\n chain?: React.ComponentType<ChainSlotProps>;\n /** Override the commit (detail) pane. Use to add custom commit-\n * detail formatting (e.g., domain-specific updates rendering). */\n commitInspector?: React.ComponentType<CommitInspectorSlotProps>;\n /** Override the node (stage-summary) pane. Use to surface per-stage\n * custom KPIs / annotations alongside the default execution data. */\n nodeInspector?: React.ComponentType<NodeInspectorSlotProps>;\n /** Override the slider (top time-travel bar). Pass `null` to HIDE\n * the slider entirely (e.g., for static post-run views with no\n * scrub affordance). */\n slider?: React.ComponentType<SliderSlotProps> | null;\n}\n\nexport interface TraceExplorerShellProps extends BaseComponentProps {\n /** The translator bundle from `createTraceBundle()`. MUST have had\n * `bundle.attachTo(executor)` called before any commits arrive,\n * otherwise every pane shows its placeholder. */\n bundle: TraceBundle;\n /** Controlled selection (omit for uncontrolled). `null` clears. */\n selectedRuntimeStageId?: RuntimeStageId | null;\n /** Fires on selection changes. In controlled mode, required for\n * selection to take effect. In uncontrolled mode, fires as an\n * observation hook (logging/analytics) — the shell still owns the\n * state.\n *\n * Memoize via `useCallback` to avoid downstream re-renders. */\n onSelectionChange?: (rsid: RuntimeStageId | null) => void;\n /** Optional slot overrides. Should be stable across renders\n * (define at module scope or `useMemo`). */\n slots?: TraceExplorerSlots;\n}\n\nexport function TraceExplorerShell({\n bundle,\n selectedRuntimeStageId: controlledSel,\n onSelectionChange,\n slots,\n className,\n style,\n}: TraceExplorerShellProps) {\n // Controlled vs uncontrolled selection. Standard React idiom.\n const [internalSel, setInternalSel] = useState<RuntimeStageId | null>(null);\n const isControlled = controlledSel !== undefined;\n const selectedRuntimeStageId = isControlled ? controlledSel : internalSel;\n\n const handleSelect = useCallback(\n (rsid: RuntimeStageId | null) => {\n if (!isControlled) setInternalSel(rsid);\n // Fire in both modes — controlled mode requires it for parent\n // sync; uncontrolled mode fires for observability (logging,\n // analytics, URL sync without taking control).\n onSelectionChange?.(rsid);\n },\n [isControlled, onSelectionChange],\n );\n const handleSelectCommit = useCallback(\n (rsid: RuntimeStageId) => handleSelect(rsid),\n [handleSelect],\n );\n\n // Derive selected stageId from selectedRuntimeStageId by stripping\n // the '#executionIndex' suffix. Mirrors footprintjs/trace\n // `parseRuntimeStageId` invariant — kept inline because\n // explainable-ui is dep-free from footprintjs (subflow prefix is\n // preserved; nodeView keys subflow stages by the full path-prefixed\n // form per footprintjs convention).\n const selectedStageId = useMemo<StageId | null>(() => {\n if (!selectedRuntimeStageId) return null;\n const hashIdx = selectedRuntimeStageId.lastIndexOf(\"#\");\n // hashIdx === 0 → empty stageId (malformed input) → no selection.\n if (hashIdx <= 0) return null;\n return asStageId(selectedRuntimeStageId.slice(0, hashIdx));\n }, [selectedRuntimeStageId]);\n\n // Resolve slot components ONCE per slots-identity change — defends\n // against consumer footgun of passing inline `slots={{...}}` every\n // render which would otherwise remount default panes.\n const ChainPane = useMemo(\n () => slots?.chain ?? DefaultChainPane,\n [slots?.chain],\n );\n const CommitPane = useMemo(\n () => slots?.commitInspector ?? DefaultCommitPane,\n [slots?.commitInspector],\n );\n const NodePane = useMemo(\n () => slots?.nodeInspector ?? DefaultNodePane,\n [slots?.nodeInspector],\n );\n // Slider has tri-state semantics: undefined = use default; null =\n // hide; ComponentType = override. `slots?.slider === null` is the\n // \"hide\" signal; absent key = default.\n const SliderPane = useMemo<React.ComponentType<SliderSlotProps> | null>(() => {\n if (slots && \"slider\" in slots) {\n return slots.slider ?? null;\n }\n return DefaultSliderPane;\n }, [slots]);\n\n // Subscribe ONCE here to the three translators; pass the resolved\n // data down to slots (whether default or custom). Slots NEVER need\n // to subscribe themselves.\n const chain = useTranslator(bundle.commitFlow, () =>\n buildCommitChainTree(bundle.structure.getGraph(), bundle.commitFlow.getIndex()),\n );\n const commitIndex = useTranslator(bundle.commitFlow, () =>\n bundle.commitFlow.getIndex(),\n );\n const nodeIndex = useTranslator(bundle.nodeView, () => bundle.nodeView.getIndex());\n\n // Stage-click → resolve first commit and select it. One-shot lookup\n // outside useTranslator (no subscription) is intentional — this\n // fires on click, not in a render path. Picking commits[0] is the\n // documented semantic; loops resolve to iteration 1.\n const handleStageNavigate = useCallback(\n (stageId: StageId) => {\n const candidates = commitIndex.commits.filter((c) => c.stageId === stageId);\n const first = candidates[0];\n handleSelect(first ? first.runtimeStageId : null);\n },\n [commitIndex, handleSelect],\n );\n\n // Cursor → commitIdx for chain dimming. ONE-CURSOR model: the same\n // cursor that drives selection also drives time-travel reveal.\n //\n // Three states (distinguished — Panel 1 must-fix L8.5):\n // - no cursor (`null`) → `null` (reveal ALL)\n // - cursor resolves to a commit → that commit's commitIdx\n // - cursor is STALE (rsid unknown to index, e.g. removed by reset)\n // → `-1` (reveal NONE), NOT `null` — prevents incoherent \"stale\n // cursor falls back to fully-revealed\" state.\n const revealedThroughCommitIdx = useMemo<number | null>(() => {\n if (!selectedRuntimeStageId) return null;\n const view = commitIndex.byRuntimeStageId.get(selectedRuntimeStageId);\n return view ? view.commitIdx : -1;\n }, [selectedRuntimeStageId, commitIndex]);\n\n // Layout: when the slider is hidden (`slots.slider === null`),\n // collapse the slider row so the grid doesn't reserve empty space.\n const layoutStyle = useMemo<CSSProperties>(\n () => (SliderPane ? SHELL_STYLE_WITH_SLIDER : SHELL_STYLE_NO_SLIDER),\n [SliderPane],\n );\n\n return (\n <div className={className} style={{ ...layoutStyle, ...style }}>\n {SliderPane && (\n <Pane area=\"slider\">\n <SliderPane\n index={commitIndex}\n cursorRuntimeStageId={selectedRuntimeStageId}\n onCursorChange={handleSelect}\n />\n </Pane>\n )}\n <Pane area=\"chain\">\n <ChainPane\n chain={chain}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={handleSelectCommit}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n </Pane>\n <Pane area=\"commit\">\n <CommitPane\n index={commitIndex}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onNavigate={handleSelectCommit}\n />\n </Pane>\n <Pane area=\"node\">\n <NodePane\n index={nodeIndex}\n selectedStageId={selectedStageId}\n onNavigate={handleStageNavigate}\n />\n </Pane>\n </div>\n );\n}\n\n// ── Default panes (pure data props, no internal subscriptions) ──────\n\nfunction DefaultChainPane({\n chain,\n selectedRuntimeStageId,\n onSelectCommit,\n revealedThroughCommitIdx,\n}: ChainSlotProps) {\n return (\n <CommitChainView\n chain={chain}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={onSelectCommit}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n );\n}\n\nfunction DefaultCommitPane({\n index,\n selectedRuntimeStageId,\n onNavigate,\n}: CommitInspectorSlotProps) {\n return (\n <CommitInspector\n index={index}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onNavigate={onNavigate}\n />\n );\n}\n\nfunction DefaultNodePane({ index, selectedStageId, onNavigate }: NodeInspectorSlotProps) {\n return (\n <NodeInspector index={index} selectedId={selectedStageId} onNavigate={onNavigate} />\n );\n}\n\nfunction DefaultSliderPane({\n index,\n cursorRuntimeStageId,\n onCursorChange,\n}: SliderSlotProps) {\n return (\n <RunSlider\n index={index}\n cursorRuntimeStageId={cursorRuntimeStageId}\n onCursorChange={onCursorChange}\n />\n );\n}\n\n// ── Layout helpers ──────────────────────────────────────────────────\n\nconst SHELL_STYLE_WITH_SLIDER: CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: \"minmax(280px, 1fr) minmax(320px, 1fr)\",\n gridTemplateRows: \"auto 1fr auto\",\n gridTemplateAreas: '\"slider slider\" \"chain commit\" \"node node\"',\n gap: 12,\n padding: 12,\n background: theme.bgPrimary,\n color: theme.textPrimary,\n};\n\nconst SHELL_STYLE_NO_SLIDER: CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: \"minmax(280px, 1fr) minmax(320px, 1fr)\",\n gridTemplateRows: \"1fr auto\",\n gridTemplateAreas: '\"chain commit\" \"node node\"',\n gap: 12,\n padding: 12,\n background: theme.bgPrimary,\n color: theme.textPrimary,\n};\n\nconst PANE_BASE_STYLE: CSSProperties = {\n border: `1px solid ${theme.border}`,\n borderRadius: 6,\n background: theme.bgSecondary,\n overflow: \"auto\",\n minHeight: 0, // permit shrinking inside grid\n};\n\nfunction Pane({ area, children }: { area: string; children: React.ReactNode }) {\n // Wrap each pane as an accessibility landmark so screen readers can\n // jump between panels.\n return (\n <div role=\"region\" aria-label={area} style={{ ...PANE_BASE_STYLE, gridArea: area }}>\n {children}\n </div>\n );\n}\n","/**\n * RunSlider — time-travel cursor over the commit timeline.\n *\n * Implements the **ONE-CURSOR** model from the Lens architecture: the\n * slider position IS the same `runtimeStageId` cursor that selection\n * uses everywhere else (chain view, inspectors). Moving the slider\n * advances the cursor; clicking a commit in the chain view moves the\n * slider. Same underlying state, two affordances.\n *\n * Internal mapping\n * ────────────────\n * Slider value is a `commitIdx` integer in `[0, commits.length - 1]`.\n * - slider value N ↔ `commits[N].runtimeStageId` (the cursor)\n * - cursor === null ↔ slider at value 0 (initial/empty state)\n *\n * When `commits[]` grows mid-run the slider's max bound expands\n * automatically (`index.commits.length` re-evaluates on every\n * render via the consumer's `useTranslator` subscription). The\n * cursor does NOT auto-advance — consumers that want \"follow latest\n * commit\" behavior wire a `useEffect` on `index.commits.length`.\n *\n * @example\n * ```tsx\n * const [cursor, setCursor] = useState<RuntimeStageId | null>(null);\n * const index = useTranslator(commitFlow, () => commitFlow.getIndex());\n * return (\n * <RunSlider\n * index={index}\n * cursorRuntimeStageId={cursor}\n * onCursorChange={setCursor}\n * />\n * );\n * ```\n *\n * @example Follow-latest behavior (consumer-owned)\n * ```tsx\n * useEffect(() => {\n * const last = index.commits[index.commits.length - 1];\n * if (last) setCursor(last.runtimeStageId);\n * }, [index.commits.length]);\n * ```\n *\n * Pairs with `<CommitChainView>` (via shared `revealedThroughCommitIdx`\n * to dim future commits) and `<TraceExplorerShell>` (which wires the\n * slider as a top bar driving the same cursor as the chain selection).\n */\n\nimport { useCallback, useMemo } from \"react\";\nimport type { CommitFlowIndex, CommitView } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface RunSliderProps extends BaseComponentProps {\n /** Live commit flow index (pure data prop — pass via\n * `useTranslator(commitFlow, () => commitFlow.getIndex())`).\n * Source: `createCommitFlowRecorder` — see `<CommitInspector>` for\n * the canonical consumer pattern. */\n index: CommitFlowIndex;\n /** The shared time cursor. `null` = no commit yet selected (slider\n * sits at value 0). */\n cursorRuntimeStageId: RuntimeStageId | null;\n /** Fires when the slider moves. */\n onCursorChange: (rsid: RuntimeStageId | null) => void;\n /** Optional label callback. Default renders `\"#commitIdx · stageId\"`.\n * Receives the full resolved `commit` + the `index` for richer\n * labels (step name, duration from a sibling translator, etc.). */\n renderLabel?: (info: {\n commitIdx: number;\n total: number;\n runtimeStageId: RuntimeStageId | null;\n /** Resolved commit at the cursor, or `null` when index is empty. */\n commit: CommitView | null;\n /** Full index — for cross-lookups (e.g., finding the previous\n * commit's stage label). */\n index: CommitFlowIndex;\n }) => React.ReactNode;\n}\n\nexport function RunSlider({\n index,\n cursorRuntimeStageId,\n onCursorChange,\n renderLabel,\n className,\n style,\n}: RunSliderProps) {\n const total = index.commits.length;\n\n // Map cursor → slider value. If cursor is null OR unknown to the\n // index, value 0 (placeholder).\n const cursorCommitIdx = useMemo<number>(() => {\n if (!cursorRuntimeStageId) return 0;\n const view = index.byRuntimeStageId.get(cursorRuntimeStageId);\n return view ? view.commitIdx : 0;\n }, [index, cursorRuntimeStageId]);\n\n const handleSliderChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = Number(e.target.value);\n const view = index.commits[value];\n onCursorChange(view ? view.runtimeStageId : null);\n },\n [index, onCursorChange],\n );\n\n const label = useMemo(() => {\n const commit = index.commits[cursorCommitIdx] ?? null;\n const rsid = cursorRuntimeStageId ?? commit?.runtimeStageId ?? null;\n if (renderLabel)\n return renderLabel({\n commitIdx: cursorCommitIdx,\n total,\n runtimeStageId: rsid,\n commit,\n index,\n });\n if (total === 0) return <span style={{ color: theme.textMuted }}>No commits yet</span>;\n return (\n <span style={{ fontFamily: \"monospace\", fontSize: 11, color: theme.textSecondary }}>\n #{cursorCommitIdx + 1} / {total} · {commit?.runtimeStageId ?? \"—\"}\n </span>\n );\n }, [renderLabel, cursorCommitIdx, total, index, cursorRuntimeStageId]);\n\n // Disabled state — slider is non-interactive when there are 0 or 1\n // commits (sliding has no effect).\n const disabled = total < 2;\n\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 12,\n padding: \"8px 12px\",\n background: theme.bgSecondary,\n border: `1px solid ${theme.border}`,\n borderRadius: 6,\n ...style,\n }}\n >\n <span\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n }}\n >\n Time\n </span>\n <input\n type=\"range\"\n min={0}\n max={Math.max(0, total - 1)}\n step={1}\n value={Math.min(cursorCommitIdx, Math.max(0, total - 1))}\n onChange={handleSliderChange}\n disabled={disabled}\n aria-label=\"Commit time cursor\"\n aria-valuemin={0}\n aria-valuemax={Math.max(0, total - 1)}\n aria-valuenow={cursorCommitIdx}\n aria-valuetext={\n total === 0 ? \"no commits\" : `commit ${cursorCommitIdx + 1} of ${total}`\n }\n style={{ flex: 1, accentColor: theme.success }}\n />\n <div style={{ minWidth: 200, textAlign: \"right\" }}>{label}</div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAAwC;AACxC,IAAAA,gBAAiC;;;ACDjC,mBAA0C;;;AC8CnC,IAAM,cAAc;AAAA,EACzB,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,OAAO;AAAA,IACP,SAAS;AAAA,IACT,WAAW;AAAA,IACX,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,QAAQ;AAAA,EACV;AAAA,EACA,QAAQ;AAAA,EACR,YAAY;AAAA,IACV,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;AAGO,IAAM,gBAER;AAAA,EACH,QAAQ;AAAA,IACN,SAAS,2BAA2B,YAAY,OAAO,OAAO;AAAA,IAC9D,SAAS,2BAA2B,YAAY,OAAO,OAAO;AAAA,IAC9D,OAAO,yBAAyB,YAAY,OAAO,KAAK;AAAA,IACxD,SAAS,2BAA2B,YAAY,OAAO,OAAO;AAAA,IAC9D,WAAW,wBAAwB,YAAY,OAAO,SAAS;AAAA,IAC/D,aAAa,0BAA0B,YAAY,OAAO,WAAW;AAAA,IACrE,YAAY,yBAAyB,YAAY,OAAO,UAAU;AAAA,IAClE,aAAa,0BAA0B,YAAY,OAAO,WAAW;AAAA,IACrE,eAAe,4BAA4B,YAAY,OAAO,aAAa;AAAA,IAC3E,WAAW,wBAAwB,YAAY,OAAO,SAAS;AAAA,IAC/D,QAAQ,oBAAoB,YAAY,OAAO,MAAM;AAAA,EACvD;AAAA,EACA,QAAQ,oBAAoB,YAAY,MAAM;AAAA,EAC9C,YAAY;AAAA,IACV,MAAM,uBAAuB,YAAY,WAAW,IAAI;AAAA,IACxD,MAAM,uBAAuB,YAAY,WAAW,IAAI;AAAA,EAC1D;AACF;;;ADnDM;AAlCN,IAAM,mBAAe,4BAA2B,CAAC,CAAC;;;AEE3C,SAAS,EAAE,SAAiB,UAA0B;AAC3D,SAAO,OAAO,OAAO,KAAK,QAAQ;AACpC;AAGO,IAAM,QAAQ;AAAA,EACnB,SAAS,EAAE,sBAAsB,SAAS;AAAA,EAC1C,SAAS,EAAE,sBAAsB,SAAS;AAAA,EAC1C,OAAO,EAAE,oBAAoB,SAAS;AAAA,EACtC,SAAS,EAAE,sBAAsB,SAAS;AAAA,EAC1C,WAAW,EAAE,mBAAmB,SAAS;AAAA,EACzC,aAAa,EAAE,qBAAqB,SAAS;AAAA,EAC7C,YAAY,EAAE,oBAAoB,SAAS;AAAA,EAC3C,aAAa,EAAE,qBAAqB,SAAS;AAAA,EAC7C,eAAe,EAAE,uBAAuB,SAAS;AAAA,EACjD,WAAW,EAAE,mBAAmB,SAAS;AAAA,EACzC,QAAQ,EAAE,eAAe,SAAS;AAAA,EAClC,QAAQ,EAAE,eAAe,KAAK;AAAA,EAC9B,UAAU,EAAE,kBAAkB,6CAA6C;AAAA,EAC3E,UAAU,EAAE,kBAAkB,0CAA0C;AAC1E;AAGO,IAAM,WAAyE;AAAA,EACpF,SAAS,EAAE,OAAO,IAAI,MAAM,IAAI,OAAO,EAAE;AAAA,EACzC,SAAS,EAAE,OAAO,IAAI,MAAM,IAAI,OAAO,GAAG;AAAA,EAC1C,UAAU,EAAE,OAAO,IAAI,MAAM,IAAI,OAAO,GAAG;AAC7C;AAGO,IAAM,UAAgC;AAAA,EAC3C,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AACZ;;;AClBA,IAAAC,gBAAoC;;;AJwD5B,IAAAC,sBAAA;AAzER,IAAM,eAAe;AACrB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6DtB,IAAM,YAAY;AAElB,SAAS,UAAU,EAAE,MAAM,MAAM,GAAoC;AACnE,QAAM,IAAI;AACV,QAAM,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,OAAO,CAAC,IAAI,CAAC,IAAI,MAAM,QAAQ,OAAO,EAAE,YAAY,EAAE,EAAW;AAE/G,UAAQ,MAAM;AAAA;AAAA,IAEZ,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI,QAAQ,OAAO,aAAY,OAAM;AAAA,QAC7D,6CAAC,UAAK,GAAE,4CAA2C,QAAQ,OAAO,aAAY,OAAM,eAAc,SAAQ;AAAA,QAC1G,6CAAC,YAAO,IAAG,KAAI,IAAG,OAAM,GAAE,KAAI,MAAM,OAAO;AAAA,QAC3C,6CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,KAAI,IAAG,OAAM,QAAQ,OAAO,aAAY,KAAI,eAAc,SAAQ;AAAA,QACzF,6CAAC,UAAK,IAAG,QAAO,IAAG,KAAI,IAAG,QAAO,IAAG,KAAI,QAAQ,OAAO,aAAY,KAAI,eAAc,SAAQ;AAAA,QAC7F,6CAAC,UAAK,IAAG,OAAM,IAAG,KAAI,IAAG,OAAM,IAAG,KAAI,QAAQ,OAAO,aAAY,KAAI,eAAc,SAAQ;AAAA,SAC7F;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI,QAAQ,OAAO,aAAY,OAAM;AAAA,QAC5D,CAAC,GAAG,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAG,EAAE,IAAI,CAAC,UAAU;AACnD,gBAAM,MAAO,QAAQ,KAAK,KAAM;AAChC,gBAAM,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI;AAC/B,gBAAM,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI;AAC/B,gBAAM,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI;AAC/B,gBAAM,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI;AAC/B,iBAAO,6CAAC,UAAiB,IAAQ,IAAQ,IAAQ,IAAQ,QAAQ,OAAO,aAAY,OAAM,eAAc,WAAtF,KAA8F;AAAA,QAClH,CAAC;AAAA,SACH;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI,QAAQ,OAAO,aAAY,OAAM;AAAA,QAC7D,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,QAAO,IAAG,QAAO,QAAQ,OAAO,aAAY,OAAM,eAAc,SAAQ;AAAA,QACjG,6CAAC,UAAK,IAAG,OAAM,IAAG,KAAI,IAAG,OAAM,IAAG,KAAI,QAAQ,OAAO,aAAY,KAAI,eAAc,SAAQ;AAAA,QAC3F,6CAAC,UAAK,IAAG,OAAM,IAAG,KAAI,IAAG,OAAM,IAAG,KAAI,QAAQ,OAAO,aAAY,KAAI,eAAc,SAAQ;AAAA,SAC7F;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aACE,6CAAC,SAAK,GAAG,OACP,uDAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,KAAI,QAAO,KAAI,IAAG,OAAM,QAAQ,OAAO,aAAY,OAAM,WAAU,kBAAiB,GAC9G;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aACE,6CAAC,SAAK,GAAG,OACP,uDAAC,UAAK,GAAE,6BAA4B,MAAM,OAAO,SAAQ,OAAM,GACjE;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aACE,6CAAC,SAAK,GAAG,OACP,uDAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,KAAI,QAAO,KAAI,IAAG,OAAM,MAAM,OAAO,SAAQ,OAAM,GAC7E;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM,QAAQ,OAAO,aAAY,OAAM;AAAA,QAC/D,6CAAC,UAAK,GAAE,4CAA2C,QAAQ,OAAO,aAAY,OAAM,eAAc,SAAQ;AAAA,SAC5G;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI,QAAQ,OAAO,aAAY,OAAM;AAAA,QAC7D,6CAAC,YAAO,IAAG,MAAK,IAAG,KAAI,GAAE,KAAI,QAAQ,OAAO,aAAY,OAAM;AAAA,QAC9D,6CAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,KAAI,QAAQ,OAAO,aAAY,OAAM;AAAA,QAC9D,6CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,KAAI,IAAG,KAAI,QAAQ,OAAO,aAAY,KAAI,SAAQ,OAAM;AAAA,QAC/E,6CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,KAAI,QAAQ,OAAO,aAAY,KAAI,SAAQ,OAAM;AAAA,SAClF;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,UAAK,GAAE,+DAA8D,QAAQ,OAAO,aAAY,OAAM,gBAAe,SAAQ;AAAA,QAC9H,6CAAC,UAAK,GAAE,uBAAsB,QAAQ,OAAO,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ;AAAA,SAC9G;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,UAAK,GAAE,+BAA8B,QAAQ,OAAO,aAAY,OAAM,eAAc,SAAQ,MAAK,QAAO;AAAA,QACzG,6CAAC,UAAK,GAAE,kCAAiC,QAAQ,OAAO,aAAY,KAAI,eAAc,SAAQ,MAAK,QAAO,SAAQ,OAAM;AAAA,SAC1H;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,aAAQ,IAAG,KAAI,IAAG,OAAM,IAAG,KAAI,IAAG,KAAI,QAAQ,OAAO,aAAY,OAAM;AAAA,QACxE,6CAAC,UAAK,IAAG,KAAI,IAAG,OAAM,IAAG,KAAI,IAAG,QAAO,QAAQ,OAAO,aAAY,OAAM;AAAA,QACxE,6CAAC,UAAK,IAAG,MAAK,IAAG,OAAM,IAAG,MAAK,IAAG,QAAO,QAAQ,OAAO,aAAY,OAAM;AAAA,QAC1E,6CAAC,aAAQ,IAAG,KAAI,IAAG,QAAO,IAAG,KAAI,IAAG,KAAI,QAAQ,OAAO,aAAY,OAAM;AAAA,SAC3E;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,UAAK,GAAE,uBAAsB,QAAQ,OAAO,aAAY,OAAM,eAAc,SAAQ,MAAK,QAAO;AAAA,QACjG,6CAAC,UAAK,GAAE,uBAAsB,QAAQ,OAAO,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ,MAAK,QAAO;AAAA,SAC1H;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aACE,6CAAC,SAAK,GAAG,OACP;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,QAAQ;AAAA,UACR,aAAY;AAAA,UACZ,eAAc;AAAA,UACd,MAAK;AAAA;AAAA,MACP,GACF;AAAA;AAAA,IAIJ,KAAK;AAAA,IACL,KAAK;AACH,aACE,8CAAC,SAAK,GAAG,OACP;AAAA,qDAAC,UAAK,GAAE,uBAAsB,QAAQ,OAAO,aAAY,OAAM,MAAK,QAAO;AAAA,QAC3E,6CAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM,MAAM,OAAO;AAAA,SAC7C;AAAA,IAGJ;AACE,aAAO;AAAA,EACX;AACF;AAOO,IAAM,gBAAY,oBAAK,SAASC,WAAU;AAAA,EAC/C;AACF,GAAwC;AACtC,QAAM,EAAE,OAAO,QAAQ,MAAM,OAAO,QAAQ,MAAM,aAAa,QAAQ,WAAW,QAAQ,WAAW,QAAQ,aAAa,SAAS,YAAY,IAAI;AAGnJ,QAAM,gBAAgB,SAAS,SAAS,SAAS;AAEjD,QAAM,mBAAmB,UAAU,CAAC,QAAQ,CAAC;AAG7C,QAAM,kBAAc,sBAAO,KAAK;AAChC,+BAAU,MAAM;AACd,QAAI,YAAY,QAAS;AACzB,QAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,YAAY,GAAG;AAC7E,YAAM,UAAU,SAAS,cAAc,OAAO;AAC9C,cAAQ,KAAK;AACb,cAAQ,cAAc;AACtB,eAAS,KAAK,YAAY,OAAO;AAAA,IACnC;AACA,gBAAY,UAAU;AAAA,EACxB,GAAG,CAAC,CAAC;AAEL,QAAM,WAAW,UAAU;AAE3B,QAAM,KAAK,SACP,MAAM,UACN,OACE,MAAM,UACN,QACE,MAAM,QACN,MAAM;AAEd,QAAM,cAAc,SAChB,MAAM,UACN,OACE,MAAM,UACN,QACE,MAAM,QACN,MAAM;AAEd,QAAM,SAAS,SACX,+BAA+B,MAAM,OAAO,uBAC5C,OACE,8BAA8B,MAAM,OAAO,uBAC3C,QACE,+BAA+B,MAAM,KAAK,uBAC1C;AAGR,QAAM,YACJ,UAAU,QAAQ,QAAQ,SAAS,MAAM;AAE3C,SACE,8EACE;AAAA,iDAAC,wBAAO,MAAK,UAAS,UAAU,uBAAS,KAAK,OAAO,EAAE,SAAS,EAAE,GAAG;AAAA,IACrE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,UAAU;AAAA,UACV,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,KAAK;AAAA,QACP;AAAA,QAGC;AAAA,yBAAe,YAAY,SAAS,KAAK,YACxC;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,SAAS;AAAA,gBACT,KAAK;AAAA,gBACL,QAAQ;AAAA,cACV;AAAA,cAEC,sBAAY,IAAI,CAAC,KAAK,MAAM;AAC3B,sBAAM,WAAW,MAAM,YAAY,SAAS;AAC5C,sBAAM,UAAU,YAAY,SAAS,MAAM,UAAU,MAAM;AAC3D,sBAAM,OAAO,YAAY,SACrB,sBAAsB,MAAM,OAAO,uBACnC,sBAAsB,MAAM,OAAO;AACvC,uBACE;AAAA,kBAAC;AAAA;AAAA,oBAEC,OAAO;AAAA,sBACL,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,cAAc;AAAA,sBACd,YAAY;AAAA,sBACZ,OAAO;AAAA,sBACP,UAAU;AAAA,sBACV,YAAY;AAAA,sBACZ,SAAS;AAAA,sBACT,YAAY;AAAA,sBACZ,gBAAgB;AAAA,sBAChB,WAAW,WAAW,IAAI;AAAA,oBAC5B;AAAA,oBAEC;AAAA;AAAA,kBAfI;AAAA,gBAgBP;AAAA,cAEJ,CAAC;AAAA;AAAA,UACH;AAAA,UAID,UACC;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc,YAAY,IAAI,QAAQ,MAAM,MAAM;AAAA,gBAClD,UAAU,YAAY,gDAAgD;AAAA,gBACtE,QAAQ,aAAa,MAAM,OAAO;AAAA,gBAClC,SAAS;AAAA,gBACT,WAAW;AAAA,cACb;AAAA;AAAA,UACF;AAAA,UAID,UACC;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc,YAAY,IAAI,QAAQ,MAAM,MAAM;AAAA,gBAClD,UAAU,YAAY,gDAAgD;AAAA,gBACtE,QAAQ,aAAa,MAAM,OAAO;AAAA,gBAClC,SAAS;AAAA,gBACT,WAAW;AAAA,cACb;AAAA;AAAA,UACF;AAAA,UAID,YACC,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,OAAO,KAAK,QAAQ,GAAG,GAEzD;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,UAAU;AAAA,kBACV,OAAO;AAAA,kBACP,YAAY;AAAA,kBACZ,UAAU;AAAA,kBACV,QAAQ;AAAA,kBACR,WAAW;AAAA,kBACX,YAAY;AAAA,gBACd;AAAA;AAAA,YACF;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,UAAU;AAAA,kBACV,OAAO;AAAA,kBACP,UAAU;AAAA,kBACV,YAAY;AAAA,kBACZ,QAAQ;AAAA,kBACR,GAAI,mBAAmB;AAAA,oBACrB,YAAY;AAAA;AAAA,kBAEd,IAAI,CAAC;AAAA,gBACP;AAAA;AAAA,YACF;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,UAAU;AAAA,kBACV,OAAO;AAAA,kBACP,SAAS;AAAA,kBACT,eAAe;AAAA,kBACf,YAAY;AAAA,kBACZ,gBAAgB;AAAA,kBAChB,KAAK;AAAA,kBACL,YAAY,MAAM;AAAA,kBAClB,QAAQ;AAAA,gBACV;AAAA,gBAEA;AAAA,gEAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAE,GACzD;AAAA,qCAAiB,6CAAC,aAAU,MAAM,eAAe,OAAO,WAAW;AAAA,oBACnE,CAAC,iBACA,6CAAC,UAAK,OAAO,EAAE,UAAU,GAAG,OAAO,UAAU,GAAG,oBAAQ;AAAA,oBAE1D;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,UAAU;AAAA,0BACV,YAAY;AAAA,0BACZ,OAAO;AAAA,0BACP,YAAY;AAAA,wBACd;AAAA,wBAEC;AAAA;AAAA,oBACH;AAAA,qBACF;AAAA,kBACC,eACC;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO;AAAA,wBACL,UAAU;AAAA,wBACV,YAAY;AAAA,wBACZ,OAAO;AAAA,wBACP,SAAS;AAAA,wBACT,YAAY;AAAA,wBACZ,UAAU;AAAA,wBACV,cAAc;AAAA,wBACd,UAAU;AAAA,sBACZ;AAAA,sBAEC;AAAA;AAAA,kBACH;AAAA,kBAED,eAAe,WACd;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO;AAAA,wBACL,UAAU;AAAA,wBACV,YAAY;AAAA,wBACZ,OAAO;AAAA,wBACP,SAAS;AAAA,wBACT,YAAY;AAAA,wBACZ,UAAU;AAAA,wBACV,cAAc;AAAA,wBACd,UAAU;AAAA,sBACZ;AAAA,sBACA,OAAO,YAAY,OAAO;AAAA,sBAEzB;AAAA;AAAA,kBACH;AAAA;AAAA;AAAA,YAEJ;AAAA,aACF;AAAA;AAAA,YAGA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,YAAY;AAAA,kBACZ,QAAQ,OAAO,mBAAmB,WAAW,OAAO,IAAI,WAAW;AAAA,kBACnE,cAAc,MAAM;AAAA,kBACpB,SAAS,cAAc,aAAa;AAAA,kBACpC,SAAS;AAAA,kBACT,eAAe;AAAA,kBACf,YAAY;AAAA,kBACZ,KAAK,cAAc,IAAI;AAAA,kBACvB,WAAW;AAAA,kBACX,YAAY;AAAA,kBACZ,YAAY,MAAM;AAAA,kBAClB,UAAU;AAAA,kBACV,gBAAgB;AAAA,gBAClB;AAAA,gBAEA;AAAA,gEAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAE,GAEzD;AAAA,qCAAiB,6CAAC,aAAU,MAAM,eAAe,OAAO,WAAW;AAAA,oBAGnE,QAAQ,CAAC,iBACR,6CAAC,UAAK,OAAO,EAAE,UAAU,IAAI,OAAO,UAAU,GAAG,oBAAQ;AAAA,oBAE1D,UAAU,CAAC,iBACV;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,OAAO;AAAA,0BACP,QAAQ;AAAA,0BACR,cAAc;AAAA,0BACd,YAAY;AAAA,0BACZ,WAAW;AAAA,0BACX,YAAY;AAAA,wBACd;AAAA;AAAA,oBACF;AAAA,oBAED,SAAS,CAAC,iBACT,6CAAC,UAAK,OAAO,EAAE,UAAU,IAAI,OAAO,UAAU,GAAG,oBAAQ;AAAA,oBAG3D;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,UAAU;AAAA,0BACV,YAAY;AAAA,0BACZ,OAAO;AAAA,0BACP,YAAY;AAAA,wBACd;AAAA,wBAEC;AAAA;AAAA,oBACH;AAAA,oBAEC,aACC;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,SAAS;AAAA,0BACT,YAAY;AAAA,0BACZ,gBAAgB;AAAA,0BAChB,OAAO;AAAA,0BACP,QAAQ;AAAA,0BACR,cAAc;AAAA,0BACd,QAAQ,eAAe,SAAS;AAAA,0BAChC,UAAU;AAAA,0BACV,SAAS;AAAA,0BACT,YAAY;AAAA,wBACd;AAAA,wBAEA;AAAA,0BAAC;AAAA;AAAA,4BACC,OAAO;AAAA,8BACL,OAAO;AAAA,8BACP,QAAQ;AAAA,8BACR,cAAc;AAAA,8BACd,QAAQ,aAAa,SAAS;AAAA,4BAChC;AAAA;AAAA,wBACF;AAAA;AAAA,oBACF;AAAA,qBAEJ;AAAA,kBAEC,eACC;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO;AAAA,wBACL,UAAU;AAAA,wBACV,YAAY;AAAA,wBACZ,OAAO;AAAA,wBACP,SAAS;AAAA,wBACT,YAAY;AAAA,wBACZ,UAAU;AAAA,wBACV,cAAc;AAAA,wBACd,UAAU;AAAA,sBACZ;AAAA,sBAEC;AAAA;AAAA,kBACH;AAAA,kBAMD,eAAe,WACd;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO;AAAA,wBACL,UAAU;AAAA,wBACV,YAAY;AAAA,wBACZ,OAAO;AAAA,wBACP,SAAS;AAAA,wBACT,YAAY;AAAA,wBACZ,UAAU;AAAA,wBACV,cAAc;AAAA,wBACd,UAAU;AAAA,sBACZ;AAAA,sBACA,OAAO,YAAY,OAAO;AAAA,sBAEzB;AAAA;AAAA,kBACH;AAAA;AAAA;AAAA,YAEJ;AAAA;AAAA;AAAA;AAAA,IAEJ;AAAA,IACA,6CAAC,wBAAO,MAAK,UAAS,UAAU,uBAAS,QAAQ,OAAO,EAAE,SAAS,EAAE,GAAG;AAAA,IAGxE;AAAA,MAAC;AAAA;AAAA,QACC,IAAG;AAAA,QACH,MAAK;AAAA,QACL,UAAU,uBAAS;AAAA,QACnB,OAAO,EAAE,YAAY,eAAe,QAAQ,QAAQ,OAAO,GAAG,QAAQ,GAAG,MAAM,MAAM;AAAA;AAAA,IACvF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,IAAG;AAAA,QACH,MAAK;AAAA,QACL,UAAU,uBAAS;AAAA,QACnB,OAAO,EAAE,YAAY,eAAe,QAAQ,QAAQ,OAAO,GAAG,QAAQ,EAAE;AAAA;AAAA,IAC1E;AAAA,KACF;AAEJ,CAAC;;;AK3mBD,IAAAC,iBAAyB;;;ACAzB,IAAAC,gBAAgC;AAoG1B,IAAAC,sBAAA;AAxEC,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,OAAO;AAAA,EACP,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAyB;AAEvB,QAAM,eAAW,sBAA2B,IAAI;AAEhD,QAAM,EAAE,QAAQ,QAAQ,QAAI,uBAAQ,MAAM;AACxC,QAAI,MAAM;AACR,aAAO,EAAE,QAAQ,MAAM,SAAS,oBAAI,IAAY,EAAE;AAAA,IACpD;AACA,QAAI,CAAC,aAAa,UAAU,WAAW,GAAG;AACxC,aAAO,EAAE,QAAQ,CAAC,GAAG,SAAS,oBAAI,IAAY,EAAE;AAAA,IAClD;AAEA,UAAM,UAAU,KAAK,IAAI,eAAe,UAAU,SAAS,CAAC;AAC5D,QAAI;AACJ,UAAM,QAAQ,SAAS;AAEvB,QAAI,SAAS,MAAM,cAAc,aAAa,MAAM,SAAS,SAAS;AAEpE,eAAS,EAAE,GAAG,MAAM,YAAY;AAChC,eAAS,IAAI,MAAM,QAAQ,GAAG,KAAK,SAAS,KAAK;AAC/C,eAAO,OAAO,QAAQ,UAAU,CAAC,GAAG,MAAM;AAAA,MAC5C;AAAA,IACF,OAAO;AAEL,eAAS,CAAC;AACV,eAAS,IAAI,GAAG,KAAK,SAAS,KAAK;AACjC,eAAO,OAAO,QAAQ,UAAU,CAAC,GAAG,MAAM;AAAA,MAC5C;AAAA,IACF;AAGA,aAAS,UAAU,EAAE,WAAW,OAAO,SAAS,aAAa,OAAO;AAEpE,UAAM,KAAK,oBAAI,IAAY;AAC3B,QAAI,gBAAgB,UAAU,GAAG;AAE/B,UAAI;AACJ,UAAI,SAAS,MAAM,cAAc,aAAa,MAAM,UAAU,UAAU,GAAG;AACzE,eAAO,MAAM;AAAA,MACf,OAAO;AACL,eAAO,CAAC;AACR,iBAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,iBAAO,OAAO,MAAM,UAAU,CAAC,GAAG,MAAM;AAAA,QAC1C;AAAA,MACF;AACA,YAAM,UAAU,UAAU,OAAO,GAAG,UAAU,CAAC;AAC/C,iBAAW,KAAK,OAAO,KAAK,OAAO,GAAG;AACpC,YAAI,EAAE,KAAK,MAAO,IAAG,IAAI,CAAC;AAAA,MAC5B;AAAA,IACF,WAAW,gBAAgB,YAAY,KAAK,UAAU,CAAC,GAAG;AACxD,iBAAW,KAAK,OAAO,KAAK,UAAU,CAAC,EAAE,MAAM,EAAG,IAAG,IAAI,CAAC;AAAA,IAC5D;AAEA,WAAO,EAAE,QAAQ,QAAQ,SAAS,GAAG;AAAA,EACvC,GAAG,CAAC,MAAM,WAAW,eAAe,YAAY,CAAC;AAEjD,QAAM,UAAU,OAAO,QAAQ,MAAM;AACrC,QAAM,KAAK,SAAS,IAAI;AACxB,QAAM,MAAM,QAAQ,IAAI;AAExB,MAAI,UAAU;AACZ,WACE,8CAAC,SAAI,WAAsB,OAAc,WAAQ,oBAAmB,MAAK,UAAS,cAAW,gBAC3F;AAAA,mDAAC,SAAI,WAAQ,gBAAe,0BAAY;AAAA,MACxC,6CAAC,SAAI,WAAQ,eACX,uDAAC,UAAM,eAAK,UAAU,QAAQ,MAAM,CAAC,GAAE,GACzC;AAAA,OACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY,MAAM;AAAA,QAClB,GAAG;AAAA,MACL;AAAA,MACA,WAAQ;AAAA,MACR,MAAK;AAAA,MACL,cAAW;AAAA,MAEX;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU,GAAG;AAAA,cACb,YAAY;AAAA,cACZ,OAAO,MAAM;AAAA,cACb,eAAe;AAAA,cACf,eAAe;AAAA,YACjB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,YAAY,MAAM;AAAA,cAClB,QAAQ,aAAa,MAAM,MAAM;AAAA,cACjC,cAAc,MAAM;AAAA,cACpB,SAAS,GAAG,GAAG,MAAM,MAAM,CAAC;AAAA,cAC5B,YAAY,MAAM;AAAA,cAClB,UAAU,GAAG;AAAA,cACb,YAAY;AAAA,YACd;AAAA,YAEA;AAAA,2DAAC,UAAK,OAAO,EAAE,OAAO,MAAM,UAAU,GAAI,eAAI;AAAA,cAC7C,QAAQ,WAAW,KAClB;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO;AAAA,oBACL,aAAa;AAAA,oBACb,OAAO,MAAM;AAAA,oBACb,WAAW;AAAA,kBACb;AAAA,kBAEC;AAAA;AAAA,cACH;AAAA,cAED,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,GAAG,MAAM;AAChC,sBAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,sBAAM,SAAS,MAAM,QAAQ,SAAS;AACtC,uBACE;AAAA,kBAAC;AAAA;AAAA,oBAEC,OAAO;AAAA,sBACL,aAAa;AAAA,sBACb,YAAY,QACR,sBAAsB,MAAM,OAAO,uBACnC;AAAA,sBACJ,cAAc;AAAA,sBACd,YAAY;AAAA,sBACZ,aAAa;AAAA,sBACb,cAAc;AAAA,oBAChB;AAAA,oBAEA;AAAA,oEAAC,UAAK,OAAO,EAAE,OAAO,MAAM,QAAQ,GAAG;AAAA;AAAA,wBAAO;AAAA,wBAAI;AAAA,yBAAM;AAAA,sBACxD,6CAAC,UAAK,OAAO,EAAE,OAAO,MAAM,UAAU,GAAG,gBAAE;AAAA,sBAC3C,6CAAC,UAAK,OAAO,EAAE,OAAO,MAAM,QAAQ,GACjC,sBAAY,KAAK,GACpB;AAAA,sBACC,aACC;AAAA,wBAAC;AAAA;AAAA,0BACC,OAAO;AAAA,4BACL,OAAO,MAAM;AAAA,4BACb,UAAU,GAAG;AAAA,4BACb,YAAY;AAAA,4BACZ,SAAS;AAAA,0BACX;AAAA,0BACD;AAAA;AAAA,4BACG,OAAO;AAAA,4BAAM;AAAA;AAAA;AAAA,sBACjB;AAAA,sBAED,CAAC,UAAU,6CAAC,UAAK,OAAO,EAAE,OAAO,MAAM,UAAU,GAAG,eAAC;AAAA;AAAA;AAAA,kBA7BjD;AAAA,gBA8BP;AAAA,cAEJ,CAAC;AAAA,cACD,6CAAC,UAAK,OAAO,EAAE,OAAO,MAAM,UAAU,GAAI,eAAI;AAAA;AAAA;AAAA,QAChD;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,YAAY,OAAwB;AAC3C,MAAI,OAAO,UAAU,SAAU,QAAO,IAAI,KAAK;AAC/C,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO,KAAK,UAAU,KAAK;AAC5E,SAAO,OAAO,KAAK;AACrB;;;AC5MA,IAAAC,gBAAwB;AA6Cd,IAAAC,sBAAA;AA5BH,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAsB;AACpB,QAAM,cAAU,uBAAQ,MAAM;AAC5B,QAAI,WAAW;AACb,aAAO,CAAC,EAAE,OAAO,UAAU,MAAM,WAAW,WAAW,KAAK,CAAC;AAAA,IAC/D;AACA,UAAM,MAAM,iBAAiB,UAAU,SAAS;AAChD,WAAO,UAAU,MAAM,GAAG,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,OAAO;AAAA,MAChD,OAAO,EAAE;AAAA,MACT,MAAM,EAAE;AAAA,MACR,WAAW,MAAM;AAAA,IACnB,EAAE;AAAA,EACJ,GAAG,CAAC,WAAW,eAAe,SAAS,CAAC;AAExC,QAAM,KAAK,SAAS,IAAI;AACxB,QAAM,MAAM,QAAQ,IAAI;AAExB,MAAI,UAAU;AACZ,WACE,6CAAC,SAAI,WAAsB,OAAc,WAAQ,iBAC9C,kBAAQ,IAAI,CAAC,OAAO,MACnB,8CAAC,SAAY,WAAQ,mBAAkB,gBAAc,MAAM,WACzD;AAAA,mDAAC,YAAQ,gBAAM,OAAM;AAAA,MACrB,6CAAC,OAAG,gBAAM,MAAK;AAAA,SAFP,CAGV,CACD,GACH;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO,EAAE,SAAS,KAAK,YAAY,MAAM,UAAU,GAAG,MAAM;AAAA,MAC5D,WAAQ;AAAA,MAER;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU,GAAG;AAAA,cACb,YAAY;AAAA,cACZ,OAAO,MAAM;AAAA,cACb,eAAe;AAAA,cACf,eAAe;AAAA,YACjB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QACA,6CAAC,SAAI,OAAO,EAAE,WAAW,GAAG,SAAS,QAAQ,eAAe,SAAS,GAClE,kBAAQ,IAAI,CAAC,OAAO,MACnB;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO;AAAA,cACL,SAAS;AAAA,cACT,KAAK;AAAA,cACL,SAAS,GAAG,GAAG;AAAA,cACf,cACE,IAAI,QAAQ,SAAS,IAAI,aAAa,MAAM,MAAM,KAAK;AAAA,YAC3D;AAAA,YAGA;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO;AAAA,oBACL,SAAS;AAAA,oBACT,eAAe;AAAA,oBACf,YAAY;AAAA,oBACZ,OAAO;AAAA,oBACP,YAAY;AAAA,oBACZ,YAAY;AAAA,kBACd;AAAA,kBAEA;AAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,OAAO;AAAA,0BACP,QAAQ;AAAA,0BACR,cAAc;AAAA,0BACd,YAAY,MAAM,YAAY,MAAM,UAAU,MAAM;AAAA,0BACpD,YAAY;AAAA,wBACd;AAAA;AAAA,oBACF;AAAA,oBACC,IAAI,QAAQ,SAAS,KACpB;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,OAAO;AAAA,0BACP,MAAM;AAAA,0BACN,YAAY,MAAM;AAAA,0BAClB,WAAW;AAAA,wBACb;AAAA;AAAA,oBACF;AAAA;AAAA;AAAA,cAEJ;AAAA,cAGA,8CAAC,SAAI,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,GACjC;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO;AAAA,sBACL,UAAU,GAAG;AAAA,sBACb,YAAY;AAAA,sBACZ,OAAO,MAAM,YAAY,MAAM,UAAU,MAAM;AAAA,oBACjD;AAAA,oBAEC,gBAAM;AAAA;AAAA,gBACT;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO;AAAA,sBACL,UAAU,GAAG;AAAA,sBACb,YAAY;AAAA,sBACZ,OAAO,MAAM,YAAY,MAAM,cAAc,MAAM;AAAA,sBACnD,WAAW;AAAA,oBACb;AAAA,oBAEC,gBAAM;AAAA;AAAA,gBACT;AAAA,iBACF;AAAA;AAAA;AAAA,UA9DK;AAAA,QA+DP,CACD,GACH;AAAA;AAAA;AAAA,EACF;AAEJ;;;AC9IA,IAAAC,gBAAqD;AAwEzC,IAAAC,sBAAA;AApDL,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA,OAAO;AAAA,EACP,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,iBAAiB;AACnB,GAAuB;AACrB,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,KAAK;AAC9C,QAAM,mBAAe,sBAA8B,IAAI;AACvD,QAAM,yBAAqB,sBAA8B,IAAI;AAE7D,QAAM,oBAAgB;AAAA,IACpB,MAAM,KAAK,IAAI,GAAG,UAAU,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,CAAC;AAAA,IACnE,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,KAAK,SAAS,IAAI;AACxB,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,aAAa,SAAS,YAAY,KAAK,SAAS,aAAa,MAAM;AACzE,QAAM,UAAU,SAAS,YAAY,KAAK;AAC1C,QAAM,YAAY,SAAS,YAAY,KAAK;AAE5C,QAAM,cAAc,iBAAiB,KAAK,UAAU,SAAS;AAC7D,QAAM,UAAU,YAAY,CAAC;AAG7B,+BAAU,MAAM;AACd,QAAI,CAAC,WAAW,aAAa,WAAW,mBAAmB,SAAS;AAClE,mBAAa,QAAQ,eAAe;AAAA,QAClC,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,eAAe,OAAO,CAAC;AAE3B,MAAI,UAAU;AACZ,WACE,6CAAC,SAAI,WAAsB,OAAc,WAAQ,kBAAiB,MAAK,WAAU,cAAW,sBACzF,oBAAU,IAAI,CAAC,MAAM,QACpB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAQ;AAAA,QACR,iBAAe,QAAQ;AAAA,QACvB,gBAAc,OAAO;AAAA,QACrB,MAAK;AAAA,QACL,iBAAe,QAAQ;AAAA,QACvB,cAAY,GAAG,KAAK,UAAU,KAAK,KAAK,UAAU;AAAA,QAClD,SAAS,MAAM,WAAW,GAAG;AAAA,QAE7B;AAAA,uDAAC,UAAK,WAAQ,eAAe,eAAK,YAAW;AAAA,UAC7C,8CAAC,UAAK,WAAQ,kBAAkB;AAAA,iBAAK;AAAA,YAAW;AAAA,aAAE;AAAA;AAAA;AAAA,MAV7C,GAAG,KAAK,SAAS,IAAI,GAAG;AAAA,IAW/B,CACD,GACH;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO,EAAE,SAAS,KAAK,YAAY,MAAM,UAAU,GAAG,MAAM;AAAA,MAC5D,WAAQ;AAAA,MAGR;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,gBAAgB;AAAA,YAClB;AAAA,YAEA;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO;AAAA,oBACL,UAAU,GAAG;AAAA,oBACb,YAAY;AAAA,oBACZ,OAAO,MAAM;AAAA,oBACb,eAAe;AAAA,oBACf,eAAe;AAAA,kBACjB;AAAA,kBAEC,mBAAS,YAAY,aAAa;AAAA;AAAA,cACrC;AAAA,cACC,eACC;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,kBACpC,OAAO;AAAA,oBACL,YAAY;AAAA,oBACZ,QAAQ,aAAa,MAAM,MAAM;AAAA,oBACjC,cAAc;AAAA,oBACd,OAAO,MAAM;AAAA,oBACb,UAAU,GAAG;AAAA,oBACb,SAAS;AAAA,oBACT,QAAQ;AAAA,oBACR,YAAY,MAAM;AAAA,kBACpB;AAAA,kBAEC,qBACG,aACA,GAAG,UAAU,SAAS,cAAc;AAAA;AAAA,cAC1C;AAAA;AAAA;AAAA,QAEJ;AAAA,QAGA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,MAAK;AAAA,YACL,cAAW;AAAA,YACX,OAAO;AAAA,cACL,WAAW;AAAA,cACX,SAAS;AAAA,cACT,eAAe;AAAA,cACf,KAAK;AAAA,cACL,GAAI,UACA,CAAC,IACD;AAAA,gBACE,WAAW,kBAAkB,YAAY;AAAA,gBACzC,WAAW;AAAA,gBACX,gBAAgB;AAAA,cAClB;AAAA,YACN;AAAA,YAEC,oBAAU,IAAI,CAAC,MAAM,QAAQ;AAC5B,oBAAM,UAAW,KAAK,UAAU,gBAAiB;AACjD,oBAAM,WAAW,KAAK,IAAK,KAAK,aAAa,gBAAiB,KAAK,CAAC;AACpE,oBAAM,aAAa,QAAQ;AAC3B,oBAAM,YAAY,OAAO;AAEzB,qBACE;AAAA,gBAAC;AAAA;AAAA,kBAEC,KAAK,aAAa,eAAe;AAAA,kBACjC,MAAK;AAAA,kBACL,iBAAe;AAAA,kBACf,cAAY,GAAG,KAAK,UAAU,KAAK,KAAK,UAAU;AAAA,kBAClD,SAAS,MAAM,WAAW,GAAG;AAAA,kBAC7B,OAAO;AAAA,oBACL,SAAS;AAAA,oBACT,YAAY;AAAA,oBACZ,KAAK,SAAS,YAAY,IAAI;AAAA,oBAC9B,QAAQ,WAAW,YAAY;AAAA,oBAC/B,SAAS,YAAY,IAAI;AAAA,oBACzB,YAAY;AAAA,oBACZ,QAAQ;AAAA,oBACR,YAAY;AAAA,kBACd;AAAA,kBAEA;AAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO,KAAK;AAAA,wBACZ,OAAO;AAAA,0BACL,OAAO;AAAA,0BACP,UAAU,GAAG;AAAA,0BACb,OAAO,aAAa,MAAM,UAAU,MAAM;AAAA,0BAC1C,YAAY,aAAa,MAAM;AAAA,0BAC/B,WAAW;AAAA,0BACX,YAAY;AAAA,0BACZ,UAAU;AAAA,0BACV,cAAc;AAAA,0BACd,YAAY;AAAA,wBACd;AAAA,wBAEC,eAAK;AAAA;AAAA,oBACR;AAAA,oBACA;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,MAAM;AAAA,0BACN,QAAQ,SAAS,YAAY,IAAI;AAAA,0BACjC,UAAU;AAAA,0BACV,YAAY,MAAM;AAAA,0BAClB,cAAc;AAAA,wBAChB;AAAA,wBAEC,uBACC;AAAA,0BAAC;AAAA;AAAA,4BACC,OAAO;AAAA,8BACL,UAAU;AAAA,8BACV,MAAM,GAAG,OAAO;AAAA,8BAChB,KAAK;AAAA,8BACL,OAAO,GAAG,QAAQ;AAAA,8BAClB,QAAQ;AAAA,8BACR,cAAc;AAAA,8BACd,YAAY,aAAa,MAAM,UAAU,MAAM;AAAA,8BAC/C,YAAY;AAAA,4BACd;AAAA;AAAA,wBACF;AAAA;AAAA,oBAEJ;AAAA,oBACA;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,UAAU,GAAG;AAAA,0BACb,OAAO,MAAM;AAAA,0BACb,YAAY,MAAM;AAAA,0BAClB,OAAO;AAAA,0BACP,YAAY;AAAA,wBACd;AAAA,wBAEC;AAAA,+BAAK;AAAA,0BAAW;AAAA;AAAA;AAAA,oBACnB;AAAA;AAAA;AAAA,gBAnEK,GAAG,KAAK,SAAS,IAAI,GAAG;AAAA,cAoE/B;AAAA,YAEJ,CAAC;AAAA;AAAA,QACH;AAAA,QAGA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,YAAY,cAAc,SAAS,YAAY,IAAI;AAAA,cACnD,aAAa,WAAW,SAAS,YAAY,IAAI;AAAA,cACjD,SAAS;AAAA,cACT,gBAAgB;AAAA,cAChB,UAAU,GAAG,QAAQ;AAAA,cACrB,OAAO,MAAM;AAAA,cACb,YAAY,MAAM;AAAA,YACpB;AAAA,YAEA;AAAA,2DAAC,UAAK,iBAAG;AAAA,cACR,SAAS,aACR,8CAAC,UAAO;AAAA,iCAAgB,GAAG,QAAQ,CAAC;AAAA,gBAAE;AAAA,iBAAE;AAAA,cAE1C,8CAAC,UAAM;AAAA,8BAAc,QAAQ,CAAC;AAAA,gBAAE;AAAA,iBAAE;AAAA;AAAA;AAAA,QACpC;AAAA;AAAA;AAAA,EACF;AAEJ;;;AC/MA,IAAAC,gBAA2D;AAC3D,IAAAA,gBAKO;AAiZD,IAAAC,sBAAA;AAhYN,IAAM,SAAS;AACf,IAAM,WAAW;AAsCV,IAAM,yBAA0C,CAAC,UAAU;AAChE,MAAI,MAAM,MAAM,WAAW,EAAG,QAAO,EAAE,OAAO,CAAC,GAAG,OAAO,MAAM,MAAM;AAMrE,QAAM,mBAAmB,oBAAI,IAAsB;AACnD,QAAM,iBAAiB,oBAAI,IAAsB;AACjD,QAAM,qBAAqB,oBAAI,IAAY;AAC3C,aAAW,KAAK,MAAM,OAAO;AAC3B,UAAM,OAAO,EAAE,MAAM;AACrB,QAAI,SAAS,OAAQ;AACrB,uBAAmB,IAAI,EAAE,MAAM;AAC/B,QAAI,SAAS,iBAAiB,SAAS,mBAAmB;AACxD,YAAM,MAAM,iBAAiB,IAAI,EAAE,MAAM,KAAK,CAAC;AAC/C,UAAI,KAAK,EAAE,MAAM;AACjB,uBAAiB,IAAI,EAAE,QAAQ,GAAG;AAAA,IACpC,OAAO;AAGL,YAAM,MAAM,eAAe,IAAI,EAAE,MAAM,KAAK,CAAC;AAC7C,UAAI,KAAK,EAAE,MAAM;AACjB,qBAAe,IAAI,EAAE,QAAQ,GAAG;AAAA,IAClC;AAAA,EACF;AAGA,QAAM,OAAO,MAAM,MAAM,KAAK,CAAC,MAAM,CAAC,mBAAmB,IAAI,EAAE,EAAE,CAAC,KAAK,MAAM,MAAM,CAAC;AAEpF,QAAM,YAAY,oBAAI,IAAsC;AAO5D,WAAS,cAAc,QAAgB,GAAW,GAAmB;AACnE,QAAI,UAAU,IAAI,MAAM,GAAG;AAIzB,aAAO,UAAU,IAAI,MAAM,EAAG;AAAA,IAChC;AACA,cAAU,IAAI,QAAQ,EAAE,GAAG,EAAE,CAAC;AAG9B,QAAI,iBAAiB;AACrB,UAAM,WAAW,iBAAiB,IAAI,MAAM,KAAK,CAAC;AAClD,QAAI,SAAS,SAAS,GAAG;AACvB,YAAM,SAAS,IAAI;AACnB,YAAM,cAAc,SAAS,SAAS,KAAK;AAC3C,YAAM,SAAS,IAAI,aAAa;AAChC,eAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,cAAM,UAAU,SAAS,CAAC;AAC1B,cAAM,SAAS,SAAS,IAAI;AAC5B,cAAM,gBAAgB,cAAc,SAAS,QAAQ,MAAM;AAC3D,YAAI,gBAAgB,eAAgB,kBAAiB;AAAA,MACvD;AAAA,IACF;AAKA,UAAM,eAAe,eAAe,IAAI,MAAM,KAAK,CAAC;AACpD,QAAI,aAAa,SAAS,GAAG;AAC3B,YAAM,QAAQ,SAAS,SAAS,IAAI,iBAAiB,SAAS,IAAI;AAGlE,YAAM,cAAc,aAAa,SAAS,KAAK;AAC/C,YAAM,SAAS,IAAI,aAAa;AAChC,UAAI,eAAe;AACnB,eAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,cAAM,UAAU,aAAa,CAAC;AAC9B,cAAM,SAAS,SAAS,IAAI;AAC5B,cAAM,gBAAgB,cAAc,SAAS,QAAQ,KAAK;AAC1D,YAAI,gBAAgB,aAAc,gBAAe;AAAA,MACnD;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAEA,gBAAc,KAAK,IAAI,GAAG,CAAC;AAK3B,MAAI,OAAO;AACX,aAAW,KAAK,UAAU,OAAO,GAAG;AAClC,QAAI,EAAE,IAAI,KAAM,QAAO,EAAE;AAAA,EAC3B;AACA,MAAI,UAAU,OAAO;AACrB,aAAW,KAAK,MAAM,OAAO;AAC3B,QAAI,CAAC,UAAU,IAAI,EAAE,EAAE,GAAG;AACxB,gBAAU,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG,QAAQ,CAAC;AACxC,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,MAAM,MAAM,IAAI,CAAC,OAAO;AAAA,MAC7B,GAAG;AAAA,MACH,UAAU,UAAU,IAAI,EAAE,EAAE,KAAK,EAAE;AAAA,IACrC,EAAE;AAAA,IACF,OAAO,MAAM;AAAA,EACf;AACF;AAaA,IAAM,sBAA2C;AAAA,EAC/C,MAAM,YAAY,OAAO;AAAA,EACzB,YAAY,YAAY,OAAO;AAAA,EAC/B,gBAAgB,YAAY,OAAO;AAAA,EACnC,MAAM,YAAY,OAAO;AAC3B;AAEA,SAAS,UAAU,MAAiB,QAAmC;AACrE,QAAM,OAAO,KAAK,MAAM,QAAQ;AAChC,QAAM,QACJ,SAAS,SACL,OAAO,OACP,SAAS,gBACP,OAAO,aACP,SAAS,oBACP,OAAO,iBACP,OAAO;AACjB,QAAM,SAAe;AAAA,IACnB,GAAG;AAAA,IACH,MAAM,SAAS,SAAS,SAAS;AAAA,IACjC,UAAU;AAAA,IACV,OAAO,EAAE,QAAQ,OAAO,aAAa,IAAI;AAAA,IACzC,WAAW,EAAE,MAAM,yBAAW,aAAa,OAAO,OAAO,IAAI,QAAQ,GAAG;AAAA,EAC1E;AACA,MAAI,SAAS,QAAQ;AACnB,WAAO,QAAQ,EAAE,GAAG,OAAO,OAAO,iBAAiB,MAAM;AAAA,EAC3D;AACA,SAAO;AACT;AAoDA,IAAM,qBAAgC,EAAE,WAAW,UAAU;AAa7D,SAAS,YAAY,MAAuB;AAI1C,MAAI,KAAK,SAAS,UAAa,KAAK,SAAS,SAAS;AACpD,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,KAAK;AAClB,QAAM,YAA2B;AAAA,IAC/B,OAAO,KAAK;AAAA,IACZ,WAAW,KAAK;AAAA,IAChB,QAAQ,KAAK;AAAA,IACb,WAAW,KAAK;AAAA,IAChB,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,IACP,GAAI,KAAK,gBAAgB,UAAa,EAAE,aAAa,KAAK,YAAY;AAAA,IACtE,GAAI,KAAK,SAAS,UAAa,EAAE,MAAM,KAAK,KAAK;AAAA,IACjD,GAAI,KAAK,cAAc,UAAa,EAAE,WAAW,KAAK,UAAU;AAAA,IAChE,GAAI,KAAK,WAAW,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAC7C;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;AAKA,IAAM,cAA0B,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,EAAE;AAKvD,SAAS,oBAAoB,UAAoD;AAC/E,SAAO,CAAC,aAAuC;AAC7C,QAAI,CAAC,SAAU,QAAO,MAAM;AAAA,IAAC;AAC7B,WAAO,SAAS,UAAU,QAAQ;AAAA,EACpC;AACF;AAEA,SAAS,mBAAmB,UAAoD;AAC9E,SAAO,MAAc;AACnB,QAAI,CAAC,SAAU,QAAO;AACtB,WAAO,SAAS,QAAQ;AAAA,EAC1B;AACF;AAEO,SAAS,UAAU,OAAuB;AAG/C,QAAM,OAAQ,WAA6D;AAC3E,QAAM,QAAQ,MAAM,KAAK,aAAa;AACtC,MAAI,SAAS,CAAC,MAAM,YAAY,CAAC,MAAM,OAAO;AAE5C,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,iBAAa;AAAA,IACjB,OAAO,EAAE,GAAG,qBAAqB,GAAI,MAAM,cAAc,CAAC,EAAG;AAAA,IAC7D,CAAC,MAAM,UAAU;AAAA,EACnB;AAMA,QAAM,gBAAY;AAAA,IAChB,MAAM,oBAAoB,MAAM,QAAQ;AAAA,IACxC,CAAC,MAAM,QAAQ;AAAA,EACjB;AACA,QAAM,iBAAa;AAAA,IACjB,MAAM,mBAAmB,MAAM,QAAQ;AAAA,IACvC,CAAC,MAAM,QAAQ;AAAA,EACjB;AACA,QAAM,cAAU,oCAAqB,WAAW,YAAY,UAAU;AAKtE,QAAM,EAAE,UAAU,OAAO,UAAU,IAAI;AACvC,QAAM,YAAoB,uBAAoB,MAAM;AAClD,QAAI,SAAU,QAAO,SAAS,SAAS;AACvC,QAAI,UAAW,QAAO;AACtB,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,WAAW,OAAO,CAAC;AAEjC,QAAM,iBAAa,uBAAoB,MAAM;AAC3C,QAAI,WAAW,cAAe,QAAO;AACrC,WAAO,OAAO,KAAK;AAAA,EACrB,GAAG,CAAC,OAAO,MAAM,CAAC;AAElB,QAAM,qBAAiB;AAAA,IACrB,MAAM,WAAW,MAAM,IAAI,WAAW;AAAA,IACtC,CAAC,WAAW,KAAK;AAAA,EACnB;AACA,QAAM,qBAAiB;AAAA,IACrB,MAAM,WAAW,MAAM,IAAI,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC;AAAA,IAC1D,CAAC,WAAW,OAAO,UAAU;AAAA,EAC/B;AAEA,QAAM,iBAAiB,MAAM;AAC7B,QAAM,sBAAkB;AAAA,IACtB,CAAC,GAAY,SAAe;AAC1B,uBAAiB,KAAK,EAAE;AAAA,IAC1B;AAAA,IACA,CAAC,cAAc;AAAA,EACjB;AAEA,QAAM,EAAE,WAAW,eAAe,WAAW,cAAc,IAAI;AAC/D,QAAM,sBAAkB;AAAA,IACtB,MAAO,gBAAgB,EAAE,GAAG,oBAAoB,GAAG,cAAc,IAAI;AAAA,IACrE,CAAC,aAAa;AAAA,EAChB;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,MAAM;AAAA,MACjB,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,GAAG,MAAM;AAAA,MACX;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,OAAO;AAAA,UACP,WAAW;AAAA,UACV,GAAI,iBAAiB,EAAE,WAAW,cAAc;AAAA,UACjD,aAAa;AAAA,UACb,SAAO;AAAA,UACP,YAAY,EAAE,iBAAiB,KAAK;AAAA,UAEpC;AAAA,yDAAC,4BAAW,SAAS,gCAAkB,MAAM,KAAK,IAAI,MAAM,GAAG;AAAA,YAC9D,MAAM;AAAA;AAAA;AAAA,MACT;AAAA;AAAA,EACF;AAEJ;;;ACxaA,IAAAC,iBAAuD;AACvD,IAAAA,iBAKO;;;ACjCA,SAAS,eAAwB;AACtC,QAAM,OAAQ,WAA6D;AAC3E,SAAO,MAAM,KAAK,aAAa;AACjC;AAMO,SAAS,QAAQ,cAA4B,QAAyB;AAC3E,MAAI,CAAC,aAAa,EAAG;AAErB,UAAQ,KAAK,UAAU,GAAG,GAAG,MAAM;AACrC;;;AC8BO,SAAS,eAAe,QAAQ,YAAsB;AAC3D,QAAM,YAAY,oBAAI,IAAgB;AACtC,MAAIC,KAAI;AACR,MAAI,UAAU;AAEd,WAAS,QAAc;AACrB,QAAI,CAAC,QAAS;AACd,cAAU;AAOV,UAAM,WAAW,MAAM,KAAK,SAAS;AACrC,eAAW,KAAK,UAAU;AACxB,UAAI;AACF,UAAE;AAAA,MACJ,SAAS,KAAK;AACZ;AAAA,UACE,MACE,IAAI,KAAK;AAAA,UACX;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,UAAkC;AAC1C,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM;AACX,kBAAU,OAAO,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,UAAkB;AAChB,aAAOA;AAAA,IACT;AAAA,IACA,SAAe;AACb,MAAAA,MAAK;AACL,UAAI,QAAS;AACb,gBAAU;AAGV,qBAAe,KAAK;AAAA,IACtB;AAAA,IACA,eAAqB;AACnB,YAAM;AAAA,IACR;AAAA,EACF;AACF;;;AC8CA,SAAS,+BAA+B,gBAAgC;AACtE,QAAM,UAAU,eAAe,QAAQ,GAAG;AAC1C,SAAO,WAAW,IAAI,eAAe,MAAM,GAAG,OAAO,IAAI;AAC3D;AAMO,SAAS,0BACd,UAA4C,CAAC,GAClB;AAC3B,QAAM,KAAK,QAAQ,MAAM;AACzB,QAAM,YAAY,YAAY,IAAI;AAElC,MAAI,iBAAyC,CAAC;AAK9C,QAAM,0BAA0B,oBAAI,IAAY;AAChD,QAAM,SAAS,oBAAI,IAAoB;AACvC,MAAI,UAAU;AACd,QAAM,WAAW,eAAe,qBAAqB;AACrD,QAAM,eAAe,SAAS;AAE9B,WAAS,SAAS,gBAAwB,SAAiB,WAAyB;AAClF,QAAI,wBAAwB,IAAI,cAAc,EAAG;AACjD,4BAAwB,IAAI,cAAc;AAC1C,mBAAe,KAAK;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,YAAY,IAAI,IAAI;AAAA,IACnC,CAAC;AACD,iBAAa;AAAA,EACf;AAEA,QAAM,WAAgC;AAAA,IACpC;AAAA,IACA,aAAa;AACX,gBAAU;AACV,mBAAa;AAAA,IACf;AAAA,IACA,WAAW;AACT,gBAAU;AACV,mBAAa;AAAA,IACf;AAAA,IACA,gBAAgB,OAAO;AAIrB,YAAM,iBAAiB,MAAM,iBAAiB;AAC9C,YAAM,cAAc,+BAA+B,cAAc;AACjE,eAAS,gBAAgB,aAAa,MAAM,SAAS;AAAA,IACvD;AAAA,IACA,QAAQ,OAAO;AACb,YAAM,aACJ,MAAM,YACL,MAAM,mBACH,+BAA+B,MAAM,iBAAiB,cAAc,IACpE,MAAM;AACZ,aAAO,IAAI,YAAY,MAAM,WAAW,OAAO;AAC/C,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,aAA6B;AAC3B,aAAO;AAAA,QACL,gBAAgB,eAAe,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;AAAA,QACpD,QAAQ,IAAI,IAAI,MAAM;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAAA,IACA,WAAW,SAAS;AAAA,IACpB,SAAS,SAAS;AAAA,IAClB,QAAc;AACZ,uBAAiB,CAAC;AAClB,8BAAwB,MAAM;AAC9B,aAAO,MAAM;AACb,gBAAU;AAAA,IAIZ;AAAA,EACF;AACF;AAkCO,SAAS,aACd,SACA,OACqB;AACrB,QAAM,QAAQ,QAAQ;AACtB,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,MACL,cAAc,oBAAI,IAAI;AAAA,MACtB,eAAe;AAAA,MACf,kBAAkB,oBAAI,IAAI;AAAA,MAC1B,kBAAkB,CAAC;AAAA,MACnB,QAAQ,QAAQ;AAAA,IAClB;AAAA,EACF;AACA,QAAM,eAAe,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM,SAAS,CAAC,CAAC;AAClE,QAAM,eAAe,oBAAI,IAAY;AACrC,WAAS,IAAI,GAAG,IAAI,cAAc,KAAK;AACrC,iBAAa,IAAI,MAAM,CAAC,EAAG,OAAO;AAAA,EACpC;AACA,QAAM,aAAa,MAAM,YAAY;AACrC,QAAM,gBAAgB,aAAa,WAAW,UAAU;AACxD,QAAM,mBAAmB,IAAI,IAAI,YAAY;AAC7C,MAAI,cAAe,kBAAiB,IAAI,aAAa;AACrD,QAAM,mBAAmB,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO;AAC9E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,QAAQ;AAAA,EAClB;AACF;;;ACpRO,SAAS,oBACd,OACA,kBACY;AACZ,MAAI,MAAM,MAAM,WAAW,EAAG,QAAO;AACrC,QAAM,eAAe,CAAC,cACpB,qBAAqB,OAAO,cAAc,SAAY,cAAc;AACtE,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,KAAK,MAAM,OAAO;AAC3B,QAAI,aAAa,EAAE,MAAM,SAAS,EAAG,YAAW,IAAI,EAAE,EAAE;AAAA,EAC1D;AACA,MAAI,WAAW,SAAS,MAAM,MAAM,OAAQ,QAAO;AACnD,SAAO;AAAA,IACL,OAAO,MAAM,MAAM,OAAO,CAAC,MAAM,WAAW,IAAI,EAAE,EAAE,CAAC;AAAA,IACrD,OAAO,MAAM,MAAM,OAAO,CAAC,MAAM,WAAW,IAAI,EAAE,MAAM,KAAK,WAAW,IAAI,EAAE,MAAM,CAAC;AAAA,EACvF;AACF;AAkBO,SAAS,uBACd,OACA,kBACmB;AACnB,QAAM,MAAyB,CAAC,EAAE,WAAW,MAAM,OAAO,QAAQ,CAAC;AACnE,MAAI,qBAAqB,MAAM;AAC7B,UAAM,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,MAAM,cAAc,gBAAgB;AAC5E,QAAI,KAAK;AAAA,MACP,WAAW;AAAA,MACX,OAAO,OAAO,MAAM,SAAS;AAAA,IAC/B,CAAC;AAAA,EACH;AACA,SAAO;AACT;;;AC9CA,SAAS,OAAO,IAAoB;AAClC,QAAM,IAAI,GAAG,YAAY,GAAG;AAC5B,SAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI;AACpC;AAMO,SAAS,sBAAsB,OAAmC;AACvE,SAAO;AAAA,IACL,cAAc,IAAI,IAAI,MAAM,KAAK,MAAM,YAAY,EAAE,IAAI,MAAM,CAAC;AAAA,IAChE,eAAe,MAAM,gBAAgB,OAAO,MAAM,aAAa,IAAI;AAAA,IACnE,kBAAkB,IAAI,IAAI,MAAM,KAAK,MAAM,gBAAgB,EAAE,IAAI,MAAM,CAAC;AAAA,IACxE,kBAAkB,MAAM,iBAAiB,IAAI,MAAM;AAAA,IACnD,QAAQ,IAAI,IAAI,MAAM,KAAK,MAAM,MAAM,EAAE,IAAI,CAAC,CAAC,GAAGC,EAAC,MAAM,CAAC,OAAO,CAAC,GAAGA,EAAC,CAAC,CAAC;AAAA,EAC1E;AACF;AAcO,SAAS,qBACd,OACA,OACA,kBACc;AACd,MAAI,MAAM,MAAM,WAAW,EAAG,QAAO;AACrC,QAAM,SAAS,MAAM,MAAM,OAAO,CAAC,MAAM,EAAE,MAAM,aAAa,EAAE,MAAM,SAAS;AAC/E,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,UAAU,IAAI,IAAI,MAAM,YAAY;AAC1C,MAAI,WAAW,MAAM;AACrB,aAAW,SAAS,QAAQ;AAC1B,UAAM,OAAO,MAAM,KAAM;AACzB,UAAM,UAAU,MAAM,MAAM,OAAO,CAAC,MAAM,EAAE,MAAM,cAAc,IAAI;AACpE,QAAI,QAAQ,WAAW,EAAG;AAC1B,UAAM,YAAY,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,aAAa;AAClE,UAAM,UAAU,QAAQ,KAAK,CAAC,MAAM,MAAM,aAAa,IAAI,EAAE,EAAE,CAAC;AAChE,UAAM,UAAU,QAAQ,MAAM,CAAC,MAAM,MAAM,aAAa,IAAI,EAAE,EAAE,CAAC;AACjE,QAAI,QAAS,SAAQ,IAAI,MAAM,EAAE;AAAA,cACvB,aAAa,YAAY,qBAAqB,MAAM;AAC5D,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF;AACA,SAAO,EAAE,GAAG,OAAO,cAAc,SAAS,eAAe,SAAS;AACpE;;;ACnEA,IAAAC,iBAAyD;AAclD,SAAS,gBACd,OACA,iBACoB;AACpB,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,yBAAwB,IAAI;AAY5E,QAAM,mBAAe,uBAA0B,IAAI;AACnD,MAAI,aAAa,YAAY,OAAO;AAClC,iBAAa,UAAU;AACvB,QACE,qBAAqB,QACrB,CAAC,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,MAAM,cAAc,gBAAgB,GAC/D;AAEA,qBAAe,MAAM,oBAAoB,IAAI,CAAC;AAAA,IAChD;AAAA,EACF;AAIA,QAAM,sBAAkB,uBAAkC,MAAS;AACnE,gCAAU,MAAM;AACd,QAAI,gBAAgB,YAAY,iBAAkB;AAClD,oBAAgB,UAAU;AAC1B,QAAI,qBAAqB,MAAM;AAC7B,wBAAkB,IAAI;AAAA,IACxB,OAAO;AACL,YAAM,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,MAAM,cAAc,gBAAgB;AAC5E,UAAI,MAAO,mBAAkB,MAAM,EAAE;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,kBAAkB,OAAO,eAAe,CAAC;AAE7C,QAAM,gBAAY,4BAAY,CAAC,cAAsB;AACnD,wBAAoB,SAAS;AAAA,EAC/B,GAAG,CAAC,CAAC;AACL,QAAM,cAAU,4BAAY,MAAM;AAChC,wBAAoB,IAAI;AAAA,EAC1B,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,kBAAkB,WAAW,SAAS,oBAAoB;AACrE;;;AC5DA,IAAAC,iBAA0B;AAInB,SAAS,kBACd,YACA,YACA,UAAmD,CAAC,GAC9C;AACN,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAMC,WAAU,QAAQ,WAAW;AAEnC,gCAAU,MAAM;AACd,UAAM,KAAK,WAAW;AACtB,QAAI,CAAC,MAAM,CAAC,WAAY;AACxB,QAAI,MAAM;AACV,UAAM,QAAQ,MAAM;AAClB,2BAAqB,GAAG;AACxB,YAAM,sBAAsB,MAAM;AAChC,mBAAW,QAAQ,EAAE,UAAU,SAAAA,SAAQ,CAAC;AAAA,MAC1C,CAAC;AAAA,IACH;AACA,UAAM,KAAK,IAAI,eAAe,KAAK;AACnC,OAAG,QAAQ,EAAE;AACb,WAAO,iBAAiB,UAAU,KAAK;AACvC,WAAO,MAAM;AACX,SAAG,WAAW;AACd,aAAO,oBAAoB,UAAU,KAAK;AAC1C,2BAAqB,GAAG;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,YAAY,YAAY,UAAUA,QAAO,CAAC;AAChD;;;ACVU,IAAAC,sBAAA;AAlBH,SAAS,qBAAqB,EAAE,SAAS,WAAW,GAA8B;AACvF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY,YAAY,OAAO;AAAA,QAC/B,cAAc,aAAa,YAAY,OAAO,MAAM;AAAA,QACpD,YAAY;AAAA,MACd;AAAA,MACA,cAAW;AAAA,MAEV,kBAAQ,IAAI,CAAC,OAAO,MAAM;AACzB,cAAM,SAAS,MAAM,QAAQ,SAAS;AACtC,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO,EAAE,SAAS,eAAe,YAAY,UAAU,KAAK,EAAE;AAAA,YAE9D;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAS,MAAM,WAAW,MAAM,SAAS;AAAA,kBACzC,UAAU;AAAA,kBACV,OAAO;AAAA,oBACL,YAAY;AAAA,oBACZ,QAAQ;AAAA,oBACR,SAAS;AAAA,oBACT,UAAU;AAAA,oBACV,YAAY,SAAS,MAAM;AAAA,oBAC3B,OAAO,SAAS,YAAY,OAAO,cAAc,YAAY,OAAO;AAAA,oBACpE,QAAQ,SAAS,YAAY;AAAA,oBAC7B,gBAAgB,SAAS,SAAS;AAAA,oBAClC,YAAY;AAAA,kBACd;AAAA,kBAEC,gBAAM;AAAA;AAAA,cACT;AAAA,cACC,CAAC,UAAU,6CAAC,UAAK,OAAO,EAAE,OAAO,YAAY,OAAO,UAAU,GAAG,oBAAC;AAAA;AAAA;AAAA,UArB9D,MAAM,aAAa;AAAA,QAsB1B;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH;AAEJ;;;ARkRQ,IAAAC,sBAAA;AAxQR,IAAM,iBAAmC;AAAA,EACvC,SAAS,YAAY,OAAO;AAAA,EAC5B,MAAM,YAAY,OAAO;AAAA,EACzB,QAAQ,YAAY,OAAO;AAAA,EAC3B,OAAO,YAAY,OAAO;AAAA,EAC1B,MAAM,YAAY,OAAO;AAC3B;AAMA,SAAS,uBACP,MACA,cACA,eACA,cACA,kBACM;AAON,MAAI,KAAK,SAAS,UAAa,KAAK,SAAS,SAAS;AACpD,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,aAAa,IAAI,KAAK,EAAE;AACvC,QAAM,WAAW,kBAAkB,KAAK;AACxC,QAAM,cAAc,UAAU;AAC9B,QAAM,WAAW,CAAC,CAAC;AACnB,QAAM,SAAS,CAAC,eAAe,iBAAiB,SAAS;AAGzD,MAAI;AACJ,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,OAAiB,CAAC;AACxB,aAAS,IAAI,GAAG,IAAI,iBAAiB,QAAQ,KAAK;AAChD,UAAI,iBAAiB,CAAC,MAAM,KAAK,GAAI,MAAK,KAAK,IAAI,CAAC;AAAA,IACtD;AACA,QAAI,KAAK,SAAS,EAAG,eAAc;AAAA,EACrC;AAEA,QAAM,YAA2B;AAAA,IAC/B,OAAO,KAAK,KAAK;AAAA,IACjB,WAAW,KAAK,KAAK;AAAA,IACrB,QAAQ,KAAK,KAAK;AAAA,IAClB,WAAW,KAAK,KAAK;AAAA,IACrB,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,IACP,GAAI,KAAK,KAAK,gBAAgB,UAAa,EAAE,aAAa,KAAK,KAAK,YAAY;AAAA,IAChF,GAAI,KAAK,KAAK,SAAS,UAAa,EAAE,MAAM,KAAK,KAAK,KAAK;AAAA,IAC3D,GAAI,KAAK,KAAK,cAAc,UAAa,EAAE,WAAW,KAAK,KAAK,UAAU;AAAA,IAC1E,GAAI,KAAK,KAAK,WAAW,QAAQ,EAAE,QAAQ,KAAK;AAAA,IAChD,GAAI,UAAU,EAAE,QAAQ,KAAK;AAAA,IAC7B,GAAI,eAAe,EAAE,YAAY;AAAA,IACjC,GAAI,gBAAgB,EAAE,aAAa;AAAA,EACrC;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,IACN,MAAM;AAAA,IACN,GAAI,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE;AAAA,EAC3C;AACF;AAEA,SAAS,qBACP,MACA,cACA,eACA,QACM;AACN,QAAM,OAAO,KAAK,MAAM,QAAQ;AAChC,QAAM,iBAAiB,aAAa,IAAI,KAAK,MAAM,KAAK,kBAAkB,KAAK;AAC/E,QAAM,iBAAiB,aAAa,IAAI,KAAK,MAAM,KAAK,kBAAkB,KAAK;AAC/E,QAAM,YAAY,kBAAkB;AACpC,QAAM,gBAAgB,kBAAkB,KAAK,UAAU,CAAC,aAAa,IAAI,KAAK,MAAM;AAEpF,MAAI,QAAgB,OAAO;AAC3B,MAAI,SAAS,OAAQ,SAAQ,OAAO;AAAA,WAC3B,cAAe,SAAQ,OAAO;AAAA,WAC9B,UAAW,SAAQ,OAAO;AAEnC,QAAM,SAAe;AAAA,IACnB,GAAG;AAAA,IACH,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO,EAAE,QAAQ,OAAO,aAAa,YAAY,IAAI,IAAI;AAAA,IACzD,WAAW,EAAE,MAAM,0BAAW,aAAa,OAAO,OAAO,IAAI,QAAQ,GAAG;AAAA,EAC1E;AACA,MAAI,SAAS,QAAQ;AAGnB,WAAO,QAAQ,EAAE,GAAG,OAAO,OAAO,iBAAiB,MAAM;AACzD,IAAC,OAAO,OAAe;AAAA,MACrB,GAAI,OAAO,QAAQ,CAAC;AAAA,MACpB,aAAa,EAAE,cAAc,IAAI,QAAQ,GAAG;AAAA,IAC9C;AACA,WAAO,eAAe;AACtB,WAAO,eAAe;AAAA,EACxB;AACA,SAAO;AACT;AAiDA,IAAMC,sBAAgC,EAAE,WAAW,UAAU;AAEtD,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,SAAS,cAAc;AAC7B,QAAM,aAAS;AAAA,IACb,OAAO,EAAE,GAAG,gBAAgB,GAAI,kBAAkB,CAAC,EAAG;AAAA,IACtD,CAAC,cAAc;AAAA,EACjB;AACA,QAAM,sBAAkB;AAAA,IACtB,MAAO,gBAAgB,EAAE,GAAGA,qBAAoB,GAAG,cAAc,IAAIA;AAAA,IACrE,CAAC,aAAa;AAAA,EAChB;AAGA,QAAM,QAAQ,gBAAgB,OAAO,eAAe;AACpD,QAAM,oBAAgB;AAAA,IACpB,MAAM,oBAAoB,OAAO,MAAM,gBAAgB;AAAA,IACvD,CAAC,OAAO,MAAM,gBAAgB;AAAA,EAChC;AACA,QAAM,iBAAa;AAAA,IACjB,MAAM,uBAAuB,OAAO,MAAM,gBAAgB;AAAA,IAC1D,CAAC,OAAO,MAAM,gBAAgB;AAAA,EAChC;AACA,QAAM,iBAAa;AAAA,IACjB,MAAO,WAAW,gBAAgB,gBAAgB,OAAO,aAAa;AAAA,IACtE,CAAC,eAAe,MAAM;AAAA,EACxB;AAGA,QAAM,YAAQ,wBAAQ,MAAM;AAC1B,UAAM,QAAQ;AAAA,MACZ,cAAc,oBAAI,IAAY;AAAA,MAC9B,eAAe;AAAA,MACf,kBAAkB,oBAAI,IAAY;AAAA,MAClC,kBAAkB,CAAC;AAAA,MACnB,QAAQ,oBAAI,IAAoB;AAAA,IAClC;AACA,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,MAAM,cAAc,KAAK,IAAI,GAAG,QAAQ,eAAe,SAAS,CAAC;AACvE,UAAM,aAAa,sBAAsB,aAAa,SAAS,GAAG,CAAC;AACnE,WAAO,qBAAqB,YAAY,OAAO,MAAM,gBAAgB;AAAA,EACvE,GAAG,CAAC,SAAS,YAAY,OAAO,MAAM,gBAAgB,CAAC;AAGvD,QAAM,qBAAiB;AAAA,IACrB,MACE,WAAW,MAAM;AAAA,MAAI,CAAC,MACpB;AAAA,QACE;AAAA,QACA,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM,OAAO,IAAI,EAAE,EAAE;AAAA,QACrB,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACF,CAAC,WAAW,OAAO,KAAK;AAAA,EAC1B;AACA,QAAM,qBAAiB;AAAA,IACrB,MACE,WAAW,MAAM;AAAA,MAAI,CAAC,MACpB,qBAAqB,GAAG,MAAM,cAAc,MAAM,eAAe,MAAM;AAAA,IACzE;AAAA,IACF,CAAC,WAAW,OAAO,OAAO,MAAM;AAAA,EAClC;AAGA,QAAM,sBAAkB;AAAA,IACtB,CAAC,GAAY,SAAe;AAC1B,YAAM,OAAQ,KAAK,QAAQ,CAAC;AAC5B,UAAI,KAAK,aAAa,KAAK,WAAW;AACpC,cAAM,UAAU,KAAK,SAAS;AAAA,MAChC;AACA,oBAAc,KAAK,EAAE;AAAA,IACvB;AAAA,IACA,CAAC,OAAO,WAAW;AAAA,EACrB;AAGA,QAAM,iBAAa,uBAAuB,IAAI;AAC9C,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAmC,IAAI;AAC3E,oBAAkB,YAAY,UAAU;AAExC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAS;AAAA,QACT,eAAe;AAAA,QACf,GAAG;AAAA,MACL;AAAA,MAEC;AAAA,mBAAW,SAAS,KACnB;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,YAAY,MAAM;AAAA;AAAA,QACpB;AAAA,QAEF,6CAAC,SAAI,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAClC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,OAAO;AAAA,YACP,WAAW;AAAA,YACV,GAAI,iBAAiB,EAAE,WAAW,cAAc;AAAA,YACjD,aAAa;AAAA,YACb,QAAQ;AAAA,YACR,SAAO;AAAA,YACP,YAAY,EAAE,iBAAiB,KAAK;AAAA,YAEpC;AAAA,2DAAC,6BAAW,SAAS,iCAAkB,MAAM,KAAK,IAAI,MAAM,GAAG;AAAA,cAC9D;AAAA;AAAA;AAAA,QACH,GACF;AAAA;AAAA;AAAA,EACF;AAEJ;;;ALjTM,IAAAC,sBAAA;AAlBC,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,CAAC,eAAe,gBAAgB,QAAI,yBAAS,CAAC;AACpD,QAAM,KAAK,SAAS,IAAI;AACxB,QAAM,MAAM,QAAQ,IAAI;AAExB,MAAI,UAAU,WAAW,GAAG;AAC1B,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO;AAAA,UACL,SAAS,MAAM;AAAA,UACf,WAAW;AAAA,UACX,OAAO,MAAM;AAAA,UACb,GAAG;AAAA,QACL;AAAA,QACD;AAAA;AAAA,IAED;AAAA,EAEJ;AAEA,QAAM,eAAe,WAAW;AAKhC,QAAM,kBAAkB,CAAC,YAAoB;AAC3C,UAAM,MAAM,UAAU;AAAA,MACpB,CAAC,MAAM,EAAE,cAAc,WAAW,EAAE,eAAe;AAAA,IACrD;AACA,QAAI,OAAO,EAAG,kBAAiB,GAAG;AAAA,EACpC;AAEA,QAAM,QAAQ,iBACZ;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,aAAa;AAAA;AAAA,EACf,IAEA,6CAAC,aAAU,OAAc,aAAa,iBAAiB;AAGzD,MAAI,UAAU;AACZ,WACE,8CAAC,SAAI,WAAsB,OAAc,WAAQ,wBAC/C;AAAA,mDAAC,QAAI,iBAAM;AAAA,MACX;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,UAAU,SAAS;AAAA,UACxB,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,iBAAiB,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA;AAAA,MAC5D;AAAA,MACC;AAAA,MACD;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,UAAQ;AAAA;AAAA,MACV;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,UAAQ;AAAA;AAAA,MACV;AAAA,MACC,aACC;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACV,UAAQ;AAAA;AAAA,MACV;AAAA,OAEJ;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe;AAAA,QACf,QAAQ;AAAA,QACR,YAAY,MAAM;AAAA,QAClB,YAAY,MAAM;AAAA,QAClB,UAAU;AAAA,QACV,GAAG;AAAA,MACL;AAAA,MACA,WAAQ;AAAA,MAGR;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,SAAS,GAAG,GAAG,MAAM,MAAM,CAAC;AAAA,cAC5B,cAAc,aAAa,MAAM,MAAM;AAAA,cACvC,YAAY,MAAM;AAAA,cAClB,YAAY;AAAA,YACd;AAAA,YAEA;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO;AAAA,oBACL,SAAS;AAAA,oBACT,YAAY;AAAA,oBACZ,KAAK;AAAA,oBACL,cAAc;AAAA,kBAChB;AAAA,kBAEA;AAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,UAAU,GAAG,OAAO;AAAA,0BACpB,YAAY;AAAA,0BACZ,OAAO,MAAM;AAAA,wBACf;AAAA,wBAEC;AAAA;AAAA,oBACH;AAAA,oBACA;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,0BACL,UAAU,GAAG;AAAA,0BACb,OAAO,MAAM;AAAA,wBACf;AAAA,wBACD;AAAA;AAAA,oBAED;AAAA;AAAA;AAAA,cACF;AAAA,cACA,8CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAE,GAC1D;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAM;AAAA,oBACN,UAAU,kBAAkB;AAAA,oBAC5B,SAAS,MAAM,iBAAiB,CAAC,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA;AAAA,gBAC3D;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,KAAK;AAAA,oBACL,KAAK,UAAU,SAAS;AAAA,oBACxB,OAAO;AAAA,oBACP,UAAU,CAAC,MAAM,iBAAiB,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA,oBAC1D,OAAO;AAAA,sBACL,MAAM;AAAA,sBACN,QAAQ;AAAA,sBACR,aAAa,MAAM;AAAA,sBACnB,QAAQ;AAAA,oBACV;AAAA;AAAA,gBACF;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAM;AAAA,oBACN,UAAU,kBAAkB,UAAU,SAAS;AAAA,oBAC/C,SAAS,MACP,iBAAiB,CAAC,MAAM,KAAK,IAAI,UAAU,SAAS,GAAG,IAAI,CAAC,CAAC;AAAA;AAAA,gBAEjE;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO;AAAA,sBACL,UAAU,GAAG;AAAA,sBACb,OAAO,MAAM;AAAA,sBACb,YAAY;AAAA,sBACZ,YAAY,MAAM;AAAA,oBACpB;AAAA,oBAEC;AAAA,sCAAgB;AAAA,sBAAE;AAAA,sBAAE,UAAU;AAAA;AAAA;AAAA,gBACjC;AAAA,iBACF;AAAA;AAAA;AAAA,QACF;AAAA,QAGA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,MAAM;AAAA,cACN,SAAS;AAAA,cACT,eAAe,eAAe,QAAQ;AAAA,cACtC,UAAU;AAAA,YACZ;AAAA,YAGA;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,UAAU;AAAA,oBACV,aAAa,eACT,aAAa,MAAM,MAAM,KACzB;AAAA,oBACJ,cAAc,CAAC,eACX,aAAa,MAAM,MAAM,KACzB;AAAA,kBACN;AAAA,kBAEC;AAAA;AAAA,cACH;AAAA,cAGA,8CAAC,SAAI,OAAO,EAAE,MAAM,GAAG,UAAU,OAAO,GACtC;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC;AAAA,oBACA;AAAA,oBACA;AAAA;AAAA,gBACF;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO;AAAA,sBACL,QAAQ;AAAA,sBACR,YAAY,MAAM;AAAA,sBAClB,QAAQ,KAAK,GAAG;AAAA,oBAClB;AAAA;AAAA,gBACF;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC;AAAA,oBACA;AAAA,oBACA;AAAA;AAAA,gBACF;AAAA,iBACF;AAAA;AAAA;AAAA,QACF;AAAA,QAGC,aACC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW,aAAa,MAAM,MAAM;AAAA,cACpC,YAAY,MAAM;AAAA,cAClB,YAAY;AAAA,YACd;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA,UAAU;AAAA,gBACV;AAAA;AAAA,YACF;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,OAAO;AAAA,QACL,YAAY,MAAM;AAAA,QAClB,QAAQ,aAAa,MAAM,MAAM;AAAA,QACjC,OAAO,WAAW,MAAM,YAAY,MAAM;AAAA,QAC1C,cAAc;AAAA,QACd,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,QAAQ,WAAW,gBAAgB;AAAA,QACnC,SAAS,WAAW,MAAM;AAAA,QAC1B,UAAU;AAAA,QACV,YAAY;AAAA,MACd;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;;;Ac7TA,IAAAC,iBAAqB;AAuCP,IAAAC,uBAAA;AA1BP,IAAM,wBAAoB,qBAAK,SAASC,mBAAkB;AAAA,EAC/D;AAAA,EACA;AACF,GAA2B;AACzB,MAAI,YAAY,UAAU,EAAG,QAAO;AAEpC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,SAAS;AAAA,QACT,YAAY,MAAM;AAAA,QAClB,cAAc,aAAa,MAAM,MAAM;AAAA,QACvC,UAAU;AAAA,QACV,YAAY,MAAM;AAAA,QAClB,YAAY;AAAA,QACZ,WAAW;AAAA,MACb;AAAA,MAEC,sBAAY,IAAI,CAAC,OAAO,MAAM;AAC7B,cAAM,SAAS,MAAM,YAAY,SAAS;AAC1C,eACE,+CAAC,UAAiC,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAE,GACtF;AAAA,cAAI,KACH,8CAAC,UAAK,OAAO,EAAE,OAAO,MAAM,WAAW,UAAU,GAAG,GAAG,oBAEvD;AAAA,UAED,SACC,+CAAC,UAAK,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAE,GAC3D;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,OAAO,MAAM;AAAA,kBACb,YAAY;AAAA,gBACd;AAAA,gBAEC,gBAAM;AAAA;AAAA,YACT;AAAA,YACC,MAAM,eACL;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,OAAO,MAAM;AAAA,kBACb,YAAY;AAAA,kBACZ,UAAU;AAAA,gBACZ;AAAA,gBACD;AAAA;AAAA,kBACI,MAAM;AAAA;AAAA;AAAA,YACX;AAAA,aAEJ,IAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM,WAAW,CAAC;AAAA,cAC3B,OAAO;AAAA,gBACL,YAAY;AAAA,gBACZ,QAAQ;AAAA,gBACR,OAAO,MAAM;AAAA,gBACb,QAAQ;AAAA,gBACR,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,cAAc,CAAC,MAAM;AACnB,kBAAE,cAAc,MAAM,QAAQ,GAAG,MAAM,OAAO;AAAA,cAChD;AAAA,cACA,cAAc,CAAC,MAAM;AACnB,kBAAE,cAAc,MAAM,QAAQ,GAAG,MAAM,aAAa;AAAA,cACtD;AAAA,cAEC,gBAAM;AAAA;AAAA,UACT;AAAA,aAnDO,GAAG,MAAM,KAAK,IAAI,CAAC,EAqD9B;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH;AAEJ,CAAC;;;ACxED,IAAAC,iBAA+C;AAiC/C,IAAMC,eAA0B,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,EAAE;AAShD,SAAS,qBACd,WACmB;AACnB,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAA4B,CAAC,CAAC;AAExD,QAAM,gBAAgB,aAAaA;AAKnC,QAAM,oBAAgB,wBAAQ,MAAM;AAClC,UAAM,MAAM,oBAAI,IAGd;AACF,eAAW,QAAQ,cAAc,OAAO;AACtC,UAAI,CAAC,KAAK,MAAM,UAAW;AAC3B,YAAM,YACJ,OAAO,KAAK,KAAK,cAAc,WAAW,KAAK,KAAK,YAAY,KAAK;AACvE,YAAM,QACJ,OAAO,KAAK,KAAK,UAAU,WAAW,KAAK,KAAK,QAAQ,KAAK;AAC/D,YAAM,QAAoE;AAAA,QACxE;AAAA,QACA;AAAA,MACF;AACA,UAAI,OAAO,KAAK,KAAK,gBAAgB,UAAU;AAC7C,cAAM,cAAc,KAAK,KAAK;AAAA,MAChC;AAEA,UAAI,IAAI,KAAK,IAAI,KAAK;AACtB,UAAI,IAAI,WAAW,KAAK;AAAA,IAC1B;AACA,WAAO;AAAA,EACT,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,kBAAiC,wBAAQ,MAAM;AACnD,UAAM,YAAY;AAClB,UAAM,OAAwB,EAAE,OAAO,UAAU;AACjD,WAAO,CAAC,MAAM,GAAG,KAAK;AAAA,EACxB,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,sBAAkB;AAAA,IACtB,CAAC,WAA4B;AAC3B,YAAM,QAAQ,cAAc,IAAI,MAAM;AACtC,UAAI,CAAC,MAAO,QAAO;AACnB,eAAS,CAAC,SAAS;AACjB,cAAM,QAAyB;AAAA,UAC7B,OAAO,MAAM;AAAA,UACb,WAAW,MAAM;AAAA,QACnB;AACA,YAAI,MAAM,gBAAgB,OAAW,OAAM,cAAc,MAAM;AAC/D,eAAO,CAAC,GAAG,MAAM,KAAK;AAAA,MACxB,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AAEA,QAAM,iBAAa,4BAAY,CAAC,UAAkB;AAChD,QAAI,UAAU,GAAG;AACf,eAAS,CAAC,CAAC;AAAA,IACb,OAAO;AACL,eAAS,CAAC,SAAS,KAAK,MAAM,GAAG,KAAK,CAAC;AAAA,IACzC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,MAAM,MAAM,MAAM,SAAS,CAAC;AAClC,SAAO;AAAA,IACL;AAAA;AAAA;AAAA,IAGA,cAAc;AAAA,IACd,kBAAkB,KAAK,aAAa;AAAA,IACpC,wBAAwB,KAAK,SAAS;AAAA,IACtC;AAAA,IACA;AAAA,IACA,aAAa,MAAM,SAAS;AAAA,EAC9B;AACF;;;ACtHA,IAAAC,iBAAqD;AA0EjD,IAAAC,uBAAA;AA3CG,SAAS,sBAAsB,OAAuC;AAC3E,MAAI,CAAC,OAAO,OAAO,OAAQ,QAAO,CAAC;AACnC,QAAM,UAA8B,CAAC;AACrC,aAAW,QAAQ,MAAM,OAAO;AAC9B,QAAI,CAAC,KAAK,MAAM,UAAW;AAC3B,UAAM,QAA0B;AAAA,MAC9B,MAAM,OAAO,KAAK,KAAK,UAAU,WAAW,KAAK,KAAK,QAAQ,KAAK;AAAA,MACnE,WAAW;AAAA,IACb;AACA,QAAI,OAAO,KAAK,KAAK,gBAAgB,SAAU,OAAM,cAAc,KAAK,KAAK;AAC7E,QAAI,OAAO,KAAK,KAAK,cAAc,SAAU,OAAM,YAAY,KAAK,KAAK;AACzE,YAAQ,KAAK,KAAK;AAAA,EACpB;AACA,SAAO;AACT;AAGA,IAAM,eAAW,qBAAK,SAASC,UAAS;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,IAAI;AAC7C,QAAM,cAAc,MAAM,YAAY,MAAM,SAAS,SAAS;AAC9D,QAAM,WAAW,gBAAgB,MAAM;AACvC,QAAM,SAAS,YAAY,IAAI,MAAM,IAAI;AAEzC,QAAM,kBAAc,4BAAY,MAAM;AACpC,QAAI,aAAa;AACf,kBAAY,CAAC,SAAS,CAAC,IAAI;AAAA,IAC7B;AACA,mBAAe,MAAM,MAAM,CAAC,CAAC,MAAM,SAAS;AAAA,EAC9C,GAAG,CAAC,aAAa,cAAc,MAAM,MAAM,MAAM,SAAS,CAAC;AAE3D,SACE,gFACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAQ;AAAA,QACR,OAAO;AAAA,UACL,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,KAAK;AAAA,UACL,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,YAAY,WACR,sBAAsB,MAAM,OAAO,uBACnC;AAAA,UACJ,QAAQ;AAAA,UACR,SAAS,eAAe,IAAI,QAAQ,EAAE;AAAA,UACtC,YAAY,MAAM;AAAA,UAClB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,cAAc;AAAA,UACd,YAAY;AAAA,QACd;AAAA,QACA,cAAc,CAAC,MAAM;AACnB,cAAI,CAAC,UAAU;AACb,cAAE,cAAc,MAAM,aAAa,sBAAsB,MAAM,SAAS;AAAA,UAC1E;AAAA,QACF;AAAA,QACA,cAAc,CAAC,MAAM;AACnB,cAAI,CAAC,UAAU;AACb,cAAE,cAAc,MAAM,aAAa;AAAA,UACrC;AAAA,QACF;AAAA,QAGC;AAAA,wBACC;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,OAAO,MAAM;AAAA,gBACb,OAAO;AAAA,gBACP,WAAW;AAAA,gBACX,YAAY;AAAA,gBACZ,YAAY;AAAA,gBACZ,WAAW,WAAW,kBAAkB;AAAA,gBACxC,SAAS;AAAA,cACX;AAAA,cACD;AAAA;AAAA,UAED,IAEA,8CAAC,UAAK,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,GAAG;AAAA,UAI7C;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,YAAY,WACR,MAAM,UACN,SACE,MAAM,UACN,MAAM;AAAA,cACd;AAAA;AAAA,UACF;AAAA,UAGA,+CAAC,UAAK,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,UAAU,EAAE,GACnE;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,OAAO,WACH,MAAM,UACN,SACE,MAAM,cACN,MAAM;AAAA,kBACZ,YAAY,WAAW,MAAM,MAAM,YAAY,MAAM;AAAA,kBACrD,YAAY;AAAA,kBACZ,UAAU;AAAA,kBACV,cAAc;AAAA,gBAChB;AAAA,gBAEC;AAAA,wBAAM;AAAA,kBACN,MAAM,aACL,8CAAC,UAAK,OAAO,EAAE,SAAS,KAAK,YAAY,GAAG,UAAU,GAAG,GAAG,oBAAC;AAAA;AAAA;AAAA,YAEjE;AAAA,YACC,MAAM,eACL;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,OAAO,MAAM;AAAA,kBACb,UAAU;AAAA,kBACV,YAAY;AAAA,kBACZ,UAAU;AAAA,kBACV,cAAc;AAAA,gBAChB;AAAA,gBAEC,gBAAM;AAAA;AAAA,YACT;AAAA,aAEJ;AAAA;AAAA;AAAA,IACF;AAAA,IAGC,eAAe,YACd,8CAAC,SACE,gBAAM,SAAU,IAAI,CAAC,OAAO,MAC3B;AAAA,MAACA;AAAA,MAAA;AAAA,QAEC,OAAO;AAAA,QACP,OAAO,QAAQ;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA;AAAA,MALK,MAAM,aAAa,GAAG,MAAM,IAAI,IAAI,CAAC;AAAA,IAM5C,CACD,GACH;AAAA,KAEJ;AAEJ,CAAC;AAGD,IAAM,mBAAe,qBAAK,SAASC,cAAa,EAAE,SAAS,GAAyB;AAClF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,eAAe;AAAA,QACf,OAAO,MAAM;AAAA,MACf;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ,CAAC;AAEM,IAAM,kBAAc,qBAAK,SAASC,aAAY;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,oBAAgB,wBAAQ,MAAM,sBAAsB,KAAK,GAAG,CAAC,KAAK,CAAC;AAGzE,MAAI,cAAc,WAAW,EAAG,QAAO;AAEvC,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAQ;AAAA,MACR,OAAO;AAAA,QACL,GAAI,WACA,CAAC,IACD;AAAA,UACE,YAAY,MAAM;AAAA,UAClB,UAAU;AAAA,UACV,YAAY,MAAM;AAAA,UAClB,aAAa,aAAa,MAAM,MAAM;AAAA,UACtC,WAAW;AAAA,UACX,WAAW;AAAA,UACX,SAAS;AAAA,QACX;AAAA,QACJ,GAAG;AAAA,MACL;AAAA,MAEC;AAAA,SAAC,YAAY,8CAAC,gBAAa,sBAAQ;AAAA,QACnC,cAAc,IAAI,CAAC,OAAO,MACzB;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA,OAAO;AAAA,YACP;AAAA,YACA;AAAA,YACA;AAAA;AAAA,UALK,MAAM,aAAa,GAAG,MAAM,IAAI,IAAI,CAAC;AAAA,QAM5C,CACD;AAAA;AAAA;AAAA,EACH;AAEJ,CAAC;;;AChOM,SAAS,UAAU,GAAoB;AAC5C,SAAO;AACT;AAOO,SAAS,iBAAiB,GAA2B;AAC1D,SAAO;AACT;;;AC5BO,SAAS,oBACd,MACA,aACA,MACM;AACN,WAAS,MAAM,aAAa,MAAM,oBAAI,IAAY,CAAC;AACrD;AAEA,SAAS,SACP,MACA,aACA,MACA,SACM;AACN,MAAI,QAAQ,IAAI,KAAK,EAAE,EAAG;AAC1B,UAAQ,IAAI,KAAK,EAAE;AACnB,MAAI,KAAK,gBAAiB;AAG1B,MAAI,KAAK,iBAAiB,KAAK,cAAc,UAAa,KAAK,kBAAkB;AAC/E,UAAM,aAAa,GAAG,WAAW,IAAI,KAAK,SAAS;AACnD,aAAS,KAAK,kBAAkB,YAAY,MAAM,OAAO;AAAA,EAG3D;AAGA,QAAM,OAAO,KAAK,QAAQ;AAC1B,QAAM,YAAY,SAAS,aAAa,SAAS;AACjD,QAAM,SAAS,SAAS;AACxB,QAAM,cAAc,SAAS;AAC7B,QAAM,YAAY,CAAC,CAAC,KAAK;AAEzB,QAAM,UAAU,UAAU,KAAK,EAAE;AACjC,QAAM,OAAsB;AAAA,IAC1B,OAAO,KAAK;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACZ;AACA,MAAI,KAAK,gBAAgB,OAAW,MAAK,cAAc,KAAK;AAC5D,MAAI,KAAK,SAAS,OAAW,MAAK,OAAO,KAAK;AAC9C,MAAI,KAAK,cAAc,OAAW,MAAK,YAAY,KAAK;AACxD,MAAI,KAAK,WAAW,KAAM,MAAK,SAAS;AACxC,MAAI,KAAK,eAAe,KAAM,MAAK,aAAa;AAEhD,OAAK,WAAW;AAAA,IACd,IAAI,KAAK;AAAA,IACT,MAAM;AAAA,IACN,UAAU,EAAE,GAAG,GAAG,GAAG,EAAE;AAAA,IACvB;AAAA,EACF,CAAC;AAGD,MAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAAG;AAC7C,UAAM,WAA8C,SAAS,SAAS,gBAAgB;AACtF,eAAW,SAAS,KAAK,UAAU;AACjC,YAAM,SAAS,GAAG,KAAK,EAAE,KAAK,MAAM,EAAE,IAAI,QAAQ,GAAG,aAAa,oBAAoB,IAAI,MAAM,EAAE,KAAK,EAAE;AACzG,YAAM,WAA0B,EAAE,MAAM,SAAS;AACjD,UAAI,aAAa,kBAAmB,UAAS,QAAQ,MAAM;AAC3D,YAAM,OAA4B;AAAA,QAChC,IAAI;AAAA,QACJ,QAAQ,KAAK;AAAA,QACb,QAAQ,MAAM;AAAA,QACd,MAAM;AAAA,MACR;AACA,UAAI,aAAa,kBAAmB,MAAK,QAAQ,MAAM;AACvD,WAAK,SAAS,IAAI;AAClB,eAAS,OAAO,aAAa,MAAM,OAAO;AAAA,IAC5C;AAAA,EACF;AAGA,MAAI,KAAK,MAAM;AACb,QAAI,KAAK,KAAK,mBAAmB,KAAK,YAAY;AAChD,WAAK,SAAS;AAAA,QACZ,IAAI,GAAG,KAAK,EAAE,KAAK,KAAK,UAAU;AAAA,QAClC,QAAQ,KAAK;AAAA,QACb,QAAQ,KAAK;AAAA,QACb,MAAM,EAAE,MAAM,OAAO;AAAA,MACvB,CAAC;AAAA,IACH,OAAO;AACL,YAAM,SAAS,GAAG,KAAK,EAAE,KAAK,KAAK,KAAK,EAAE;AAC1C,WAAK,SAAS;AAAA,QACZ,IAAI;AAAA,QACJ,QAAQ,KAAK;AAAA,QACb,QAAQ,KAAK,KAAK;AAAA,QAClB,MAAM,EAAE,MAAM,OAAO;AAAA,MACvB,CAAC;AACD,eAAS,KAAK,MAAM,aAAa,MAAM,OAAO;AAAA,IAChD;AAAA,EACF;AAGA,OAAK;AACP;;;AC+KO,SAAS,6BACd,UAA+C,CAAC,GAClB;AAC9B,QAAM,KAAK,QAAQ,MAAM;AACzB,QAAM,WAAW,QAAQ;AAEzB,MAAI,QAAqB,CAAC;AAC1B,MAAI,QAAqB,CAAC;AAE1B,QAAM,YAAY,oBAAI,IAAoB;AAC1C,QAAM,cAAc,oBAAI,IAAY;AAKpC,QAAM,YAAY,oBAAI,IAAuB;AAC7C,QAAM,YAAY,oBAAI,IAAuB;AAE7C,QAAM,WAAW,eAAe,wBAAwB;AAExD,WAAS,eAAqB;AAC5B,QAAI,UAAU;AACZ,UAAI;AACF,iBAAS,EAAE,OAAO,MAAM,CAAC;AAAA,MAC3B,SAAS,KAAK;AACZ;AAAA,UACE,MAAM;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,aAAS,OAAO;AAAA,EAClB;AAEA,WAAS,WAAW,MAAuB;AACzC,UAAM,WAAW,UAAU,IAAI,KAAK,EAAE;AACtC,QAAI,aAAa,QAAW;AAG1B,YAAM,QAAQ,IAAI;AAAA,QAChB,GAAG,MAAM,QAAQ;AAAA,QACjB,GAAG;AAAA,QACH,MAAM,EAAE,GAAG,MAAM,QAAQ,EAAG,MAAM,GAAG,KAAK,KAAK;AAAA,MACjD;AAAA,IACF,OAAO;AACL,gBAAU,IAAI,KAAK,IAAI,MAAM,MAAM;AACnC,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AAEA,WAAS,SAAS,MAAuB;AAIvC,QAAI,YAAY,IAAI,KAAK,EAAE,EAAG;AAC9B,gBAAY,IAAI,KAAK,EAAE;AACvB,UAAM,KAAK,IAAI;AAIf,UAAM,OAAO,KAAK,MAAM;AACxB,QAAI,SAAS,OAAQ;AACrB,UAAM,SAAS,UAAU,KAAK,MAAM;AACpC,UAAM,SAAS,UAAU,KAAK,MAAM;AACpC,UAAM,UAAU,UAAU,IAAI,MAAM,KAAK,CAAC;AAC1C,YAAQ,KAAK,MAAM;AACnB,cAAU,IAAI,QAAQ,OAAO;AAC7B,UAAM,UAAU,UAAU,IAAI,MAAM,KAAK,CAAC;AAC1C,YAAQ,KAAK,MAAM;AACnB,cAAU,IAAI,QAAQ,OAAO;AAM7B,sBAAkB,MAAM;AACxB,sBAAkB,MAAM;AAAA,EAC1B;AAEA,WAAS,kBAAkB,SAAwB;AACjD,UAAM,MAAM,UAAU,IAAI,OAAO;AACjC,QAAI,QAAQ,OAAW;AACvB,UAAM,OAAO,MAAM,GAAG;AAOtB,UAAM,QAAQ,UAAU,IAAI,OAAO;AACnC,UAAM,QAAQ,UAAU,IAAI,OAAO;AACnC,SAAK,KAAK,UAAU,QAAQ,MAAM,MAAM,IAAI,CAAC;AAC7C,SAAK,KAAK,UAAU,QAAQ,MAAM,MAAM,IAAI,CAAC;AAAA,EAC/C;AAEA,QAAM,WAAqC;AAAA,IACzC;AAAA,IACA,aAAa,OAAO;AAClB,YAAM,OAAO,MAAM;AACnB,YAAM,OAAO,MAAM;AACnB,YAAM,YAAY,SAAS,aAAa,SAAS;AACjD,YAAM,SAAS,SAAS;AACxB,YAAM,cAAc,SAAS;AAC7B,YAAM,YAAY,CAAC,CAAC,KAAK;AAEzB,YAAM,UAAU,UAAU,MAAM,OAAO;AACvC,YAAM,OAAsB;AAAA,QAC1B,OAAO,MAAM;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOA,UAAU,UAAU,IAAI,OAAO,KAAK,CAAC,GAAG,MAAM;AAAA,QAC9C,UAAU,UAAU,IAAI,OAAO,KAAK,CAAC,GAAG,MAAM;AAAA,MAChD;AACA,UAAI,KAAK,gBAAgB,OAAW,MAAK,cAAc,KAAK;AAC5D,UAAI,KAAK,SAAS,OAAW,MAAK,OAAO,KAAK;AAC9C,UAAI,KAAK,cAAc,OAAW,MAAK,YAAY,KAAK;AACxD,UAAI,KAAK,WAAW,KAAM,MAAK,SAAS;AACxC,UAAI,MAAM,eAAe,KAAM,MAAK,aAAa;AAMjD,iBAAW;AAAA,QACT,IAAI,MAAM;AAAA,QACV,MAAM;AAAA;AAAA,QAEN,UAAU,EAAE,GAAG,GAAG,GAAG,EAAE;AAAA,QACvB;AAAA,MACF,CAAC;AACD,mBAAa;AAAA,IACf;AAAA,IAEA,YAAY,OAAO;AACjB,YAAM,SAAS,GAAG,MAAM,IAAI,KAAK,MAAM,EAAE,IAAI,MAAM,IAAI,GAAG,MAAM,QAAQ,IAAI,MAAM,KAAK,KAAK,EAAE;AAC9F,YAAM,OAAsB,EAAE,MAAM,MAAM,KAAK;AAC/C,UAAI,MAAM,UAAU,OAAW,MAAK,QAAQ,MAAM;AAClD,YAAM,OAAkB;AAAA,QACtB,IAAI;AAAA,QACJ,QAAQ,MAAM;AAAA,QACd,QAAQ,MAAM;AAAA,QACd;AAAA,MACF;AACA,UAAI,MAAM,UAAU,OAAW,MAAK,QAAQ,MAAM;AAClD,eAAS,IAAI;AACb,mBAAa;AAAA,IACf;AAAA,IAEA,gBAAgB,OAAO;AACrB,YAAM,SAAS,GAAG,MAAM,IAAI,KAAK,MAAM,EAAE;AACzC,eAAS;AAAA,QACP,IAAI;AAAA,QACJ,QAAQ,MAAM;AAAA,QACd,QAAQ,MAAM;AAAA,QACd,MAAM,EAAE,MAAM,OAAO;AAAA,MACvB,CAAC;AACD,mBAAa;AAAA,IACf;AAAA,IAEA,kBAAkB,OAAO;AAEvB,YAAM,WAAW,UAAU,IAAI,MAAM,OAAO;AAC5C,UAAI,aAAa,QAAW;AAM1B;AAAA,UACE,MACE,yEAAyE,MAAM,OAAO;AAAA,QAC1F;AACA;AAAA,MACF;AACA,YAAM,OAAO,MAAM,QAAQ;AAC3B,YAAM,OAAsB;AAAA,QAC1B,GAAG,KAAK;AAAA,QACR,WAAW,MAAM;AAAA,MACnB;AACA,UAAI,MAAM,kBAAkB,OAAW,MAAK,gBAAgB,MAAM;AAClE,YAAM,QAAQ,IAAI,EAAE,GAAG,MAAM,KAAK;AAClC,mBAAa;AAAA,IACf;AAAA,IAEA,iBAAiB,OAAO;AAItB,YAAM,WAAW,UAAU,IAAI,MAAM,WAAW;AAChD,UAAI,aAAa,QAAW;AAC1B;AAAA,UACE,MACE,4EAA4E,MAAM,WAAW,iBAAiB,MAAM,SAAS;AAAA,QACjI;AACA;AAAA,MACF;AACA,YAAM,OAAO,MAAM,QAAQ;AAC3B,YAAM,OAAsB;AAAA,QAC1B,GAAG,KAAK;AAAA,QACR,WAAW;AAAA,QACX,WAAW,MAAM;AAAA,MACnB;AACA,UAAI,MAAM,WAAW,KAAM,MAAK,SAAS;AACzC,YAAM,QAAQ,IAAI,EAAE,GAAG,MAAM,KAAK;AAQlC,YAAM,cAAc,MAAM,eAAe,MAAM;AAC/C,UAAI,MAAM,aAAa;AAIrB,4BAAoB,MAAM,aAA0D,aAAa;AAAA,UAC/F;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AACA,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAuB;AACrB,aAAO;AAAA,QACL,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;AAAA,QACvD,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,IAAI,OAAU,EAAE;AAAA,MAC9E;AAAA,IACF;AAAA,IACA,cAAoC;AAClC,aAAO,EAAE,OAAO,MAAM;AAAA,IACxB;AAAA,IACA,WAAW,SAAS;AAAA,IACpB,SAAS,SAAS;AAAA,IAClB,QAAc;AACZ,cAAQ,CAAC;AACT,cAAQ,CAAC;AACT,gBAAU,MAAM;AAChB,kBAAY,MAAM;AAClB,gBAAU,MAAM;AAChB,gBAAU,MAAM;AAAA,IAUlB;AAAA,EACF;AACF;;;ACvVA,SAAS,cAAc,gBAAgC;AACrD,QAAM,UAAU,eAAe,QAAQ,GAAG;AAC1C,SAAO,WAAW,IAAI,eAAe,MAAM,GAAG,OAAO,IAAI;AAC3D;AAMO,SAAS,uBACd,SACwB;AACxB,QAAM,KAAK,QAAQ,MAAM;AACzB,QAAM,YAAY,QAAQ;AAC1B,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAKA,MAAI,eAAgD,oBAAI,IAAI;AAC5D,MAAI,eAA+C,oBAAI,IAAI;AAI3D,MAAI,0BAAwD,oBAAI,IAAI;AAEpE,QAAM,WAAW,eAAe,WAAW;AAK3C,QAAM,iBAAiB,UAAU,UAAU,MAAM,SAAS,OAAO,CAAC;AAElE,WAAS,gBAAgB,OAAqC;AAK5D,UAAM,OAAO,MAAM,kBAAkB;AACrC,QAAI,CAAC,MAAM;AACT;AAAA,QACE,MACE,sIAAiI,MAAM,SAAS;AAAA,MACpJ;AACA;AAAA,IACF;AACA,UAAM,UAAU,UAAU,cAAc,IAAI,CAAC;AAC7C,UAAM,iBAAiB,iBAAiB,IAAI;AAC5C,UAAM,WAAW,aAAa,IAAI,OAAO,KAAK,CAAC;AAC/C,UAAM,SAA0B;AAAA,MAC9B;AAAA,MACA,GAAI,MAAM,iBAAiB,cAAc,UAAa;AAAA,QACpD,WAAW,MAAM,iBAAiB;AAAA,MACpC;AAAA,MACA,GAAI,MAAM,cAAc,UAAa,EAAE,SAAS,MAAM,UAAU;AAAA,MAChE,GAAI,MAAM,YAAY,UAAa,EAAE,OAAO,MAAM,QAAQ;AAAA,IAC5D;AACA,aAAS,KAAK,MAAM;AACpB,iBAAa,IAAI,SAAS,QAAQ;AAClC,4BAAwB,IAAI,gBAAgB,OAAO;AACnD,aAAS,OAAO;AAAA,EAClB;AAEA,WAAS,YAAY,OAA6B;AAChD,UAAM,OAAO,MAAM,kBAAkB;AACrC,QAAI,CAAC,MAAM;AACT;AAAA,QACE,MACE,0HAAqH,MAAM,SAAS;AAAA,MACxI;AACA;AAAA,IACF;AACA,UAAM,UAAU,UAAU,cAAc,IAAI,CAAC;AAC7C,UAAM,iBAAiB,iBAAiB,IAAI;AAC5C,UAAM,WAAW,aAAa,IAAI,OAAO;AAMzC,UAAM,WAAW,WACb,SAAS,UAAU,CAAC,MAAM,EAAE,mBAAmB,cAAc,IAC7D;AACJ,QAAI,CAAC,YAAY,aAAa,IAAI;AAGhC,YAAM,QAAyB;AAAA,QAC7B;AAAA,QACA,cAAc,MAAM,WAAW;AAAA,MACjC;AACA,UAAI,UAAU;AACZ,iBAAS,KAAK,KAAK;AAAA,MACrB,OAAO;AACL,qBAAa,IAAI,SAAS,CAAC,KAAK,CAAC;AAAA,MACnC;AAAA,IACF,OAAO;AACL,YAAM,QAAQ,SAAS,QAAQ;AAC/B,eAAS,QAAQ,IAAI,EAAE,GAAG,OAAO,cAAc,MAAM,WAAW,QAAQ;AAAA,IAC1E;AACA,4BAAwB,IAAI,gBAAgB,OAAO;AACnD,aAAS,OAAO;AAAA,EAClB;AAEA,WAAS,aAAa,OAA+B;AAInD,UAAM,OAAO,MAAM;AACnB,QAAI,CAAC,MAAM;AACT;AAAA,QACE,MACE,2GAAsG,MAAM,SAAS,MAAM,WAAW,GAAG;AAAA,MAC7I;AACA;AAAA,IACF;AACA,UAAM,UAAU,UAAU,cAAc,IAAI,CAAC;AAC7C,UAAM,OAAO,aAAa,IAAI,OAAO,KAAK,CAAC;AAC3C,SAAK,KAAK,iBAAiB,IAAI,CAAC;AAChC,iBAAa,IAAI,SAAS,IAAI;AAC9B,4BAAwB,IAAI,iBAAiB,IAAI,GAAG,OAAO;AAC3D,aAAS,OAAO;AAAA,EAClB;AAEA,QAAM,WAAoC;AAAA,IACxC;AAAA,IACA,iBAAiB;AAAA,IACjB,SAAS;AAAA,IACT,UAAU;AAAA;AAAA;AAAA;AAAA,IAIV,aAAa;AAAA,IAEb;AAAA,IACA,WAAW;AAAA,IAEX;AAAA,EACF;AAEA,WAAS,UAAU,YAAiC;AAClD,UAAM,UAAU,UAAU,WAAW,EAAE;AACvC,UAAM,QAAQ,aAAa,IAAI,OAAO,KAAK,CAAC;AAC5C,UAAM,aAAa,aAAa,IAAI,OAAO,KAAK,CAAC;AAGjD,UAAM,eAAe,MAAM,SAAS;AACpC,UAAM,iBAAiB,MAAM;AAC7B,UAAM,kBAAkB,MAAM,SAAS,KAAK,MAAM,CAAC,EAAG,YAAY,SAC9D,MAAM,CAAC,EAAG,UACV;AACJ,UAAM,iBAAiB,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,CAAC,EAAG,UAAU,SAC1E,MAAM,MAAM,SAAS,CAAC,EAAG,QACzB;AACJ,QAAI,kBAAkB;AACtB,QAAI,aAAa;AACjB,eAAW,KAAK,OAAO;AACrB,UAAI,EAAE,YAAY,UAAa,EAAE,UAAU,QAAW;AACpD,2BAAmB,EAAE,QAAQ,EAAE;AAAA,MACjC;AACA,UAAI,EAAE,aAAc;AAAA,IACtB;AAEA,UAAM,IAAI,WAAW;AACrB,WAAO;AAAA,MACL;AAAA,MACA,OAAO,EAAE;AAAA,MACT,MAAO,WAAW,QAA6B;AAAA,MAC/C,WAAW,EAAE;AAAA,MACb,QAAQ,EAAE;AAAA,MACV,WAAW,EAAE;AAAA,MACb,aAAa,EAAE;AAAA,MACf,YAAY,EAAE,eAAe;AAAA,MAC7B,GAAI,EAAE,gBAAgB,UAAa,EAAE,aAAa,EAAE,YAAY;AAAA,MAChE,GAAI,EAAE,SAAS,UAAa,EAAE,MAAM,EAAE,KAAK;AAAA,MAC3C,GAAI,EAAE,cAAc,UAAa,EAAE,WAAW,EAAE,UAAU;AAAA;AAAA;AAAA;AAAA,MAI1D,GAAI,EAAE,cAAc,UAAa,EAAE,WAAW,EAAE,UAAU,MAAM,EAAE;AAAA,MAClE,GAAI,EAAE,kBAAkB,UAAa,EAAE,eAAe,EAAE,cAAc;AAAA;AAAA;AAAA,MAGtE,SAAS,EAAE,QAAQ,MAAM;AAAA,MACzB,SAAS,EAAE,QAAQ,MAAM;AAAA,MACzB,YAAY,MAAM,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uBAAuB,WAAW,MAAM;AAAA,IAC1C;AAAA,EACF;AAQA,MAAI,cAAoC;AACxC,MAAI,mBAAmB;AACvB,MAAI,yBAAyB;AAE7B,SAAO;AAAA,IACL;AAAA,IACA,WAA0B;AACxB,YAAM,MAAM,SAAS,QAAQ;AAC7B,YAAM,SAAS,UAAU,QAAQ;AACjC,UACE,gBAAgB,QAChB,qBAAqB,OACrB,2BAA2B,QAC3B;AACA,eAAO;AAAA,MACT;AAKA,YAAM,WAAW,UAAU,YAAY;AACvC,YAAM,YAAY,oBAAI,IAAuB;AAC7C,YAAM,mBAAmB,oBAAI,IAA8B;AAC3D,YAAM,MAAkB,CAAC;AACzB,iBAAW,cAAc,SAAS,OAAO;AACvC,cAAM,OAAO,UAAU,UAAU;AACjC,kBAAU,IAAI,KAAK,SAAS,IAAI;AAChC,YAAI,KAAK,IAAI;AAEb,mBAAW,QAAQ,KAAK,YAAY;AAClC,2BAAiB,IAAI,KAAK,gBAAgB,IAAI;AAAA,QAChD;AAIA,mBAAW,QAAQ,KAAK,uBAAuB;AAC7C,2BAAiB,IAAI,MAAM,IAAI;AAAA,QACjC;AAAA,MACF;AACA,oBAAc,EAAE,WAAW,kBAAkB,IAAI;AACjD,yBAAmB;AACnB,+BAAyB;AACzB,aAAO;AAAA,IACT;AAAA,IACA,WAAW,SAAS;AAAA,IACpB,SAAS,SAAS;AAAA,IAClB,QAAc;AACZ,qBAAe,oBAAI,IAAI;AACvB,qBAAe,oBAAI,IAAI;AACvB,gCAA0B,oBAAI,IAAI;AAOlC,oBAAc;AACd,yBAAmB;AACnB,+BAAyB;AAGzB,WAAK;AAAA,IACP;AAAA,EACF;AACF;;;ACxPA,SAASC,eAAc,gBAAgC;AACrD,QAAM,UAAU,eAAe,QAAQ,GAAG;AAC1C,SAAO,WAAW,IAAI,eAAe,MAAM,GAAG,OAAO,IAAI;AAC3D;AAMO,SAAS,yBACd,SAC0B;AAC1B,QAAM,KAAK,QAAQ,MAAM;AACzB,QAAM,YAAY,QAAQ;AAC1B,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAYA,MAAI,aAA0B,CAAC;AAE/B,QAAM,WAAW,eAAe,aAAa;AAC7C,QAAM,iBAAiB,UAAU,UAAU,MAAM,SAAS,OAAO,CAAC;AAElE,WAAS,aAAa,OAA+B;AAInD,UAAM,OAAO,MAAM;AACnB,QAAI,CAAC,MAAM;AACT;AAAA,QACE,MACE,2FAAsF,MAAM,SAAS,MAAM,WAAW,GAAG;AAAA,MAC7H;AACA;AAAA,IACF;AACA,UAAM,UAAU,UAAUA,eAAc,IAAI,CAAC;AAC7C,eAAW,KAAK;AAAA,MACd,gBAAgB,iBAAiB,IAAI;AAAA,MACrC;AAAA,MACA,WAAW,WAAW;AAAA,MACtB,SAAS,MAAM,UAAU,EAAE,GAAG,MAAM,QAAQ,IAAI,CAAC;AAAA,MACjD,OAAO,MAAM,QAAQ,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA,IAC3C,CAAC;AACD,aAAS,OAAO;AAAA,EAClB;AAQA,QAAM,WAAsC;AAAA,IAC1C;AAAA,IACA,UAAU;AAAA,IACV,kBAAkB;AAAA,IAElB;AAAA,IACA,UAAU;AAAA,IAEV;AAAA,IACA,aAAa;AAAA,IAEb;AAAA,IACA,WAAW;AAAA,IAEX;AAAA,EACF;AAEA,WAAS,aAA8B;AAGrC,UAAM,WAAW,UAAU,YAAY;AACvC,UAAM,gBAAgB,oBAAI,IAA6C;AACvE,eAAW,KAAK,SAAS,MAAO,eAAc,IAAI,EAAE,IAAI,CAAC;AAUzD,UAAM,YAAY,oBAAI,IAAyB;AAC/C,eAAW,MAAM,YAAY;AAC3B,iBAAW,KAAK,OAAO,KAAK,GAAG,OAAO,GAAG;AACvC,cAAM,OAAO,UAAU,IAAI,CAAC,KAAK,CAAC;AAClC,aAAK,KAAK,EAAE,WAAW,GAAG,WAAW,gBAAgB,GAAG,eAAe,CAAC;AACxE,kBAAU,IAAI,GAAG,IAAI;AAAA,MACvB;AAAA,IACF;AAKA,UAAM,iBAAiB,oBAAI,IAAsB;AACjD,eAAW,MAAM,YAAY;AAC3B,YAAM,OAAO,eAAe,IAAI,GAAG,OAAO,KAAK,CAAC;AAChD,WAAK,KAAK,GAAG,SAAS;AACtB,qBAAe,IAAI,GAAG,SAAS,IAAI;AAAA,IACrC;AAEA,UAAM,UAAwB,CAAC;AAC/B,UAAM,mBAAmB,oBAAI,IAAgC;AAC7D,UAAM,YAAyD,CAAC;AAEhE,eAAW,MAAM,YAAY;AAC3B,YAAM,aAAa,cAAc,IAAI,GAAG,OAAO;AAC/C,YAAM,qBAAqB,YAAY,KAAK,WAAW,CAAC,GAAG,MAAM;AACjE,YAAM,qBAAqB,YAAY,KAAK,WAAW,CAAC,GAAG,MAAM;AAIjE,YAAM,iBAAmC,CAAC;AAC1C,iBAAW,YAAY,mBAAmB;AACxC,cAAM,OAAO,eAAe,IAAI,QAAQ;AACxC,YAAI,CAAC,KAAM;AAGX,YAAI,YAA2B;AAC/B,iBAAS,IAAI,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK;AACzC,cAAI,KAAK,CAAC,IAAK,GAAG,WAAW;AAC3B,wBAAY,KAAK,CAAC;AAClB;AAAA,UACF;AAAA,QACF;AACA,YAAI,cAAc,MAAM;AACtB,yBAAe,KAAK,WAAW,SAAS,EAAG,cAAc;AAAA,QAC3D;AAAA,MACF;AAIA,YAAM,iBAAmC,CAAC;AAC1C,iBAAW,YAAY,mBAAmB;AACxC,cAAM,OAAO,eAAe,IAAI,QAAQ;AACxC,YAAI,CAAC,KAAM;AACX,YAAI,YAA2B;AAC/B,iBAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,cAAI,KAAK,CAAC,IAAK,GAAG,WAAW;AAC3B,wBAAY,KAAK,CAAC;AAClB;AAAA,UACF;AAAA,QACF;AACA,YAAI,cAAc,MAAM;AACtB,yBAAe,KAAK,WAAW,SAAS,EAAG,cAAc;AAAA,QAC3D;AAAA,MACF;AAGA,YAAM,mBAAqC,CAAC;AAC5C,iBAAW,OAAO,GAAG,OAAO;AAC1B,cAAM,UAAU,UAAU,IAAI,GAAG;AACjC,YAAI,SAA2B;AAC/B,YAAI,SAAS;AACX,mBAAS,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KAAK;AAC5C,gBAAI,QAAQ,CAAC,EAAG,YAAY,GAAG,WAAW;AACxC,uBAAS,QAAQ,CAAC;AAClB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,YAAI,QAAQ;AACV,2BAAiB,KAAK;AAAA,YACpB;AAAA,YACA,sBAAsB,OAAO;AAAA,YAC7B,iBAAiB,OAAO;AAAA,UAC1B,CAAC;AAID,oBAAU;AAAA,YACR,OAAO,OAAO,EAAE,MAAM,OAAO,WAAW,IAAI,GAAG,WAAW,IAAI,CAAC;AAAA,UACjE;AAAA,QACF,OAAO;AAGL,2BAAiB,KAAK;AAAA,YACpB;AAAA,YACA,sBAAsB;AAAA,YACtB,iBAAiB;AAAA,UACnB,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM,OAAmB;AAAA,QACvB,gBAAgB,GAAG;AAAA,QACnB,SAAS,GAAG;AAAA,QACZ,WAAW,GAAG;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,EAAE,GAAG,GAAG,QAAQ;AAAA,QACzB,OAAO,GAAG,MAAM,MAAM;AAAA,MACxB;AACA,cAAQ,KAAK,IAAI;AACjB,uBAAiB,IAAI,KAAK,gBAAgB,IAAI;AAAA,IAChD;AAEA,WAAO,EAAE,SAAS,kBAAkB,UAAU;AAAA,EAChD;AAIA,MAAI,cAAsC;AAC1C,MAAI,mBAAmB;AACvB,MAAI,yBAAyB;AAE7B,SAAO;AAAA,IACL;AAAA,IACA,WAA4B;AAC1B,YAAM,MAAM,SAAS,QAAQ;AAC7B,YAAM,SAAS,UAAU,QAAQ;AACjC,UACE,gBAAgB,QAChB,qBAAqB,OACrB,2BAA2B,QAC3B;AACA,eAAO;AAAA,MACT;AACA,oBAAc,WAAW;AACzB,yBAAmB;AACnB,+BAAyB;AACzB,aAAO;AAAA,IACT;AAAA,IACA,WAAW,SAAS;AAAA,IACpB,SAAS,SAAS;AAAA,IAClB,QAAc;AACZ,mBAAa,CAAC;AAGd,oBAAc;AACd,yBAAmB;AACnB,+BAAyB;AAOzB,WAAK;AAAA,IACP;AAAA,EACF;AACF;AAwBO,SAAS,kBACd,OACA,qBACc;AACd,QAAM,QAAQ,MAAM,iBAAiB,IAAI,mBAAmB;AAC5D,MAAI,CAAC,MAAO,QAAO,CAAC;AASpB,QAAM,aAAa,oBAAI,IAAY,CAAC,MAAM,SAAS,CAAC;AACpD,QAAM,QAAkB,CAAC,MAAM,SAAS;AACxC,QAAM,gBAAgB,oBAAI,IAAY,CAAC,MAAM,SAAS,CAAC;AACvD,MAAI,OAAO;AACX,SAAO,OAAO,MAAM,QAAQ;AAC1B,UAAM,MAAM,MAAM,QAAQ,MAAM,MAAM,CAAE;AACxC,QAAI,CAAC,IAAK;AACV,eAAW,OAAO,IAAI,kBAAkB;AACtC,UAAI,IAAI,oBAAoB,KAAM;AAClC,UAAI,WAAW,IAAI,IAAI,eAAe,EAAG;AACzC,iBAAW,IAAI,IAAI,eAAe;AAClC,oBAAc,IAAI,IAAI,eAAe;AACrC,YAAM,KAAK,IAAI,eAAe;AAAA,IAChC;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,aAAa,EAC5B,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,EACpB,IAAI,CAAC,QAAQ,MAAM,QAAQ,GAAG,CAAE,EAChC,OAAO,CAAC,MAAuB,MAAM,MAAS;AACnD;;;ACjdO,SAAS,kBACd,UAAoC,CAAC,GACxB;AACb,QAAM,YAAY,6BAA6B,QAAQ,SAAS;AAChE,QAAM,iBAAiB,0BAA0B,QAAQ,cAAc;AAKvE,QAAM,WAAW,uBAAuB;AAAA,IACtC,GAAI,QAAQ,YAAY,CAAC;AAAA,IACzB;AAAA,EACF,CAAC;AACD,QAAM,aAAa,yBAAyB;AAAA,IAC1C,GAAI,QAAQ,cAAc,CAAC;AAAA,IAC3B;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,UAAiC;AASxC,eAAS,mBAAmB,eAAe,QAAQ;AACnD,eAAS,mBAAmB,SAAS,QAAQ;AAC7C,eAAS,mBAAmB,WAAW,QAAQ;AAC/C,UAAI,OAAO,SAAS,wBAAwB,YAAY;AACtD,iBAAS,oBAAoB,SAAS,QAAQ;AAC9C,iBAAS,oBAAoB,WAAW,QAAQ;AAAA,MAClD,OAAO;AAIL;AAAA,UACE,MACE;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACzIA,IAAAC,iBAA8C;AAgBvC,SAAS,cACd,QACA,aACG;AACH,QAAM,gBAAY,wBAAQ,MAAM,OAAO,UAAU,KAAK,MAAM,GAAG,CAAC,MAAM,CAAC;AACvE,QAAM,iBAAa,wBAAQ,MAAM,OAAO,QAAQ,KAAK,MAAM,GAAG,CAAC,MAAM,CAAC;AACtE,QAAM,cAAU,qCAAqB,WAAW,YAAY,UAAU;AAEtE,aAAO,wBAAQ,MAAM,YAAY,GAAG,CAAC,SAAS,WAAW,CAAC;AAC5D;;;ACGO,SAAS,YACd,OACA,SACA,UAAuB,CAAC,GACZ;AACZ,SAAO,QAAQ,OAAO,SAAS,CAAC,MAAM,EAAE,SAAS,OAAO;AAC1D;AASO,SAAS,aACd,OACA,SACA,UAAuB,CAAC,GACZ;AACZ,SAAO,QAAQ,OAAO,SAAS,CAAC,MAAM,EAAE,SAAS,OAAO;AAC1D;AAYO,SAAS,oBACd,OACA,SACA,UAAyD,CAAC,GAC9C;AACZ,QAAM,QAAQ,MAAM,UAAU,IAAI,OAAO;AACzC,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,QAAoB,CAAC,KAAK;AAChC,QAAM,MAAM,QAAQ,YAAY,MAAM,IAAI;AAC1C,QAAM,UAAU,oBAAI,IAAa,CAAC,OAAO,CAAC;AAC1C,MAAI,MAA4B;AAChC,MAAI,OAAO;AACX,SAAO,OAAO,OAAO,KAAK;AACxB,QAAI,IAAI,QAAQ,WAAW,KAAK,IAAI,QAAQ,SAAS,GAAG;AAEtD;AAAA,IACF;AACA,UAAM,SAAS,IAAI,QAAQ,CAAC;AAC5B,QAAI,QAAQ,IAAI,MAAM,EAAG;AACzB,YAAQ,IAAI,MAAM;AAClB,UAAM,OAA6B,MAAM,UAAU,IAAI,MAAM;AAC7D,QAAI,CAAC,KAAM;AACX,QAAI,QAAQ,eAAe,CAAC,KAAK,aAAc;AAC/C,UAAM,QAAQ,IAAI;AAClB,UAAM;AACN;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,uBACd,OACA,SACA,UAAyD,CAAC,GAC9C;AACZ,QAAM,QAAQ,MAAM,UAAU,IAAI,OAAO;AACzC,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,QAAoB,CAAC,KAAK;AAChC,QAAM,MAAM,QAAQ,YAAY,MAAM,IAAI;AAC1C,QAAM,UAAU,oBAAI,IAAa,CAAC,OAAO,CAAC;AAC1C,MAAI,MAA4B;AAChC,MAAI,OAAO;AACX,SAAO,OAAO,OAAO,KAAK;AACxB,QAAI,IAAI,QAAQ,WAAW,KAAK,IAAI,QAAQ,SAAS,EAAG;AACxD,UAAM,SAAS,IAAI,QAAQ,CAAC;AAC5B,QAAI,QAAQ,IAAI,MAAM,EAAG;AACzB,YAAQ,IAAI,MAAM;AAClB,UAAM,OAA6B,MAAM,UAAU,IAAI,MAAM;AAC7D,QAAI,CAAC,KAAM;AACX,QAAI,QAAQ,eAAe,CAAC,KAAK,aAAc;AAC/C,UAAM,KAAK,IAAI;AACf,UAAM;AACN;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,QACP,OACA,SACA,aACA,SACY;AACZ,QAAM,QAAQ,MAAM,UAAU,IAAI,OAAO;AACzC,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,MAAM,QAAQ,YAAY,MAAM,IAAI;AAC1C,QAAM,UAAU,oBAAI,IAAa;AACjC,UAAQ,IAAI,OAAO;AACnB,QAAM,MAAkB,CAAC;AACzB,MAAI,QAAQ,aAAc,KAAI,KAAK,KAAK;AAQxC,QAAM,QAAmC,CAAC,CAAC,OAAO,CAAC,CAAC;AACpD,MAAI,OAAO;AACX,SAAO,OAAO,MAAM,QAAQ;AAC1B,UAAM,CAAC,MAAM,KAAK,IAAI,MAAM,MAAM;AAClC,QAAI,SAAS,IAAK;AAClB,eAAW,cAAc,YAAY,IAAI,GAAG;AAC1C,UAAI,QAAQ,IAAI,UAAU,EAAG;AAC7B,cAAQ,IAAI,UAAU;AACtB,YAAM,WAAW,MAAM,UAAU,IAAI,UAAU;AAC/C,UAAI,CAAC,SAAU;AACf,UAAI,QAAQ,eAAe,CAAC,SAAS,aAAc;AACnD,UAAI,KAAK,QAAQ;AACjB,YAAM,KAAK,CAAC,UAAU,QAAQ,CAAC,CAAC;AAAA,IAClC;AAAA,EACF;AACA,SAAO;AACT;;;AC7KA,IAAAC,iBAAwB;AAgDlB,IAAAC,uBAAA;AAxBC,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,OAAO,aAAa,MAAM,UAAU,IAAI,UAAU,KAAK,OAAO;AAIpE,QAAM,gBAAY;AAAA,IAChB,MAAO,OAAO,oBAAoB,OAAO,KAAK,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC;AAAA,IAC3E,CAAC,OAAO,MAAM,WAAW;AAAA,EAC3B;AAEA,QAAM,gBAAY;AAAA,IAChB,MAAO,OAAO,uBAAuB,OAAO,KAAK,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC;AAAA,IAC9E,CAAC,OAAO,MAAM,WAAW;AAAA,EAC3B;AAEA,MAAI,CAAC,MAAM;AACT,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,MAAM;AAAA,UACb,WAAW;AAAA,UACX,GAAG;AAAA,QACL;AAAA,QACD;AAAA;AAAA,IAED;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,MAAM;AAAA,QACb,UAAU;AAAA,QACV,UAAU;AAAA,QACV,GAAG;AAAA,MACL;AAAA,MAGA;AAAA,uDAAC,SAAI,OAAO,EAAE,cAAc,GAAG,GAC7B;AAAA,wDAAC,SAAI,OAAO,EAAE,UAAU,IAAI,YAAY,KAAK,OAAO,MAAM,YAAY,GACnE,eAAK,OACR;AAAA,UACA,+CAAC,SAAI,OAAO,EAAE,UAAU,IAAI,YAAY,aAAa,OAAO,MAAM,WAAW,WAAW,EAAE,GACvF;AAAA,iBAAK;AAAA,YAAQ;AAAA,YAAI,KAAK;AAAA,YACtB,KAAK,aAAa;AAAA,YAClB,KAAK,UAAU;AAAA,YACf,KAAK,aAAa;AAAA,YAClB,KAAK,eAAe;AAAA,YACpB,KAAK,cAAc;AAAA,aACtB;AAAA,UACC,KAAK,eACJ,8CAAC,SAAI,OAAO,EAAE,UAAU,IAAI,OAAO,MAAM,eAAe,WAAW,EAAE,GAClE,eAAK,aACR;AAAA,WAEJ;AAAA,QAGA,+CAAC,WAAQ,OAAM,WACb;AAAA,wDAAC,OAAI,OAAM,WAAU,OAAO,KAAK,eAAe,QAAQ,MAAM;AAAA,UAC7D,KAAK,gBACJ,gFACE;AAAA,0DAAC,OAAI,OAAM,cAAa,OAAO,OAAO,KAAK,cAAc,GAAG;AAAA,YAC3D,KAAK,oBAAoB,QACxB,8CAAC,OAAI,OAAM,YAAW,OAAO,GAAG,KAAK,gBAAgB,QAAQ,CAAC,CAAC,MAAM;AAAA,YAEtE,KAAK,mBAAmB,QACvB,8CAAC,OAAI,OAAM,WAAU,OAAO,GAAG,KAAK,eAAe,QAAQ,CAAC,CAAC,MAAM;AAAA,YAEpE,KAAK,kBAAkB,KACtB,8CAAC,OAAI,OAAM,SAAQ,OAAO,GAAG,KAAK,gBAAgB,QAAQ,CAAC,CAAC,MAAM;AAAA,YAEnE,KAAK,aAAa,KACjB,8CAAC,OAAI,OAAM,UAAS,OAAO,OAAO,KAAK,UAAU,GAAG,YAAY,MAAM,OAAO;AAAA,aAEjF;AAAA,WAEJ;AAAA,QAGC,UAAU,SAAS,KAClB,8CAAC,WAAQ,OAAO,eAAe,UAAU,SAAS,CAAC,UACjD,wDAAC,UAAO,OAAO,UAAU,MAAM,GAAG,EAAE,GAAG,SAAS,YAAY,GAC9D;AAAA,QAED,KAAK,QAAQ,SAAS,KACrB,8CAAC,WAAQ,OAAM,+BACb;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,KAAK,QACT,IAAI,CAAC,OAAO,MAAM,UAAU,IAAI,EAAE,CAAC,EACnC,OAAO,CAAC,MAAqB,MAAM,MAAS;AAAA,YAC/C,SAAS;AAAA;AAAA,QACX,GACF;AAAA,QAID,UAAU,SAAS,KAClB,8CAAC,WAAQ,OAAO,eAAe,UAAU,SAAS,CAAC,UACjD,wDAAC,UAAO,OAAO,UAAU,MAAM,CAAC,GAAG,SAAS,YAAY,GAC1D;AAAA,QAED,KAAK,QAAQ,SAAS,KACrB,8CAAC,WAAQ,OAAM,gCACb;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,KAAK,QACT,IAAI,CAAC,OAAO,MAAM,UAAU,IAAI,EAAE,CAAC,EACnC,OAAO,CAAC,MAAqB,MAAM,MAAS;AAAA,YAC/C,SAAS;AAAA;AAAA,QACX,GACF;AAAA,QAID,KAAK,sBAAsB,SAAS,KACnC,8CAAC,WAAQ,OAAO,YAAY,KAAK,sBAAsB,MAAM,KAC3D,wDAAC,SAAI,OAAO,EAAE,YAAY,aAAa,UAAU,IAAI,OAAO,MAAM,cAAc,GAC7E,eAAK,sBAAsB,IAAI,CAAC,SAC/B,8CAAC,SAAgB,kBAAP,IAAY,CACvB,GACH,GACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAIA,SAAS,QAAQ,EAAE,OAAO,SAAS,GAAiD;AAClF,SACE,+CAAC,SAAI,OAAO,EAAE,cAAc,GAAG,GAC7B;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,eAAe;AAAA,UACf,eAAe;AAAA,UACf,OAAO,MAAM;AAAA,UACb,cAAc;AAAA,QAChB;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,IACC;AAAA,KACH;AAEJ;AAEA,SAAS,IAAI,EAAE,OAAO,OAAO,WAAW,GAA0D;AAChG,SACE,+CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,iBAAiB,UAAU,IAAI,SAAS,QAAQ,GAC7F;AAAA,kDAAC,UAAK,OAAO,EAAE,OAAO,MAAM,UAAU,GAAI,iBAAM;AAAA,IAChD,8CAAC,UAAK,OAAO,EAAE,OAAO,cAAc,MAAM,eAAe,YAAY,YAAY,GAAI,iBAAM;AAAA,KAC7F;AAEJ;AAEA,SAAS,OAAO,EAAE,OAAO,QAAQ,GAA2D;AAC1F,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,8CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,UAAU,QAAQ,KAAK,EAAE,GACrD,gBAAM,IAAI,CAAC,GAAG,MACb,+CAAC,UAAqB,OAAO,EAAE,SAAS,eAAe,YAAY,UAAU,KAAK,EAAE,GAClF;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,UAAU,MAAM,QAAQ,EAAE,OAAO,IAAI;AAAA,QAC9C,OAAO;AAAA,UACL,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,SAAS;AAAA,UACT,cAAc;AAAA,UACd,QAAQ,aAAa,MAAM,MAAM;AAAA,UACjC,YAAY;AAAA,UACZ,OAAO,EAAE,eAAe,MAAM,UAAU,MAAM;AAAA,UAC9C,QAAQ,UAAU,YAAY;AAAA,QAChC;AAAA,QAEC,YAAE;AAAA;AAAA,IACL;AAAA,IACC,IAAI,MAAM,SAAS,KAAK,8CAAC,UAAK,OAAO,EAAE,OAAO,MAAM,WAAW,UAAU,GAAG,GAAG,oBAAC;AAAA,OAhBxE,EAAE,OAiBb,CACD,GACH;AAEJ;;;AC9NA,IAAAC,iBAAwB;AA+ClB,IAAAC,uBAAA;AArBC,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,OAAO,yBACT,MAAM,iBAAiB,IAAI,sBAAsB,KAAK,OACtD;AAIJ,QAAM,cAAU;AAAA,IACd,MACE,OAAO,kBAAkB,OAAO,KAAK,cAAc,IAAI,CAAC;AAAA,IAC1D,CAAC,OAAO,IAAI;AAAA,EACd;AAEA,MAAI,CAAC,MAAM;AACT,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,MAAM;AAAA,UACb,WAAW;AAAA,UACX,GAAG;AAAA,QACL;AAAA,QACD;AAAA;AAAA,IAED;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,MAAM;AAAA,QACb,UAAU;AAAA,QACV,UAAU;AAAA,QACV,GAAG;AAAA,MACL;AAAA,MAGA;AAAA,uDAAC,SAAI,OAAO,EAAE,cAAc,GAAG,GAC7B;AAAA,wDAAC,SAAI,OAAO,EAAE,UAAU,IAAI,YAAY,KAAK,OAAO,MAAM,YAAY,GACnE,eAAK,SACR;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,OAAO,MAAM;AAAA,gBACb,WAAW;AAAA,cACb;AAAA,cAEC;AAAA,qBAAK;AAAA,gBAAe;AAAA,gBAAc,KAAK;AAAA;AAAA;AAAA,UAC1C;AAAA,WACF;AAAA,QAGC,KAAK,kBAAkB,SAAS,KAC/B,8CAACC,UAAA,EAAQ,OAAM,iCACb,wDAAC,aAAU,QAAQ,KAAK,mBAAmB,GAC7C;AAAA,QAED,KAAK,kBAAkB,SAAS,KAC/B,8CAACA,UAAA,EAAQ,OAAM,iCACb,wDAAC,aAAU,QAAQ,KAAK,mBAAmB,GAC7C;AAAA,QAID,KAAK,eAAe,SAAS,KAC5B,8CAACA,UAAA,EAAQ,OAAM,iCACb,wDAAC,eAAY,MAAM,KAAK,gBAAgB,SAAS,YAAY,GAC/D;AAAA,QAED,KAAK,eAAe,SAAS,KAC5B,8CAACA,UAAA,EAAQ,OAAM,iCACb,wDAAC,eAAY,MAAM,KAAK,gBAAgB,SAAS,YAAY,GAC/D;AAAA,QAID,OAAO,KAAK,KAAK,OAAO,EAAE,SAAS,KAClC,8CAACA,UAAA,EAAQ,OAAO,YAAY,OAAO,KAAK,KAAK,OAAO,EAAE,MAAM,KAC1D,wDAAC,gBAAa,SAAS,OAAO,QAAQ,KAAK,OAAO,GAAG,GACvD;AAAA,QAED,KAAK,MAAM,SAAS,KACnB,8CAACA,UAAA,EAAQ,OAAO,UAAU,KAAK,MAAM,MAAM,KACzC,wDAAC,aAAU,QAAQ,KAAK,OAAO,GACjC;AAAA,QAID,KAAK,iBAAiB,SAAS,KAC9B,8CAACA,UAAA,EAAQ,OAAO,sBAAsB,KAAK,iBAAiB,MAAM,KAChE,wDAAC,WAAM,OAAO,EAAE,UAAU,IAAI,YAAY,aAAa,OAAO,QAAQ,gBAAgB,WAAW,GAC/F,wDAAC,WACE,eAAK,iBAAiB,IAAI,CAAC,QAC1B,+CAAC,QACC;AAAA,wDAAC,QAAG,OAAO,EAAE,OAAO,MAAM,eAAe,SAAS,gBAAgB,GAC/D,cAAI,KACP;AAAA,UACA,8CAAC,QAAG,OAAO,EAAE,OAAO,IAAI,uBAAuB,MAAM,cAAc,MAAM,UAAU,GAChF,cAAI,uBACH;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,aAAa,MAAM,WAAW,IAAI,oBAAqB,IAAI;AAAA,cACpE,OAAO,iBAAiB,eAAe,MAAS;AAAA,cACjD;AAAA;AAAA,gBACI,IAAI;AAAA;AAAA;AAAA,UACT,IAEA,8CAAC,QAAG,0DAAuC,GAE/C;AAAA,aAfO,IAAI,GAgBb,CACD,GACH,GACF,GACF;AAAA,QAID,QAAQ,SAAS,KAChB,8CAACA,UAAA,EAAQ,OAAO,kBAAkB,QAAQ,SAAS,CAAC,sBAClD,wDAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,UAAU,QAAQ,KAAK,EAAE,GACrD,kBAAQ,MAAM,GAAG,EAAE,EAAE,IAAI,CAAC,GAAG,MAC5B,+CAAC,UAA4B,OAAO,EAAE,SAAS,eAAe,YAAY,UAAU,KAAK,EAAE,GACzF;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,aAAa,MAAM,WAAW,EAAE,cAAc,IAAI;AAAA,cAC3D,OAAO,iBAAiB,eAAe,MAAS;AAAA,cAE/C,YAAE;AAAA;AAAA,UACL;AAAA,UACC,IAAI,QAAQ,SAAS,KACpB,8CAAC,UAAK,OAAO,EAAE,OAAO,MAAM,WAAW,UAAU,GAAG,GAAG,oBAAC;AAAA,aARjD,EAAE,cAUb,CACD,GACH,GACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAIA,SAASA,SAAQ,EAAE,OAAO,SAAS,GAAiD;AAClF,SACE,+CAAC,SAAI,OAAO,EAAE,cAAc,GAAG,GAC7B;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,eAAe;AAAA,UACf,eAAe;AAAA,UACf,OAAO,MAAM;AAAA,UACb,cAAc;AAAA,QAChB;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,IACC;AAAA,KACH;AAEJ;AAEA,SAAS,UAAU,EAAE,OAAO,GAAkC;AAC5D,SACE,8CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,UAAU,QAAQ,KAAK,EAAE,GACrD,iBAAO,IAAI,CAAC,MACX;AAAA,IAAC;AAAA;AAAA,MAEC,OAAO;AAAA,QACL,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,OAAO,MAAM;AAAA,MACf;AAAA,MAEC;AAAA;AAAA,IAVI;AAAA,EAWP,CACD,GACH;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,SACE,8CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,UAAU,QAAQ,KAAK,EAAE,GACrD,eAAK,IAAI,CAAC,MACT;AAAA,IAAC;AAAA;AAAA,MAEC,SAAS,UAAU,MAAM,QAAQ,CAAC,IAAI;AAAA,MACtC,OAAO,iBAAiB,YAAY,MAAS;AAAA,MAE5C;AAAA;AAAA,IAJI;AAAA,EAKP,CACD,GACH;AAEJ;AAEA,SAAS,aAAa,EAAE,QAAQ,GAAkD;AAChF,SACE,8CAAC,WAAM,OAAO,EAAE,UAAU,IAAI,YAAY,aAAa,OAAO,QAAQ,gBAAgB,WAAW,GAC/F,wDAAC,WACE,kBAAQ,IAAI,CAAC,CAAC,GAAGC,EAAC,MACjB,+CAAC,QACC;AAAA,kDAAC,QAAG,OAAO,EAAE,OAAO,MAAM,eAAe,SAAS,iBAAiB,eAAe,MAAM,GACrF,aACH;AAAA,IACA,8CAAC,QAAG,OAAO,EAAE,OAAO,MAAM,aAAa,WAAW,aAAa,GAC5D,iBAAOA,OAAM,WAAW,KAAK,UAAUA,EAAC,IAAI,OAAOA,EAAC,GACvD;AAAA,OANO,CAOT,CACD,GACH,GACF;AAEJ;AAEA,SAAS,iBAAiB,WAAyC;AACjE,SAAO;AAAA,IACL,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ,aAAa,MAAM,MAAM;AAAA,IACjC,YAAY;AAAA,IACZ,OAAO,MAAM;AAAA,IACb,QAAQ,YAAY,YAAY;AAAA,EAClC;AACF;;;ACtJA,SAAS,WAAW,OAA+B;AACjD,QAAM,YAAY,oBAAI,IAGpB;AACF,QAAM,aAAwB,CAAC;AAE/B,aAAW,QAAQ,MAAM,OAAO;AAC9B,UAAM,UAAU,UAAU,KAAK,EAAE;AACjC,eAAW,KAAK,OAAO;AAGvB,cAAU,IAAI,SAAS,EAAE,gBAAgB,CAAC,GAAG,YAAY,CAAC,EAAE,CAAC;AAAA,EAC/D;AAEA,aAAW,QAAQ,MAAM,OAAO;AAC9B,UAAM,OAAO,KAAK,MAAM;AACxB,QAAI,SAAS,OAAQ;AACrB,UAAM,cAAc,UAAU,IAAI,UAAU,KAAK,MAAM,CAAC;AACxD,QAAI,CAAC,YAAa;AAKlB,UAAM,SAAS,UAAU,KAAK,MAAM;AACpC,QAAI,CAAC,UAAU,IAAI,MAAM,EAAG;AAC5B,QAAI,SAAS,iBAAiB,SAAS,mBAAmB;AACxD,kBAAY,eAAe,KAAK,MAAM;AAAA,IACxC,OAAO;AAEL,kBAAY,WAAW,KAAK,MAAM;AAAA,IACpC;AAAA,EACF;AAEA,SAAO,EAAE,WAAW,WAAW;AACjC;AAIA,SAAS,SAAS,OAAmB,aAAuC;AAC1E,MAAI,aAAa;AACf,UAAM,IAAI,MAAM,MAAM,KAAK,CAACC,OAAMA,GAAE,OAAO,WAAW;AACtD,WAAO,IAAI,UAAU,EAAE,EAAE,IAAI;AAAA,EAC/B;AACA,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,KAAK,MAAM,OAAO;AAC3B,QAAI,EAAE,MAAM,SAAS,OAAQ,aAAY,IAAI,EAAE,MAAM;AAAA,EACvD;AACA,QAAM,OAAO,MAAM,MAAM,KAAK,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC,KAAK,MAAM,MAAM,CAAC;AAC7E,SAAO,OAAO,UAAU,KAAK,EAAE,IAAI;AACrC;AAMA,SAAS,aACP,SACA,OAC+C;AAC/C,QAAM,YAAY,oBAAI,IAAa,CAAC,OAAO,CAAC;AAC5C,QAAM,QAAmB,CAAC,OAAO;AACjC,QAAM,QAAmB,CAAC,OAAO;AACjC,MAAI,OAAO;AACX,SAAO,OAAO,MAAM,QAAQ;AAC1B,UAAM,MAAM,MAAM,MAAM;AACxB,UAAM,QAAQ,MAAM,UAAU,IAAI,GAAG;AACrC,QAAI,CAAC,MAAO;AACZ,eAAW,QAAQ,CAAC,GAAG,MAAM,gBAAgB,GAAG,MAAM,UAAU,GAAG;AACjE,UAAI,UAAU,IAAI,IAAI,EAAG;AACzB,gBAAU,IAAI,IAAI;AAClB,YAAM,KAAK,IAAI;AACf,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AACA,SAAO,EAAE,OAAO,UAAU;AAC5B;AAYA,SAAS,gBACP,UACA,OACgB;AAChB,MAAI,SAAS,SAAS,EAAG,QAAO;AAGhC,QAAM,YAAY,aAAa,SAAS,CAAC,GAAI,KAAK;AAClD,QAAM,gBAAgC,CAAC,UAAU,SAAS;AAC1D,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,kBAAc,KAAK,aAAa,SAAS,CAAC,GAAI,KAAK,EAAE,SAAS;AAAA,EAChE;AAGA,QAAM,WAAW,IAAI,IAAI,QAAQ;AACjC,aAAW,aAAa,UAAU,OAAO;AACvC,QAAI,SAAS,IAAI,SAAS,EAAG;AAC7B,QAAI,cAAc,MAAM,CAAC,MAAM,EAAE,IAAI,SAAS,CAAC,GAAG;AAChD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAeA,SAAS,UACP,SACA,SACA,OACA,SACuB;AACvB,QAAM,QAA0B,CAAC;AACjC,MAAI,MAAsB;AAC1B,SAAO,QAAQ,QAAQ,QAAQ,SAAS;AACtC,QAAI,QAAQ,IAAI,GAAG,EAAG;AACtB,YAAQ,IAAI,GAAG;AACf,UAAM,QAAQ,MAAM,UAAU,IAAI,GAAG;AACrC,QAAI,CAAC,MAAO;AAEZ,UAAM,WAAW,MAAM;AACvB,UAAM,cAAc,MAAM;AAI1B,UAAM,KAAK,EAAE,MAAM,QAAQ,SAAS,IAAI,CAAC;AAEzC,QAAI,SAAS,UAAU,GAAG;AAExB,YAAM,cAAc,gBAAgB,UAAU,KAAK;AACnD,YAAM,eAAiC,CAAC;AACxC,iBAAW,KAAK,UAAU;AAQxB,cAAM,gBAAgB,IAAI,IAAI,OAAO;AACrC,cAAM,MAAM,UAAU,GAAG,aAAa,OAAO,aAAa;AAC1D,YAAI,QAAQ,KAAM,cAAa,KAAK,GAAG;AACvC,mBAAWC,MAAK,cAAe,SAAQ,IAAIA,EAAC;AAAA,MAC9C;AACA,UAAI,aAAa,SAAS,GAAG;AAC3B,cAAM,KAAK,EAAE,MAAM,YAAY,UAAU,aAAa,CAAC;AAAA,MACzD;AACA,YAAM;AAAA,IACR,WAAW,SAAS,WAAW,KAAK,YAAY,WAAW,GAAG;AAE5D,YAAM,SAAS,CAAC;AAAA,IAClB,WAAW,YAAY,UAAU,GAAG;AAKlC,UAAI,YAAY,SAAS,GAAG;AAC1B;AAAA,UACE,MACE,iCAAiC,GAAG,SAAS,YAAY,MAAM,oEAAoE,YAAY,CAAC,CAAC;AAAA,QACrJ;AAAA,MACF;AACA,YAAM,YAAY,CAAC;AAAA,IACrB,OAAO;AAEL,YAAM;AAAA,IACR;AAAA,EACF;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,MAAI,MAAM,WAAW,EAAG,QAAO,MAAM,CAAC;AACtC,SAAO,EAAE,MAAM,UAAU,MAAM;AACjC;AAiBO,SAAS,qBACd,OACA,UAA4B,CAAC,GACN;AACvB,MAAI,MAAM,MAAM,WAAW,EAAG,QAAO;AACrC,QAAM,QAAQ,WAAW,KAAK;AAC9B,QAAM,OAAO,SAAS,OAAO,QAAQ,WAAW;AAChD,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,UAAU,oBAAI,IAAa;AACjC,SAAO,UAAU,MAAM,MAAM,OAAO,OAAO;AAC7C;AAoBO,SAAS,qBACd,OACA,YACA,UAA4B,CAAC,GACT;AACpB,QAAM,aAAa,qBAAqB,OAAO,OAAO;AACtD,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,mBAAmB,oBAAI,IAA2B;AACxD,aAAW,KAAK,WAAW,SAAS;AAClC,UAAM,OAAO,iBAAiB,IAAI,EAAE,OAAO,KAAK,CAAC;AACjD,SAAK,KAAK,CAAC;AACX,qBAAiB,IAAI,EAAE,SAAS,IAAI;AAAA,EACtC;AACA,SAAO,SAAS,YAAY,gBAAgB;AAC9C;AAEA,SAAS,SACP,MACA,kBACa;AACb,MAAI,KAAK,SAAS,QAAQ;AACxB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,KAAK;AAAA,MACd,SAAS,iBAAiB,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IAClD;AAAA,EACF;AACA,MAAI,KAAK,SAAS,UAAU;AAC1B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,KAAK,MAAM,IAAI,CAAC,MAAM,SAAS,GAAG,gBAAgB,CAAC;AAAA,IAC5D;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU,KAAK,SAAS,IAAI,CAAC,MAAM,SAAS,GAAG,gBAAgB,CAAC;AAAA,EAClE;AACF;;;AC5SM,IAAAC,uBAAA;AAXC,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,yBAAyB;AAAA,EACzB;AAAA,EACA;AAAA,EACA,2BAA2B;AAAA,EAC3B;AAAA,EACA;AACF,GAAyB;AACvB,MAAI,CAAC,OAAO;AACV,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,MAAM;AAAA,UACb,WAAW;AAAA,UACX,GAAG;AAAA,QACL;AAAA,QACD;AAAA;AAAA,IAED;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,MAAM;AAAA,QACb,UAAU;AAAA,QACV,UAAU;AAAA,QACV,GAAG;AAAA,MACL;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,YAAY,CAAC,SACX;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA;AAAA,UACF;AAAA;AAAA,MAEJ;AAAA;AAAA,EACF;AAEJ;AAYA,SAAS,WAAW,EAAE,MAAM,WAAW,GAAwC;AAC7E,MAAI,KAAK,SAAS,QAAQ;AACxB,WAAO,+EAAG,qBAAW,IAAI,GAAE;AAAA,EAC7B;AAEA,MAAI,KAAK,SAAS,UAAU;AAC1B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,SAAS;AAAA,UACT,eAAe;AAAA,UACf,YAAY;AAAA,UACZ,KAAK;AAAA,QACP;AAAA,QAEC,eAAK,MAAM,IAAI,CAAC,OAAO,MACtB;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,YAAY,SAAS;AAAA,YAExE;AAAA,4DAAC,cAAW,MAAM,OAAO,YAAwB;AAAA,cAChD,IAAI,KAAK,MAAM,SAAS,KAAK,8CAAC,aAAU,aAAY,YAAW;AAAA;AAAA;AAAA,UAJ3D,SAAS,OAAO,CAAC;AAAA,QAKxB,CACD;AAAA;AAAA,IACH;AAAA,EAEJ;AAGA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe;AAAA,QACf,YAAY;AAAA,QACZ,KAAK;AAAA,MACP;AAAA,MAEA;AAAA,sDAAC,cAAW;AAAA,QACZ;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,SAAS;AAAA,cACT,eAAe;AAAA,cACf,YAAY;AAAA,cACZ,KAAK;AAAA,cACL,SAAS;AAAA,cACT,YAAY,cAAc,MAAM,MAAM;AAAA,cACtC,aAAa,cAAc,MAAM,MAAM;AAAA,cACvC,aAAa;AAAA,cACb,cAAc;AAAA,YAChB;AAAA,YAEC,eAAK,SAAS,IAAI,CAAC,QAAQ,MAC1B;AAAA,cAAC;AAAA;AAAA,gBAEC,OAAO;AAAA,kBACL,SAAS;AAAA,kBACT,eAAe;AAAA,kBACf,YAAY;AAAA,kBACZ,UAAU;AAAA,gBACZ;AAAA,gBAEA,wDAAC,cAAW,MAAM,QAAQ,YAAwB;AAAA;AAAA,cAR7C,SAAS,QAAQ,CAAC;AAAA,YASzB,CACD;AAAA;AAAA,QACH;AAAA,QACA,8CAAC,cAAW;AAAA;AAAA;AAAA,EACd;AAEJ;AAQA,SAAS,SAAS,MAAgB,eAA+B;AAC/D,QAAM,OAAO,YAAY,IAAI;AAC7B,SAAO,OAAO,GAAG,KAAK,IAAI,IAAI,KAAK,OAAO,KAAK,GAAG,KAAK,IAAI,OAAO,aAAa;AACjF;AAEA,SAAS,YAAY,MAAgC;AACnD,MAAI,KAAK,SAAS,OAAQ,QAAO;AACjC,MAAI,KAAK,SAAS,UAAU;AAC1B,eAAW,QAAQ,KAAK,OAAO;AAC7B,YAAM,IAAI,YAAY,IAAI;AAC1B,UAAI,EAAG,QAAO;AAAA,IAChB;AACA,WAAO;AAAA,EACT;AACA,aAAW,UAAU,KAAK,UAAU;AAClC,UAAM,IAAI,YAAY,MAAM;AAC5B,QAAI,EAAG,QAAO;AAAA,EAChB;AACA,SAAO;AACT;AAIA,SAAS,KAAK;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,QAAQ,eAAe,aAAa,KAAK,OAAO,IAAI,KAAK;AAC/D,QAAM,UACJ,aAAa,OAAO,KAAK,UAAU,CAAC;AAEtC,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,GAAG;AAAA,UACH,aAAa;AAAA,UACb,OAAO,MAAM;AAAA,UACb,YAAY;AAAA,QACd;AAAA,QACA,OAAO,GAAG,KAAK,OAAO;AAAA,QAEtB;AAAA,wDAAC,SAAI,OAAO,EAAE,YAAY,IAAI,GAAI,iBAAM;AAAA,UACxC,8CAAC,SAAI,OAAO,EAAE,UAAU,IAAI,WAAW,SAAS,GAAG,0BAAY;AAAA;AAAA;AAAA,IACjE;AAAA,EAEJ;AAEA,SACE,8CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,YAAY,UAAU,KAAK,EAAE,GAClF,kBAAQ,IAAI,CAAC,GAAG,MAAM;AACrB,UAAM,aAAa,EAAE,mBAAmB;AACxC,UAAM,YAAY,mBAAmB;AAQrC,UAAM,aACJ,6BAA6B,QAC7B,EAAE,aAAa;AACjB,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,SAAS,YAAY,MAAM,eAAe,EAAE,cAAc,IAAI;AAAA,QAC9D,OAAO;AAAA,UACL,GAAG;AAAA,UACH,QAAQ,YAAY,YAAY;AAAA,UAChC,aAAa,aAAa,MAAM,UAAU,MAAM;AAAA,UAChD,aAAa,aAAa,IAAI;AAAA,UAC9B,YAAY,aAAa,yBAAyB;AAAA,UAClD,OAAO,MAAM;AAAA,UACb,WAAW;AAAA,UACX,YAAY;AAAA,UACZ,SAAS;AAAA,UACT,SAAS,aAAa,IAAI;AAAA,QAC5B;AAAA,QACA,iBAAe,CAAC;AAAA,QAChB,gBAAc,aAAa,SAAS;AAAA,QACpC,OAAO,EAAE;AAAA,QAET;AAAA,yDAAC,SAAI,OAAO,EAAE,YAAY,IAAI,GAC3B;AAAA;AAAA,YACA,QAAQ,SAAS,KAChB,+CAAC,UAAK,OAAO,EAAE,OAAO,MAAM,WAAW,YAAY,KAAK,YAAY,EAAE,GAAG;AAAA;AAAA,cACjE,IAAI;AAAA,cAAE;AAAA,cAAE,QAAQ;AAAA,eACxB;AAAA,aAEJ;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,OAAO,MAAM;AAAA,gBACb,WAAW;AAAA,cACb;AAAA,cACD;AAAA;AAAA,gBACG,EAAE;AAAA,gBAAU;AAAA,gBAAI,EAAE;AAAA;AAAA;AAAA,UACtB;AAAA;AAAA;AAAA,MApCK,EAAE;AAAA,IAqCT;AAAA,EAEJ,CAAC,GACH;AAEJ;AAIA,SAAS,UAAU,EAAE,YAAY,GAA+C;AAC9E,SAAO,gBAAgB,aACrB;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,MACX,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,YAAY,MAAM;AAAA,MACpB;AAAA;AAAA,EACF,IAEA;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,MACX,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,YAAY,MAAM;AAAA,MACpB;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,aAAa;AACpB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,MACX,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,YAAY,MAAM;AAAA,QAClB,QAAQ;AAAA,MACV;AAAA;AAAA,EACF;AAEJ;AAEA,IAAM,eAAoC;AAAA,EACxC,SAAS;AAAA,EACT,UAAU;AAAA,EACV,SAAS;AAAA,EACT,QAAQ,aAAa,MAAM,MAAM;AAAA,EACjC,cAAc;AAAA,EACd,UAAU;AAAA,EACV,OAAO,MAAM;AAAA,EACb,YAAY;AACd;;;ACrSA,IAAAC,iBAA+C;;;ACnE/C,IAAAC,iBAAqC;AAsET,IAAAC,uBAAA;AAtCrB,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,QAAM,QAAQ,MAAM,QAAQ;AAI5B,QAAM,sBAAkB,wBAAgB,MAAM;AAC5C,QAAI,CAAC,qBAAsB,QAAO;AAClC,UAAM,OAAO,MAAM,iBAAiB,IAAI,oBAAoB;AAC5D,WAAO,OAAO,KAAK,YAAY;AAAA,EACjC,GAAG,CAAC,OAAO,oBAAoB,CAAC;AAEhC,QAAM,yBAAqB;AAAA,IACzB,CAAC,MAA2C;AAC1C,YAAM,QAAQ,OAAO,EAAE,OAAO,KAAK;AACnC,YAAM,OAAO,MAAM,QAAQ,KAAK;AAChC,qBAAe,OAAO,KAAK,iBAAiB,IAAI;AAAA,IAClD;AAAA,IACA,CAAC,OAAO,cAAc;AAAA,EACxB;AAEA,QAAM,YAAQ,wBAAQ,MAAM;AAC1B,UAAM,SAAS,MAAM,QAAQ,eAAe,KAAK;AACjD,UAAM,OAAO,wBAAwB,QAAQ,kBAAkB;AAC/D,QAAI;AACF,aAAO,YAAY;AAAA,QACjB,WAAW;AAAA,QACX;AAAA,QACA,gBAAgB;AAAA,QAChB;AAAA,QACA;AAAA,MACF,CAAC;AACH,QAAI,UAAU,EAAG,QAAO,8CAAC,UAAK,OAAO,EAAE,OAAO,MAAM,UAAU,GAAG,4BAAc;AAC/E,WACE,+CAAC,UAAK,OAAO,EAAE,YAAY,aAAa,UAAU,IAAI,OAAO,MAAM,cAAc,GAAG;AAAA;AAAA,MAChF,kBAAkB;AAAA,MAAE;AAAA,MAAI;AAAA,MAAM;AAAA,MAAI,QAAQ,kBAAkB;AAAA,OAChE;AAAA,EAEJ,GAAG,CAAC,aAAa,iBAAiB,OAAO,OAAO,oBAAoB,CAAC;AAIrE,QAAM,WAAW,QAAQ;AAEzB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,SAAS;AAAA,QACT,YAAY,MAAM;AAAA,QAClB,QAAQ,aAAa,MAAM,MAAM;AAAA,QACjC,cAAc;AAAA,QACd,GAAG;AAAA,MACL;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,eAAe;AAAA,cACf,OAAO,MAAM;AAAA,YACf;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,KAAK;AAAA,YACL,KAAK,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,YAC1B,MAAM;AAAA,YACN,OAAO,KAAK,IAAI,iBAAiB,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,YACvD,UAAU;AAAA,YACV;AAAA,YACA,cAAW;AAAA,YACX,iBAAe;AAAA,YACf,iBAAe,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,YACpC,iBAAe;AAAA,YACf,kBACE,UAAU,IAAI,eAAe,UAAU,kBAAkB,CAAC,OAAO,KAAK;AAAA,YAExE,OAAO,EAAE,MAAM,GAAG,aAAa,MAAM,QAAQ;AAAA;AAAA,QAC/C;AAAA,QACA,8CAAC,SAAI,OAAO,EAAE,UAAU,KAAK,WAAW,QAAQ,GAAI,iBAAM;AAAA;AAAA;AAAA,EAC5D;AAEJ;;;AD6JI,IAAAC,uBAAA;AAlHG,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA,wBAAwB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAE1B,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAgC,IAAI;AAC1E,QAAM,eAAe,kBAAkB;AACvC,QAAM,yBAAyB,eAAe,gBAAgB;AAE9D,QAAM,mBAAe;AAAA,IACnB,CAAC,SAAgC;AAC/B,UAAI,CAAC,aAAc,gBAAe,IAAI;AAItC,0BAAoB,IAAI;AAAA,IAC1B;AAAA,IACA,CAAC,cAAc,iBAAiB;AAAA,EAClC;AACA,QAAM,yBAAqB;AAAA,IACzB,CAAC,SAAyB,aAAa,IAAI;AAAA,IAC3C,CAAC,YAAY;AAAA,EACf;AAQA,QAAM,sBAAkB,wBAAwB,MAAM;AACpD,QAAI,CAAC,uBAAwB,QAAO;AACpC,UAAM,UAAU,uBAAuB,YAAY,GAAG;AAEtD,QAAI,WAAW,EAAG,QAAO;AACzB,WAAO,UAAU,uBAAuB,MAAM,GAAG,OAAO,CAAC;AAAA,EAC3D,GAAG,CAAC,sBAAsB,CAAC;AAK3B,QAAM,gBAAY;AAAA,IAChB,MAAM,OAAO,SAAS;AAAA,IACtB,CAAC,OAAO,KAAK;AAAA,EACf;AACA,QAAM,iBAAa;AAAA,IACjB,MAAM,OAAO,mBAAmB;AAAA,IAChC,CAAC,OAAO,eAAe;AAAA,EACzB;AACA,QAAM,eAAW;AAAA,IACf,MAAM,OAAO,iBAAiB;AAAA,IAC9B,CAAC,OAAO,aAAa;AAAA,EACvB;AAIA,QAAM,iBAAa,wBAAqD,MAAM;AAC5E,QAAI,SAAS,YAAY,OAAO;AAC9B,aAAO,MAAM,UAAU;AAAA,IACzB;AACA,WAAO;AAAA,EACT,GAAG,CAAC,KAAK,CAAC;AAKV,QAAM,QAAQ;AAAA,IAAc,OAAO;AAAA,IAAY,MAC7C,qBAAqB,OAAO,UAAU,SAAS,GAAG,OAAO,WAAW,SAAS,CAAC;AAAA,EAChF;AACA,QAAM,cAAc;AAAA,IAAc,OAAO;AAAA,IAAY,MACnD,OAAO,WAAW,SAAS;AAAA,EAC7B;AACA,QAAM,YAAY,cAAc,OAAO,UAAU,MAAM,OAAO,SAAS,SAAS,CAAC;AAMjF,QAAM,0BAAsB;AAAA,IAC1B,CAAC,YAAqB;AACpB,YAAM,aAAa,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,OAAO;AAC1E,YAAM,QAAQ,WAAW,CAAC;AAC1B,mBAAa,QAAQ,MAAM,iBAAiB,IAAI;AAAA,IAClD;AAAA,IACA,CAAC,aAAa,YAAY;AAAA,EAC5B;AAWA,QAAM,+BAA2B,wBAAuB,MAAM;AAC5D,QAAI,CAAC,uBAAwB,QAAO;AACpC,UAAM,OAAO,YAAY,iBAAiB,IAAI,sBAAsB;AACpE,WAAO,OAAO,KAAK,YAAY;AAAA,EACjC,GAAG,CAAC,wBAAwB,WAAW,CAAC;AAIxC,QAAM,kBAAc;AAAA,IAClB,MAAO,aAAa,0BAA0B;AAAA,IAC9C,CAAC,UAAU;AAAA,EACb;AAEA,SACE,+CAAC,SAAI,WAAsB,OAAO,EAAE,GAAG,aAAa,GAAG,MAAM,GAC1D;AAAA,kBACC,8CAAC,QAAK,MAAK,UACT;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,sBAAsB;AAAA,QACtB,gBAAgB;AAAA;AAAA,IAClB,GACF;AAAA,IAEF,8CAAC,QAAK,MAAK,SACT;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,gBAAgB;AAAA,QAChB;AAAA;AAAA,IACF,GACF;AAAA,IACA,8CAAC,QAAK,MAAK,UACT;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP;AAAA,QACA,YAAY;AAAA;AAAA,IACd,GACF;AAAA,IACA,8CAAC,QAAK,MAAK,QACT;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP;AAAA,QACA,YAAY;AAAA;AAAA,IACd,GACF;AAAA,KACF;AAEJ;AAIA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,GAA6B;AAC3B,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,gBAAgB,EAAE,OAAO,iBAAiB,WAAW,GAA2B;AACvF,SACE,8CAAC,iBAAc,OAAc,YAAY,iBAAiB,YAAwB;AAEtF;AAEA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;AAIA,IAAM,0BAAyC;AAAA,EAC7C,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,KAAK;AAAA,EACL,SAAS;AAAA,EACT,YAAY,MAAM;AAAA,EAClB,OAAO,MAAM;AACf;AAEA,IAAM,wBAAuC;AAAA,EAC3C,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,KAAK;AAAA,EACL,SAAS;AAAA,EACT,YAAY,MAAM;AAAA,EAClB,OAAO,MAAM;AACf;AAEA,IAAM,kBAAiC;AAAA,EACrC,QAAQ,aAAa,MAAM,MAAM;AAAA,EACjC,cAAc;AAAA,EACd,YAAY,MAAM;AAAA,EAClB,UAAU;AAAA,EACV,WAAW;AAAA;AACb;AAEA,SAAS,KAAK,EAAE,MAAM,SAAS,GAAgD;AAG7E,SACE,8CAAC,SAAI,MAAK,UAAS,cAAY,MAAM,OAAO,EAAE,GAAG,iBAAiB,UAAU,KAAK,GAC9E,UACH;AAEJ;","names":["import_react","import_react","import_jsx_runtime","StageNode","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","v","v","import_react","import_react","padding","import_jsx_runtime","import_jsx_runtime","DEFAULT_NODE_TYPES","import_jsx_runtime","import_react","import_jsx_runtime","SubflowBreadcrumb","import_react","EMPTY_GRAPH","import_react","import_jsx_runtime","TreeNode","SectionLabel","SubflowTree","baseStageIdOf","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","Section","v","n","v","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime"]}