footprint-explainable-ui 0.3.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/flowchart.ts","../src/components/FlowchartView/FlowchartView.tsx","../src/components/StageNode/StageNode.tsx","../src/theme/ThemeProvider.tsx","../src/theme/tokens.ts","../src/theme/styles.ts","../src/components/FlowchartView/SubflowBreadcrumb.tsx","../src/components/FlowchartView/useSubflowNavigation.ts","../src/components/FlowchartView/specToReactFlow.ts","../src/components/TimeTravelDebugger/TimeTravelDebugger.tsx","../src/components/MemoryInspector/MemoryInspector.tsx","../src/components/NarrativeLog/NarrativeLog.tsx","../src/components/GanttTimeline/GanttTimeline.tsx"],"sourcesContent":["// Flowchart components (require @xyflow/react peer dependency)\n// Import from \"footprint-explainable-ui/flowchart\"\n\nexport { FlowchartView } from \"./components/FlowchartView\";\nexport type { FlowchartViewProps } from \"./components/FlowchartView\";\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\nexport { specToReactFlow } from \"./components/FlowchartView/specToReactFlow\";\nexport type {\n SpecNode,\n ExecutionOverlay,\n FlowchartColors,\n} from \"./components/FlowchartView/specToReactFlow\";\n\n// Subflow drill-down navigation\nexport { SubflowBreadcrumb } from \"./components/FlowchartView\";\nexport type { SubflowBreadcrumbProps } from \"./components/FlowchartView\";\nexport { useSubflowNavigation } from \"./components/FlowchartView\";\nexport type { SubflowNavigation, BreadcrumbEntry } from \"./components/FlowchartView\";\n","import { useMemo, useCallback } from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n useNodesState,\n useEdgesState,\n} from \"@xyflow/react\";\nimport type { Node, Edge } from \"@xyflow/react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { StageNode } from \"../StageNode\";\nimport type { StageNodeData } from \"../StageNode\";\nimport { theme } from \"../../theme\";\n\nexport interface FlowchartViewProps extends BaseComponentProps {\n /** ReactFlow nodes */\n nodes: Node[];\n /** ReactFlow edges */\n edges: Edge[];\n /** Optional snapshots for state-aware rendering (done/active coloring) */\n snapshots?: StageSnapshot[];\n /** Currently selected snapshot index (for state coloring) */\n selectedIndex?: number;\n /** Callback when a node is clicked */\n onNodeClick?: (index: number) => void;\n}\n\nconst nodeTypes = { stageNode: StageNode };\n\n/**\n * Pipeline flowchart visualization using ReactFlow.\n * When snapshots are provided, nodes are colored by execution state.\n */\nexport function FlowchartView({\n nodes: rawNodes,\n edges: rawEdges,\n snapshots,\n selectedIndex = 0,\n onNodeClick,\n unstyled = false,\n className,\n style,\n}: FlowchartViewProps) {\n // Enhance nodes with execution state\n const enhancedNodes = useMemo(() => {\n if (!snapshots || snapshots.length === 0) {\n return rawNodes.map((n) => ({\n ...n,\n type: \"stageNode\",\n data: {\n ...n.data,\n label: (n.data as StageNodeData).label || n.id,\n active: false,\n done: false,\n error: false,\n },\n }));\n }\n\n const doneNames = new Set(\n snapshots.slice(0, selectedIndex).map((s) => s.stageName)\n );\n const activeName = snapshots[selectedIndex]?.stageName;\n\n return rawNodes.map((n) => ({\n ...n,\n type: \"stageNode\",\n data: {\n ...n.data,\n label: (n.data as StageNodeData).label || n.id,\n active: n.id === activeName,\n done: doneNames.has(n.id),\n error: false,\n },\n }));\n }, [rawNodes, snapshots, selectedIndex]);\n\n // Enhance edges with state coloring\n const enhancedEdges = useMemo(() => {\n if (!snapshots || snapshots.length === 0) {\n return rawEdges.map((e) => ({\n ...e,\n style: { stroke: theme.textMuted, strokeWidth: 1.5 },\n animated: false,\n }));\n }\n\n const doneNames = new Set(\n snapshots.slice(0, selectedIndex + 1).map((s) => s.stageName)\n );\n const activeName = snapshots[selectedIndex]?.stageName;\n\n return rawEdges.map((e) => {\n const sourceIsDone = doneNames.has(e.source);\n const isFromActive = e.source === activeName;\n return {\n ...e,\n style: {\n stroke: sourceIsDone ? theme.success : theme.textMuted,\n strokeWidth: 1.5,\n },\n animated: isFromActive,\n };\n });\n }, [rawEdges, snapshots, selectedIndex]);\n\n const [nodes, , onNodesChange] = useNodesState(enhancedNodes);\n const [edges, , onEdgesChange] = useEdgesState(enhancedEdges);\n\n const handleNodeClick = useCallback(\n (_: unknown, node: Node) => {\n if (!onNodeClick || !snapshots) return;\n const idx = snapshots.findIndex((s) => s.stageName === node.id);\n if (idx >= 0) onNodeClick(idx);\n },\n [onNodeClick, snapshots]\n );\n\n return (\n <div\n className={className}\n style={{\n width: \"100%\",\n height: \"100%\",\n ...style,\n }}\n data-fp=\"flowchart-view\"\n >\n <ReactFlow\n nodes={nodes}\n edges={edges}\n onNodesChange={onNodesChange}\n onEdgesChange={onEdgesChange}\n onNodeClick={handleNodeClick}\n nodeTypes={nodeTypes}\n fitView\n panOnDrag={false}\n zoomOnScroll={false}\n zoomOnPinch={false}\n zoomOnDoubleClick={false}\n preventScrolling={false}\n nodesDraggable={false}\n nodesConnectable={false}\n elementsSelectable={!!onNodeClick}\n >\n {!unstyled && (\n <Background variant={BackgroundVariant.Dots} gap={16} size={1} />\n )}\n </ReactFlow>\n </div>\n );\n}\n","import { memo } from \"react\";\nimport { Handle, Position } from \"@xyflow/react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport { theme } from \"../../theme\";\n\nexport interface StageNodeData {\n label: string;\n active?: boolean;\n done?: boolean;\n error?: boolean;\n linked?: boolean;\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 [key: string]: unknown;\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, stepNumbers, dimmed, isSubflow } = data;\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: `calc(${theme.radius} + 4px)`,\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: `calc(${theme.radius} + 4px)`,\n border: `2px solid ${theme.primary}`,\n opacity: 0.3,\n animation: \"fp-pulse 1.5s ease-out infinite\",\n }}\n />\n )}\n\n <div\n style={{\n background: bg,\n border: `2px solid ${borderColor}`,\n borderRadius: theme.radius,\n padding: \"10px 20px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n boxShadow: shadow,\n transition: \"all 0.3s ease\",\n fontFamily: theme.fontSans,\n minWidth: 100,\n justifyContent: \"center\",\n }}\n >\n {/* State icon */}\n {done && (\n <span style={{ fontSize: 10, color: textColor }}>&#x2713;</span>\n )}\n {active && (\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 && (\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 </div>\n <Handle type=\"source\" position={Position.Bottom} style={{ opacity: 0 }} />\n {/* Right-side handles for loop-back edges (so they don't overlap center edges) */}\n <Handle\n id=\"loop-source\"\n type=\"source\"\n position={Position.Right}\n style={{ background: \"transparent\", border: \"none\", width: 6, height: 6 }}\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 */\nexport function FootprintTheme({ tokens = {}, children }: FootprintThemeProps) {\n const cssVars = tokensToCSSVars(tokens);\n\n return (\n <ThemeContext.Provider value={tokens}>\n <div style={cssVars as React.CSSProperties} className=\"fp-theme-root\">\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/** Default dark theme values (used as CSS variable fallbacks). */\nexport const defaultTokens: Required<{\n [K in keyof ThemeTokens]-?: Required<ThemeTokens[K]>;\n}> = {\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};\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","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={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\n style={{\n color: theme.primary,\n fontWeight: 600,\n }}\n >\n {crumb.label}\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","import { useState, useCallback, useMemo } from \"react\";\nimport { specToReactFlow } from \"./specToReactFlow\";\nimport type { SpecNode, ExecutionOverlay, FlowchartColors } from \"./specToReactFlow\";\nimport type { Node, Edge } from \"@xyflow/react\";\n\nexport interface BreadcrumbEntry {\n /** Display name for this level */\n label: string;\n /** The spec node tree at this level */\n spec: SpecNode;\n}\n\nexport interface SubflowNavigation {\n /** Current breadcrumb path (root → ... → current) */\n breadcrumbs: BreadcrumbEntry[];\n /** Current level's ReactFlow nodes */\n nodes: Node[];\n /** Current level's ReactFlow edges */\n edges: Edge[];\n /** Call when a node is clicked — drills in if it's a subflow */\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 /** Name of the subflow node we drilled into (for finding execution data) */\n currentSubflowNodeName: string | null;\n}\n\n/**\n * Hook that manages subflow drill-down navigation for a flowchart spec.\n *\n * Maintains a breadcrumb stack. When a subflow node is clicked, pushes its\n * nested spec onto the stack and re-derives nodes/edges. Breadcrumb clicks\n * pop back to that level.\n */\nexport function useSubflowNavigation(\n rootSpec: SpecNode | null,\n overlay?: ExecutionOverlay,\n colors?: Partial<FlowchartColors>\n): SubflowNavigation {\n const [stack, setStack] = useState<BreadcrumbEntry[]>([]);\n\n // Current spec = top of stack, or root\n const currentSpec = stack.length > 0 ? stack[stack.length - 1].spec : rootSpec;\n\n // Derive nodes/edges from current spec\n // Overlay is always passed through — consumer provides the appropriate overlay\n // (root overlay at root level, subflow overlay when drilled in)\n const { nodes, edges } = useMemo(() => {\n if (!currentSpec) return { nodes: [], edges: [] };\n return specToReactFlow(currentSpec, overlay, colors);\n }, [currentSpec, overlay, colors]);\n\n // Build a lookup of subflow nodes at the current level\n const subflowMap = useMemo(() => {\n const map = new Map<string, SpecNode>();\n if (!currentSpec) return map;\n\n function collectSubflows(node: SpecNode) {\n if (node.isSubflowRoot && node.subflowStructure) {\n const id = node.name || node.id || \"\";\n map.set(id, node);\n }\n if (node.children) node.children.forEach(collectSubflows);\n if (node.next) collectSubflows(node.next);\n }\n collectSubflows(currentSpec);\n return map;\n }, [currentSpec]);\n\n const breadcrumbs: BreadcrumbEntry[] = useMemo(() => {\n const root: BreadcrumbEntry = {\n label: rootSpec?.name || \"Pipeline\",\n spec: rootSpec!,\n };\n return [root, ...stack];\n }, [rootSpec, stack]);\n\n const handleNodeClick = useCallback(\n (nodeId: string): boolean => {\n const subflowNode = subflowMap.get(nodeId);\n if (!subflowNode?.subflowStructure) return false;\n\n setStack((prev) => [\n ...prev,\n {\n label: subflowNode.subflowName || subflowNode.name,\n spec: subflowNode.subflowStructure!,\n },\n ]);\n return true;\n },\n [subflowMap]\n );\n\n const navigateTo = useCallback(\n (level: number) => {\n if (level === 0) {\n setStack([]);\n } else {\n setStack((prev) => prev.slice(0, level));\n }\n },\n []\n );\n\n return {\n breadcrumbs,\n nodes,\n edges,\n handleNodeClick,\n navigateTo,\n isInSubflow: stack.length > 0,\n currentSubflowNodeName: stack.length > 0 ? stack[0].label : null,\n };\n}\n","/**\n * Converts a SerializedPipelineStructure (from builder.toSpec()) into\n * ReactFlow nodes and edges with auto-layout.\n *\n * Supports two modes:\n * 1. Build-time only (no executionState) — all nodes gray\n * 2. With execution overlay — executed nodes colored, active node highlighted,\n * unvisited nodes stay gray\n */\nimport type { Node, Edge } from \"@xyflow/react\";\nimport { defaultTokens } from \"../../theme/tokens\";\n\nexport interface SpecNode {\n name: string;\n id?: string;\n type?: \"stage\" | \"decider\" | \"fork\" | \"streaming\";\n description?: string;\n children?: SpecNode[];\n next?: SpecNode;\n branchIds?: string[];\n hasDecider?: boolean;\n hasSelector?: boolean;\n loopTarget?: string;\n isSubflowRoot?: boolean;\n subflowId?: string;\n subflowName?: string;\n subflowStructure?: SpecNode;\n}\n\nexport interface ExecutionOverlay {\n /** Names of stages that have completed (before the active one) */\n doneStages: Set<string>;\n /** Name of the currently active stage */\n activeStage: string | null;\n /** Names of all stages that were executed (done + active) */\n executedStages: Set<string>;\n /** Ordered list of executed stage names (for step numbering) */\n executionOrder?: string[];\n}\n\n/** Colors for the flowchart — consumer provides these to match their theme */\nexport interface FlowchartColors {\n edgeDefault: string;\n edgeExecuted: string;\n edgeActive: string;\n edgeLoop: string;\n labelDefault: string;\n labelExecuted: string;\n labelLoop: string;\n pathGlow: string;\n}\n\n/** Default colors derived from theme tokens. Consumer can override per-call. */\nconst DEFAULT_COLORS: FlowchartColors = {\n edgeDefault: defaultTokens.colors.textMuted,\n edgeExecuted: defaultTokens.colors.success,\n edgeActive: defaultTokens.colors.primary,\n edgeLoop: defaultTokens.colors.warning,\n labelDefault: defaultTokens.colors.textSecondary,\n labelExecuted: defaultTokens.colors.success,\n labelLoop: defaultTokens.colors.warning,\n pathGlow: `${defaultTokens.colors.success}4D`, // ~30% opacity hex\n};\n\ninterface LayoutState {\n nodes: Node[];\n edges: Edge[];\n edgeCounter: number;\n seen: Set<string>;\n overlay: ExecutionOverlay | null;\n colors: FlowchartColors;\n}\n\nconst Y_STEP = 100;\nconst X_SPREAD = 200;\n\nfunction nid(n: SpecNode): string {\n return n.name || n.id || `spec-${Math.random()}`;\n}\n\nfunction addEdge(\n state: LayoutState,\n source: string,\n target: string,\n label?: string,\n isLoop?: boolean\n) {\n state.edgeCounter++;\n const o = state.overlay;\n const c = state.colors;\n const executed =\n o && o.executedStages.has(source) && o.executedStages.has(target);\n const isLeadingEdge = o && source === o.activeStage && !o.doneStages.has(target);\n\n // Loop edges — route via right-side handles so they don't overlap center edges\n // Only mark as executed when the loop has actually fired:\n // the target must appear AFTER the source in executionOrder\n if (isLoop) {\n let loopExecuted = false;\n if (o?.executionOrder) {\n const lastSourceIdx = o.executionOrder.lastIndexOf(source);\n if (lastSourceIdx >= 0) {\n loopExecuted = o.executionOrder.slice(lastSourceIdx + 1).includes(target);\n }\n }\n\n state.edges.push({\n id: `se${state.edgeCounter}`,\n source,\n target,\n sourceHandle: \"loop-source\",\n targetHandle: \"loop-target\",\n label: label ?? \"loop\",\n type: \"smoothstep\",\n pathOptions: { offset: 40, borderRadius: 16 },\n style: {\n stroke: c.edgeLoop,\n strokeWidth: loopExecuted ? 3 : 2,\n strokeDasharray: \"6 3\",\n opacity: o && !loopExecuted ? 0.35 : 1,\n },\n labelStyle: { fontSize: 10, fontWeight: 700, fill: c.labelLoop },\n animated: loopExecuted,\n zIndex: 2,\n } as Edge);\n return;\n }\n\n if (executed) {\n // \"Google Maps route\" — thick glowing path for executed edges\n // Background glow layer (subtle, behind the route line)\n state.edges.push({\n id: `se${state.edgeCounter}-glow`,\n source,\n target,\n style: {\n stroke: c.pathGlow,\n strokeWidth: 8,\n opacity: 0.4,\n },\n zIndex: 0,\n selectable: false,\n focusable: false,\n });\n // Foreground path (solid route line)\n state.edges.push({\n id: `se${state.edgeCounter}`,\n source,\n target,\n label,\n style: {\n stroke: isLeadingEdge ? c.edgeActive : c.edgeExecuted,\n strokeWidth: 3.5,\n },\n labelStyle: { fontSize: 10, fontWeight: 600, fill: c.labelExecuted },\n animated: !!isLeadingEdge,\n zIndex: 1,\n });\n } else {\n // Non-executed — thin, faded base map edge\n state.edges.push({\n id: `se${state.edgeCounter}`,\n source,\n target,\n label,\n style: {\n stroke: c.edgeDefault,\n strokeWidth: 1.5,\n opacity: o ? 0.3 : 1,\n },\n labelStyle: { fontSize: 10, fill: c.labelDefault },\n });\n }\n}\n\nfunction walk(\n node: SpecNode,\n state: LayoutState,\n x: number,\n y: number\n): { lastIds: string[]; bottomY: number } {\n const id = nid(node);\n\n if (state.seen.has(id)) {\n return { lastIds: [id], bottomY: y };\n }\n state.seen.add(id);\n\n const isDecider = node.type === \"decider\" || node.hasDecider;\n const isFork = node.type === \"fork\";\n const o = state.overlay;\n\n const isDone = o ? o.doneStages.has(id) : false;\n const isActive = o ? o.activeStage === id : false;\n const wasExecuted = o ? o.executedStages.has(id) : false;\n // When overlay is present, dim unvisited nodes\n const dimmed = o && !wasExecuted;\n\n // Step numbers for executed nodes (1-based) — multiple when revisited via loops\n let stepNumbers: number[] | undefined;\n if (o?.executionOrder) {\n const nums: number[] = [];\n for (let i = 0; i < o.executionOrder.length; i++) {\n if (o.executionOrder[i] === id) nums.push(i + 1);\n }\n if (nums.length > 0) stepNumbers = nums;\n }\n\n state.nodes.push({\n id,\n position: { x, y },\n data: {\n label: node.name,\n active: isActive,\n done: isDone,\n error: false,\n isDecider,\n isFork,\n description: node.description,\n dimmed,\n stepNumbers,\n isSubflow: !!node.isSubflowRoot,\n },\n type: \"stage\",\n style: dimmed ? { opacity: 0.35 } : undefined,\n });\n\n let lastIds = [id];\n let bottomY = y;\n\n // Handle children (fork/decider branches)\n if (node.children && node.children.length > 0) {\n const totalWidth = (node.children.length - 1) * X_SPREAD;\n const startX = x - totalWidth / 2;\n const childY = y + Y_STEP;\n\n const childResults: { lastIds: string[]; bottomY: number }[] = [];\n\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const childX = startX + i * X_SPREAD;\n const edgeLabel = node.branchIds?.[i];\n addEdge(state, id, nid(child), edgeLabel);\n const result = walk(child, state, childX, childY);\n childResults.push(result);\n }\n\n lastIds = childResults.flatMap((r) => r.lastIds);\n bottomY = Math.max(...childResults.map((r) => r.bottomY));\n }\n\n // Handle loop-back edge — visually distinct dashed orange arrow\n // Must be added before processing `next`, since `next` returns early\n if (node.loopTarget) {\n addEdge(state, id, node.loopTarget, \"loop\", true);\n }\n\n // Handle linear continuation\n if (node.next) {\n const nextY = bottomY + Y_STEP;\n const nextId = nid(node.next);\n for (const lid of lastIds) {\n // Skip forward edge when a loop edge already connects to the same target\n if (node.loopTarget && lid === id && node.loopTarget === nextId) continue;\n addEdge(state, lid, nextId);\n }\n const result = walk(node.next, state, x, nextY);\n return result;\n }\n\n return { lastIds, bottomY };\n}\n\n/**\n * Convert a pipeline spec to ReactFlow graph.\n * Pass `overlay` to color nodes/edges by execution state.\n */\nexport function specToReactFlow(\n spec: SpecNode,\n overlay?: ExecutionOverlay,\n colors?: Partial<FlowchartColors>\n): {\n nodes: Node[];\n edges: Edge[];\n} {\n const state: LayoutState = {\n nodes: [],\n edges: [],\n edgeCounter: 0,\n seen: new Set(),\n overlay: overlay ?? null,\n colors: { ...DEFAULT_COLORS, ...colors },\n };\n\n walk(spec, state, 300, 0);\n\n return { nodes: state.nodes, edges: state.edges };\n}\n","import { useState } from \"react\";\nimport type { Node, Edge } from \"@xyflow/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 { FlowchartView } from \"../FlowchartView\";\n\nexport interface TimeTravelDebuggerProps extends BaseComponentProps {\n /** Stage snapshots */\n snapshots: StageSnapshot[];\n /** ReactFlow nodes (required for flowchart) */\n nodes: Node[];\n /** ReactFlow edges (required for flowchart) */\n edges: Edge[];\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 + flowchart + memory + narrative + gantt.\n * This is the \"batteries included\" component for pipeline debugging.\n */\nexport function TimeTravelDebugger({\n snapshots,\n nodes,\n edges,\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 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 <FlowchartView\n nodes={nodes}\n edges={edges}\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onNodeClick={setSelectedIndex}\n unstyled\n />\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=\"\\u25C0\"\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=\"\\u25B6\"\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 <FlowchartView\n nodes={nodes}\n edges={edges}\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onNodeClick={setSelectedIndex}\n size={size}\n />\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 } 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/**\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 // Compute accumulated memory from snapshots\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 merged: Record<string, unknown> = {};\n for (let i = 0; i <= Math.min(selectedIndex, snapshots.length - 1); i++) {\n Object.assign(merged, snapshots[i]?.memory);\n }\n\n const nk = new Set<string>();\n if (highlightNew && selectedIndex > 0) {\n const prev: Record<string, unknown> = {};\n for (let i = 0; i < selectedIndex; i++) {\n Object.assign(prev, snapshots[i]?.memory);\n }\n const current = snapshots[selectedIndex]?.memory ?? {};\n for (const k of Object.keys(current)) {\n if (!(k in prev)) nk.add(k);\n }\n } else if (highlightNew && selectedIndex === 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\">\n <div data-fp=\"memory-label\">Memory State</div>\n <pre data-fp=\"memory-json\">\n {JSON.stringify(memory, null, 2)}\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 >\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 { useMemo } 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}\n\n/**\n * Horizontal Gantt-style timeline showing stage durations and overlap.\n * Great for performance analysis of pipeline execution.\n */\nexport function GanttTimeline({\n snapshots,\n selectedIndex = 0,\n onSelect,\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: GanttTimelineProps) {\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\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"gantt-timeline\">\n {snapshots.map((snap, idx) => (\n <div\n key={snap.stageName}\n data-fp=\"gantt-bar\"\n data-selected={idx === selectedIndex}\n data-visible={idx <= selectedIndex}\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 <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 <div\n style={{\n marginTop: 8,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 4,\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}\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 }}\n >\n <span\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"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","StageNode","import_jsx_runtime","import_react","import_jsx_runtime","SubflowBreadcrumb","import_react","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime"]}
@@ -0,0 +1,199 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as _xyflow_react from '@xyflow/react';
3
+ import { Node, Edge } from '@xyflow/react';
4
+ import * as react from 'react';
5
+
6
+ /** Snapshot of a single pipeline stage — the core data shape for all components. */
7
+ interface StageSnapshot {
8
+ /** Internal stage identifier */
9
+ stageName: string;
10
+ /** Human-readable label */
11
+ stageLabel: string;
12
+ /** Accumulated memory state after this stage ran */
13
+ memory: Record<string, unknown>;
14
+ /** Narrative text describing what happened */
15
+ narrative: string;
16
+ /** When this stage started (ms from pipeline start) */
17
+ startMs: number;
18
+ /** How long this stage took (ms) */
19
+ durationMs: number;
20
+ /** Execution status */
21
+ status?: "pending" | "active" | "done" | "error";
22
+ }
23
+ /** Component size variants */
24
+ type Size = "compact" | "default" | "detailed";
25
+ /** Common props shared by all visualization components */
26
+ interface BaseComponentProps {
27
+ /** Size variant */
28
+ size?: Size;
29
+ /** Strip all built-in styles — bring your own */
30
+ unstyled?: boolean;
31
+ /** Additional CSS class name */
32
+ className?: string;
33
+ /** Inline style overrides */
34
+ style?: React.CSSProperties;
35
+ }
36
+
37
+ interface FlowchartViewProps extends BaseComponentProps {
38
+ /** ReactFlow nodes */
39
+ nodes: Node[];
40
+ /** ReactFlow edges */
41
+ edges: Edge[];
42
+ /** Optional snapshots for state-aware rendering (done/active coloring) */
43
+ snapshots?: StageSnapshot[];
44
+ /** Currently selected snapshot index (for state coloring) */
45
+ selectedIndex?: number;
46
+ /** Callback when a node is clicked */
47
+ onNodeClick?: (index: number) => void;
48
+ }
49
+ /**
50
+ * Pipeline flowchart visualization using ReactFlow.
51
+ * When snapshots are provided, nodes are colored by execution state.
52
+ */
53
+ declare function FlowchartView({ nodes: rawNodes, edges: rawEdges, snapshots, selectedIndex, onNodeClick, unstyled, className, style, }: FlowchartViewProps): react_jsx_runtime.JSX.Element;
54
+
55
+ /**
56
+ * Converts a SerializedPipelineStructure (from builder.toSpec()) into
57
+ * ReactFlow nodes and edges with auto-layout.
58
+ *
59
+ * Supports two modes:
60
+ * 1. Build-time only (no executionState) — all nodes gray
61
+ * 2. With execution overlay — executed nodes colored, active node highlighted,
62
+ * unvisited nodes stay gray
63
+ */
64
+
65
+ interface SpecNode {
66
+ name: string;
67
+ id?: string;
68
+ type?: "stage" | "decider" | "fork" | "streaming";
69
+ description?: string;
70
+ children?: SpecNode[];
71
+ next?: SpecNode;
72
+ branchIds?: string[];
73
+ hasDecider?: boolean;
74
+ hasSelector?: boolean;
75
+ loopTarget?: string;
76
+ isSubflowRoot?: boolean;
77
+ subflowId?: string;
78
+ subflowName?: string;
79
+ subflowStructure?: SpecNode;
80
+ }
81
+ interface ExecutionOverlay {
82
+ /** Names of stages that have completed (before the active one) */
83
+ doneStages: Set<string>;
84
+ /** Name of the currently active stage */
85
+ activeStage: string | null;
86
+ /** Names of all stages that were executed (done + active) */
87
+ executedStages: Set<string>;
88
+ /** Ordered list of executed stage names (for step numbering) */
89
+ executionOrder?: string[];
90
+ }
91
+ /** Colors for the flowchart — consumer provides these to match their theme */
92
+ interface FlowchartColors {
93
+ edgeDefault: string;
94
+ edgeExecuted: string;
95
+ edgeActive: string;
96
+ edgeLoop: string;
97
+ labelDefault: string;
98
+ labelExecuted: string;
99
+ labelLoop: string;
100
+ pathGlow: string;
101
+ }
102
+ /**
103
+ * Convert a pipeline spec to ReactFlow graph.
104
+ * Pass `overlay` to color nodes/edges by execution state.
105
+ */
106
+ declare function specToReactFlow(spec: SpecNode, overlay?: ExecutionOverlay, colors?: Partial<FlowchartColors>): {
107
+ nodes: Node[];
108
+ edges: Edge[];
109
+ };
110
+
111
+ interface BreadcrumbEntry {
112
+ /** Display name for this level */
113
+ label: string;
114
+ /** The spec node tree at this level */
115
+ spec: SpecNode;
116
+ }
117
+ interface SubflowNavigation {
118
+ /** Current breadcrumb path (root → ... → current) */
119
+ breadcrumbs: BreadcrumbEntry[];
120
+ /** Current level's ReactFlow nodes */
121
+ nodes: Node[];
122
+ /** Current level's ReactFlow edges */
123
+ edges: Edge[];
124
+ /** Call when a node is clicked — drills in if it's a subflow */
125
+ handleNodeClick: (nodeId: string) => boolean;
126
+ /** Navigate to a specific breadcrumb level (0 = root) */
127
+ navigateTo: (level: number) => void;
128
+ /** Whether we're currently inside a subflow (not at root) */
129
+ isInSubflow: boolean;
130
+ /** Name of the subflow node we drilled into (for finding execution data) */
131
+ currentSubflowNodeName: string | null;
132
+ }
133
+ /**
134
+ * Hook that manages subflow drill-down navigation for a flowchart spec.
135
+ *
136
+ * Maintains a breadcrumb stack. When a subflow node is clicked, pushes its
137
+ * nested spec onto the stack and re-derives nodes/edges. Breadcrumb clicks
138
+ * pop back to that level.
139
+ */
140
+ declare function useSubflowNavigation(rootSpec: SpecNode | null, overlay?: ExecutionOverlay, colors?: Partial<FlowchartColors>): SubflowNavigation;
141
+
142
+ interface SubflowBreadcrumbProps {
143
+ breadcrumbs: BreadcrumbEntry[];
144
+ onNavigate: (level: number) => void;
145
+ }
146
+ /**
147
+ * Breadcrumb bar for subflow drill-down navigation.
148
+ * Shows: Root > SubflowA > SubflowB — clicking any crumb navigates back.
149
+ */
150
+ declare const SubflowBreadcrumb: react.NamedExoticComponent<SubflowBreadcrumbProps>;
151
+
152
+ interface StageNodeData {
153
+ label: string;
154
+ active?: boolean;
155
+ done?: boolean;
156
+ error?: boolean;
157
+ linked?: boolean;
158
+ /** Step numbers in execution order (shown as badges — multiple when revisited via loops) */
159
+ stepNumbers?: number[];
160
+ /** Node was not executed (dim it) */
161
+ dimmed?: boolean;
162
+ /** Node is a subflow root (show nested indicator) */
163
+ isSubflow?: boolean;
164
+ [key: string]: unknown;
165
+ }
166
+ /**
167
+ * Custom ReactFlow node for pipeline stages.
168
+ * All colors and fonts come from `--fp-*` CSS variables (via theme).
169
+ * Shows execution state via color, icon, step badge, and pulse animation.
170
+ */
171
+ declare const StageNode: react.NamedExoticComponent<Pick<_xyflow_react.Node<Record<string, unknown>, string | undefined>, "id" | "data" | "width" | "height" | "sourcePosition" | "targetPosition" | "dragHandle" | "parentId"> & Required<Pick<_xyflow_react.Node<Record<string, unknown>, string | undefined>, "type" | "dragging" | "zIndex" | "selectable" | "deletable" | "selected" | "draggable">> & {
172
+ isConnectable: boolean;
173
+ positionAbsoluteX: number;
174
+ positionAbsoluteY: number;
175
+ } & {
176
+ data: StageNodeData;
177
+ }>;
178
+
179
+ interface TimeTravelDebuggerProps extends BaseComponentProps {
180
+ /** Stage snapshots */
181
+ snapshots: StageSnapshot[];
182
+ /** ReactFlow nodes (required for flowchart) */
183
+ nodes: Node[];
184
+ /** ReactFlow edges (required for flowchart) */
185
+ edges: Edge[];
186
+ /** Show Gantt timeline */
187
+ showGantt?: boolean;
188
+ /** Layout direction */
189
+ layout?: "horizontal" | "vertical";
190
+ /** Title */
191
+ title?: string;
192
+ }
193
+ /**
194
+ * Full time-travel debugger: scrubber + flowchart + memory + narrative + gantt.
195
+ * This is the "batteries included" component for pipeline debugging.
196
+ */
197
+ declare function TimeTravelDebugger({ snapshots, nodes, edges, showGantt, layout, title, size, unstyled, className, style, }: TimeTravelDebuggerProps): react_jsx_runtime.JSX.Element;
198
+
199
+ export { type BreadcrumbEntry, type ExecutionOverlay, type FlowchartColors, FlowchartView, type FlowchartViewProps, type SpecNode, StageNode, type StageNodeData, SubflowBreadcrumb, type SubflowBreadcrumbProps, type SubflowNavigation, TimeTravelDebugger, type TimeTravelDebuggerProps, specToReactFlow, useSubflowNavigation };
@@ -0,0 +1,199 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as _xyflow_react from '@xyflow/react';
3
+ import { Node, Edge } from '@xyflow/react';
4
+ import * as react from 'react';
5
+
6
+ /** Snapshot of a single pipeline stage — the core data shape for all components. */
7
+ interface StageSnapshot {
8
+ /** Internal stage identifier */
9
+ stageName: string;
10
+ /** Human-readable label */
11
+ stageLabel: string;
12
+ /** Accumulated memory state after this stage ran */
13
+ memory: Record<string, unknown>;
14
+ /** Narrative text describing what happened */
15
+ narrative: string;
16
+ /** When this stage started (ms from pipeline start) */
17
+ startMs: number;
18
+ /** How long this stage took (ms) */
19
+ durationMs: number;
20
+ /** Execution status */
21
+ status?: "pending" | "active" | "done" | "error";
22
+ }
23
+ /** Component size variants */
24
+ type Size = "compact" | "default" | "detailed";
25
+ /** Common props shared by all visualization components */
26
+ interface BaseComponentProps {
27
+ /** Size variant */
28
+ size?: Size;
29
+ /** Strip all built-in styles — bring your own */
30
+ unstyled?: boolean;
31
+ /** Additional CSS class name */
32
+ className?: string;
33
+ /** Inline style overrides */
34
+ style?: React.CSSProperties;
35
+ }
36
+
37
+ interface FlowchartViewProps extends BaseComponentProps {
38
+ /** ReactFlow nodes */
39
+ nodes: Node[];
40
+ /** ReactFlow edges */
41
+ edges: Edge[];
42
+ /** Optional snapshots for state-aware rendering (done/active coloring) */
43
+ snapshots?: StageSnapshot[];
44
+ /** Currently selected snapshot index (for state coloring) */
45
+ selectedIndex?: number;
46
+ /** Callback when a node is clicked */
47
+ onNodeClick?: (index: number) => void;
48
+ }
49
+ /**
50
+ * Pipeline flowchart visualization using ReactFlow.
51
+ * When snapshots are provided, nodes are colored by execution state.
52
+ */
53
+ declare function FlowchartView({ nodes: rawNodes, edges: rawEdges, snapshots, selectedIndex, onNodeClick, unstyled, className, style, }: FlowchartViewProps): react_jsx_runtime.JSX.Element;
54
+
55
+ /**
56
+ * Converts a SerializedPipelineStructure (from builder.toSpec()) into
57
+ * ReactFlow nodes and edges with auto-layout.
58
+ *
59
+ * Supports two modes:
60
+ * 1. Build-time only (no executionState) — all nodes gray
61
+ * 2. With execution overlay — executed nodes colored, active node highlighted,
62
+ * unvisited nodes stay gray
63
+ */
64
+
65
+ interface SpecNode {
66
+ name: string;
67
+ id?: string;
68
+ type?: "stage" | "decider" | "fork" | "streaming";
69
+ description?: string;
70
+ children?: SpecNode[];
71
+ next?: SpecNode;
72
+ branchIds?: string[];
73
+ hasDecider?: boolean;
74
+ hasSelector?: boolean;
75
+ loopTarget?: string;
76
+ isSubflowRoot?: boolean;
77
+ subflowId?: string;
78
+ subflowName?: string;
79
+ subflowStructure?: SpecNode;
80
+ }
81
+ interface ExecutionOverlay {
82
+ /** Names of stages that have completed (before the active one) */
83
+ doneStages: Set<string>;
84
+ /** Name of the currently active stage */
85
+ activeStage: string | null;
86
+ /** Names of all stages that were executed (done + active) */
87
+ executedStages: Set<string>;
88
+ /** Ordered list of executed stage names (for step numbering) */
89
+ executionOrder?: string[];
90
+ }
91
+ /** Colors for the flowchart — consumer provides these to match their theme */
92
+ interface FlowchartColors {
93
+ edgeDefault: string;
94
+ edgeExecuted: string;
95
+ edgeActive: string;
96
+ edgeLoop: string;
97
+ labelDefault: string;
98
+ labelExecuted: string;
99
+ labelLoop: string;
100
+ pathGlow: string;
101
+ }
102
+ /**
103
+ * Convert a pipeline spec to ReactFlow graph.
104
+ * Pass `overlay` to color nodes/edges by execution state.
105
+ */
106
+ declare function specToReactFlow(spec: SpecNode, overlay?: ExecutionOverlay, colors?: Partial<FlowchartColors>): {
107
+ nodes: Node[];
108
+ edges: Edge[];
109
+ };
110
+
111
+ interface BreadcrumbEntry {
112
+ /** Display name for this level */
113
+ label: string;
114
+ /** The spec node tree at this level */
115
+ spec: SpecNode;
116
+ }
117
+ interface SubflowNavigation {
118
+ /** Current breadcrumb path (root → ... → current) */
119
+ breadcrumbs: BreadcrumbEntry[];
120
+ /** Current level's ReactFlow nodes */
121
+ nodes: Node[];
122
+ /** Current level's ReactFlow edges */
123
+ edges: Edge[];
124
+ /** Call when a node is clicked — drills in if it's a subflow */
125
+ handleNodeClick: (nodeId: string) => boolean;
126
+ /** Navigate to a specific breadcrumb level (0 = root) */
127
+ navigateTo: (level: number) => void;
128
+ /** Whether we're currently inside a subflow (not at root) */
129
+ isInSubflow: boolean;
130
+ /** Name of the subflow node we drilled into (for finding execution data) */
131
+ currentSubflowNodeName: string | null;
132
+ }
133
+ /**
134
+ * Hook that manages subflow drill-down navigation for a flowchart spec.
135
+ *
136
+ * Maintains a breadcrumb stack. When a subflow node is clicked, pushes its
137
+ * nested spec onto the stack and re-derives nodes/edges. Breadcrumb clicks
138
+ * pop back to that level.
139
+ */
140
+ declare function useSubflowNavigation(rootSpec: SpecNode | null, overlay?: ExecutionOverlay, colors?: Partial<FlowchartColors>): SubflowNavigation;
141
+
142
+ interface SubflowBreadcrumbProps {
143
+ breadcrumbs: BreadcrumbEntry[];
144
+ onNavigate: (level: number) => void;
145
+ }
146
+ /**
147
+ * Breadcrumb bar for subflow drill-down navigation.
148
+ * Shows: Root > SubflowA > SubflowB — clicking any crumb navigates back.
149
+ */
150
+ declare const SubflowBreadcrumb: react.NamedExoticComponent<SubflowBreadcrumbProps>;
151
+
152
+ interface StageNodeData {
153
+ label: string;
154
+ active?: boolean;
155
+ done?: boolean;
156
+ error?: boolean;
157
+ linked?: boolean;
158
+ /** Step numbers in execution order (shown as badges — multiple when revisited via loops) */
159
+ stepNumbers?: number[];
160
+ /** Node was not executed (dim it) */
161
+ dimmed?: boolean;
162
+ /** Node is a subflow root (show nested indicator) */
163
+ isSubflow?: boolean;
164
+ [key: string]: unknown;
165
+ }
166
+ /**
167
+ * Custom ReactFlow node for pipeline stages.
168
+ * All colors and fonts come from `--fp-*` CSS variables (via theme).
169
+ * Shows execution state via color, icon, step badge, and pulse animation.
170
+ */
171
+ declare const StageNode: react.NamedExoticComponent<Pick<_xyflow_react.Node<Record<string, unknown>, string | undefined>, "id" | "data" | "width" | "height" | "sourcePosition" | "targetPosition" | "dragHandle" | "parentId"> & Required<Pick<_xyflow_react.Node<Record<string, unknown>, string | undefined>, "type" | "dragging" | "zIndex" | "selectable" | "deletable" | "selected" | "draggable">> & {
172
+ isConnectable: boolean;
173
+ positionAbsoluteX: number;
174
+ positionAbsoluteY: number;
175
+ } & {
176
+ data: StageNodeData;
177
+ }>;
178
+
179
+ interface TimeTravelDebuggerProps extends BaseComponentProps {
180
+ /** Stage snapshots */
181
+ snapshots: StageSnapshot[];
182
+ /** ReactFlow nodes (required for flowchart) */
183
+ nodes: Node[];
184
+ /** ReactFlow edges (required for flowchart) */
185
+ edges: Edge[];
186
+ /** Show Gantt timeline */
187
+ showGantt?: boolean;
188
+ /** Layout direction */
189
+ layout?: "horizontal" | "vertical";
190
+ /** Title */
191
+ title?: string;
192
+ }
193
+ /**
194
+ * Full time-travel debugger: scrubber + flowchart + memory + narrative + gantt.
195
+ * This is the "batteries included" component for pipeline debugging.
196
+ */
197
+ declare function TimeTravelDebugger({ snapshots, nodes, edges, showGantt, layout, title, size, unstyled, className, style, }: TimeTravelDebuggerProps): react_jsx_runtime.JSX.Element;
198
+
199
+ export { type BreadcrumbEntry, type ExecutionOverlay, type FlowchartColors, FlowchartView, type FlowchartViewProps, type SpecNode, StageNode, type StageNodeData, SubflowBreadcrumb, type SubflowBreadcrumbProps, type SubflowNavigation, TimeTravelDebugger, type TimeTravelDebuggerProps, specToReactFlow, useSubflowNavigation };