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,1512 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/flowchart.ts
21
+ var flowchart_exports = {};
22
+ __export(flowchart_exports, {
23
+ FlowchartView: () => FlowchartView,
24
+ StageNode: () => StageNode,
25
+ SubflowBreadcrumb: () => SubflowBreadcrumb,
26
+ TimeTravelDebugger: () => TimeTravelDebugger,
27
+ specToReactFlow: () => specToReactFlow,
28
+ useSubflowNavigation: () => useSubflowNavigation
29
+ });
30
+ module.exports = __toCommonJS(flowchart_exports);
31
+
32
+ // src/components/FlowchartView/FlowchartView.tsx
33
+ var import_react4 = require("react");
34
+ var import_react5 = require("@xyflow/react");
35
+
36
+ // src/components/StageNode/StageNode.tsx
37
+ var import_react2 = require("react");
38
+ var import_react3 = require("@xyflow/react");
39
+
40
+ // src/theme/ThemeProvider.tsx
41
+ var import_react = require("react");
42
+
43
+ // src/theme/tokens.ts
44
+ var defaultTokens = {
45
+ colors: {
46
+ primary: "#6366f1",
47
+ success: "#22c55e",
48
+ error: "#ef4444",
49
+ warning: "#f59e0b",
50
+ bgPrimary: "#0f172a",
51
+ bgSecondary: "#1e293b",
52
+ bgTertiary: "#334155",
53
+ textPrimary: "#f8fafc",
54
+ textSecondary: "#94a3b8",
55
+ textMuted: "#64748b",
56
+ border: "#334155"
57
+ },
58
+ radius: "8px",
59
+ fontFamily: {
60
+ sans: "Inter, system-ui, -apple-system, sans-serif",
61
+ mono: "'JetBrains Mono', 'Fira Code', monospace"
62
+ }
63
+ };
64
+
65
+ // src/theme/ThemeProvider.tsx
66
+ var import_jsx_runtime = require("react/jsx-runtime");
67
+ var ThemeContext = (0, import_react.createContext)({});
68
+
69
+ // src/theme/styles.ts
70
+ function v(varName, fallback) {
71
+ return `var(${varName}, ${fallback})`;
72
+ }
73
+ var theme = {
74
+ primary: v("--fp-color-primary", "#6366f1"),
75
+ success: v("--fp-color-success", "#22c55e"),
76
+ error: v("--fp-color-error", "#ef4444"),
77
+ warning: v("--fp-color-warning", "#f59e0b"),
78
+ bgPrimary: v("--fp-bg-primary", "#0f172a"),
79
+ bgSecondary: v("--fp-bg-secondary", "#1e293b"),
80
+ bgTertiary: v("--fp-bg-tertiary", "#334155"),
81
+ textPrimary: v("--fp-text-primary", "#f8fafc"),
82
+ textSecondary: v("--fp-text-secondary", "#94a3b8"),
83
+ textMuted: v("--fp-text-muted", "#64748b"),
84
+ border: v("--fp-border", "#334155"),
85
+ radius: v("--fp-radius", "8px"),
86
+ fontSans: v("--fp-font-sans", "Inter, system-ui, -apple-system, sans-serif"),
87
+ fontMono: v("--fp-font-mono", "'JetBrains Mono', 'Fira Code', monospace")
88
+ };
89
+ var fontSize = {
90
+ compact: { label: 10, body: 11, small: 9 },
91
+ default: { label: 11, body: 12, small: 10 },
92
+ detailed: { label: 12, body: 13, small: 11 }
93
+ };
94
+ var padding = {
95
+ compact: 8,
96
+ default: 12,
97
+ detailed: 16
98
+ };
99
+
100
+ // src/components/StageNode/StageNode.tsx
101
+ var import_jsx_runtime2 = require("react/jsx-runtime");
102
+ var StageNode = (0, import_react2.memo)(function StageNode2({
103
+ data
104
+ }) {
105
+ const { label, active, done, error, linked, stepNumbers, dimmed, isSubflow } = data;
106
+ const isOnPath = active || done;
107
+ const bg = active ? theme.primary : done ? theme.success : error ? theme.error : theme.bgSecondary;
108
+ const borderColor = active ? theme.primary : done ? theme.success : error ? theme.error : theme.border;
109
+ const shadow = active ? `0 0 16px color-mix(in srgb, ${theme.primary} 40%, transparent)` : done ? `0 0 8px color-mix(in srgb, ${theme.success} 20%, transparent)` : error ? `0 0 12px color-mix(in srgb, ${theme.error} 30%, transparent)` : `0 2px 8px rgba(0,0,0,0.15)`;
110
+ const textColor = active || done || error ? "#fff" : theme.textPrimary;
111
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
112
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.Handle, { type: "target", position: import_react3.Position.Top, style: { opacity: 0 } }),
113
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
114
+ "div",
115
+ {
116
+ style: {
117
+ position: "relative",
118
+ display: "flex",
119
+ alignItems: "center",
120
+ gap: 6
121
+ },
122
+ children: [
123
+ stepNumbers && stepNumbers.length > 0 && isOnPath && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
124
+ "div",
125
+ {
126
+ style: {
127
+ position: "absolute",
128
+ top: -10,
129
+ left: -10,
130
+ display: "flex",
131
+ gap: 3,
132
+ zIndex: 10
133
+ },
134
+ children: stepNumbers.map((num, i) => {
135
+ const isLatest = i === stepNumbers.length - 1;
136
+ const badgeBg = isLatest && active ? theme.primary : theme.success;
137
+ const glow = isLatest && active ? `color-mix(in srgb, ${theme.primary} 50%, transparent)` : `color-mix(in srgb, ${theme.success} 40%, transparent)`;
138
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
139
+ "div",
140
+ {
141
+ style: {
142
+ width: 22,
143
+ height: 22,
144
+ borderRadius: "50%",
145
+ background: badgeBg,
146
+ color: "#fff",
147
+ fontSize: 11,
148
+ fontWeight: 700,
149
+ display: "flex",
150
+ alignItems: "center",
151
+ justifyContent: "center",
152
+ boxShadow: `0 0 8px ${glow}`
153
+ },
154
+ children: num
155
+ },
156
+ num
157
+ );
158
+ })
159
+ }
160
+ ),
161
+ linked && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
162
+ "div",
163
+ {
164
+ style: {
165
+ position: "absolute",
166
+ inset: -6,
167
+ borderRadius: `calc(${theme.radius} + 4px)`,
168
+ border: `2px solid ${theme.primary}`,
169
+ opacity: 0.4,
170
+ animation: "fp-pulse 2s ease-in-out infinite"
171
+ }
172
+ }
173
+ ),
174
+ active && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
175
+ "div",
176
+ {
177
+ style: {
178
+ position: "absolute",
179
+ inset: -6,
180
+ borderRadius: `calc(${theme.radius} + 4px)`,
181
+ border: `2px solid ${theme.primary}`,
182
+ opacity: 0.3,
183
+ animation: "fp-pulse 1.5s ease-out infinite"
184
+ }
185
+ }
186
+ ),
187
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
188
+ "div",
189
+ {
190
+ style: {
191
+ background: bg,
192
+ border: `2px solid ${borderColor}`,
193
+ borderRadius: theme.radius,
194
+ padding: "10px 20px",
195
+ display: "flex",
196
+ alignItems: "center",
197
+ gap: 6,
198
+ boxShadow: shadow,
199
+ transition: "all 0.3s ease",
200
+ fontFamily: theme.fontSans,
201
+ minWidth: 100,
202
+ justifyContent: "center"
203
+ },
204
+ children: [
205
+ done && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: 10, color: textColor }, children: "\u2713" }),
206
+ active && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
207
+ "span",
208
+ {
209
+ style: {
210
+ width: 8,
211
+ height: 8,
212
+ borderRadius: "50%",
213
+ background: "#fff",
214
+ animation: "fp-blink 1s ease-in-out infinite",
215
+ flexShrink: 0
216
+ }
217
+ }
218
+ ),
219
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: 10, color: textColor }, children: "\u2717" }),
220
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
221
+ "span",
222
+ {
223
+ style: {
224
+ fontSize: 13,
225
+ fontWeight: 500,
226
+ color: textColor,
227
+ whiteSpace: "nowrap"
228
+ },
229
+ children: label
230
+ }
231
+ ),
232
+ isSubflow && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
233
+ "span",
234
+ {
235
+ style: {
236
+ display: "inline-flex",
237
+ alignItems: "center",
238
+ justifyContent: "center",
239
+ width: 16,
240
+ height: 16,
241
+ borderRadius: 3,
242
+ border: `1.5px solid ${textColor}`,
243
+ position: "relative",
244
+ opacity: 0.7,
245
+ flexShrink: 0
246
+ },
247
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
248
+ "span",
249
+ {
250
+ style: {
251
+ width: 8,
252
+ height: 8,
253
+ borderRadius: 2,
254
+ border: `1px solid ${textColor}`
255
+ }
256
+ }
257
+ )
258
+ }
259
+ )
260
+ ]
261
+ }
262
+ )
263
+ ]
264
+ }
265
+ ),
266
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.Handle, { type: "source", position: import_react3.Position.Bottom, style: { opacity: 0 } }),
267
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
268
+ import_react3.Handle,
269
+ {
270
+ id: "loop-source",
271
+ type: "source",
272
+ position: import_react3.Position.Right,
273
+ style: { background: "transparent", border: "none", width: 6, height: 6 }
274
+ }
275
+ ),
276
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
277
+ import_react3.Handle,
278
+ {
279
+ id: "loop-target",
280
+ type: "target",
281
+ position: import_react3.Position.Right,
282
+ style: { background: "transparent", border: "none", width: 6, height: 6 }
283
+ }
284
+ )
285
+ ] });
286
+ });
287
+
288
+ // src/components/FlowchartView/FlowchartView.tsx
289
+ var import_jsx_runtime3 = require("react/jsx-runtime");
290
+ var nodeTypes = { stageNode: StageNode };
291
+ function FlowchartView({
292
+ nodes: rawNodes,
293
+ edges: rawEdges,
294
+ snapshots,
295
+ selectedIndex = 0,
296
+ onNodeClick,
297
+ unstyled = false,
298
+ className,
299
+ style
300
+ }) {
301
+ const enhancedNodes = (0, import_react4.useMemo)(() => {
302
+ if (!snapshots || snapshots.length === 0) {
303
+ return rawNodes.map((n) => ({
304
+ ...n,
305
+ type: "stageNode",
306
+ data: {
307
+ ...n.data,
308
+ label: n.data.label || n.id,
309
+ active: false,
310
+ done: false,
311
+ error: false
312
+ }
313
+ }));
314
+ }
315
+ const doneNames = new Set(
316
+ snapshots.slice(0, selectedIndex).map((s) => s.stageName)
317
+ );
318
+ const activeName = snapshots[selectedIndex]?.stageName;
319
+ return rawNodes.map((n) => ({
320
+ ...n,
321
+ type: "stageNode",
322
+ data: {
323
+ ...n.data,
324
+ label: n.data.label || n.id,
325
+ active: n.id === activeName,
326
+ done: doneNames.has(n.id),
327
+ error: false
328
+ }
329
+ }));
330
+ }, [rawNodes, snapshots, selectedIndex]);
331
+ const enhancedEdges = (0, import_react4.useMemo)(() => {
332
+ if (!snapshots || snapshots.length === 0) {
333
+ return rawEdges.map((e) => ({
334
+ ...e,
335
+ style: { stroke: theme.textMuted, strokeWidth: 1.5 },
336
+ animated: false
337
+ }));
338
+ }
339
+ const doneNames = new Set(
340
+ snapshots.slice(0, selectedIndex + 1).map((s) => s.stageName)
341
+ );
342
+ const activeName = snapshots[selectedIndex]?.stageName;
343
+ return rawEdges.map((e) => {
344
+ const sourceIsDone = doneNames.has(e.source);
345
+ const isFromActive = e.source === activeName;
346
+ return {
347
+ ...e,
348
+ style: {
349
+ stroke: sourceIsDone ? theme.success : theme.textMuted,
350
+ strokeWidth: 1.5
351
+ },
352
+ animated: isFromActive
353
+ };
354
+ });
355
+ }, [rawEdges, snapshots, selectedIndex]);
356
+ const [nodes, , onNodesChange] = (0, import_react5.useNodesState)(enhancedNodes);
357
+ const [edges, , onEdgesChange] = (0, import_react5.useEdgesState)(enhancedEdges);
358
+ const handleNodeClick = (0, import_react4.useCallback)(
359
+ (_, node) => {
360
+ if (!onNodeClick || !snapshots) return;
361
+ const idx = snapshots.findIndex((s) => s.stageName === node.id);
362
+ if (idx >= 0) onNodeClick(idx);
363
+ },
364
+ [onNodeClick, snapshots]
365
+ );
366
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
367
+ "div",
368
+ {
369
+ className,
370
+ style: {
371
+ width: "100%",
372
+ height: "100%",
373
+ ...style
374
+ },
375
+ "data-fp": "flowchart-view",
376
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
377
+ import_react5.ReactFlow,
378
+ {
379
+ nodes,
380
+ edges,
381
+ onNodesChange,
382
+ onEdgesChange,
383
+ onNodeClick: handleNodeClick,
384
+ nodeTypes,
385
+ fitView: true,
386
+ panOnDrag: false,
387
+ zoomOnScroll: false,
388
+ zoomOnPinch: false,
389
+ zoomOnDoubleClick: false,
390
+ preventScrolling: false,
391
+ nodesDraggable: false,
392
+ nodesConnectable: false,
393
+ elementsSelectable: !!onNodeClick,
394
+ children: !unstyled && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react5.Background, { variant: import_react5.BackgroundVariant.Dots, gap: 16, size: 1 })
395
+ }
396
+ )
397
+ }
398
+ );
399
+ }
400
+
401
+ // src/components/FlowchartView/SubflowBreadcrumb.tsx
402
+ var import_react6 = require("react");
403
+ var import_jsx_runtime4 = require("react/jsx-runtime");
404
+ var SubflowBreadcrumb = (0, import_react6.memo)(function SubflowBreadcrumb2({
405
+ breadcrumbs,
406
+ onNavigate
407
+ }) {
408
+ if (breadcrumbs.length <= 1) return null;
409
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
410
+ "div",
411
+ {
412
+ style: {
413
+ display: "flex",
414
+ alignItems: "center",
415
+ gap: 4,
416
+ padding: "6px 12px",
417
+ background: theme.bgSecondary,
418
+ borderBottom: `1px solid ${theme.border}`,
419
+ fontSize: 12,
420
+ fontFamily: theme.fontSans,
421
+ flexShrink: 0,
422
+ overflowX: "auto"
423
+ },
424
+ children: breadcrumbs.map((crumb, i) => {
425
+ const isLast = i === breadcrumbs.length - 1;
426
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
427
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: theme.textMuted, fontSize: 10 }, children: "\u203A" }),
428
+ isLast ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
429
+ "span",
430
+ {
431
+ style: {
432
+ color: theme.primary,
433
+ fontWeight: 600
434
+ },
435
+ children: crumb.label
436
+ }
437
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
438
+ "button",
439
+ {
440
+ onClick: () => onNavigate(i),
441
+ style: {
442
+ background: "none",
443
+ border: "none",
444
+ color: theme.textSecondary,
445
+ cursor: "pointer",
446
+ padding: "2px 4px",
447
+ borderRadius: 4,
448
+ fontSize: 12,
449
+ fontFamily: "inherit",
450
+ fontWeight: 500,
451
+ transition: "color 0.15s"
452
+ },
453
+ onMouseEnter: (e) => {
454
+ e.currentTarget.style.color = `${theme.primary}`;
455
+ },
456
+ onMouseLeave: (e) => {
457
+ e.currentTarget.style.color = `${theme.textSecondary}`;
458
+ },
459
+ children: crumb.label
460
+ }
461
+ )
462
+ ] }, i);
463
+ })
464
+ }
465
+ );
466
+ });
467
+
468
+ // src/components/FlowchartView/useSubflowNavigation.ts
469
+ var import_react7 = require("react");
470
+
471
+ // src/components/FlowchartView/specToReactFlow.ts
472
+ var DEFAULT_COLORS = {
473
+ edgeDefault: defaultTokens.colors.textMuted,
474
+ edgeExecuted: defaultTokens.colors.success,
475
+ edgeActive: defaultTokens.colors.primary,
476
+ edgeLoop: defaultTokens.colors.warning,
477
+ labelDefault: defaultTokens.colors.textSecondary,
478
+ labelExecuted: defaultTokens.colors.success,
479
+ labelLoop: defaultTokens.colors.warning,
480
+ pathGlow: `${defaultTokens.colors.success}4D`
481
+ // ~30% opacity hex
482
+ };
483
+ var Y_STEP = 100;
484
+ var X_SPREAD = 200;
485
+ function nid(n) {
486
+ return n.name || n.id || `spec-${Math.random()}`;
487
+ }
488
+ function addEdge(state, source, target, label, isLoop) {
489
+ state.edgeCounter++;
490
+ const o = state.overlay;
491
+ const c = state.colors;
492
+ const executed = o && o.executedStages.has(source) && o.executedStages.has(target);
493
+ const isLeadingEdge = o && source === o.activeStage && !o.doneStages.has(target);
494
+ if (isLoop) {
495
+ let loopExecuted = false;
496
+ if (o?.executionOrder) {
497
+ const lastSourceIdx = o.executionOrder.lastIndexOf(source);
498
+ if (lastSourceIdx >= 0) {
499
+ loopExecuted = o.executionOrder.slice(lastSourceIdx + 1).includes(target);
500
+ }
501
+ }
502
+ state.edges.push({
503
+ id: `se${state.edgeCounter}`,
504
+ source,
505
+ target,
506
+ sourceHandle: "loop-source",
507
+ targetHandle: "loop-target",
508
+ label: label ?? "loop",
509
+ type: "smoothstep",
510
+ pathOptions: { offset: 40, borderRadius: 16 },
511
+ style: {
512
+ stroke: c.edgeLoop,
513
+ strokeWidth: loopExecuted ? 3 : 2,
514
+ strokeDasharray: "6 3",
515
+ opacity: o && !loopExecuted ? 0.35 : 1
516
+ },
517
+ labelStyle: { fontSize: 10, fontWeight: 700, fill: c.labelLoop },
518
+ animated: loopExecuted,
519
+ zIndex: 2
520
+ });
521
+ return;
522
+ }
523
+ if (executed) {
524
+ state.edges.push({
525
+ id: `se${state.edgeCounter}-glow`,
526
+ source,
527
+ target,
528
+ style: {
529
+ stroke: c.pathGlow,
530
+ strokeWidth: 8,
531
+ opacity: 0.4
532
+ },
533
+ zIndex: 0,
534
+ selectable: false,
535
+ focusable: false
536
+ });
537
+ state.edges.push({
538
+ id: `se${state.edgeCounter}`,
539
+ source,
540
+ target,
541
+ label,
542
+ style: {
543
+ stroke: isLeadingEdge ? c.edgeActive : c.edgeExecuted,
544
+ strokeWidth: 3.5
545
+ },
546
+ labelStyle: { fontSize: 10, fontWeight: 600, fill: c.labelExecuted },
547
+ animated: !!isLeadingEdge,
548
+ zIndex: 1
549
+ });
550
+ } else {
551
+ state.edges.push({
552
+ id: `se${state.edgeCounter}`,
553
+ source,
554
+ target,
555
+ label,
556
+ style: {
557
+ stroke: c.edgeDefault,
558
+ strokeWidth: 1.5,
559
+ opacity: o ? 0.3 : 1
560
+ },
561
+ labelStyle: { fontSize: 10, fill: c.labelDefault }
562
+ });
563
+ }
564
+ }
565
+ function walk(node, state, x, y) {
566
+ const id = nid(node);
567
+ if (state.seen.has(id)) {
568
+ return { lastIds: [id], bottomY: y };
569
+ }
570
+ state.seen.add(id);
571
+ const isDecider = node.type === "decider" || node.hasDecider;
572
+ const isFork = node.type === "fork";
573
+ const o = state.overlay;
574
+ const isDone = o ? o.doneStages.has(id) : false;
575
+ const isActive = o ? o.activeStage === id : false;
576
+ const wasExecuted = o ? o.executedStages.has(id) : false;
577
+ const dimmed = o && !wasExecuted;
578
+ let stepNumbers;
579
+ if (o?.executionOrder) {
580
+ const nums = [];
581
+ for (let i = 0; i < o.executionOrder.length; i++) {
582
+ if (o.executionOrder[i] === id) nums.push(i + 1);
583
+ }
584
+ if (nums.length > 0) stepNumbers = nums;
585
+ }
586
+ state.nodes.push({
587
+ id,
588
+ position: { x, y },
589
+ data: {
590
+ label: node.name,
591
+ active: isActive,
592
+ done: isDone,
593
+ error: false,
594
+ isDecider,
595
+ isFork,
596
+ description: node.description,
597
+ dimmed,
598
+ stepNumbers,
599
+ isSubflow: !!node.isSubflowRoot
600
+ },
601
+ type: "stage",
602
+ style: dimmed ? { opacity: 0.35 } : void 0
603
+ });
604
+ let lastIds = [id];
605
+ let bottomY = y;
606
+ if (node.children && node.children.length > 0) {
607
+ const totalWidth = (node.children.length - 1) * X_SPREAD;
608
+ const startX = x - totalWidth / 2;
609
+ const childY = y + Y_STEP;
610
+ const childResults = [];
611
+ for (let i = 0; i < node.children.length; i++) {
612
+ const child = node.children[i];
613
+ const childX = startX + i * X_SPREAD;
614
+ const edgeLabel = node.branchIds?.[i];
615
+ addEdge(state, id, nid(child), edgeLabel);
616
+ const result = walk(child, state, childX, childY);
617
+ childResults.push(result);
618
+ }
619
+ lastIds = childResults.flatMap((r) => r.lastIds);
620
+ bottomY = Math.max(...childResults.map((r) => r.bottomY));
621
+ }
622
+ if (node.loopTarget) {
623
+ addEdge(state, id, node.loopTarget, "loop", true);
624
+ }
625
+ if (node.next) {
626
+ const nextY = bottomY + Y_STEP;
627
+ const nextId = nid(node.next);
628
+ for (const lid of lastIds) {
629
+ if (node.loopTarget && lid === id && node.loopTarget === nextId) continue;
630
+ addEdge(state, lid, nextId);
631
+ }
632
+ const result = walk(node.next, state, x, nextY);
633
+ return result;
634
+ }
635
+ return { lastIds, bottomY };
636
+ }
637
+ function specToReactFlow(spec, overlay, colors) {
638
+ const state = {
639
+ nodes: [],
640
+ edges: [],
641
+ edgeCounter: 0,
642
+ seen: /* @__PURE__ */ new Set(),
643
+ overlay: overlay ?? null,
644
+ colors: { ...DEFAULT_COLORS, ...colors }
645
+ };
646
+ walk(spec, state, 300, 0);
647
+ return { nodes: state.nodes, edges: state.edges };
648
+ }
649
+
650
+ // src/components/FlowchartView/useSubflowNavigation.ts
651
+ function useSubflowNavigation(rootSpec, overlay, colors) {
652
+ const [stack, setStack] = (0, import_react7.useState)([]);
653
+ const currentSpec = stack.length > 0 ? stack[stack.length - 1].spec : rootSpec;
654
+ const { nodes, edges } = (0, import_react7.useMemo)(() => {
655
+ if (!currentSpec) return { nodes: [], edges: [] };
656
+ return specToReactFlow(currentSpec, overlay, colors);
657
+ }, [currentSpec, overlay, colors]);
658
+ const subflowMap = (0, import_react7.useMemo)(() => {
659
+ const map = /* @__PURE__ */ new Map();
660
+ if (!currentSpec) return map;
661
+ function collectSubflows(node) {
662
+ if (node.isSubflowRoot && node.subflowStructure) {
663
+ const id = node.name || node.id || "";
664
+ map.set(id, node);
665
+ }
666
+ if (node.children) node.children.forEach(collectSubflows);
667
+ if (node.next) collectSubflows(node.next);
668
+ }
669
+ collectSubflows(currentSpec);
670
+ return map;
671
+ }, [currentSpec]);
672
+ const breadcrumbs = (0, import_react7.useMemo)(() => {
673
+ const root = {
674
+ label: rootSpec?.name || "Pipeline",
675
+ spec: rootSpec
676
+ };
677
+ return [root, ...stack];
678
+ }, [rootSpec, stack]);
679
+ const handleNodeClick = (0, import_react7.useCallback)(
680
+ (nodeId) => {
681
+ const subflowNode = subflowMap.get(nodeId);
682
+ if (!subflowNode?.subflowStructure) return false;
683
+ setStack((prev) => [
684
+ ...prev,
685
+ {
686
+ label: subflowNode.subflowName || subflowNode.name,
687
+ spec: subflowNode.subflowStructure
688
+ }
689
+ ]);
690
+ return true;
691
+ },
692
+ [subflowMap]
693
+ );
694
+ const navigateTo = (0, import_react7.useCallback)(
695
+ (level) => {
696
+ if (level === 0) {
697
+ setStack([]);
698
+ } else {
699
+ setStack((prev) => prev.slice(0, level));
700
+ }
701
+ },
702
+ []
703
+ );
704
+ return {
705
+ breadcrumbs,
706
+ nodes,
707
+ edges,
708
+ handleNodeClick,
709
+ navigateTo,
710
+ isInSubflow: stack.length > 0,
711
+ currentSubflowNodeName: stack.length > 0 ? stack[0].label : null
712
+ };
713
+ }
714
+
715
+ // src/components/TimeTravelDebugger/TimeTravelDebugger.tsx
716
+ var import_react11 = require("react");
717
+
718
+ // src/components/MemoryInspector/MemoryInspector.tsx
719
+ var import_react8 = require("react");
720
+ var import_jsx_runtime5 = require("react/jsx-runtime");
721
+ function MemoryInspector({
722
+ data,
723
+ snapshots,
724
+ selectedIndex = 0,
725
+ showTypes = false,
726
+ highlightNew = true,
727
+ size = "default",
728
+ unstyled = false,
729
+ className,
730
+ style
731
+ }) {
732
+ const { memory, newKeys } = (0, import_react8.useMemo)(() => {
733
+ if (data) {
734
+ return { memory: data, newKeys: /* @__PURE__ */ new Set() };
735
+ }
736
+ if (!snapshots || snapshots.length === 0) {
737
+ return { memory: {}, newKeys: /* @__PURE__ */ new Set() };
738
+ }
739
+ const merged = {};
740
+ for (let i = 0; i <= Math.min(selectedIndex, snapshots.length - 1); i++) {
741
+ Object.assign(merged, snapshots[i]?.memory);
742
+ }
743
+ const nk = /* @__PURE__ */ new Set();
744
+ if (highlightNew && selectedIndex > 0) {
745
+ const prev = {};
746
+ for (let i = 0; i < selectedIndex; i++) {
747
+ Object.assign(prev, snapshots[i]?.memory);
748
+ }
749
+ const current = snapshots[selectedIndex]?.memory ?? {};
750
+ for (const k of Object.keys(current)) {
751
+ if (!(k in prev)) nk.add(k);
752
+ }
753
+ } else if (highlightNew && selectedIndex === 0 && snapshots[0]) {
754
+ for (const k of Object.keys(snapshots[0].memory)) nk.add(k);
755
+ }
756
+ return { memory: merged, newKeys: nk };
757
+ }, [data, snapshots, selectedIndex, highlightNew]);
758
+ const entries = Object.entries(memory);
759
+ const fs = fontSize[size];
760
+ const pad = padding[size];
761
+ if (unstyled) {
762
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className, style, "data-fp": "memory-inspector", children: [
763
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { "data-fp": "memory-label", children: "Memory State" }),
764
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("pre", { "data-fp": "memory-json", children: JSON.stringify(memory, null, 2) })
765
+ ] });
766
+ }
767
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
768
+ "div",
769
+ {
770
+ className,
771
+ style: {
772
+ padding: pad,
773
+ fontFamily: theme.fontSans,
774
+ ...style
775
+ },
776
+ "data-fp": "memory-inspector",
777
+ children: [
778
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
779
+ "span",
780
+ {
781
+ style: {
782
+ fontSize: fs.label,
783
+ fontWeight: 600,
784
+ color: theme.textMuted,
785
+ textTransform: "uppercase",
786
+ letterSpacing: "0.08em"
787
+ },
788
+ children: "Memory State"
789
+ }
790
+ ),
791
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
792
+ "div",
793
+ {
794
+ style: {
795
+ marginTop: 8,
796
+ background: theme.bgSecondary,
797
+ border: `1px solid ${theme.border}`,
798
+ borderRadius: theme.radius,
799
+ padding: `${pad}px ${pad + 4}px`,
800
+ fontFamily: theme.fontMono,
801
+ fontSize: fs.body,
802
+ lineHeight: 1.8
803
+ },
804
+ children: [
805
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.textMuted }, children: "{" }),
806
+ entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
807
+ "div",
808
+ {
809
+ style: {
810
+ paddingLeft: 16,
811
+ color: theme.textMuted,
812
+ fontStyle: "italic"
813
+ },
814
+ children: "// empty"
815
+ }
816
+ ),
817
+ entries.map(([key, value], i) => {
818
+ const isNew = newKeys.has(key);
819
+ const isLast = i === entries.length - 1;
820
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
821
+ "div",
822
+ {
823
+ style: {
824
+ paddingLeft: 16,
825
+ background: isNew ? `color-mix(in srgb, ${theme.success} 10%, transparent)` : "transparent",
826
+ borderRadius: 4,
827
+ marginLeft: -4,
828
+ marginRight: -4,
829
+ paddingRight: 4
830
+ },
831
+ children: [
832
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: { color: theme.primary }, children: [
833
+ '"',
834
+ key,
835
+ '"'
836
+ ] }),
837
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.textMuted }, children: ": " }),
838
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.success }, children: formatValue(value) }),
839
+ showTypes && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
840
+ "span",
841
+ {
842
+ style: {
843
+ color: theme.textMuted,
844
+ fontSize: fs.small,
845
+ marginLeft: 8,
846
+ opacity: 0.6
847
+ },
848
+ children: [
849
+ "(",
850
+ typeof value,
851
+ ")"
852
+ ]
853
+ }
854
+ ),
855
+ !isLast && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.textMuted }, children: "," })
856
+ ]
857
+ },
858
+ key
859
+ );
860
+ }),
861
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: theme.textMuted }, children: "}" })
862
+ ]
863
+ }
864
+ )
865
+ ]
866
+ }
867
+ );
868
+ }
869
+ function formatValue(value) {
870
+ if (typeof value === "string") return `"${value}"`;
871
+ if (typeof value === "object" && value !== null) return JSON.stringify(value);
872
+ return String(value);
873
+ }
874
+
875
+ // src/components/NarrativeLog/NarrativeLog.tsx
876
+ var import_react9 = require("react");
877
+ var import_jsx_runtime6 = require("react/jsx-runtime");
878
+ function NarrativeLog({
879
+ snapshots,
880
+ selectedIndex,
881
+ narrative,
882
+ size = "default",
883
+ unstyled = false,
884
+ className,
885
+ style
886
+ }) {
887
+ const entries = (0, import_react9.useMemo)(() => {
888
+ if (narrative) {
889
+ return [{ label: "Output", text: narrative, isCurrent: true }];
890
+ }
891
+ const idx = selectedIndex ?? snapshots.length - 1;
892
+ return snapshots.slice(0, idx + 1).map((s, i) => ({
893
+ label: s.stageLabel,
894
+ text: s.narrative,
895
+ isCurrent: i === idx
896
+ }));
897
+ }, [snapshots, selectedIndex, narrative]);
898
+ const fs = fontSize[size];
899
+ const pad = padding[size];
900
+ if (unstyled) {
901
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style, "data-fp": "narrative-log", children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { "data-fp": "narrative-entry", "data-current": entry.isCurrent, children: [
902
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: entry.label }),
903
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: entry.text })
904
+ ] }, i)) });
905
+ }
906
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
907
+ "div",
908
+ {
909
+ className,
910
+ style: { padding: pad, fontFamily: theme.fontSans, ...style },
911
+ "data-fp": "narrative-log",
912
+ children: [
913
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
914
+ "span",
915
+ {
916
+ style: {
917
+ fontSize: fs.label,
918
+ fontWeight: 600,
919
+ color: theme.textMuted,
920
+ textTransform: "uppercase",
921
+ letterSpacing: "0.08em"
922
+ },
923
+ children: "Execution Log"
924
+ }
925
+ ),
926
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { marginTop: 8, display: "flex", flexDirection: "column" }, children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
927
+ "div",
928
+ {
929
+ style: {
930
+ display: "flex",
931
+ gap: 10,
932
+ padding: `${pad}px 0`,
933
+ borderBottom: i < entries.length - 1 ? `1px solid ${theme.border}` : "none"
934
+ },
935
+ children: [
936
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
937
+ "div",
938
+ {
939
+ style: {
940
+ display: "flex",
941
+ flexDirection: "column",
942
+ alignItems: "center",
943
+ width: 12,
944
+ flexShrink: 0,
945
+ paddingTop: 5
946
+ },
947
+ children: [
948
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
949
+ "div",
950
+ {
951
+ style: {
952
+ width: 8,
953
+ height: 8,
954
+ borderRadius: "50%",
955
+ background: entry.isCurrent ? theme.primary : theme.success,
956
+ flexShrink: 0
957
+ }
958
+ }
959
+ ),
960
+ i < entries.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
961
+ "div",
962
+ {
963
+ style: {
964
+ width: 1,
965
+ flex: 1,
966
+ background: theme.border,
967
+ marginTop: 4
968
+ }
969
+ }
970
+ )
971
+ ]
972
+ }
973
+ ),
974
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
975
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
976
+ "span",
977
+ {
978
+ style: {
979
+ fontSize: fs.label,
980
+ fontWeight: 600,
981
+ color: entry.isCurrent ? theme.primary : theme.textMuted
982
+ },
983
+ children: entry.label
984
+ }
985
+ ),
986
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
987
+ "div",
988
+ {
989
+ style: {
990
+ fontSize: fs.body,
991
+ lineHeight: 1.5,
992
+ color: entry.isCurrent ? theme.textPrimary : theme.textSecondary,
993
+ marginTop: 2
994
+ },
995
+ children: entry.text
996
+ }
997
+ )
998
+ ] })
999
+ ]
1000
+ },
1001
+ i
1002
+ )) })
1003
+ ]
1004
+ }
1005
+ );
1006
+ }
1007
+
1008
+ // src/components/GanttTimeline/GanttTimeline.tsx
1009
+ var import_react10 = require("react");
1010
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1011
+ function GanttTimeline({
1012
+ snapshots,
1013
+ selectedIndex = 0,
1014
+ onSelect,
1015
+ size = "default",
1016
+ unstyled = false,
1017
+ className,
1018
+ style
1019
+ }) {
1020
+ const totalWallTime = (0, import_react10.useMemo)(
1021
+ () => Math.max(...snapshots.map((s) => s.startMs + s.durationMs), 1),
1022
+ [snapshots]
1023
+ );
1024
+ const fs = fontSize[size];
1025
+ const pad = padding[size];
1026
+ const labelWidth = size === "compact" ? 50 : size === "detailed" ? 100 : 80;
1027
+ const msWidth = size === "compact" ? 28 : 36;
1028
+ if (unstyled) {
1029
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className, style, "data-fp": "gantt-timeline", children: snapshots.map((snap, idx) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1030
+ "div",
1031
+ {
1032
+ "data-fp": "gantt-bar",
1033
+ "data-selected": idx === selectedIndex,
1034
+ "data-visible": idx <= selectedIndex,
1035
+ onClick: () => onSelect?.(idx),
1036
+ children: [
1037
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "data-fp": "gantt-label", children: snap.stageLabel }),
1038
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { "data-fp": "gantt-duration", children: [
1039
+ snap.durationMs,
1040
+ "ms"
1041
+ ] })
1042
+ ]
1043
+ },
1044
+ snap.stageName
1045
+ )) });
1046
+ }
1047
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1048
+ "div",
1049
+ {
1050
+ className,
1051
+ style: { padding: pad, fontFamily: theme.fontSans, ...style },
1052
+ "data-fp": "gantt-timeline",
1053
+ children: [
1054
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1055
+ "span",
1056
+ {
1057
+ style: {
1058
+ fontSize: fs.label,
1059
+ fontWeight: 600,
1060
+ color: theme.textMuted,
1061
+ textTransform: "uppercase",
1062
+ letterSpacing: "0.08em"
1063
+ },
1064
+ children: size === "compact" ? "Timeline" : "Execution Timeline"
1065
+ }
1066
+ ),
1067
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1068
+ "div",
1069
+ {
1070
+ style: {
1071
+ marginTop: 8,
1072
+ display: "flex",
1073
+ flexDirection: "column",
1074
+ gap: 4
1075
+ },
1076
+ children: snapshots.map((snap, idx) => {
1077
+ const leftPct = snap.startMs / totalWallTime * 100;
1078
+ const widthPct = Math.max(snap.durationMs / totalWallTime * 100, 1);
1079
+ const isSelected = idx === selectedIndex;
1080
+ const isVisible = idx <= selectedIndex;
1081
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1082
+ "div",
1083
+ {
1084
+ onClick: () => onSelect?.(idx),
1085
+ style: {
1086
+ display: "flex",
1087
+ alignItems: "center",
1088
+ gap: size === "compact" ? 4 : 8,
1089
+ cursor: onSelect ? "pointer" : "default",
1090
+ opacity: isVisible ? 1 : 0.3,
1091
+ transition: "opacity 0.3s ease"
1092
+ },
1093
+ children: [
1094
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1095
+ "span",
1096
+ {
1097
+ style: {
1098
+ width: labelWidth,
1099
+ fontSize: fs.small,
1100
+ color: isSelected ? theme.primary : theme.textMuted,
1101
+ fontWeight: isSelected ? 600 : 400,
1102
+ textAlign: "right",
1103
+ flexShrink: 0,
1104
+ overflow: "hidden",
1105
+ textOverflow: "ellipsis",
1106
+ whiteSpace: "nowrap"
1107
+ },
1108
+ children: snap.stageLabel
1109
+ }
1110
+ ),
1111
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1112
+ "div",
1113
+ {
1114
+ style: {
1115
+ flex: 1,
1116
+ height: size === "compact" ? 6 : 8,
1117
+ position: "relative",
1118
+ background: theme.bgTertiary,
1119
+ borderRadius: 3
1120
+ },
1121
+ children: isVisible && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1122
+ "div",
1123
+ {
1124
+ style: {
1125
+ position: "absolute",
1126
+ left: `${leftPct}%`,
1127
+ top: 0,
1128
+ width: `${widthPct}%`,
1129
+ height: "100%",
1130
+ borderRadius: 3,
1131
+ background: isSelected ? theme.primary : theme.success,
1132
+ transition: "width 0.3s ease"
1133
+ }
1134
+ }
1135
+ )
1136
+ }
1137
+ ),
1138
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1139
+ "span",
1140
+ {
1141
+ style: {
1142
+ fontSize: fs.small,
1143
+ color: theme.textMuted,
1144
+ fontFamily: theme.fontMono,
1145
+ width: msWidth,
1146
+ flexShrink: 0
1147
+ },
1148
+ children: [
1149
+ snap.durationMs,
1150
+ "ms"
1151
+ ]
1152
+ }
1153
+ )
1154
+ ]
1155
+ },
1156
+ snap.stageName
1157
+ );
1158
+ })
1159
+ }
1160
+ ),
1161
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1162
+ "div",
1163
+ {
1164
+ style: {
1165
+ marginTop: 4,
1166
+ marginLeft: labelWidth + (size === "compact" ? 4 : 8),
1167
+ marginRight: msWidth + (size === "compact" ? 4 : 8),
1168
+ display: "flex",
1169
+ justifyContent: "space-between",
1170
+ fontSize: fs.small - 1,
1171
+ color: theme.textMuted,
1172
+ fontFamily: theme.fontMono
1173
+ },
1174
+ children: [
1175
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "0ms" }),
1176
+ size !== "compact" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1177
+ (totalWallTime / 2).toFixed(1),
1178
+ "ms"
1179
+ ] }),
1180
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1181
+ totalWallTime.toFixed(1),
1182
+ "ms"
1183
+ ] })
1184
+ ]
1185
+ }
1186
+ )
1187
+ ]
1188
+ }
1189
+ );
1190
+ }
1191
+
1192
+ // src/components/TimeTravelDebugger/TimeTravelDebugger.tsx
1193
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1194
+ function TimeTravelDebugger({
1195
+ snapshots,
1196
+ nodes,
1197
+ edges,
1198
+ showGantt = true,
1199
+ layout = "horizontal",
1200
+ title = "Time-Travel Debugger",
1201
+ size = "default",
1202
+ unstyled = false,
1203
+ className,
1204
+ style
1205
+ }) {
1206
+ const [selectedIndex, setSelectedIndex] = (0, import_react11.useState)(0);
1207
+ const fs = fontSize[size];
1208
+ const pad = padding[size];
1209
+ if (snapshots.length === 0) {
1210
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1211
+ "div",
1212
+ {
1213
+ className,
1214
+ style: {
1215
+ padding: pad * 2,
1216
+ textAlign: "center",
1217
+ color: theme.textMuted,
1218
+ ...style
1219
+ },
1220
+ children: "No snapshots to debug"
1221
+ }
1222
+ );
1223
+ }
1224
+ const isHorizontal = layout === "horizontal";
1225
+ if (unstyled) {
1226
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className, style, "data-fp": "time-travel-debugger", children: [
1227
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: title }),
1228
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1229
+ "input",
1230
+ {
1231
+ type: "range",
1232
+ min: 0,
1233
+ max: snapshots.length - 1,
1234
+ value: selectedIndex,
1235
+ onChange: (e) => setSelectedIndex(parseInt(e.target.value))
1236
+ }
1237
+ ),
1238
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1239
+ FlowchartView,
1240
+ {
1241
+ nodes,
1242
+ edges,
1243
+ snapshots,
1244
+ selectedIndex,
1245
+ onNodeClick: setSelectedIndex,
1246
+ unstyled: true
1247
+ }
1248
+ ),
1249
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1250
+ MemoryInspector,
1251
+ {
1252
+ snapshots,
1253
+ selectedIndex,
1254
+ unstyled: true
1255
+ }
1256
+ ),
1257
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1258
+ NarrativeLog,
1259
+ {
1260
+ snapshots,
1261
+ selectedIndex,
1262
+ unstyled: true
1263
+ }
1264
+ ),
1265
+ showGantt && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1266
+ GanttTimeline,
1267
+ {
1268
+ snapshots,
1269
+ selectedIndex,
1270
+ onSelect: setSelectedIndex,
1271
+ unstyled: true
1272
+ }
1273
+ )
1274
+ ] });
1275
+ }
1276
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1277
+ "div",
1278
+ {
1279
+ className,
1280
+ style: {
1281
+ display: "flex",
1282
+ flexDirection: "column",
1283
+ height: "100%",
1284
+ background: theme.bgPrimary,
1285
+ fontFamily: theme.fontSans,
1286
+ overflow: "hidden",
1287
+ ...style
1288
+ },
1289
+ "data-fp": "time-travel-debugger",
1290
+ children: [
1291
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1292
+ "div",
1293
+ {
1294
+ style: {
1295
+ padding: `${pad}px ${pad + 4}px`,
1296
+ borderBottom: `1px solid ${theme.border}`,
1297
+ background: theme.bgSecondary,
1298
+ flexShrink: 0
1299
+ },
1300
+ children: [
1301
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1302
+ "div",
1303
+ {
1304
+ style: {
1305
+ display: "flex",
1306
+ alignItems: "center",
1307
+ gap: 8,
1308
+ marginBottom: 8
1309
+ },
1310
+ children: [
1311
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1312
+ "span",
1313
+ {
1314
+ style: {
1315
+ fontSize: fs.body + 2,
1316
+ fontWeight: 600,
1317
+ color: theme.textPrimary
1318
+ },
1319
+ children: title
1320
+ }
1321
+ ),
1322
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1323
+ "span",
1324
+ {
1325
+ style: {
1326
+ fontSize: fs.small,
1327
+ color: theme.textMuted
1328
+ },
1329
+ children: "Scrub to replay execution"
1330
+ }
1331
+ )
1332
+ ]
1333
+ }
1334
+ ),
1335
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
1336
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1337
+ ScrubButton,
1338
+ {
1339
+ label: "\\u25C0",
1340
+ disabled: selectedIndex === 0,
1341
+ onClick: () => setSelectedIndex((i) => Math.max(0, i - 1))
1342
+ }
1343
+ ),
1344
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1345
+ "input",
1346
+ {
1347
+ type: "range",
1348
+ min: 0,
1349
+ max: snapshots.length - 1,
1350
+ value: selectedIndex,
1351
+ onChange: (e) => setSelectedIndex(parseInt(e.target.value)),
1352
+ style: {
1353
+ flex: 1,
1354
+ height: 4,
1355
+ accentColor: theme.primary,
1356
+ cursor: "pointer"
1357
+ }
1358
+ }
1359
+ ),
1360
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1361
+ ScrubButton,
1362
+ {
1363
+ label: "\\u25B6",
1364
+ disabled: selectedIndex === snapshots.length - 1,
1365
+ onClick: () => setSelectedIndex((i) => Math.min(snapshots.length - 1, i + 1))
1366
+ }
1367
+ ),
1368
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1369
+ "span",
1370
+ {
1371
+ style: {
1372
+ fontSize: fs.small,
1373
+ color: theme.textMuted,
1374
+ flexShrink: 0,
1375
+ fontFamily: theme.fontMono
1376
+ },
1377
+ children: [
1378
+ selectedIndex + 1,
1379
+ "/",
1380
+ snapshots.length
1381
+ ]
1382
+ }
1383
+ )
1384
+ ] })
1385
+ ]
1386
+ }
1387
+ ),
1388
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1389
+ "div",
1390
+ {
1391
+ style: {
1392
+ flex: 1,
1393
+ display: "flex",
1394
+ flexDirection: isHorizontal ? "row" : "column",
1395
+ overflow: "hidden"
1396
+ },
1397
+ children: [
1398
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1399
+ "div",
1400
+ {
1401
+ style: {
1402
+ flex: 1,
1403
+ overflow: "hidden",
1404
+ borderRight: isHorizontal ? `1px solid ${theme.border}` : "none",
1405
+ borderBottom: !isHorizontal ? `1px solid ${theme.border}` : "none"
1406
+ },
1407
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1408
+ FlowchartView,
1409
+ {
1410
+ nodes,
1411
+ edges,
1412
+ snapshots,
1413
+ selectedIndex,
1414
+ onNodeClick: setSelectedIndex,
1415
+ size
1416
+ }
1417
+ )
1418
+ }
1419
+ ),
1420
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
1421
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1422
+ MemoryInspector,
1423
+ {
1424
+ snapshots,
1425
+ selectedIndex,
1426
+ size
1427
+ }
1428
+ ),
1429
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1430
+ "div",
1431
+ {
1432
+ style: {
1433
+ height: 1,
1434
+ background: theme.border,
1435
+ margin: `0 ${pad}px`
1436
+ }
1437
+ }
1438
+ ),
1439
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1440
+ NarrativeLog,
1441
+ {
1442
+ snapshots,
1443
+ selectedIndex,
1444
+ size
1445
+ }
1446
+ )
1447
+ ] })
1448
+ ]
1449
+ }
1450
+ ),
1451
+ showGantt && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1452
+ "div",
1453
+ {
1454
+ style: {
1455
+ borderTop: `1px solid ${theme.border}`,
1456
+ background: theme.bgSecondary,
1457
+ flexShrink: 0
1458
+ },
1459
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1460
+ GanttTimeline,
1461
+ {
1462
+ snapshots,
1463
+ selectedIndex,
1464
+ onSelect: setSelectedIndex,
1465
+ size
1466
+ }
1467
+ )
1468
+ }
1469
+ )
1470
+ ]
1471
+ }
1472
+ );
1473
+ }
1474
+ function ScrubButton({
1475
+ label,
1476
+ disabled,
1477
+ onClick
1478
+ }) {
1479
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1480
+ "button",
1481
+ {
1482
+ onClick,
1483
+ disabled,
1484
+ style: {
1485
+ background: theme.bgTertiary,
1486
+ border: `1px solid ${theme.border}`,
1487
+ color: disabled ? theme.textMuted : theme.textPrimary,
1488
+ borderRadius: 6,
1489
+ width: 28,
1490
+ height: 28,
1491
+ display: "flex",
1492
+ alignItems: "center",
1493
+ justifyContent: "center",
1494
+ cursor: disabled ? "not-allowed" : "pointer",
1495
+ opacity: disabled ? 0.5 : 1,
1496
+ fontSize: 12,
1497
+ flexShrink: 0
1498
+ },
1499
+ children: label
1500
+ }
1501
+ );
1502
+ }
1503
+ // Annotate the CommonJS export names for ESM import in node:
1504
+ 0 && (module.exports = {
1505
+ FlowchartView,
1506
+ StageNode,
1507
+ SubflowBreadcrumb,
1508
+ TimeTravelDebugger,
1509
+ specToReactFlow,
1510
+ useSubflowNavigation
1511
+ });
1512
+ //# sourceMappingURL=flowchart.cjs.map