footprint-explainable-ui 0.28.0 → 0.29.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.
package/dist/index.cjs CHANGED
@@ -50,13 +50,16 @@ __export(src_exports, {
50
50
  SubflowTree: () => SubflowTree,
51
51
  TimeTravelControls: () => TimeTravelControls,
52
52
  TraceViewer: () => TraceViewer,
53
+ TraceWalkCard: () => TraceWalkCard,
53
54
  buildEntryRangeIndex: () => buildEntryRangeIndex,
55
+ buildTraceWalk: () => buildTraceWalk,
54
56
  computeRevealedEntryCount: () => computeRevealedEntryCount,
55
57
  coolDark: () => coolDark,
56
58
  coolLight: () => coolLight,
57
59
  createSnapshots: () => createSnapshots,
58
60
  defaultTokens: () => defaultTokens,
59
61
  extractSubflowNarrative: () => extractSubflowNarrative,
62
+ formatTraceWalk: () => formatTraceWalk,
60
63
  mergeWritePatch: () => mergeWritePatch,
61
64
  rawDefaults: () => rawDefaults,
62
65
  subflowResultToSnapshots: () => subflowResultToSnapshots,
@@ -2063,6 +2066,7 @@ function TimeTravelControls({
2063
2066
  selectedIndex,
2064
2067
  onIndexChange,
2065
2068
  autoPlayable = true,
2069
+ tracing = null,
2066
2070
  size = "default",
2067
2071
  unstyled = false,
2068
2072
  className,
@@ -2071,10 +2075,36 @@ function TimeTravelControls({
2071
2075
  const [playing, setPlaying] = (0, import_react10.useState)(false);
2072
2076
  const playRef = (0, import_react10.useRef)(null);
2073
2077
  const total = snapshots.length;
2074
- const canPrev = selectedIndex > 0;
2075
- const canNext = selectedIndex < total - 1;
2078
+ const isTracing = !!tracing;
2079
+ const stopSet = (0, import_react10.useMemo)(
2080
+ () => tracing ? new Set(tracing.stopIndices) : null,
2081
+ [tracing]
2082
+ );
2083
+ const earlierStop = (0, import_react10.useMemo)(() => {
2084
+ if (!tracing) return null;
2085
+ const earlier = tracing.stopIndices.filter((i) => i < selectedIndex);
2086
+ return earlier.length > 0 ? earlier[earlier.length - 1] : null;
2087
+ }, [tracing, selectedIndex]);
2088
+ const laterStop = (0, import_react10.useMemo)(() => {
2089
+ if (!tracing) return null;
2090
+ return tracing.stopIndices.find((i) => i > selectedIndex) ?? null;
2091
+ }, [tracing, selectedIndex]);
2092
+ const canPrev = isTracing ? earlierStop !== null : selectedIndex > 0;
2093
+ const canNext = isTracing ? laterStop !== null : selectedIndex < total - 1;
2094
+ const goPrev = (0, import_react10.useCallback)(() => {
2095
+ setPlaying(false);
2096
+ if (isTracing) {
2097
+ if (earlierStop !== null) onIndexChange(earlierStop);
2098
+ } else if (selectedIndex > 0) onIndexChange(selectedIndex - 1);
2099
+ }, [isTracing, earlierStop, selectedIndex, onIndexChange]);
2100
+ const goNext = (0, import_react10.useCallback)(() => {
2101
+ setPlaying(false);
2102
+ if (isTracing) {
2103
+ if (laterStop !== null) onIndexChange(laterStop);
2104
+ } else if (selectedIndex < total - 1) onIndexChange(selectedIndex + 1);
2105
+ }, [isTracing, laterStop, selectedIndex, total, onIndexChange]);
2076
2106
  (0, import_react10.useEffect)(() => {
2077
- if (!playing || !autoPlayable) return;
2107
+ if (!playing || !autoPlayable || isTracing) return;
2078
2108
  if (selectedIndex >= total - 1) {
2079
2109
  setPlaying(false);
2080
2110
  return;
@@ -2090,7 +2120,7 @@ function TimeTravelControls({
2090
2120
  return () => {
2091
2121
  if (playRef.current) clearTimeout(playRef.current);
2092
2122
  };
2093
- }, [playing, selectedIndex, snapshots, total, onIndexChange, autoPlayable]);
2123
+ }, [playing, selectedIndex, snapshots, total, onIndexChange, autoPlayable, isTracing]);
2094
2124
  const togglePlay = (0, import_react10.useCallback)(() => {
2095
2125
  if (playing) {
2096
2126
  setPlaying(false);
@@ -2103,20 +2133,22 @@ function TimeTravelControls({
2103
2133
  (e) => {
2104
2134
  if (e.key === "ArrowLeft" && canPrev && !playing) {
2105
2135
  e.preventDefault();
2106
- setPlaying(false);
2107
- onIndexChange(selectedIndex - 1);
2136
+ goPrev();
2108
2137
  } else if (e.key === "ArrowRight" && canNext && !playing) {
2109
2138
  e.preventDefault();
2110
- setPlaying(false);
2111
- onIndexChange(selectedIndex + 1);
2112
- } else if (e.key === " " && autoPlayable) {
2139
+ goNext();
2140
+ } else if (e.key === "Escape" && isTracing) {
2141
+ e.preventDefault();
2142
+ tracing.onExit();
2143
+ } else if (e.key === " " && autoPlayable && !isTracing) {
2113
2144
  e.preventDefault();
2114
2145
  togglePlay();
2115
2146
  }
2116
2147
  },
2117
- [canPrev, canNext, playing, selectedIndex, onIndexChange, autoPlayable, togglePlay]
2148
+ [canPrev, canNext, playing, goPrev, goNext, autoPlayable, togglePlay, isTracing, tracing]
2118
2149
  );
2119
2150
  const fs = fontSize[size];
2151
+ const accent = "var(--fp-accent, #6366f1)";
2120
2152
  if (unstyled) {
2121
2153
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2122
2154
  "div",
@@ -2124,52 +2156,69 @@ function TimeTravelControls({
2124
2156
  className,
2125
2157
  style,
2126
2158
  "data-fp": "time-travel-controls",
2159
+ "data-tracing": isTracing || void 0,
2127
2160
  role: "toolbar",
2128
- "aria-label": "Time travel controls",
2161
+ "aria-label": isTracing ? `Tracing ${tracing.tracedKey}` : "Time travel controls",
2129
2162
  tabIndex: 0,
2130
2163
  onKeyDown: handleKeyDown,
2131
2164
  children: [
2165
+ isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { "data-fp": "tt-tracing-header", children: [
2166
+ "Tracing ",
2167
+ tracing.tracedKey,
2168
+ tracing.viaKey && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2169
+ " ",
2170
+ "\u25B8 via ",
2171
+ tracing.viaKey,
2172
+ " ",
2173
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-fp": "tt-show-all", onClick: tracing.onShowAll, children: "show all" })
2174
+ ] }),
2175
+ " \xB7 ",
2176
+ "stop ",
2177
+ tracing.stopOrdinal,
2178
+ " of ",
2179
+ tracing.totalStops,
2180
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-fp": "tt-exit-tracing", onClick: tracing.onExit, "aria-label": "Exit tracing", children: "Done" })
2181
+ ] }),
2132
2182
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2133
2183
  "button",
2134
2184
  {
2135
2185
  "data-fp": "tt-prev",
2136
2186
  disabled: !canPrev || playing,
2137
- onClick: () => {
2138
- setPlaying(false);
2139
- onIndexChange(selectedIndex - 1);
2140
- },
2141
- "aria-label": "Previous stage",
2142
- children: "Prev"
2187
+ onClick: goPrev,
2188
+ "aria-label": isTracing ? "Earlier cause" : "Previous stage",
2189
+ children: isTracing ? "Earlier cause" : "Prev"
2143
2190
  }
2144
2191
  ),
2145
- autoPlayable && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-fp": "tt-play", onClick: togglePlay, "aria-label": playing ? "Pause" : "Play", children: playing ? "Pause" : "Play" }),
2192
+ autoPlayable && !isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-fp": "tt-play", onClick: togglePlay, "aria-label": playing ? "Pause" : "Play", children: playing ? "Pause" : "Play" }),
2146
2193
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2147
2194
  "button",
2148
2195
  {
2149
2196
  "data-fp": "tt-next",
2150
2197
  disabled: !canNext || playing,
2151
- onClick: () => {
2152
- setPlaying(false);
2153
- onIndexChange(selectedIndex + 1);
2154
- },
2155
- "aria-label": "Next stage",
2156
- children: "Next"
2198
+ onClick: goNext,
2199
+ "aria-label": isTracing ? "Toward result" : "Next stage",
2200
+ children: isTracing ? "Toward result" : "Next"
2157
2201
  }
2158
2202
  ),
2159
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "data-fp": "tt-ticks", children: snapshots.map((snap, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2160
- "button",
2161
- {
2162
- "data-fp": "tt-tick",
2163
- "data-active": i === selectedIndex,
2164
- "data-done": i < selectedIndex,
2165
- onClick: () => {
2166
- setPlaying(false);
2167
- onIndexChange(i);
2203
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "data-fp": "tt-ticks", children: snapshots.map((snap, i) => {
2204
+ const isStop = !stopSet || stopSet.has(i);
2205
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2206
+ "button",
2207
+ {
2208
+ "data-fp": "tt-tick",
2209
+ "data-active": i === selectedIndex,
2210
+ "data-done": i < selectedIndex,
2211
+ "data-stop": isTracing ? isStop : void 0,
2212
+ disabled: isTracing && !isStop,
2213
+ onClick: () => {
2214
+ setPlaying(false);
2215
+ onIndexChange(i);
2216
+ },
2217
+ title: snap.stageLabel
2168
2218
  },
2169
- title: snap.stageLabel
2170
- },
2171
- i
2172
- )) })
2219
+ i
2220
+ );
2221
+ }) })
2173
2222
  ]
2174
2223
  }
2175
2224
  );
@@ -2193,7 +2242,7 @@ function TimeTravelControls({
2193
2242
  style: {
2194
2243
  padding: "6px 12px",
2195
2244
  background: theme.bgSecondary,
2196
- borderBottom: `1px solid ${theme.border}`,
2245
+ borderBottom: isTracing ? `2px solid ${accent}` : `1px solid ${theme.border}`,
2197
2246
  display: "flex",
2198
2247
  alignItems: "center",
2199
2248
  gap: 6,
@@ -2201,25 +2250,86 @@ function TimeTravelControls({
2201
2250
  ...style
2202
2251
  },
2203
2252
  "data-fp": "time-travel-controls",
2253
+ "data-tracing": isTracing || void 0,
2204
2254
  role: "toolbar",
2205
- "aria-label": "Time travel controls",
2255
+ "aria-label": isTracing ? `Tracing ${tracing.tracedKey}` : "Time travel controls",
2206
2256
  tabIndex: 0,
2207
2257
  onKeyDown: handleKeyDown,
2208
2258
  children: [
2259
+ isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2260
+ "span",
2261
+ {
2262
+ "data-fp": "tt-tracing-header",
2263
+ style: {
2264
+ display: "flex",
2265
+ alignItems: "center",
2266
+ gap: 6,
2267
+ flexShrink: 0,
2268
+ fontSize: fs.body
2269
+ },
2270
+ children: [
2271
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2272
+ "span",
2273
+ {
2274
+ style: {
2275
+ fontSize: 10,
2276
+ fontWeight: 700,
2277
+ letterSpacing: "0.06em",
2278
+ textTransform: "uppercase",
2279
+ color: "#fff",
2280
+ background: accent,
2281
+ borderRadius: 4,
2282
+ padding: "2px 7px"
2283
+ },
2284
+ children: "Tracing"
2285
+ }
2286
+ ),
2287
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontFamily: "monospace", fontWeight: 600, color: accent }, children: tracing.tracedKey }),
2288
+ tracing.viaKey && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: { color: theme.textMuted }, children: [
2289
+ "\u25B8 via",
2290
+ " ",
2291
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontFamily: "monospace", color: theme.textSecondary }, children: tracing.viaKey }),
2292
+ " ",
2293
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2294
+ "button",
2295
+ {
2296
+ "data-fp": "tt-show-all",
2297
+ onClick: tracing.onShowAll,
2298
+ style: {
2299
+ border: "none",
2300
+ background: "transparent",
2301
+ color: accent,
2302
+ cursor: "pointer",
2303
+ fontSize: fs.body,
2304
+ textDecoration: "underline",
2305
+ padding: 0
2306
+ },
2307
+ children: "show all"
2308
+ }
2309
+ )
2310
+ ] }),
2311
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: { color: theme.textMuted }, children: [
2312
+ "\xB7 stop ",
2313
+ tracing.stopOrdinal,
2314
+ " of ",
2315
+ tracing.totalStops
2316
+ ] })
2317
+ ]
2318
+ }
2319
+ ),
2209
2320
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2210
2321
  "button",
2211
2322
  {
2212
2323
  style: btnStyle(!canPrev || playing),
2213
2324
  disabled: !canPrev || playing,
2214
- onClick: () => {
2215
- setPlaying(false);
2216
- onIndexChange(selectedIndex - 1);
2217
- },
2218
- "aria-label": "Previous stage",
2219
- children: "\u25C0"
2325
+ onClick: goPrev,
2326
+ "aria-label": isTracing ? "Earlier cause" : "Previous stage",
2327
+ title: isTracing ? "Earlier cause" : "Previous stage",
2328
+ "data-fp": "tt-prev",
2329
+ children: isTracing ? "\u25C0 earlier cause" : "\u25C0"
2220
2330
  }
2221
2331
  ),
2222
- autoPlayable && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2332
+ autoPlayable && !isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2223
2333
  "button",
2224
2334
  {
2225
2335
  onClick: togglePlay,
@@ -2247,12 +2357,11 @@ function TimeTravelControls({
2247
2357
  {
2248
2358
  style: btnStyle(!canNext || playing),
2249
2359
  disabled: !canNext || playing,
2250
- onClick: () => {
2251
- setPlaying(false);
2252
- onIndexChange(selectedIndex + 1);
2253
- },
2254
- "aria-label": "Next stage",
2255
- children: "\u25B6"
2360
+ onClick: goNext,
2361
+ "aria-label": isTracing ? "Toward result" : "Next stage",
2362
+ title: isTracing ? "Toward result" : "Next stage",
2363
+ "data-fp": "tt-next",
2364
+ children: isTracing ? "toward result \u25B6" : "\u25B6"
2256
2365
  }
2257
2366
  ),
2258
2367
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -2268,6 +2377,8 @@ function TimeTravelControls({
2268
2377
  children: snapshots.map((snap, i) => {
2269
2378
  const isActive = i === selectedIndex;
2270
2379
  const isDone = i < selectedIndex;
2380
+ const isStop = !stopSet || stopSet.has(i);
2381
+ const unlandable = isTracing && !isStop;
2271
2382
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2272
2383
  "button",
2273
2384
  {
@@ -2275,15 +2386,19 @@ function TimeTravelControls({
2275
2386
  setPlaying(false);
2276
2387
  onIndexChange(i);
2277
2388
  },
2278
- title: snap.stageLabel,
2389
+ disabled: unlandable,
2390
+ title: unlandable ? `${snap.stageLabel} (not part of this trace)` : snap.stageLabel,
2391
+ "data-fp": "tt-tick",
2392
+ "data-stop": isTracing ? isStop : void 0,
2393
+ "data-active": isActive || void 0,
2279
2394
  style: {
2280
2395
  flex: 1,
2281
- height: isActive ? 14 : 8,
2396
+ height: isActive ? 14 : unlandable ? 4 : 8,
2282
2397
  borderRadius: 3,
2283
2398
  border: "none",
2284
- cursor: "pointer",
2285
- background: isActive ? theme.primary : isDone ? theme.success : theme.bgTertiary,
2286
- opacity: isDone || isActive ? 1 : 0.4,
2399
+ cursor: unlandable ? "default" : "pointer",
2400
+ background: isTracing ? isActive ? accent : isStop ? "color-mix(in srgb, " + accent + " 55%, transparent)" : theme.bgTertiary : isActive ? theme.primary : isDone ? theme.success : theme.bgTertiary,
2401
+ opacity: unlandable ? 0.3 : isTracing || isDone || isActive ? 1 : 0.4,
2287
2402
  transition: "all 0.15s ease"
2288
2403
  }
2289
2404
  },
@@ -2291,6 +2406,16 @@ function TimeTravelControls({
2291
2406
  );
2292
2407
  })
2293
2408
  }
2409
+ ),
2410
+ isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2411
+ "button",
2412
+ {
2413
+ "data-fp": "tt-exit-tracing",
2414
+ onClick: tracing.onExit,
2415
+ "aria-label": "Exit tracing",
2416
+ style: { ...btnStyle(false), background: "transparent" },
2417
+ children: "Done \u2715"
2418
+ }
2294
2419
  )
2295
2420
  ]
2296
2421
  }
@@ -2298,7 +2423,7 @@ function TimeTravelControls({
2298
2423
  }
2299
2424
 
2300
2425
  // src/components/ExplainableShell/ExplainableShell.tsx
2301
- var import_react31 = require("react");
2426
+ var import_react32 = require("react");
2302
2427
 
2303
2428
  // src/components/ExplainableShell/_internal/dataTrace.ts
2304
2429
  function readsByStep(tree) {
@@ -2361,6 +2486,589 @@ function buildDataTrace(commitLog, executionTree, targetRuntimeStageId, maxDepth
2361
2486
  return { frames, readsAvailable };
2362
2487
  }
2363
2488
 
2489
+ // src/components/ExplainableShell/_internal/traceWalk.ts
2490
+ var DEFAULT_MAX_DEPTH = 10;
2491
+ var DEFAULT_MAX_FRAMES = 50;
2492
+ function buildTraceWalk(commitLog, executionTree, key, opts) {
2493
+ const log = commitLog ?? [];
2494
+ const cutoff = opts?.beforeCommitIdx ?? log.length;
2495
+ const maxDepth = opts?.maxDepth ?? DEFAULT_MAX_DEPTH;
2496
+ const maxFrames = opts?.maxFrames ?? DEFAULT_MAX_FRAMES;
2497
+ const writerOf = (k, beforeIdx) => {
2498
+ for (let i = Math.min(beforeIdx, log.length) - 1; i >= 0; i--) {
2499
+ if (log[i].trace.some((t) => t.path === k)) return i;
2500
+ }
2501
+ return -1;
2502
+ };
2503
+ const anchorIdx = writerOf(key, cutoff);
2504
+ if (anchorIdx < 0) {
2505
+ const firstEver = log.findIndex((c) => c.trace.some((t) => t.path === key));
2506
+ const missing = firstEver < 0 ? { reason: "never-written" } : {
2507
+ reason: "not-yet-written",
2508
+ firstWriteCommitIdx: firstEver,
2509
+ firstWriterRuntimeStageId: log[firstEver].runtimeStageId,
2510
+ firstWriterStageName: log[firstEver].stage
2511
+ };
2512
+ return { key, stops: [], missing, inputTermini: [], readsAvailable: true, truncated: false };
2513
+ }
2514
+ const slice = buildDataTrace(
2515
+ log.slice(0, anchorIdx + 1),
2516
+ executionTree,
2517
+ log[anchorIdx].runtimeStageId,
2518
+ maxDepth,
2519
+ maxFrames + 1
2520
+ );
2521
+ const truncated = slice.frames.length > maxFrames;
2522
+ const frames = truncated ? slice.frames.slice(0, maxFrames) : slice.frames;
2523
+ const idxOf = /* @__PURE__ */ new Map();
2524
+ for (let i = 0; i < log.length; i++) idxOf.set(log[i].runtimeStageId, i);
2525
+ const readsOf = readKeysByStep(executionTree);
2526
+ const inputTermini = [];
2527
+ const terminiSeen = /* @__PURE__ */ new Set();
2528
+ const stops = frames.map((f) => {
2529
+ const commitIdx = idxOf.get(f.runtimeStageId) ?? -1;
2530
+ const ingredients = (readsOf.get(f.runtimeStageId) ?? []).map((k) => {
2531
+ const w = writerOf(k, commitIdx);
2532
+ if (w < 0 && !terminiSeen.has(k)) {
2533
+ terminiSeen.add(k);
2534
+ inputTermini.push(k);
2535
+ }
2536
+ return {
2537
+ key: k,
2538
+ writerRuntimeStageId: w >= 0 ? log[w].runtimeStageId : null,
2539
+ writerStageName: w >= 0 ? log[w].stage : null,
2540
+ writerCommitIdx: w >= 0 ? w : null
2541
+ };
2542
+ });
2543
+ return {
2544
+ runtimeStageId: f.runtimeStageId,
2545
+ stageId: f.stageId,
2546
+ stageName: f.stageName,
2547
+ commitIdx,
2548
+ contributedKeys: [],
2549
+ keysWritten: f.keysWritten,
2550
+ ingredients,
2551
+ depth: f.depth,
2552
+ loopPass: 0
2553
+ };
2554
+ });
2555
+ const stopById = new Map(stops.map((s) => [s.runtimeStageId, s]));
2556
+ const contributed = /* @__PURE__ */ new Map();
2557
+ contributed.set(log[anchorIdx].runtimeStageId, /* @__PURE__ */ new Set([key]));
2558
+ for (const s of stops) {
2559
+ for (const ing of s.ingredients) {
2560
+ if (!ing.writerRuntimeStageId || !stopById.has(ing.writerRuntimeStageId)) continue;
2561
+ const set = contributed.get(ing.writerRuntimeStageId) ?? /* @__PURE__ */ new Set();
2562
+ set.add(ing.key);
2563
+ contributed.set(ing.writerRuntimeStageId, set);
2564
+ }
2565
+ }
2566
+ for (const s of stops) s.contributedKeys = [...contributed.get(s.runtimeStageId) ?? []];
2567
+ stops.sort((a, b) => b.commitIdx - a.commitIdx);
2568
+ const byStagePart = /* @__PURE__ */ new Map();
2569
+ for (const s of stops) {
2570
+ const part = s.runtimeStageId.split("#")[0];
2571
+ const arr = byStagePart.get(part) ?? [];
2572
+ arr.push(s);
2573
+ byStagePart.set(part, arr);
2574
+ }
2575
+ for (const arr of byStagePart.values()) {
2576
+ if (arr.length < 2) continue;
2577
+ for (let i = 0; i < arr.length; i++) arr[i].loopPass = arr.length - i;
2578
+ }
2579
+ return { key, stops, missing: null, inputTermini, readsAvailable: slice.readsAvailable, truncated };
2580
+ }
2581
+ function readKeysByStep(tree) {
2582
+ const byStep = /* @__PURE__ */ new Map();
2583
+ const root = tree;
2584
+ if (!root) return byStep;
2585
+ const visited = /* @__PURE__ */ new Set();
2586
+ const stack = [root];
2587
+ while (stack.length > 0) {
2588
+ const node = stack.pop();
2589
+ if (visited.has(node)) continue;
2590
+ visited.add(node);
2591
+ if (node.runtimeStageId && node.stageReads) {
2592
+ const keys = Object.keys(node.stageReads);
2593
+ if (keys.length > 0) byStep.set(node.runtimeStageId, keys);
2594
+ }
2595
+ if (node.next) stack.push(node.next);
2596
+ if (node.children) for (const c of node.children) stack.push(c);
2597
+ }
2598
+ return byStep;
2599
+ }
2600
+ function formatTraceWalk(walk, stepNumberOf) {
2601
+ const lines = [];
2602
+ if (walk.missing) {
2603
+ if (walk.missing.reason === "never-written") {
2604
+ lines.push(
2605
+ `\`${walk.key}\` was never written in this run \u2014 it arrived with the run's inputs.`
2606
+ );
2607
+ } else {
2608
+ const at = walk.missing.firstWriterRuntimeStageId ? stepNumberOf(walk.missing.firstWriterRuntimeStageId) : null;
2609
+ lines.push(
2610
+ `\`${walk.key}\` has not been written yet at this moment \u2014 its first write happens later` + (walk.missing.firstWriterStageName ? `, at ${walk.missing.firstWriterStageName}${at ? ` (step ${at})` : ""}.` : ".")
2611
+ );
2612
+ }
2613
+ return lines.join("\n");
2614
+ }
2615
+ lines.push(`Tracing \`${walk.key}\` \u2014 ${walk.stops.length} stops, newest first.`);
2616
+ walk.stops.forEach((stop, i) => {
2617
+ const step = stepNumberOf(stop.runtimeStageId);
2618
+ const pass = stop.loopPass > 0 ? ` (pass ${stop.loopPass})` : "";
2619
+ const made = stop.ingredients.length > 0 ? ` \xB7 made from: ${stop.ingredients.map(
2620
+ (ing) => ing.writerRuntimeStageId ? `${ing.key} (\u2190 ${ing.writerStageName}${stepNumberOf(ing.writerRuntimeStageId) ? `, step ${stepNumberOf(ing.writerRuntimeStageId)}` : ""})` : `${ing.key} (run input \u2014 never written)`
2621
+ ).join(", ")}` : walk.readsAvailable ? " \xB7 reads nothing \u2014 origin" : "";
2622
+ lines.push(
2623
+ `stop ${i + 1}/${walk.stops.length} \xB7 ${step ? `step ${step} \xB7 ` : ""}${stop.stageName}${pass} wrote \`${stop.contributedKeys.join("`, `")}\`${made}`
2624
+ );
2625
+ });
2626
+ if (walk.inputTermini.length > 0) {
2627
+ lines.push(`run inputs (never written): ${walk.inputTermini.join(", ")}`);
2628
+ }
2629
+ if (!walk.readsAvailable) {
2630
+ lines.push("\u26A0 reads were not recorded \u2014 dependencies are unknowable, not absent.");
2631
+ }
2632
+ if (walk.truncated) {
2633
+ lines.push("\u26A0 walk truncated at its frame budget \u2014 the earliest stop may not be the true origin.");
2634
+ }
2635
+ return lines.join("\n");
2636
+ }
2637
+
2638
+ // src/components/DataTracePanel/TraceWalkCard.tsx
2639
+ var import_react11 = require("react");
2640
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2641
+ var CHIP_COLORS = ["#0d9488", "#d97706", "#7c3aed", "#e11d48"];
2642
+ var TraceWalkCard = (0, import_react11.memo)(function TraceWalkCard2({
2643
+ walk,
2644
+ cursorRuntimeStageId,
2645
+ viaKey,
2646
+ stepNumberOf,
2647
+ previewValueOf,
2648
+ onFollowIngredient,
2649
+ onJumpToStop,
2650
+ onShowAll,
2651
+ onExit
2652
+ }) {
2653
+ const [copied, setCopied] = (0, import_react11.useState)(false);
2654
+ const accent = "var(--fp-accent, #6366f1)";
2655
+ const currentIdx = (0, import_react11.useMemo)(() => {
2656
+ if (!cursorRuntimeStageId) return 0;
2657
+ const i = walk.stops.findIndex((s) => s.runtimeStageId === cursorRuntimeStageId);
2658
+ return i >= 0 ? i : 0;
2659
+ }, [walk, cursorRuntimeStageId]);
2660
+ const current = walk.stops[currentIdx];
2661
+ const copyStory = () => {
2662
+ const text = formatTraceWalk(walk, stepNumberOf);
2663
+ void navigator.clipboard?.writeText(text).then(() => {
2664
+ setCopied(true);
2665
+ setTimeout(() => setCopied(false), 1600);
2666
+ });
2667
+ };
2668
+ if (walk.missing) {
2669
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-fp": "trace-walk-card", "data-missing": walk.missing.reason, style: { padding: "14px", fontSize: 13, lineHeight: 1.55 }, children: [
2670
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CardHeader, { label: `Why this value \u2014 \`${walk.key}\``, onExit }),
2671
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { color: theme.textPrimary, marginTop: 8 }, children: walk.missing.reason === "never-written" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2672
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { style: { color: accent }, children: walk.key }),
2673
+ " was ",
2674
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: "never written in this run" }),
2675
+ " \u2014 it arrived with the run's inputs."
2676
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2677
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { style: { color: accent }, children: walk.key }),
2678
+ " has ",
2679
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: "not been written yet at this moment" }),
2680
+ " \u2014 its first write happens later",
2681
+ walk.missing.firstWriterStageName && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2682
+ ", at ",
2683
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: walk.missing.firstWriterStageName }),
2684
+ walk.missing.firstWriterRuntimeStageId && stepNumberOf(walk.missing.firstWriterRuntimeStageId) && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2685
+ " (step ",
2686
+ stepNumberOf(walk.missing.firstWriterRuntimeStageId),
2687
+ ")"
2688
+ ] })
2689
+ ] }),
2690
+ "."
2691
+ ] }) })
2692
+ ] });
2693
+ }
2694
+ if (!current) return null;
2695
+ const step = stepNumberOf(current.runtimeStageId);
2696
+ const preview = previewValueOf ? previewValue(previewValueOf(current.contributedKeys[0] ?? walk.key)) : null;
2697
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-fp": "trace-walk-card", style: { padding: "10px 14px 14px", fontSize: 13, lineHeight: 1.5 }, children: [
2698
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2699
+ CardHeader,
2700
+ {
2701
+ label: `Why this value \u2014 stop ${currentIdx + 1} of ${walk.stops.length}`,
2702
+ onExit
2703
+ }
2704
+ ),
2705
+ viaKey && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-fp": "twc-breadcrumb", style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
2706
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { style: { color: accent }, children: walk.key }),
2707
+ " \u25B8 via ",
2708
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: viaKey }),
2709
+ onShowAll && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2710
+ " \xB7 ",
2711
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2712
+ "button",
2713
+ {
2714
+ onClick: onShowAll,
2715
+ style: { border: "none", background: "transparent", color: accent, cursor: "pointer", fontSize: 11, textDecoration: "underline", padding: 0 },
2716
+ children: "show all ingredients"
2717
+ }
2718
+ )
2719
+ ] })
2720
+ ] }),
2721
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-fp": "twc-stop-headline", style: { marginTop: 10, fontWeight: 600, color: theme.textPrimary }, children: [
2722
+ step && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted, fontWeight: 500 }, children: [
2723
+ "Step ",
2724
+ step,
2725
+ " \xB7 "
2726
+ ] }),
2727
+ current.stageName,
2728
+ current.loopPass > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted, fontWeight: 500 }, children: [
2729
+ " (pass ",
2730
+ current.loopPass,
2731
+ ")"
2732
+ ] })
2733
+ ] }),
2734
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginTop: 2, color: theme.textSecondary }, children: [
2735
+ "wrote",
2736
+ " ",
2737
+ current.contributedKeys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("code", { style: { color: accent }, children: [
2738
+ i > 0 && ", ",
2739
+ k
2740
+ ] }, k)),
2741
+ preview !== null && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted }, children: [
2742
+ " = ",
2743
+ preview
2744
+ ] })
2745
+ ] }),
2746
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 10 }, children: current.ingredients.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2747
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { fontSize: 11, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.5px", fontWeight: 600 }, children: [
2748
+ "Made from ",
2749
+ current.ingredients.length,
2750
+ " ingredient",
2751
+ current.ingredients.length > 1 ? "s" : ""
2752
+ ] }),
2753
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, marginTop: 6 }, children: current.ingredients.map((ing, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2754
+ IngredientChip,
2755
+ {
2756
+ ing,
2757
+ color: i < CHIP_COLORS.length ? CHIP_COLORS[i] : theme.textMuted,
2758
+ step: ing.writerRuntimeStageId ? stepNumberOf(ing.writerRuntimeStageId) : null,
2759
+ onFollow: onFollowIngredient
2760
+ },
2761
+ ing.key
2762
+ )) })
2763
+ ] }) : walk.readsAvailable ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { "data-fp": "twc-origin", style: { fontSize: 12, color: theme.textMuted, fontStyle: "italic" }, children: "reads nothing \u2014 this is an origin." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { "data-fp": "twc-unknowable", style: { fontSize: 12, color: theme.textMuted, fontStyle: "italic" }, children: "\u26A0 reads were not recorded \u2014 ingredients are unknowable, not absent." }) }),
2764
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginTop: 14 }, children: [
2765
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { fontSize: 11, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.5px", fontWeight: 600, marginBottom: 4 }, children: "The story, newest first" }),
2766
+ walk.stops.map((s, i) => {
2767
+ const isCurrent = i === currentIdx;
2768
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2769
+ "button",
2770
+ {
2771
+ "data-fp": "twc-itinerary-row",
2772
+ "data-current": isCurrent || void 0,
2773
+ onClick: () => onJumpToStop?.(s.runtimeStageId),
2774
+ style: {
2775
+ display: "block",
2776
+ width: "100%",
2777
+ textAlign: "left",
2778
+ border: "none",
2779
+ borderLeft: isCurrent ? `3px solid ${accent}` : "3px solid transparent",
2780
+ background: isCurrent ? "var(--fp-accent-bg, rgba(99,102,241,0.12))" : "transparent",
2781
+ padding: "4px 8px",
2782
+ cursor: onJumpToStop ? "pointer" : "default",
2783
+ color: "inherit",
2784
+ fontSize: 12
2785
+ },
2786
+ children: [
2787
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted }, children: [
2788
+ i + 1,
2789
+ "."
2790
+ ] }),
2791
+ " ",
2792
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { style: { color: accent }, children: s.contributedKeys.join(", ") }),
2793
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { color: theme.textMuted }, children: " \u2190 " }),
2794
+ s.stageName,
2795
+ s.loopPass > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted }, children: [
2796
+ " (pass ",
2797
+ s.loopPass,
2798
+ ")"
2799
+ ] }),
2800
+ stepNumberOf(s.runtimeStageId) && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted }, children: [
2801
+ " \xB7 step ",
2802
+ stepNumberOf(s.runtimeStageId)
2803
+ ] }),
2804
+ s.ingredients.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: "#d97706", fontWeight: 600 }, children: [
2805
+ " \u2442 ",
2806
+ s.ingredients.length
2807
+ ] })
2808
+ ]
2809
+ },
2810
+ s.runtimeStageId
2811
+ );
2812
+ })
2813
+ ] }),
2814
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginTop: 12, display: "flex", flexDirection: "column", gap: 4 }, children: [
2815
+ walk.inputTermini.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-fp": "twc-run-inputs", style: { fontSize: 11, color: theme.textMuted }, children: [
2816
+ "\u2691 run inputs (never written): ",
2817
+ walk.inputTermini.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("code", { children: [
2818
+ i > 0 && ", ",
2819
+ k
2820
+ ] }, k))
2821
+ ] }),
2822
+ walk.truncated && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { "data-fp": "twc-truncated", style: { fontSize: 11, color: "#d97706" }, children: "\u26A0 walk truncated at its frame budget \u2014 the earliest stop may not be the true origin." }),
2823
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2824
+ "button",
2825
+ {
2826
+ "data-fp": "twc-copy-story",
2827
+ onClick: copyStory,
2828
+ style: {
2829
+ alignSelf: "flex-start",
2830
+ marginTop: 4,
2831
+ border: `1px solid ${theme.border}`,
2832
+ background: theme.bgTertiary,
2833
+ color: theme.textPrimary,
2834
+ borderRadius: 6,
2835
+ padding: "4px 10px",
2836
+ fontSize: 11,
2837
+ fontWeight: 600,
2838
+ cursor: "pointer"
2839
+ },
2840
+ children: copied ? "Copied \u2713" : "Copy story"
2841
+ }
2842
+ )
2843
+ ] })
2844
+ ] });
2845
+ });
2846
+ function CardHeader({ label, onExit }) {
2847
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
2848
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { fontSize: 11, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.5px", fontWeight: 600 }, children: label }),
2849
+ onExit && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2850
+ "button",
2851
+ {
2852
+ "data-fp": "twc-exit",
2853
+ onClick: onExit,
2854
+ "aria-label": "Exit tracing",
2855
+ style: { border: "none", background: "transparent", color: theme.textMuted, cursor: "pointer", fontSize: 12 },
2856
+ children: "Done \u2715"
2857
+ }
2858
+ )
2859
+ ] });
2860
+ }
2861
+ function IngredientChip({
2862
+ ing,
2863
+ color,
2864
+ step,
2865
+ onFollow
2866
+ }) {
2867
+ const terminus = !ing.writerRuntimeStageId;
2868
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2869
+ "button",
2870
+ {
2871
+ "data-fp": "twc-ingredient",
2872
+ "data-terminus": terminus || void 0,
2873
+ disabled: terminus || !onFollow,
2874
+ onClick: () => onFollow?.(ing),
2875
+ title: terminus ? `${ing.key} was never written \u2014 it came in with the run's inputs` : `Follow ${ing.key} \u2014 re-anchor the walk on its writer`,
2876
+ style: {
2877
+ display: "inline-flex",
2878
+ alignItems: "center",
2879
+ gap: 4,
2880
+ border: `1px solid ${terminus ? theme.border : color}`,
2881
+ background: "transparent",
2882
+ color: terminus ? theme.textMuted : color,
2883
+ borderRadius: 12,
2884
+ padding: "3px 10px",
2885
+ fontSize: 11,
2886
+ fontWeight: 600,
2887
+ cursor: terminus || !onFollow ? "default" : "pointer"
2888
+ },
2889
+ children: [
2890
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: ing.key }),
2891
+ terminus ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { fontWeight: 400 }, children: "\u2014 run input \u2691" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { fontWeight: 400 }, children: [
2892
+ "\u2190 ",
2893
+ ing.writerStageName,
2894
+ step && ` \xB7 step ${step}`
2895
+ ] })
2896
+ ]
2897
+ }
2898
+ );
2899
+ }
2900
+ function previewValue(v2) {
2901
+ if (v2 === void 0) return null;
2902
+ try {
2903
+ const s = typeof v2 === "string" ? JSON.stringify(v2) : JSON.stringify(v2);
2904
+ if (s === void 0) return null;
2905
+ return s.length > 60 ? `${s.slice(0, 57)}\u2026` : s;
2906
+ } catch {
2907
+ return null;
2908
+ }
2909
+ }
2910
+
2911
+ // src/components/DataTracePanel/DataTracePanel.tsx
2912
+ var import_react12 = require("react");
2913
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2914
+ var DataTracePanel = (0, import_react12.memo)(function DataTracePanel2({
2915
+ frames,
2916
+ selectedStageId,
2917
+ onFrameClick,
2918
+ fromStageName,
2919
+ note
2920
+ }) {
2921
+ const noteLine = note ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", marginBottom: 8 }, children: note }) : null;
2922
+ if (frames.length === 0) {
2923
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
2924
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2925
+ "div",
2926
+ {
2927
+ style: {
2928
+ fontSize: 11,
2929
+ color: theme.textMuted,
2930
+ textTransform: "uppercase",
2931
+ letterSpacing: "0.5px",
2932
+ fontWeight: 600,
2933
+ marginBottom: 6
2934
+ },
2935
+ children: "Backward causal chain"
2936
+ }
2937
+ ),
2938
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { color: theme.textSecondary, marginBottom: 10 }, children: "Trace any value back to the stage that created it \u2014 and everything upstream that influenced it." }),
2939
+ noteLine,
2940
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { color: theme.textMuted, fontSize: 12 }, children: "Select a stage above to see its dependency chain." })
2941
+ ] });
2942
+ }
2943
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { padding: "8px 0", fontSize: 13 }, children: [
2944
+ note && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { padding: "4px 12px 0", fontSize: 11, color: theme.textMuted, fontStyle: "italic" }, children: note }),
2945
+ fromStageName && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { padding: "4px 12px 8px" }, children: [
2946
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2947
+ "div",
2948
+ {
2949
+ style: {
2950
+ fontSize: 11,
2951
+ color: theme.textMuted,
2952
+ textTransform: "uppercase",
2953
+ letterSpacing: "0.5px",
2954
+ fontWeight: 600
2955
+ },
2956
+ children: [
2957
+ "Data trace from ",
2958
+ fromStageName
2959
+ ]
2960
+ }
2961
+ ),
2962
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2963
+ "div",
2964
+ {
2965
+ style: {
2966
+ fontSize: 11,
2967
+ color: theme.textMuted,
2968
+ fontStyle: "italic",
2969
+ marginTop: 3
2970
+ },
2971
+ children: "Every value here was derived from the stages below."
2972
+ }
2973
+ )
2974
+ ] }),
2975
+ frames.map((frame, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2976
+ DataTraceFrame,
2977
+ {
2978
+ frame,
2979
+ isFirst: i === 0,
2980
+ isLast: i === frames.length - 1,
2981
+ isSelected: frame.runtimeStageId === selectedStageId,
2982
+ onClick: onFrameClick
2983
+ },
2984
+ frame.runtimeStageId
2985
+ ))
2986
+ ] });
2987
+ });
2988
+ var DataTraceFrame = (0, import_react12.memo)(function DataTraceFrame2({
2989
+ frame,
2990
+ isFirst,
2991
+ isLast,
2992
+ isSelected,
2993
+ onClick
2994
+ }) {
2995
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2996
+ "button",
2997
+ {
2998
+ onClick: () => onClick?.(frame.runtimeStageId),
2999
+ style: {
3000
+ display: "block",
3001
+ width: "100%",
3002
+ textAlign: "left",
3003
+ border: "none",
3004
+ background: isSelected ? "var(--fp-accent-bg, rgba(99,102,241,0.12))" : "transparent",
3005
+ padding: "6px 12px 6px 16px",
3006
+ cursor: onClick ? "pointer" : "default",
3007
+ borderLeft: isSelected ? "3px solid var(--fp-accent, #6366f1)" : "3px solid transparent",
3008
+ color: "inherit",
3009
+ fontSize: 13
3010
+ },
3011
+ children: [
3012
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
3013
+ !isFirst && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { color: theme.textMuted, fontSize: 11 }, children: "\u2191" }),
3014
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3015
+ "span",
3016
+ {
3017
+ style: {
3018
+ fontWeight: isFirst ? 600 : 400,
3019
+ color: isFirst ? "var(--fp-accent, #6366f1)" : theme.textPrimary
3020
+ },
3021
+ children: frame.stageName
3022
+ }
3023
+ ),
3024
+ isLast && !isFirst && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3025
+ "span",
3026
+ {
3027
+ style: {
3028
+ fontSize: 10,
3029
+ color: theme.textMuted,
3030
+ fontStyle: "italic"
3031
+ },
3032
+ children: "(origin)"
3033
+ }
3034
+ )
3035
+ ] }),
3036
+ frame.keysWritten.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3037
+ "div",
3038
+ {
3039
+ style: {
3040
+ fontSize: 11,
3041
+ color: theme.textMuted,
3042
+ paddingLeft: isFirst ? 0 : 18,
3043
+ marginTop: 2
3044
+ },
3045
+ children: [
3046
+ "wrote:",
3047
+ " ",
3048
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { color: theme.textSecondary }, children: frame.keysWritten.join(", ") })
3049
+ ]
3050
+ }
3051
+ ),
3052
+ frame.linkedBy && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3053
+ "div",
3054
+ {
3055
+ style: {
3056
+ fontSize: 11,
3057
+ color: "var(--fp-accent, #6366f1)",
3058
+ paddingLeft: 18,
3059
+ marginTop: 1
3060
+ },
3061
+ children: [
3062
+ "\u2190 via ",
3063
+ frame.linkedBy
3064
+ ]
3065
+ }
3066
+ )
3067
+ ]
3068
+ }
3069
+ );
3070
+ });
3071
+
2364
3072
  // src/utils/narrativeSync.ts
2365
3073
  function buildEntryRangeIndex(entries) {
2366
3074
  const ranges = /* @__PURE__ */ new Map();
@@ -2682,7 +3390,7 @@ function createSnapshots(stages) {
2682
3390
  }
2683
3391
 
2684
3392
  // src/components/MemoryPanel/MemoryPanel.tsx
2685
- var import_jsx_runtime11 = require("react/jsx-runtime");
3393
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2686
3394
  function MemoryPanel({
2687
3395
  snapshots,
2688
3396
  selectedIndex,
@@ -2694,12 +3402,12 @@ function MemoryPanel({
2694
3402
  const prevMemory = selectedIndex > 0 ? snapshots[selectedIndex - 1]?.memory ?? null : null;
2695
3403
  const currMemory = snapshots[selectedIndex]?.memory ?? {};
2696
3404
  if (unstyled) {
2697
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className, style, "data-fp": "memory-panel", children: [
2698
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MemoryInspector, { snapshots, selectedIndex, unstyled: true }),
2699
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScopeDiff, { previous: prevMemory, current: currMemory, unstyled: true })
3405
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className, style, "data-fp": "memory-panel", children: [
3406
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MemoryInspector, { snapshots, selectedIndex, unstyled: true }),
3407
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScopeDiff, { previous: prevMemory, current: currMemory, unstyled: true })
2700
3408
  ] });
2701
3409
  }
2702
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3410
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2703
3411
  "div",
2704
3412
  {
2705
3413
  className,
@@ -2711,19 +3419,19 @@ function MemoryPanel({
2711
3419
  },
2712
3420
  "data-fp": "memory-panel",
2713
3421
  children: [
2714
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MemoryInspector, { snapshots, selectedIndex, size }),
2715
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScopeDiff, { previous: prevMemory, current: currMemory, hideUnchanged: true, size }) })
3422
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MemoryInspector, { snapshots, selectedIndex, size }),
3423
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScopeDiff, { previous: prevMemory, current: currMemory, hideUnchanged: true, size }) })
2716
3424
  ]
2717
3425
  }
2718
3426
  );
2719
3427
  }
2720
3428
 
2721
3429
  // src/components/NarrativePanel/NarrativePanel.tsx
2722
- var import_react12 = require("react");
3430
+ var import_react14 = require("react");
2723
3431
 
2724
3432
  // src/components/StoryNarrative/StoryNarrative.tsx
2725
- var import_react11 = require("react");
2726
- var import_jsx_runtime12 = require("react/jsx-runtime");
3433
+ var import_react13 = require("react");
3434
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2727
3435
  var ENTRY_ICONS = {
2728
3436
  stage: { icon: "\u25B8", color: theme.primary, label: "Stage" },
2729
3437
  step: { icon: "\xB7", color: theme.textMuted, label: "Data operation" },
@@ -2746,7 +3454,7 @@ function StoryNarrative({
2746
3454
  const fs = fontSize[size];
2747
3455
  const pad = padding[size];
2748
3456
  const revealedCount = revealedEntryCount;
2749
- const revealed = (0, import_react11.useMemo)(() => {
3457
+ const revealed = (0, import_react13.useMemo)(() => {
2750
3458
  const raw = entries.slice(0, revealedCount);
2751
3459
  return raw.filter((e) => {
2752
3460
  const sfId = e.subflowId;
@@ -2755,7 +3463,7 @@ function StoryNarrative({
2755
3463
  return false;
2756
3464
  });
2757
3465
  }, [entries, revealedCount]);
2758
- const futureCount = (0, import_react11.useMemo)(() => {
3466
+ const futureCount = (0, import_react13.useMemo)(() => {
2759
3467
  let count = 0;
2760
3468
  for (let i = revealedCount; i < entries.length; i++) {
2761
3469
  const e = entries[i];
@@ -2763,11 +3471,11 @@ function StoryNarrative({
2763
3471
  }
2764
3472
  return count;
2765
3473
  }, [entries, revealedCount]);
2766
- const latestRef = (0, import_react11.useRef)(null);
2767
- (0, import_react11.useEffect)(() => {
3474
+ const latestRef = (0, import_react13.useRef)(null);
3475
+ (0, import_react13.useEffect)(() => {
2768
3476
  latestRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" });
2769
3477
  }, [revealed.length]);
2770
- const numberedEntries = (0, import_react11.useMemo)(() => {
3478
+ const numberedEntries = (0, import_react13.useMemo)(() => {
2771
3479
  let counter = 0;
2772
3480
  const subflowSeen = /* @__PURE__ */ new Set();
2773
3481
  let prevType = "";
@@ -2815,13 +3523,13 @@ function StoryNarrative({
2815
3523
  });
2816
3524
  }, [revealed]);
2817
3525
  if (unstyled) {
2818
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className, style: outerStyle, "data-fp": "story-narrative", role: "log", children: numberedEntries.map((entry, i) => {
3526
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className, style: outerStyle, "data-fp": "story-narrative", role: "log", children: numberedEntries.map((entry, i) => {
2819
3527
  if (entry.isSubflowExit) return null;
2820
3528
  const ht = entry.headingType;
2821
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { "data-fp": "narrative-entry", "data-type": entry.type, children: entry.heading ? entry.text.startsWith("[") ? `${entry.heading}. ${entry.text}` : `${entry.heading}. [${ht}: ${entry.stageName ?? ""}] ${entry.text}` : entry.text }, i);
3529
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { "data-fp": "narrative-entry", "data-type": entry.type, children: entry.heading ? entry.text.startsWith("[") ? `${entry.heading}. ${entry.text}` : `${entry.heading}. [${ht}: ${entry.stageName ?? ""}] ${entry.text}` : entry.text }, i);
2822
3530
  }) });
2823
3531
  }
2824
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3532
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2825
3533
  "div",
2826
3534
  {
2827
3535
  className,
@@ -2846,7 +3554,7 @@ function StoryNarrative({
2846
3554
  const isSubflow = entry.isSubflow;
2847
3555
  const isLast = i === numberedEntries.length - 1;
2848
3556
  const headingType = entry.headingType;
2849
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3557
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2850
3558
  "div",
2851
3559
  {
2852
3560
  ref: isLast ? latestRef : void 0,
@@ -2859,7 +3567,7 @@ function StoryNarrative({
2859
3567
  marginTop: isHeading && i > 0 ? 8 : 0
2860
3568
  },
2861
3569
  children: [
2862
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3570
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2863
3571
  "span",
2864
3572
  {
2865
3573
  style: {
@@ -2875,7 +3583,7 @@ function StoryNarrative({
2875
3583
  children: meta.icon
2876
3584
  }
2877
3585
  ),
2878
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3586
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2879
3587
  "span",
2880
3588
  {
2881
3589
  style: {
@@ -2885,15 +3593,15 @@ function StoryNarrative({
2885
3593
  lineHeight: 1.6,
2886
3594
  fontFamily: entry.type === "step" ? theme.fontMono : theme.fontSans
2887
3595
  },
2888
- children: entry.heading && headingType ? entry.text.startsWith("[") ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2889
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("strong", { children: [
3596
+ children: entry.heading && headingType ? entry.text.startsWith("[") ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3597
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("strong", { children: [
2890
3598
  entry.heading,
2891
3599
  "."
2892
3600
  ] }),
2893
3601
  " ",
2894
3602
  entry.text
2895
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2896
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("strong", { children: [
3603
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3604
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("strong", { children: [
2897
3605
  entry.heading,
2898
3606
  ". [",
2899
3607
  headingType,
@@ -2910,7 +3618,7 @@ function StoryNarrative({
2910
3618
  i
2911
3619
  );
2912
3620
  }),
2913
- futureCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: {
3621
+ futureCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: {
2914
3622
  opacity: 0.3,
2915
3623
  fontSize: fs.small,
2916
3624
  color: theme.textMuted,
@@ -2928,7 +3636,7 @@ function StoryNarrative({
2928
3636
  }
2929
3637
 
2930
3638
  // src/components/NarrativePanel/NarrativePanel.tsx
2931
- var import_jsx_runtime13 = require("react/jsx-runtime");
3639
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2932
3640
  function safeJsonStringify(value) {
2933
3641
  const seen = /* @__PURE__ */ new WeakSet();
2934
3642
  const MAX_CHARS = 5e5;
@@ -2966,7 +3674,7 @@ function NarrativePanel({
2966
3674
  }) {
2967
3675
  const fs = fontSize[size];
2968
3676
  const pad = padding[size];
2969
- const narrative = (0, import_react12.useMemo)(() => {
3677
+ const narrative = (0, import_react14.useMemo)(() => {
2970
3678
  const lines = [];
2971
3679
  for (const snap of snapshots) {
2972
3680
  const stageLines = (snap.narrative ?? "").split("\n").filter(Boolean);
@@ -2974,7 +3682,7 @@ function NarrativePanel({
2974
3682
  }
2975
3683
  return lines;
2976
3684
  }, [snapshots]);
2977
- const revealedCount = (0, import_react12.useMemo)(() => {
3685
+ const revealedCount = (0, import_react14.useMemo)(() => {
2978
3686
  if (snapshots.length === 0 || narrative.length === 0) return narrative.length;
2979
3687
  const stageBoundaries = [];
2980
3688
  for (let i = 0; i < narrative.length; i++) {
@@ -2991,17 +3699,17 @@ function NarrativePanel({
2991
3699
  const endIdx = groupsToShow < stageBoundaries.length ? stageBoundaries[groupsToShow] : narrative.length;
2992
3700
  return Math.max(1, endIdx);
2993
3701
  }, [snapshots.length, selectedIndex, narrative]);
2994
- const rangeIndex = (0, import_react12.useMemo)(
3702
+ const rangeIndex = (0, import_react14.useMemo)(
2995
3703
  () => narrativeEntries?.length ? buildEntryRangeIndex(narrativeEntries) : void 0,
2996
3704
  [narrativeEntries]
2997
3705
  );
2998
- const revealedEntryCount = (0, import_react12.useMemo)(
3706
+ const revealedEntryCount = (0, import_react14.useMemo)(
2999
3707
  () => narrativeEntries?.length ? computeRevealedEntryCount(narrativeEntries, snapshots, selectedIndex, rangeIndex) : 0,
3000
3708
  [narrativeEntries, snapshots, selectedIndex, rangeIndex]
3001
3709
  );
3002
3710
  const hasStructured = narrativeEntries && narrativeEntries.length > 0;
3003
- const [copied, setCopied] = (0, import_react12.useState)(false);
3004
- const buildLLMNarrative = (0, import_react12.useCallback)(() => {
3711
+ const [copied, setCopied] = (0, import_react14.useState)(false);
3712
+ const buildLLMNarrative = (0, import_react14.useCallback)(() => {
3005
3713
  if (!narrativeEntries?.length) {
3006
3714
  return narrative.join("\n");
3007
3715
  }
@@ -3113,16 +3821,16 @@ function NarrativePanel({
3113
3821
  }
3114
3822
  return sections.join("\n");
3115
3823
  }, [narrativeEntries, narrative, runtimeSnapshot, spec]);
3116
- const handleCopy = (0, import_react12.useCallback)(async () => {
3824
+ const handleCopy = (0, import_react14.useCallback)(async () => {
3117
3825
  const text = buildLLMNarrative();
3118
3826
  await navigator.clipboard.writeText(text);
3119
3827
  setCopied(true);
3120
3828
  setTimeout(() => setCopied(false), 2e3);
3121
3829
  }, [buildLLMNarrative]);
3122
3830
  if (unstyled) {
3123
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className, style, "data-fp": "narrative-panel", children: hasStructured ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(StoryNarrative, { entries: narrativeEntries, revealedEntryCount, unstyled: true }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NarrativeTrace, { narrative, revealedCount, unstyled: true }) });
3831
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className, style, "data-fp": "narrative-panel", children: hasStructured ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(StoryNarrative, { entries: narrativeEntries, revealedEntryCount, unstyled: true }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(NarrativeTrace, { narrative, revealedCount, unstyled: true }) });
3124
3832
  }
3125
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3833
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3126
3834
  "div",
3127
3835
  {
3128
3836
  className,
@@ -3134,7 +3842,7 @@ function NarrativePanel({
3134
3842
  },
3135
3843
  "data-fp": "narrative-panel",
3136
3844
  children: [
3137
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3845
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3138
3846
  "div",
3139
3847
  {
3140
3848
  style: {
@@ -3148,8 +3856,8 @@ function NarrativePanel({
3148
3856
  alignItems: "center"
3149
3857
  },
3150
3858
  children: [
3151
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontStyle: "italic" }, children: "What happened at each stage, what data flowed, what decisions were made, and why." }),
3152
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3859
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { fontStyle: "italic" }, children: "What happened at each stage, what data flowed, what decisions were made, and why." }),
3860
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3153
3861
  "button",
3154
3862
  {
3155
3863
  onClick: handleCopy,
@@ -3172,7 +3880,7 @@ function NarrativePanel({
3172
3880
  ]
3173
3881
  }
3174
3882
  ),
3175
- hasStructured ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3883
+ hasStructured ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3176
3884
  StoryNarrative,
3177
3885
  {
3178
3886
  entries: narrativeEntries,
@@ -3180,7 +3888,7 @@ function NarrativePanel({
3180
3888
  size,
3181
3889
  style: { flex: 1 }
3182
3890
  }
3183
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3891
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3184
3892
  NarrativeTrace,
3185
3893
  {
3186
3894
  narrative,
@@ -3195,8 +3903,8 @@ function NarrativePanel({
3195
3903
  }
3196
3904
 
3197
3905
  // src/components/FlowchartView/SubflowTree.tsx
3198
- var import_react13 = require("react");
3199
- var import_jsx_runtime14 = require("react/jsx-runtime");
3906
+ var import_react15 = require("react");
3907
+ var import_jsx_runtime16 = require("react/jsx-runtime");
3200
3908
  function graphToSubflowEntries(graph) {
3201
3909
  if (!graph?.nodes?.length) return [];
3202
3910
  const entries = [];
@@ -3212,25 +3920,25 @@ function graphToSubflowEntries(graph) {
3212
3920
  }
3213
3921
  return entries;
3214
3922
  }
3215
- var TreeNode = (0, import_react13.memo)(function TreeNode2({
3923
+ var TreeNode = (0, import_react15.memo)(function TreeNode2({
3216
3924
  entry,
3217
3925
  depth,
3218
3926
  activeStage,
3219
3927
  doneStages,
3220
3928
  onNodeSelect
3221
3929
  }) {
3222
- const [expanded, setExpanded] = (0, import_react13.useState)(true);
3930
+ const [expanded, setExpanded] = (0, import_react15.useState)(true);
3223
3931
  const hasChildren = entry.children && entry.children.length > 0;
3224
3932
  const isActive = activeStage === entry.name;
3225
3933
  const isDone = doneStages?.has(entry.name);
3226
- const handleClick = (0, import_react13.useCallback)(() => {
3934
+ const handleClick = (0, import_react15.useCallback)(() => {
3227
3935
  if (hasChildren) {
3228
3936
  setExpanded((prev) => !prev);
3229
3937
  }
3230
3938
  onNodeSelect?.(entry.name, !!entry.isSubflow);
3231
3939
  }, [hasChildren, onNodeSelect, entry.name, entry.isSubflow]);
3232
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3233
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3940
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
3941
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3234
3942
  "button",
3235
3943
  {
3236
3944
  onClick: handleClick,
@@ -3261,7 +3969,7 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3261
3969
  }
3262
3970
  },
3263
3971
  children: [
3264
- hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3972
+ hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3265
3973
  "span",
3266
3974
  {
3267
3975
  style: {
@@ -3276,8 +3984,8 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3276
3984
  },
3277
3985
  children: "\u25B6"
3278
3986
  }
3279
- ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { width: 12, flexShrink: 0 } }),
3280
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3987
+ ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { width: 12, flexShrink: 0 } }),
3988
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3281
3989
  "span",
3282
3990
  {
3283
3991
  style: {
@@ -3289,8 +3997,8 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3289
3997
  }
3290
3998
  }
3291
3999
  ),
3292
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { style: { display: "flex", flexDirection: "column", minWidth: 0 }, children: [
3293
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
4000
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: { display: "flex", flexDirection: "column", minWidth: 0 }, children: [
4001
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3294
4002
  "span",
3295
4003
  {
3296
4004
  style: {
@@ -3302,11 +4010,11 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3302
4010
  },
3303
4011
  children: [
3304
4012
  entry.name,
3305
- entry.isSubflow && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { opacity: 0.5, marginLeft: 4, fontSize: 10 }, children: "\u229E" })
4013
+ entry.isSubflow && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { opacity: 0.5, marginLeft: 4, fontSize: 10 }, children: "\u229E" })
3306
4014
  ]
3307
4015
  }
3308
4016
  ),
3309
- entry.description && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4017
+ entry.description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3310
4018
  "span",
3311
4019
  {
3312
4020
  style: {
@@ -3323,7 +4031,7 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3323
4031
  ]
3324
4032
  }
3325
4033
  ),
3326
- hasChildren && expanded && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { children: entry.children.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4034
+ hasChildren && expanded && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { children: entry.children.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3327
4035
  TreeNode2,
3328
4036
  {
3329
4037
  entry: child,
@@ -3336,8 +4044,8 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3336
4044
  )) })
3337
4045
  ] });
3338
4046
  });
3339
- var SectionLabel = (0, import_react13.memo)(function SectionLabel2({ children }) {
3340
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4047
+ var SectionLabel = (0, import_react15.memo)(function SectionLabel2({ children }) {
4048
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3341
4049
  "div",
3342
4050
  {
3343
4051
  style: {
@@ -3352,7 +4060,7 @@ var SectionLabel = (0, import_react13.memo)(function SectionLabel2({ children })
3352
4060
  }
3353
4061
  );
3354
4062
  });
3355
- var SubflowTree = (0, import_react13.memo)(function SubflowTree2({
4063
+ var SubflowTree = (0, import_react15.memo)(function SubflowTree2({
3356
4064
  graph,
3357
4065
  activeStage,
3358
4066
  doneStages,
@@ -3361,9 +4069,9 @@ var SubflowTree = (0, import_react13.memo)(function SubflowTree2({
3361
4069
  className,
3362
4070
  style
3363
4071
  }) {
3364
- const subflowStages = (0, import_react13.useMemo)(() => graphToSubflowEntries(graph), [graph]);
4072
+ const subflowStages = (0, import_react15.useMemo)(() => graphToSubflowEntries(graph), [graph]);
3365
4073
  if (subflowStages.length === 0) return null;
3366
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
4074
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3367
4075
  "div",
3368
4076
  {
3369
4077
  className,
@@ -3381,8 +4089,8 @@ var SubflowTree = (0, import_react13.memo)(function SubflowTree2({
3381
4089
  ...style
3382
4090
  },
3383
4091
  children: [
3384
- !unstyled && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionLabel, { children: "Subflows" }),
3385
- subflowStages.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4092
+ !unstyled && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SectionLabel, { children: "Subflows" }),
4093
+ subflowStages.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3386
4094
  TreeNode,
3387
4095
  {
3388
4096
  entry,
@@ -3399,14 +4107,14 @@ var SubflowTree = (0, import_react13.memo)(function SubflowTree2({
3399
4107
  });
3400
4108
 
3401
4109
  // src/components/FlowchartView/SubflowBreadcrumb.tsx
3402
- var import_react14 = require("react");
3403
- var import_jsx_runtime15 = require("react/jsx-runtime");
3404
- var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
4110
+ var import_react16 = require("react");
4111
+ var import_jsx_runtime17 = require("react/jsx-runtime");
4112
+ var SubflowBreadcrumb = (0, import_react16.memo)(function SubflowBreadcrumb2({
3405
4113
  breadcrumbs,
3406
4114
  onNavigate
3407
4115
  }) {
3408
4116
  if (breadcrumbs.length <= 1) return null;
3409
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4117
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3410
4118
  "div",
3411
4119
  {
3412
4120
  style: {
@@ -3423,10 +4131,10 @@ var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
3423
4131
  },
3424
4132
  children: breadcrumbs.map((crumb, i) => {
3425
4133
  const isLast = i === breadcrumbs.length - 1;
3426
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
3427
- i > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { color: theme.textMuted, fontSize: 10 }, children: "\u203A" }),
3428
- isLast ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
3429
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4134
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
4135
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { color: theme.textMuted, fontSize: 10 }, children: "\u203A" }),
4136
+ isLast ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4137
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3430
4138
  "span",
3431
4139
  {
3432
4140
  style: {
@@ -3436,7 +4144,7 @@ var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
3436
4144
  children: crumb.label
3437
4145
  }
3438
4146
  ),
3439
- crumb.description && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4147
+ crumb.description && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3440
4148
  "span",
3441
4149
  {
3442
4150
  style: {
@@ -3450,7 +4158,7 @@ var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
3450
4158
  ]
3451
4159
  }
3452
4160
  )
3453
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4161
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3454
4162
  "button",
3455
4163
  {
3456
4164
  onClick: () => onNavigate(i),
@@ -3482,8 +4190,8 @@ var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
3482
4190
  });
3483
4191
 
3484
4192
  // src/components/FlowchartView/TracedFlow.tsx
3485
- var import_react25 = require("react");
3486
- var import_react26 = require("@xyflow/react");
4193
+ var import_react27 = require("react");
4194
+ var import_react28 = require("@xyflow/react");
3487
4195
 
3488
4196
  // src/components/FlowchartView/_internal/dagreTraceLayout.ts
3489
4197
  var import_dagre = __toESM(require("dagre"), 1);
@@ -3824,9 +4532,9 @@ function sliceOverlay(overlay, index) {
3824
4532
  }
3825
4533
 
3826
4534
  // src/components/StageNode/StageNode.tsx
3827
- var import_react15 = require("react");
3828
- var import_react16 = require("@xyflow/react");
3829
- var import_jsx_runtime16 = require("react/jsx-runtime");
4535
+ var import_react17 = require("react");
4536
+ var import_react18 = require("@xyflow/react");
4537
+ var import_jsx_runtime18 = require("react/jsx-runtime");
3830
4538
  var KEYFRAMES_ID = "fp-stage-node-keyframes";
3831
4539
  var KEYFRAMES_CSS = `
3832
4540
  @media (prefers-reduced-motion: no-preference) {
@@ -3852,128 +4560,128 @@ function StageIcon({ type, color }) {
3852
4560
  // LLM / AI call — brain/sparkle
3853
4561
  case "llm":
3854
4562
  case "ai":
3855
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3856
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: color, strokeWidth: "1.5" }),
3857
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M5.5 8C5.5 6.5 6.5 5 8 5S10.5 6.5 10.5 8", stroke: color, strokeWidth: "1.2", strokeLinecap: "round" }),
3858
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "8", cy: "9.5", r: "1", fill: color }),
3859
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "3.5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
3860
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "12.5", y1: "4", x2: "11.2", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
3861
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "3.5", y1: "4", x2: "4.8", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
4563
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4564
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: color, strokeWidth: "1.5" }),
4565
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M5.5 8C5.5 6.5 6.5 5 8 5S10.5 6.5 10.5 8", stroke: color, strokeWidth: "1.2", strokeLinecap: "round" }),
4566
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "9.5", r: "1", fill: color }),
4567
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "3.5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4568
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "12.5", y1: "4", x2: "11.2", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4569
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "3.5", y1: "4", x2: "4.8", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
3862
4570
  ] });
3863
4571
  // Tool / function call — gear
3864
4572
  case "tool":
3865
4573
  case "function":
3866
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3867
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "8", cy: "8", r: "3", stroke: color, strokeWidth: "1.5" }),
4574
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4575
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "8", r: "3", stroke: color, strokeWidth: "1.5" }),
3868
4576
  [0, 45, 90, 135, 180, 225, 270, 315].map((angle) => {
3869
4577
  const rad = angle * Math.PI / 180;
3870
4578
  const x1 = 8 + Math.cos(rad) * 4.5;
3871
4579
  const y1 = 8 + Math.sin(rad) * 4.5;
3872
4580
  const x2 = 8 + Math.cos(rad) * 6;
3873
4581
  const y2 = 8 + Math.sin(rad) * 6;
3874
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1, y1, x2, y2, stroke: color, strokeWidth: "1.5", strokeLinecap: "round" }, angle);
4582
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1, y1, x2, y2, stroke: color, strokeWidth: "1.5", strokeLinecap: "round" }, angle);
3875
4583
  })
3876
4584
  ] });
3877
4585
  // RAG / retrieval — magnifying glass + doc
3878
4586
  case "rag":
3879
4587
  case "search":
3880
4588
  case "retrieval":
3881
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3882
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "7", cy: "7", r: "4", stroke: color, strokeWidth: "1.5" }),
3883
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "10", y1: "10", x2: "13.5", y2: "13.5", stroke: color, strokeWidth: "1.5", strokeLinecap: "round" }),
3884
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "5.5", y1: "6", x2: "8.5", y2: "6", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
3885
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "5.5", y1: "8", x2: "7.5", y2: "8", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
4589
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4590
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "7", cy: "7", r: "4", stroke: color, strokeWidth: "1.5" }),
4591
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "10", y1: "10", x2: "13.5", y2: "13.5", stroke: color, strokeWidth: "1.5", strokeLinecap: "round" }),
4592
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5.5", y1: "6", x2: "8.5", y2: "6", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4593
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5.5", y1: "8", x2: "7.5", y2: "8", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
3886
4594
  ] });
3887
4595
  // Parse / process — diamond with arrows
3888
4596
  case "parse":
3889
4597
  case "process":
3890
4598
  case "transform":
3891
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", stroke: color, strokeWidth: "1.5", transform: "rotate(45 8 8)" }) });
4599
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", stroke: color, strokeWidth: "1.5", transform: "rotate(45 8 8)" }) });
3892
4600
  // Start / seed — play triangle
3893
4601
  case "start":
3894
4602
  case "seed":
3895
4603
  case "init":
3896
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M5 3.5L12.5 8L5 12.5V3.5Z", fill: color, opacity: "0.8" }) });
4604
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M5 3.5L12.5 8L5 12.5V3.5Z", fill: color, opacity: "0.8" }) });
3897
4605
  // End / finalize — stop square
3898
4606
  case "end":
3899
4607
  case "finalize":
3900
4608
  case "output":
3901
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", fill: color, opacity: "0.8" }) });
4609
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", fill: color, opacity: "0.8" }) });
3902
4610
  // Agent — person silhouette
3903
4611
  case "agent":
3904
4612
  case "orchestrator":
3905
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3906
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "8", cy: "5", r: "2.5", stroke: color, strokeWidth: "1.5" }),
3907
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M3.5 14C3.5 11 5.5 9 8 9S12.5 11 12.5 14", stroke: color, strokeWidth: "1.5", strokeLinecap: "round" })
4613
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4614
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "5", r: "2.5", stroke: color, strokeWidth: "1.5" }),
4615
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M3.5 14C3.5 11 5.5 9 8 9S12.5 11 12.5 14", stroke: color, strokeWidth: "1.5", strokeLinecap: "round" })
3908
4616
  ] });
3909
4617
  // Swarm — multi-agent
3910
4618
  case "swarm":
3911
4619
  case "multi-agent":
3912
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3913
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "5", cy: "5", r: "2", stroke: color, strokeWidth: "1.2" }),
3914
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "11", cy: "5", r: "2", stroke: color, strokeWidth: "1.2" }),
3915
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "8", cy: "11", r: "2", stroke: color, strokeWidth: "1.2" }),
3916
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "5", y1: "7", x2: "8", y2: "9", stroke: color, strokeWidth: "1", opacity: "0.5" }),
3917
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "11", y1: "7", x2: "8", y2: "9", stroke: color, strokeWidth: "1", opacity: "0.5" })
4620
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4621
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "5", cy: "5", r: "2", stroke: color, strokeWidth: "1.2" }),
4622
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "11", cy: "5", r: "2", stroke: color, strokeWidth: "1.2" }),
4623
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "11", r: "2", stroke: color, strokeWidth: "1.2" }),
4624
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5", y1: "7", x2: "8", y2: "9", stroke: color, strokeWidth: "1", opacity: "0.5" }),
4625
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "11", y1: "7", x2: "8", y2: "9", stroke: color, strokeWidth: "1", opacity: "0.5" })
3918
4626
  ] });
3919
4627
  // Guard / guardrail — shield
3920
4628
  case "guard":
3921
4629
  case "guardrail":
3922
4630
  case "validate":
3923
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3924
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M8 2L3 5V9C3 11.5 5 13.5 8 14.5C11 13.5 13 11.5 13 9V5L8 2Z", stroke: color, strokeWidth: "1.5", strokeLinejoin: "round" }),
3925
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M6 8L7.5 9.5L10 6.5", stroke: color, strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
4631
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4632
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M8 2L3 5V9C3 11.5 5 13.5 8 14.5C11 13.5 13 11.5 13 9V5L8 2Z", stroke: color, strokeWidth: "1.5", strokeLinejoin: "round" }),
4633
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M6 8L7.5 9.5L10 6.5", stroke: color, strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
3926
4634
  ] });
3927
4635
  // Stream — wave
3928
4636
  case "stream":
3929
4637
  case "streaming":
3930
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3931
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M2 8C4 5 6 11 8 8S12 5 14 8", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", fill: "none" }),
3932
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M2 11C4 8 6 14 8 11S12 8 14 11", stroke: color, strokeWidth: "1", strokeLinecap: "round", fill: "none", opacity: "0.5" })
4638
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4639
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M2 8C4 5 6 11 8 8S12 5 14 8", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", fill: "none" }),
4640
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M2 11C4 8 6 14 8 11S12 8 14 11", stroke: color, strokeWidth: "1", strokeLinecap: "round", fill: "none", opacity: "0.5" })
3933
4641
  ] });
3934
4642
  // Memory / state — database cylinder
3935
4643
  case "memory":
3936
4644
  case "state":
3937
4645
  case "db":
3938
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3939
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("ellipse", { cx: "8", cy: "4.5", rx: "5", ry: "2", stroke: color, strokeWidth: "1.3" }),
3940
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "3", y1: "4.5", x2: "3", y2: "11.5", stroke: color, strokeWidth: "1.3" }),
3941
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "13", y1: "4.5", x2: "13", y2: "11.5", stroke: color, strokeWidth: "1.3" }),
3942
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("ellipse", { cx: "8", cy: "11.5", rx: "5", ry: "2", stroke: color, strokeWidth: "1.3" })
4646
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4647
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ellipse", { cx: "8", cy: "4.5", rx: "5", ry: "2", stroke: color, strokeWidth: "1.3" }),
4648
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "3", y1: "4.5", x2: "3", y2: "11.5", stroke: color, strokeWidth: "1.3" }),
4649
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "13", y1: "4.5", x2: "13", y2: "11.5", stroke: color, strokeWidth: "1.3" }),
4650
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ellipse", { cx: "8", cy: "11.5", rx: "5", ry: "2", stroke: color, strokeWidth: "1.3" })
3943
4651
  ] });
3944
4652
  // System prompt — document with lines
3945
4653
  case "system-prompt":
3946
4654
  case "prompt":
3947
4655
  case "instructions":
3948
4656
  case "document":
3949
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3950
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: "3.5", y: "2", width: "9", height: "12", rx: "1.5", stroke: color, strokeWidth: "1.3", fill: "none" }),
3951
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "5.5", y1: "5", x2: "10.5", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
3952
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "5.5", y1: "7.5", x2: "10.5", y2: "7.5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
3953
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "5.5", y1: "10", x2: "8.5", y2: "10", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
4657
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4658
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "3.5", y: "2", width: "9", height: "12", rx: "1.5", stroke: color, strokeWidth: "1.3", fill: "none" }),
4659
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5.5", y1: "5", x2: "10.5", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4660
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5.5", y1: "7.5", x2: "10.5", y2: "7.5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4661
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5.5", y1: "10", x2: "8.5", y2: "10", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
3954
4662
  ] });
3955
4663
  // Messages / conversation — chat bubble
3956
4664
  case "messages":
3957
4665
  case "chat":
3958
4666
  case "conversation":
3959
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3960
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: "2.5", y: "3", width: "11", height: "8", rx: "2", stroke: color, strokeWidth: "1.3", fill: "none" }),
3961
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M5.5 11L5.5 13.5L8.5 11", stroke: color, strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }),
3962
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "5", y1: "6", x2: "11", y2: "6", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
3963
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "5", y1: "8.5", x2: "9", y2: "8.5", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
4667
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4668
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("rect", { x: "2.5", y: "3", width: "11", height: "8", rx: "2", stroke: color, strokeWidth: "1.3", fill: "none" }),
4669
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M5.5 11L5.5 13.5L8.5 11", stroke: color, strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }),
4670
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5", y1: "6", x2: "11", y2: "6", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4671
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5", y1: "8.5", x2: "9", y2: "8.5", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
3964
4672
  ] });
3965
4673
  // Loop — circular arrow
3966
4674
  case "loop":
3967
4675
  case "retry":
3968
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3969
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M12 8A4 4 0 1 1 8 4", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", fill: "none" }),
3970
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M8 1.5L10.5 4L8 6.5", stroke: color, strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", fill: "none" })
4676
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4677
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M12 8A4 4 0 1 1 8 4", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", fill: "none" }),
4678
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M8 1.5L10.5 4L8 6.5", stroke: color, strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", fill: "none" })
3971
4679
  ] });
3972
4680
  // Lazy / service — cloud (deferred resolution, loaded on demand)
3973
4681
  case "lazy":
3974
4682
  case "service":
3975
4683
  case "cloud":
3976
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4684
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3977
4685
  "path",
3978
4686
  {
3979
4687
  d: "M4.5 12C2.8 12 1.5 10.7 1.5 9C1.5 7.5 2.5 6.3 3.8 6C4 4 5.8 2.5 8 2.5C9.8 2.5 11.3 3.5 11.9 5C13.9 5.2 15.5 6.8 15.5 8.8C15.5 10.8 13.9 12.5 11.8 12.5H4.5",
@@ -3986,22 +4694,22 @@ function StageIcon({ type, color }) {
3986
4694
  // Decision — diamond (already handled by isDecider shape)
3987
4695
  case "decision":
3988
4696
  case "router":
3989
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, children: [
3990
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M8 2L14 8L8 14L2 8Z", stroke: color, strokeWidth: "1.5", fill: "none" }),
3991
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "8", cy: "8", r: "1.5", fill: color })
4697
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4698
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M8 2L14 8L8 14L2 8Z", stroke: color, strokeWidth: "1.5", fill: "none" }),
4699
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "8", r: "1.5", fill: color })
3992
4700
  ] });
3993
4701
  default:
3994
4702
  return null;
3995
4703
  }
3996
4704
  }
3997
- var StageNode = (0, import_react15.memo)(function StageNode2({
4705
+ var StageNode = (0, import_react17.memo)(function StageNode2({
3998
4706
  data
3999
4707
  }) {
4000
4708
  const { label, active, done, error, linked, icon, stepNumbers, dimmed, isSubflow, isLazy, isDecider, isFork, description, stageId, showStageId } = data;
4001
4709
  const effectiveIcon = icon || (isLazy ? "lazy" : void 0);
4002
4710
  const isLazyUnresolved = isLazy && !done && !active;
4003
- const injectedRef = (0, import_react15.useRef)(false);
4004
- (0, import_react15.useEffect)(() => {
4711
+ const injectedRef = (0, import_react17.useRef)(false);
4712
+ (0, import_react17.useEffect)(() => {
4005
4713
  if (injectedRef.current) return;
4006
4714
  if (typeof document !== "undefined" && !document.getElementById(KEYFRAMES_ID)) {
4007
4715
  const styleEl = document.createElement("style");
@@ -4022,9 +4730,9 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4022
4730
  const borderColor = active ? theme.nodeCursor : isHero && done ? theme.nodeMain : done ? theme.nodeVisited : error ? theme.error : restingBorder;
4023
4731
  const shadow = active ? `0 0 22px color-mix(in srgb, ${theme.nodeCursor} 55%, transparent)` : isHero && done ? `0 0 12px color-mix(in srgb, ${theme.nodeMain} 30%, transparent)` : done ? `0 0 8px color-mix(in srgb, ${theme.nodeVisited} 20%, transparent)` : error ? `0 0 12px color-mix(in srgb, ${theme.error} 30%, transparent)` : restingShadow;
4024
4732
  const textColor = active ? "#1a1a1a" : done || error ? "#fff" : theme.textPrimary;
4025
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
4026
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react16.Handle, { type: "target", position: import_react16.Position.Top, style: { opacity: 0 } }),
4027
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { width: "100%", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4733
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4734
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react18.Handle, { type: "target", position: import_react18.Position.Top, style: { opacity: 0 } }),
4735
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { width: "100%", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4028
4736
  "div",
4029
4737
  {
4030
4738
  style: {
@@ -4037,7 +4745,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4037
4745
  opacity: isMuted ? 0.5 : void 0
4038
4746
  },
4039
4747
  children: [
4040
- stepNumbers && stepNumbers.length > 0 && isOnPath && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4748
+ stepNumbers && stepNumbers.length > 0 && isOnPath && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4041
4749
  "div",
4042
4750
  {
4043
4751
  style: {
@@ -4052,7 +4760,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4052
4760
  const isLatest = i === stepNumbers.length - 1;
4053
4761
  const badgeBg = isLatest && active ? theme.nodeCursor : theme.nodeVisited;
4054
4762
  const glow = isLatest && active ? `color-mix(in srgb, ${theme.nodeCursor} 50%, transparent)` : `color-mix(in srgb, ${theme.nodeVisited} 40%, transparent)`;
4055
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4763
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4056
4764
  "div",
4057
4765
  {
4058
4766
  style: {
@@ -4075,7 +4783,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4075
4783
  })
4076
4784
  }
4077
4785
  ),
4078
- linked && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4786
+ linked && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4079
4787
  "div",
4080
4788
  {
4081
4789
  style: {
@@ -4089,7 +4797,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4089
4797
  }
4090
4798
  }
4091
4799
  ),
4092
- active && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4800
+ active && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4093
4801
  "div",
4094
4802
  {
4095
4803
  style: {
@@ -4103,7 +4811,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4103
4811
  }
4104
4812
  }
4105
4813
  ),
4106
- active && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4814
+ active && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4107
4815
  "div",
4108
4816
  {
4109
4817
  style: {
@@ -4123,8 +4831,8 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4123
4831
  children: "NOW"
4124
4832
  }
4125
4833
  ),
4126
- isDecider ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { position: "relative", width: 120, height: 72 }, children: [
4127
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4834
+ isDecider ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { position: "relative", width: 120, height: 72 }, children: [
4835
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4128
4836
  "div",
4129
4837
  {
4130
4838
  style: {
@@ -4138,7 +4846,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4138
4846
  }
4139
4847
  }
4140
4848
  ),
4141
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4849
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4142
4850
  "div",
4143
4851
  {
4144
4852
  style: {
@@ -4154,7 +4862,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4154
4862
  }
4155
4863
  }
4156
4864
  ),
4157
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4865
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4158
4866
  "div",
4159
4867
  {
4160
4868
  style: {
@@ -4169,10 +4877,10 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4169
4877
  zIndex: 1
4170
4878
  },
4171
4879
  children: [
4172
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
4173
- effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StageIcon, { type: effectiveIcon, color: textColor }),
4174
- !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontSize: 9, color: textColor }, children: "\u25C7" }),
4175
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4880
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
4881
+ effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StageIcon, { type: effectiveIcon, color: textColor }),
4882
+ !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontSize: 9, color: textColor }, children: "\u25C7" }),
4883
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4176
4884
  "span",
4177
4885
  {
4178
4886
  style: {
@@ -4185,7 +4893,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4185
4893
  }
4186
4894
  )
4187
4895
  ] }),
4188
- description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4896
+ description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4189
4897
  "span",
4190
4898
  {
4191
4899
  style: {
@@ -4201,7 +4909,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4201
4909
  children: description
4202
4910
  }
4203
4911
  ),
4204
- showStageId && stageId && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4912
+ showStageId && stageId && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4205
4913
  "span",
4206
4914
  {
4207
4915
  style: {
@@ -4223,7 +4931,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4223
4931
  )
4224
4932
  ] }) : (
4225
4933
  /* Standard rectangular node */
4226
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4934
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4227
4935
  "div",
4228
4936
  {
4229
4937
  style: {
@@ -4242,10 +4950,10 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4242
4950
  justifyContent: "center"
4243
4951
  },
4244
4952
  children: [
4245
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4246
- effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StageIcon, { type: effectiveIcon, color: textColor }),
4247
- done && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontSize: 10, color: textColor }, children: "\u2713" }),
4248
- active && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4953
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4954
+ effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StageIcon, { type: effectiveIcon, color: textColor }),
4955
+ done && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontSize: 10, color: textColor }, children: "\u2713" }),
4956
+ active && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4249
4957
  "span",
4250
4958
  {
4251
4959
  style: {
@@ -4258,8 +4966,8 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4258
4966
  }
4259
4967
  }
4260
4968
  ),
4261
- error && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontSize: 10, color: textColor }, children: "\u2717" }),
4262
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4969
+ error && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontSize: 10, color: textColor }, children: "\u2717" }),
4970
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4263
4971
  "span",
4264
4972
  {
4265
4973
  style: {
@@ -4271,7 +4979,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4271
4979
  children: label
4272
4980
  }
4273
4981
  ),
4274
- isSubflow && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4982
+ isSubflow && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4275
4983
  "span",
4276
4984
  {
4277
4985
  style: {
@@ -4286,7 +4994,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4286
4994
  opacity: 0.7,
4287
4995
  flexShrink: 0
4288
4996
  },
4289
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4997
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4290
4998
  "span",
4291
4999
  {
4292
5000
  style: {
@@ -4300,7 +5008,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4300
5008
  }
4301
5009
  )
4302
5010
  ] }),
4303
- description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5011
+ description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4304
5012
  "span",
4305
5013
  {
4306
5014
  style: {
@@ -4316,7 +5024,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4316
5024
  children: description
4317
5025
  }
4318
5026
  ),
4319
- showStageId && stageId && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5027
+ showStageId && stageId && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4320
5028
  "span",
4321
5029
  {
4322
5030
  style: {
@@ -4340,7 +5048,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4340
5048
  ]
4341
5049
  }
4342
5050
  ) }),
4343
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react16.Handle, { type: "source", position: import_react16.Position.Bottom, style: { opacity: 0 } })
5051
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react18.Handle, { type: "source", position: import_react18.Position.Bottom, style: { opacity: 0 } })
4344
5052
  ] });
4345
5053
  });
4346
5054
 
@@ -4392,18 +5100,18 @@ function aggregateMountStatus(slice, graph, currentSubflowId) {
4392
5100
  }
4393
5101
 
4394
5102
  // src/components/FlowchartView/_internal/useSubflowDrill.ts
4395
- var import_react17 = require("react");
5103
+ var import_react19 = require("react");
4396
5104
  function useSubflowDrill(graph, onSubflowChange) {
4397
- const [currentSubflowId, setCurrentSubflowId] = (0, import_react17.useState)(null);
4398
- const lastGraphRef = (0, import_react17.useRef)(null);
5105
+ const [currentSubflowId, setCurrentSubflowId] = (0, import_react19.useState)(null);
5106
+ const lastGraphRef = (0, import_react19.useRef)(null);
4399
5107
  if (lastGraphRef.current !== graph) {
4400
5108
  lastGraphRef.current = graph;
4401
5109
  if (currentSubflowId !== null && !graph.nodes.some((n) => n.data?.subflowId === currentSubflowId)) {
4402
5110
  queueMicrotask(() => setCurrentSubflowId(null));
4403
5111
  }
4404
5112
  }
4405
- const lastNotifiedRef = (0, import_react17.useRef)(void 0);
4406
- (0, import_react17.useEffect)(() => {
5113
+ const lastNotifiedRef = (0, import_react19.useRef)(void 0);
5114
+ (0, import_react19.useEffect)(() => {
4407
5115
  if (lastNotifiedRef.current === currentSubflowId) return;
4408
5116
  lastNotifiedRef.current = currentSubflowId;
4409
5117
  if (currentSubflowId === null) {
@@ -4413,22 +5121,22 @@ function useSubflowDrill(graph, onSubflowChange) {
4413
5121
  if (mount) onSubflowChange?.(mount.id);
4414
5122
  }
4415
5123
  }, [currentSubflowId, graph, onSubflowChange]);
4416
- const drillInto = (0, import_react17.useCallback)((subflowId) => {
5124
+ const drillInto = (0, import_react19.useCallback)((subflowId) => {
4417
5125
  setCurrentSubflowId(subflowId);
4418
5126
  }, []);
4419
- const drillUp = (0, import_react17.useCallback)(() => {
5127
+ const drillUp = (0, import_react19.useCallback)(() => {
4420
5128
  setCurrentSubflowId(null);
4421
5129
  }, []);
4422
5130
  return { currentSubflowId, drillInto, drillUp, setCurrentSubflowId };
4423
5131
  }
4424
5132
 
4425
5133
  // src/components/FlowchartView/_internal/useChartAutoRefit.ts
4426
- var import_react18 = require("react");
5134
+ var import_react20 = require("react");
4427
5135
  function useChartAutoRefit(wrapperRef, rfInstance, options = {}) {
4428
5136
  const duration = options.duration ?? 200;
4429
5137
  const padding2 = options.padding ?? 0.1;
4430
5138
  const refitKey = options.refitKey;
4431
- (0, import_react18.useEffect)(() => {
5139
+ (0, import_react20.useEffect)(() => {
4432
5140
  const el = wrapperRef.current;
4433
5141
  if (!el || !rfInstance) return;
4434
5142
  let raf = 0;
@@ -4447,7 +5155,7 @@ function useChartAutoRefit(wrapperRef, rfInstance, options = {}) {
4447
5155
  cancelAnimationFrame(raf);
4448
5156
  };
4449
5157
  }, [rfInstance, wrapperRef, duration, padding2]);
4450
- (0, import_react18.useEffect)(() => {
5158
+ (0, import_react20.useEffect)(() => {
4451
5159
  if (!rfInstance) return;
4452
5160
  let raf2 = 0;
4453
5161
  const raf1 = requestAnimationFrame(() => {
@@ -4463,9 +5171,9 @@ function useChartAutoRefit(wrapperRef, rfInstance, options = {}) {
4463
5171
  }
4464
5172
 
4465
5173
  // src/components/FlowchartView/SubflowBreadcrumbBar.tsx
4466
- var import_jsx_runtime17 = require("react/jsx-runtime");
5174
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4467
5175
  function SubflowBreadcrumbBar({ entries, onNavigate }) {
4468
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5176
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4469
5177
  "div",
4470
5178
  {
4471
5179
  style: {
@@ -4481,12 +5189,12 @@ function SubflowBreadcrumbBar({ entries, onNavigate }) {
4481
5189
  "aria-label": "Subflow breadcrumb",
4482
5190
  children: entries.map((entry, i) => {
4483
5191
  const isLast = i === entries.length - 1;
4484
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5192
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4485
5193
  "span",
4486
5194
  {
4487
5195
  style: { display: "inline-flex", alignItems: "center", gap: 6 },
4488
5196
  children: [
4489
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5197
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4490
5198
  "button",
4491
5199
  {
4492
5200
  type: "button",
@@ -4506,7 +5214,7 @@ function SubflowBreadcrumbBar({ entries, onNavigate }) {
4506
5214
  children: entry.label
4507
5215
  }
4508
5216
  ),
4509
- !isLast && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { color: theme.textMuted }, children: "\u203A" })
5217
+ !isLast && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { color: theme.textMuted }, children: "\u203A" })
4510
5218
  ]
4511
5219
  },
4512
5220
  entry.subflowId ?? "__top__"
@@ -4517,12 +5225,12 @@ function SubflowBreadcrumbBar({ entries, onNavigate }) {
4517
5225
  }
4518
5226
 
4519
5227
  // src/components/GroupContainerNode/GroupContainerNode.tsx
4520
- var import_react19 = require("@xyflow/react");
4521
- var import_jsx_runtime18 = require("react/jsx-runtime");
5228
+ var import_react21 = require("@xyflow/react");
5229
+ var import_jsx_runtime20 = require("react/jsx-runtime");
4522
5230
  function GroupContainerNode({ data }) {
4523
5231
  const d = data;
4524
5232
  const borderColor = d.error ? theme.error : d.active ? theme.primary : d.done ? theme.nodeVisited : theme.border;
4525
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5233
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4526
5234
  "div",
4527
5235
  {
4528
5236
  style: {
@@ -4538,7 +5246,7 @@ function GroupContainerNode({ data }) {
4538
5246
  position: "relative"
4539
5247
  },
4540
5248
  children: [
4541
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5249
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4542
5250
  "div",
4543
5251
  {
4544
5252
  style: {
@@ -4552,20 +5260,20 @@ function GroupContainerNode({ data }) {
4552
5260
  letterSpacing: 0.2
4553
5261
  },
4554
5262
  children: [
4555
- d.icon ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, children: d.icon }) : null,
4556
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: d.label })
5263
+ d.icon ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { "aria-hidden": true, children: d.icon }) : null,
5264
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: d.label })
4557
5265
  ]
4558
5266
  }
4559
5267
  ),
4560
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react19.Handle, { type: "target", position: import_react19.Position.Top, style: { opacity: 0 } }),
4561
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react19.Handle, { type: "source", position: import_react19.Position.Bottom, style: { opacity: 0 } })
5268
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react21.Handle, { type: "target", position: import_react21.Position.Top, style: { opacity: 0 } }),
5269
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react21.Handle, { type: "source", position: import_react21.Position.Bottom, style: { opacity: 0 } })
4562
5270
  ]
4563
5271
  }
4564
5272
  );
4565
5273
  }
4566
5274
 
4567
5275
  // src/components/LoopBackEdge/LoopBackEdge.tsx
4568
- var import_react20 = require("@xyflow/react");
5276
+ var import_react22 = require("@xyflow/react");
4569
5277
 
4570
5278
  // src/components/FlowchartView/_internal/loopRouting.ts
4571
5279
  var LOOP_LANE_GAP = 56;
@@ -4784,7 +5492,7 @@ function wrapInMainChartBox(graph, opts) {
4784
5492
  }
4785
5493
 
4786
5494
  // src/components/LoopBackEdge/LoopBackEdge.tsx
4787
- var import_jsx_runtime19 = require("react/jsx-runtime");
5495
+ var import_jsx_runtime21 = require("react/jsx-runtime");
4788
5496
  var LOOP_DASH = "5 5";
4789
5497
  var LOOP_STROKE_OPACITY_CAP = 0.55;
4790
5498
  var LOOP_STROKE_WIDTH = 1.5;
@@ -4805,7 +5513,7 @@ function centerY(node) {
4805
5513
  return node.internals.positionAbsolute.y + (node.measured.height ?? 0) / 2;
4806
5514
  }
4807
5515
  function LoopBackEdge({ id, source, target, markerEnd, style }) {
4808
- const path = (0, import_react20.useStore)((s) => {
5516
+ const path = (0, import_react22.useStore)((s) => {
4809
5517
  const src = s.nodeLookup.get(source);
4810
5518
  const tgt = s.nodeLookup.get(target);
4811
5519
  if (!src || !tgt) return "";
@@ -4823,8 +5531,8 @@ function LoopBackEdge({ id, source, target, markerEnd, style }) {
4823
5531
  );
4824
5532
  });
4825
5533
  if (!path) return null;
4826
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4827
- import_react20.BaseEdge,
5534
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5535
+ import_react22.BaseEdge,
4828
5536
  {
4829
5537
  id,
4830
5538
  path,
@@ -4836,8 +5544,8 @@ function LoopBackEdge({ id, source, target, markerEnd, style }) {
4836
5544
  }
4837
5545
 
4838
5546
  // src/components/SmartStepEdge/SmartStepEdge.tsx
4839
- var import_react21 = require("@xyflow/react");
4840
- var import_react22 = require("@xyflow/react");
5547
+ var import_react23 = require("@xyflow/react");
5548
+ var import_react24 = require("@xyflow/react");
4841
5549
 
4842
5550
  // src/components/FlowchartView/_internal/stepRouting.ts
4843
5551
  function staggeredBendY(sourceBottom, targetTop, others, minGapFromTarget = 8) {
@@ -4861,7 +5569,7 @@ function resolveStepBendY(forkBend, staggeredBend) {
4861
5569
  }
4862
5570
 
4863
5571
  // src/components/SmartStepEdge/SmartStepEdge.tsx
4864
- var import_jsx_runtime20 = require("react/jsx-runtime");
5572
+ var import_jsx_runtime22 = require("react/jsx-runtime");
4865
5573
  function SmartStepEdge({
4866
5574
  id,
4867
5575
  source,
@@ -4875,7 +5583,7 @@ function SmartStepEdge({
4875
5583
  markerEnd,
4876
5584
  style
4877
5585
  }) {
4878
- const bendY = (0, import_react21.useStore)((s) => {
5586
+ const bendY = (0, import_react23.useStore)((s) => {
4879
5587
  const src = s.nodeLookup.get(source);
4880
5588
  const tgt = s.nodeLookup.get(target);
4881
5589
  if (!src || !tgt) return null;
@@ -4901,23 +5609,23 @@ function SmartStepEdge({
4901
5609
  const staggered = staggeredBendY(sourceBottom, targetTop, others);
4902
5610
  return resolveStepBendY(fan, staggered);
4903
5611
  });
4904
- const [path] = (0, import_react21.getSmoothStepPath)({
5612
+ const [path] = (0, import_react23.getSmoothStepPath)({
4905
5613
  sourceX,
4906
5614
  sourceY,
4907
- sourcePosition: sourcePosition ?? import_react22.Position.Bottom,
5615
+ sourcePosition: sourcePosition ?? import_react24.Position.Bottom,
4908
5616
  targetX,
4909
5617
  targetY,
4910
- targetPosition: targetPosition ?? import_react22.Position.Top,
5618
+ targetPosition: targetPosition ?? import_react24.Position.Top,
4911
5619
  // Override the bend only for a staggered edge; otherwise let getSmoothStepPath
4912
5620
  // use its default centerY (== the built-in `smoothstep` path, byte-for-byte).
4913
5621
  ...bendY !== null ? { centerY: bendY } : {}
4914
5622
  });
4915
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react21.BaseEdge, { id, path, markerEnd, style });
5623
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react23.BaseEdge, { id, path, markerEnd, style });
4916
5624
  }
4917
5625
 
4918
5626
  // src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
4919
- var import_react23 = require("react");
4920
- var import_react24 = require("@xyflow/react");
5627
+ var import_react25 = require("react");
5628
+ var import_react26 = require("@xyflow/react");
4921
5629
 
4922
5630
  // src/components/FlowchartView/_internal/measuredFootprints.ts
4923
5631
  function extractMeasuredFootprints(entries) {
@@ -4946,12 +5654,12 @@ function MeasuredNodeSizes({
4946
5654
  onSizes,
4947
5655
  includeHiddenNodes = false
4948
5656
  }) {
4949
- const initialized = (0, import_react24.useNodesInitialized)({ includeHiddenNodes });
4950
- const sizes = (0, import_react24.useStore)(
5657
+ const initialized = (0, import_react26.useNodesInitialized)({ includeHiddenNodes });
5658
+ const sizes = (0, import_react26.useStore)(
4951
5659
  (s) => extractMeasuredFootprints(s.nodeLookup),
4952
5660
  sameFootprints
4953
5661
  );
4954
- (0, import_react23.useEffect)(() => {
5662
+ (0, import_react25.useEffect)(() => {
4955
5663
  if (!initialized || sizes.size === 0) return;
4956
5664
  onSizes(sizes);
4957
5665
  }, [initialized, sizes, onSizes]);
@@ -4959,7 +5667,7 @@ function MeasuredNodeSizes({
4959
5667
  }
4960
5668
 
4961
5669
  // src/components/FlowchartView/TracedFlow.tsx
4962
- var import_jsx_runtime21 = require("react/jsx-runtime");
5670
+ var import_jsx_runtime23 = require("react/jsx-runtime");
4963
5671
  var DEFAULT_COLORS = {
4964
5672
  default: rawDefaults.colors.textMuted,
4965
5673
  done: rawDefaults.colors.success,
@@ -5067,7 +5775,7 @@ function styleEdgeWithOverlay(edge, doneStageIds, activeStageId, colors) {
5067
5775
  type: kind === "loop" ? "loopBack" : "smartStep",
5068
5776
  animated: isLeadingEdge,
5069
5777
  style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },
5070
- markerEnd: { type: import_react26.MarkerType.ArrowClosed, color, width: 16, height: 16 }
5778
+ markerEnd: { type: import_react28.MarkerType.ArrowClosed, color, width: 16, height: 16 }
5071
5779
  };
5072
5780
  if (kind === "loop") {
5073
5781
  styled.style = { ...styled.style, strokeDasharray: "4 3" };
@@ -5098,28 +5806,28 @@ function TracedFlow({
5098
5806
  style
5099
5807
  }) {
5100
5808
  const layout = layoutProp ?? dagreTraceLayout;
5101
- (0, import_react25.useEffect)(() => {
5809
+ (0, import_react27.useEffect)(() => {
5102
5810
  if (layoutProp === dagreTraceLayout) {
5103
5811
  devWarn(
5104
5812
  () => "[footprint-explainable-ui] <TracedFlow layout={dagreTraceLayout}> bypasses the built-in measure-then-layout pipeline (content-exact sizing, fork/merge centering, straight spines). OMIT the `layout` prop to use it \u2014 passing the raw dagreTraceLayout silently forfeits every layout improvement eui ships."
5105
5813
  );
5106
5814
  }
5107
5815
  }, [layoutProp]);
5108
- const colors = (0, import_react25.useMemo)(
5816
+ const colors = (0, import_react27.useMemo)(
5109
5817
  () => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
5110
5818
  [colorOverrides]
5111
5819
  );
5112
- const mergedNodeTypes = (0, import_react25.useMemo)(
5820
+ const mergedNodeTypes = (0, import_react27.useMemo)(
5113
5821
  () => userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES,
5114
5822
  [userNodeTypes]
5115
5823
  );
5116
- const mergedEdgeTypes = (0, import_react25.useMemo)(
5824
+ const mergedEdgeTypes = (0, import_react27.useMemo)(
5117
5825
  () => userEdgeTypes ? { ...DEFAULT_EDGE_TYPES, ...userEdgeTypes } : DEFAULT_EDGE_TYPES,
5118
5826
  [userEdgeTypes]
5119
5827
  );
5120
5828
  const drill = useSubflowDrill(graph, onSubflowChange);
5121
- const groupedSet = (0, import_react25.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
5122
- const filteredGraph = (0, import_react25.useMemo)(() => {
5829
+ const groupedSet = (0, import_react27.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
5830
+ const filteredGraph = (0, import_react27.useMemo)(() => {
5123
5831
  const base = filterGraphForDrill(graph, drill.currentSubflowId);
5124
5832
  if (groupedSet.size === 0) return base;
5125
5833
  const baseIds = new Set(base.nodes.map((n) => n.id));
@@ -5134,12 +5842,12 @@ function TracedFlow({
5134
5842
  );
5135
5843
  return { nodes: [...base.nodes, ...extraNodes], edges: [...base.edges, ...extraEdges] };
5136
5844
  }, [graph, drill.currentSubflowId, groupedSet]);
5137
- const breadcrumb = (0, import_react25.useMemo)(
5845
+ const breadcrumb = (0, import_react27.useMemo)(
5138
5846
  () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),
5139
5847
  [graph, drill.currentSubflowId]
5140
5848
  );
5141
- const [measuredSizes, setMeasuredSizes] = (0, import_react25.useState)(null);
5142
- const positioned = (0, import_react25.useMemo)(() => {
5849
+ const [measuredSizes, setMeasuredSizes] = (0, import_react27.useState)(null);
5850
+ const positioned = (0, import_react27.useMemo)(() => {
5143
5851
  const nodeSize = measuredSizes ? (n) => measuredSizes.get(n.id) : void 0;
5144
5852
  const sizeOpts = nodeSize ? { nodeSize } : {};
5145
5853
  const dagreBase = withForkCentering(
@@ -5163,7 +5871,7 @@ function TracedFlow({
5163
5871
  }
5164
5872
  return realBase(filteredGraph);
5165
5873
  }, [filteredGraph, layout, layoutProp, groupedSet, mainChartBox, measuredSizes]);
5166
- const slice = (0, import_react25.useMemo)(() => {
5874
+ const slice = (0, import_react27.useMemo)(() => {
5167
5875
  const empty = {
5168
5876
  doneStageIds: /* @__PURE__ */ new Set(),
5169
5877
  activeStageId: null,
@@ -5175,7 +5883,7 @@ function TracedFlow({
5175
5883
  const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);
5176
5884
  return aggregateMountStatus(sliceOverlay(overlay, idx), graph, drill.currentSubflowId);
5177
5885
  }, [overlay, scrubIndex, graph, drill.currentSubflowId]);
5178
- const reactFlowNodes = (0, import_react25.useMemo)(
5886
+ const reactFlowNodes = (0, import_react27.useMemo)(
5179
5887
  () => positioned.nodes.map(
5180
5888
  (n) => toStageNodeWithOverlay(
5181
5889
  n,
@@ -5188,20 +5896,20 @@ function TracedFlow({
5188
5896
  ),
5189
5897
  [positioned.nodes, slice, coActiveStageIds]
5190
5898
  );
5191
- const reactFlowEdges = (0, import_react25.useMemo)(
5899
+ const reactFlowEdges = (0, import_react27.useMemo)(
5192
5900
  () => positioned.edges.map(
5193
5901
  (e) => styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors)
5194
5902
  ),
5195
5903
  [positioned.edges, slice, colors]
5196
5904
  );
5197
- const [coneRevealed, setConeRevealed] = (0, import_react25.useState)(false);
5198
- (0, import_react25.useEffect)(() => {
5905
+ const [coneRevealed, setConeRevealed] = (0, import_react27.useState)(false);
5906
+ (0, import_react27.useEffect)(() => {
5199
5907
  if (!sliceCone) return;
5200
5908
  setConeRevealed(false);
5201
5909
  const raf = requestAnimationFrame(() => setConeRevealed(true));
5202
5910
  return () => cancelAnimationFrame(raf);
5203
5911
  }, [sliceCone]);
5204
- const conedNodes = (0, import_react25.useMemo)(() => {
5912
+ const conedNodes = (0, import_react27.useMemo)(() => {
5205
5913
  if (!sliceCone || sliceCone.size === 0) return reactFlowNodes;
5206
5914
  return reactFlowNodes.map((n) => {
5207
5915
  const depth = sliceCone.get(n.id);
@@ -5219,14 +5927,14 @@ function TracedFlow({
5219
5927
  };
5220
5928
  });
5221
5929
  }, [reactFlowNodes, sliceCone, coneRevealed]);
5222
- const conedEdges = (0, import_react25.useMemo)(() => {
5930
+ const conedEdges = (0, import_react27.useMemo)(() => {
5223
5931
  if (!sliceCone || sliceCone.size === 0) return reactFlowEdges;
5224
5932
  return reactFlowEdges.map((e) => {
5225
5933
  const inCone = sliceCone.has(e.source) && sliceCone.has(e.target);
5226
5934
  return inCone ? e : { ...e, style: { ...e.style, opacity: 0.12, transition: "opacity 260ms ease" } };
5227
5935
  });
5228
5936
  }, [reactFlowEdges, sliceCone]);
5229
- const handleNodeClick = (0, import_react25.useCallback)(
5937
+ const handleNodeClick = (0, import_react27.useCallback)(
5230
5938
  (_, node) => {
5231
5939
  const data = node.data ?? {};
5232
5940
  if (data.isSubflow && data.subflowId && !groupedSet.has(data.subflowId)) {
@@ -5236,14 +5944,14 @@ function TracedFlow({
5236
5944
  },
5237
5945
  [drill, onNodeClick, groupedSet]
5238
5946
  );
5239
- const wrapperRef = (0, import_react25.useRef)(null);
5240
- const [rfInstance, setRfInstance] = (0, import_react25.useState)(null);
5947
+ const wrapperRef = (0, import_react27.useRef)(null);
5948
+ const [rfInstance, setRfInstance] = (0, import_react27.useState)(null);
5241
5949
  useChartAutoRefit(wrapperRef, rfInstance, {
5242
5950
  // Re-fit on drill AND after the measured-size re-layout settles.
5243
5951
  refitKey: `${drill.currentSubflowId ?? ""}:${measuredSizes ? "measured" : "estimated"}`,
5244
5952
  padding: 0.18
5245
5953
  });
5246
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
5954
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5247
5955
  "div",
5248
5956
  {
5249
5957
  ref: wrapperRef,
@@ -5257,15 +5965,15 @@ function TracedFlow({
5257
5965
  ...style
5258
5966
  },
5259
5967
  children: [
5260
- breadcrumb.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5968
+ breadcrumb.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5261
5969
  SubflowBreadcrumbBar,
5262
5970
  {
5263
5971
  entries: breadcrumb,
5264
5972
  onNavigate: drill.setCurrentSubflowId
5265
5973
  }
5266
5974
  ),
5267
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
5268
- import_react26.ReactFlow,
5975
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5976
+ import_react28.ReactFlow,
5269
5977
  {
5270
5978
  nodes: conedNodes,
5271
5979
  edges: conedEdges,
@@ -5278,8 +5986,8 @@ function TracedFlow({
5278
5986
  minZoom: 0.1,
5279
5987
  proOptions: { hideAttribution: true },
5280
5988
  children: [
5281
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MeasuredNodeSizes, { onSizes: setMeasuredSizes }),
5282
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react26.Background, { variant: import_react26.BackgroundVariant.Dots, gap: 20, size: 1 }),
5989
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(MeasuredNodeSizes, { onSizes: setMeasuredSizes }),
5990
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.Background, { variant: import_react28.BackgroundVariant.Dots, gap: 20, size: 1 }),
5283
5991
  children
5284
5992
  ]
5285
5993
  }
@@ -5290,187 +5998,27 @@ function TracedFlow({
5290
5998
  }
5291
5999
 
5292
6000
  // src/components/InspectorPanel/InspectorPanel.tsx
5293
- var import_react28 = require("react");
5294
-
5295
- // src/components/DataTracePanel/DataTracePanel.tsx
5296
- var import_react27 = require("react");
5297
- var import_jsx_runtime22 = require("react/jsx-runtime");
5298
- var DataTracePanel = (0, import_react27.memo)(function DataTracePanel2({
5299
- frames,
5300
- selectedStageId,
5301
- onFrameClick,
5302
- fromStageName,
5303
- note
5304
- }) {
5305
- const noteLine = note ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", marginBottom: 8 }, children: note }) : null;
5306
- if (frames.length === 0) {
5307
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
5308
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5309
- "div",
5310
- {
5311
- style: {
5312
- fontSize: 11,
5313
- color: theme.textMuted,
5314
- textTransform: "uppercase",
5315
- letterSpacing: "0.5px",
5316
- fontWeight: 600,
5317
- marginBottom: 6
5318
- },
5319
- children: "Backward causal chain"
5320
- }
5321
- ),
5322
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: theme.textSecondary, marginBottom: 10 }, children: "Trace any value back to the stage that created it \u2014 and everything upstream that influenced it." }),
5323
- noteLine,
5324
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: theme.textMuted, fontSize: 12 }, children: "Select a stage above to see its dependency chain." })
5325
- ] });
5326
- }
5327
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "8px 0", fontSize: 13 }, children: [
5328
- note && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { padding: "4px 12px 0", fontSize: 11, color: theme.textMuted, fontStyle: "italic" }, children: note }),
5329
- fromStageName && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "4px 12px 8px" }, children: [
5330
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5331
- "div",
5332
- {
5333
- style: {
5334
- fontSize: 11,
5335
- color: theme.textMuted,
5336
- textTransform: "uppercase",
5337
- letterSpacing: "0.5px",
5338
- fontWeight: 600
5339
- },
5340
- children: [
5341
- "Data trace from ",
5342
- fromStageName
5343
- ]
5344
- }
5345
- ),
5346
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5347
- "div",
5348
- {
5349
- style: {
5350
- fontSize: 11,
5351
- color: theme.textMuted,
5352
- fontStyle: "italic",
5353
- marginTop: 3
5354
- },
5355
- children: "Every value here was derived from the stages below."
5356
- }
5357
- )
5358
- ] }),
5359
- frames.map((frame, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5360
- DataTraceFrame,
5361
- {
5362
- frame,
5363
- isFirst: i === 0,
5364
- isLast: i === frames.length - 1,
5365
- isSelected: frame.runtimeStageId === selectedStageId,
5366
- onClick: onFrameClick
5367
- },
5368
- frame.runtimeStageId
5369
- ))
5370
- ] });
5371
- });
5372
- var DataTraceFrame = (0, import_react27.memo)(function DataTraceFrame2({
5373
- frame,
5374
- isFirst,
5375
- isLast,
5376
- isSelected,
5377
- onClick
5378
- }) {
5379
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5380
- "button",
5381
- {
5382
- onClick: () => onClick?.(frame.runtimeStageId),
5383
- style: {
5384
- display: "block",
5385
- width: "100%",
5386
- textAlign: "left",
5387
- border: "none",
5388
- background: isSelected ? "var(--fp-accent-bg, rgba(99,102,241,0.12))" : "transparent",
5389
- padding: "6px 12px 6px 16px",
5390
- cursor: onClick ? "pointer" : "default",
5391
- borderLeft: isSelected ? "3px solid var(--fp-accent, #6366f1)" : "3px solid transparent",
5392
- color: "inherit",
5393
- fontSize: 13
5394
- },
5395
- children: [
5396
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
5397
- !isFirst && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { color: theme.textMuted, fontSize: 11 }, children: "\u2191" }),
5398
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5399
- "span",
5400
- {
5401
- style: {
5402
- fontWeight: isFirst ? 600 : 400,
5403
- color: isFirst ? "var(--fp-accent, #6366f1)" : theme.textPrimary
5404
- },
5405
- children: frame.stageName
5406
- }
5407
- ),
5408
- isLast && !isFirst && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5409
- "span",
5410
- {
5411
- style: {
5412
- fontSize: 10,
5413
- color: theme.textMuted,
5414
- fontStyle: "italic"
5415
- },
5416
- children: "(origin)"
5417
- }
5418
- )
5419
- ] }),
5420
- frame.keysWritten.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5421
- "div",
5422
- {
5423
- style: {
5424
- fontSize: 11,
5425
- color: theme.textMuted,
5426
- paddingLeft: isFirst ? 0 : 18,
5427
- marginTop: 2
5428
- },
5429
- children: [
5430
- "wrote:",
5431
- " ",
5432
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { color: theme.textSecondary }, children: frame.keysWritten.join(", ") })
5433
- ]
5434
- }
5435
- ),
5436
- frame.linkedBy && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5437
- "div",
5438
- {
5439
- style: {
5440
- fontSize: 11,
5441
- color: "var(--fp-accent, #6366f1)",
5442
- paddingLeft: 18,
5443
- marginTop: 1
5444
- },
5445
- children: [
5446
- "\u2190 via ",
5447
- frame.linkedBy
5448
- ]
5449
- }
5450
- )
5451
- ]
5452
- }
5453
- );
5454
- });
5455
-
5456
- // src/components/InspectorPanel/InspectorPanel.tsx
5457
- var import_jsx_runtime23 = require("react/jsx-runtime");
5458
- var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
6001
+ var import_react29 = require("react");
6002
+ var import_jsx_runtime24 = require("react/jsx-runtime");
6003
+ var InspectorPanel = (0, import_react29.memo)(function InspectorPanel2({
5459
6004
  snapshots,
5460
6005
  selectedIndex,
5461
6006
  dataTraceFrames,
5462
6007
  dataTraceNote,
5463
6008
  selectedStageId,
5464
6009
  onNavigateToStage,
5465
- onTabChange
6010
+ onTabChange,
6011
+ tab: controlledTab,
6012
+ traceContent
5466
6013
  }) {
5467
- const [tab, setTabState] = (0, import_react28.useState)("state");
6014
+ const [internalTab, setTabState] = (0, import_react29.useState)("state");
6015
+ const tab = controlledTab ?? internalTab;
5468
6016
  const setTab = (t) => {
5469
6017
  setTabState(t);
5470
6018
  onTabChange?.(t);
5471
6019
  };
5472
6020
  const currentSnapshot = snapshots[selectedIndex];
5473
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6021
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5474
6022
  "div",
5475
6023
  {
5476
6024
  style: {
@@ -5480,7 +6028,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5480
6028
  overflow: "hidden"
5481
6029
  },
5482
6030
  children: [
5483
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6031
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5484
6032
  "div",
5485
6033
  {
5486
6034
  style: {
@@ -5489,7 +6037,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5489
6037
  flexShrink: 0
5490
6038
  },
5491
6039
  children: [
5492
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6040
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5493
6041
  TabButton,
5494
6042
  {
5495
6043
  active: tab === "state",
@@ -5497,7 +6045,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5497
6045
  label: "State"
5498
6046
  }
5499
6047
  ),
5500
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6048
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5501
6049
  TabButton,
5502
6050
  {
5503
6051
  active: tab === "trace",
@@ -5509,15 +6057,15 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5509
6057
  ]
5510
6058
  }
5511
6059
  ),
5512
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
5513
- tab === "state" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6060
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
6061
+ tab === "state" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5514
6062
  MemoryPanel,
5515
6063
  {
5516
6064
  snapshots,
5517
6065
  selectedIndex
5518
6066
  }
5519
6067
  ),
5520
- tab === "trace" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6068
+ tab === "trace" && (traceContent ?? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5521
6069
  DataTracePanel,
5522
6070
  {
5523
6071
  frames: dataTraceFrames,
@@ -5526,7 +6074,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5526
6074
  onFrameClick: onNavigateToStage,
5527
6075
  fromStageName: currentSnapshot?.stageName
5528
6076
  }
5529
- )
6077
+ ))
5530
6078
  ] })
5531
6079
  ]
5532
6080
  }
@@ -5538,7 +6086,7 @@ function TabButton({
5538
6086
  label,
5539
6087
  badge
5540
6088
  }) {
5541
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6089
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5542
6090
  "button",
5543
6091
  {
5544
6092
  onClick,
@@ -5557,7 +6105,7 @@ function TabButton({
5557
6105
  },
5558
6106
  children: [
5559
6107
  label,
5560
- badge && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6108
+ badge && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5561
6109
  "span",
5562
6110
  {
5563
6111
  style: {
@@ -5577,28 +6125,28 @@ function TabButton({
5577
6125
  }
5578
6126
 
5579
6127
  // src/components/InsightPanel/InsightPanel.tsx
5580
- var import_react29 = require("react");
5581
- var import_jsx_runtime24 = require("react/jsx-runtime");
5582
- var InsightPanel = (0, import_react29.memo)(function InsightPanel2({
6128
+ var import_react30 = require("react");
6129
+ var import_jsx_runtime25 = require("react/jsx-runtime");
6130
+ var InsightPanel = (0, import_react30.memo)(function InsightPanel2({
5583
6131
  insights,
5584
6132
  expandedId,
5585
6133
  mode
5586
6134
  }) {
5587
6135
  if (insights.length === 0) {
5588
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { padding: 12, color: theme.textMuted, fontSize: 13 }, children: "No insights available. Attach recorders to see data." });
6136
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { padding: 12, color: theme.textMuted, fontSize: 13 }, children: "No insights available. Attach recorders to see data." });
5589
6137
  }
5590
6138
  if (mode === "grid") {
5591
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(InsightGrid, { insights });
6139
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InsightGrid, { insights });
5592
6140
  }
5593
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(InsightTabs, { insights, defaultId: expandedId });
6141
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InsightTabs, { insights, defaultId: expandedId });
5594
6142
  });
5595
- var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
6143
+ var InsightTabs = (0, import_react30.memo)(function InsightTabs2({
5596
6144
  insights,
5597
6145
  defaultId
5598
6146
  }) {
5599
- const [activeId, setActiveId] = (0, import_react29.useState)(defaultId ?? insights[0]?.id);
6147
+ const [activeId, setActiveId] = (0, import_react30.useState)(defaultId ?? insights[0]?.id);
5600
6148
  const active = insights.find((i) => i.id === activeId) ?? insights[0];
5601
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6149
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5602
6150
  "div",
5603
6151
  {
5604
6152
  style: {
@@ -5608,7 +6156,7 @@ var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
5608
6156
  overflow: "hidden"
5609
6157
  },
5610
6158
  children: [
5611
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6159
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5612
6160
  "div",
5613
6161
  {
5614
6162
  style: {
@@ -5617,7 +6165,7 @@ var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
5617
6165
  flexShrink: 0,
5618
6166
  overflowX: "auto"
5619
6167
  },
5620
- children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6168
+ children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5621
6169
  "button",
5622
6170
  {
5623
6171
  onClick: () => setActiveId(insight.id),
@@ -5638,16 +6186,16 @@ var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
5638
6186
  ))
5639
6187
  }
5640
6188
  ),
5641
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: active?.render() })
6189
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: active?.render() })
5642
6190
  ]
5643
6191
  }
5644
6192
  );
5645
6193
  });
5646
- var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
6194
+ var InsightGrid = (0, import_react30.memo)(function InsightGrid2({
5647
6195
  insights
5648
6196
  }) {
5649
6197
  const cols = insights.length <= 2 ? 1 : 2;
5650
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6198
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5651
6199
  "div",
5652
6200
  {
5653
6201
  style: {
@@ -5658,7 +6206,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5658
6206
  gap: 1,
5659
6207
  background: theme.border
5660
6208
  },
5661
- children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6209
+ children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5662
6210
  "div",
5663
6211
  {
5664
6212
  style: {
@@ -5668,7 +6216,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5668
6216
  overflow: "hidden"
5669
6217
  },
5670
6218
  children: [
5671
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6219
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5672
6220
  "div",
5673
6221
  {
5674
6222
  style: {
@@ -5683,7 +6231,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5683
6231
  },
5684
6232
  children: [
5685
6233
  insight.name,
5686
- insight.summary && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6234
+ insight.summary && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5687
6235
  "span",
5688
6236
  {
5689
6237
  style: {
@@ -5698,7 +6246,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5698
6246
  ]
5699
6247
  }
5700
6248
  ),
5701
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: insight.render() })
6249
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: insight.render() })
5702
6250
  ]
5703
6251
  },
5704
6252
  insight.id
@@ -5708,17 +6256,17 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5708
6256
  });
5709
6257
 
5710
6258
  // src/components/CompactTimeline/CompactTimeline.tsx
5711
- var import_react30 = require("react");
5712
- var import_jsx_runtime25 = require("react/jsx-runtime");
5713
- var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
6259
+ var import_react31 = require("react");
6260
+ var import_jsx_runtime26 = require("react/jsx-runtime");
6261
+ var CompactTimeline = (0, import_react31.memo)(function CompactTimeline2({
5714
6262
  snapshots,
5715
6263
  selectedIndex,
5716
6264
  defaultExpanded = false
5717
6265
  }) {
5718
- const [expanded, setExpanded] = (0, import_react30.useState)(defaultExpanded);
6266
+ const [expanded, setExpanded] = (0, import_react31.useState)(defaultExpanded);
5719
6267
  if (snapshots.length === 0) return null;
5720
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
5721
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6268
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
6269
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5722
6270
  "button",
5723
6271
  {
5724
6272
  onClick: () => setExpanded((e) => !e),
@@ -5738,13 +6286,13 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5738
6286
  letterSpacing: "0.5px"
5739
6287
  },
5740
6288
  children: [
5741
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 10 }, children: expanded ? "\u25BC" : "\u25B8" }),
6289
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontSize: 10 }, children: expanded ? "\u25BC" : "\u25B8" }),
5742
6290
  "Timeline",
5743
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { style: { fontWeight: 400, fontSize: 10 }, children: [
6291
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { style: { fontWeight: 400, fontSize: 10 }, children: [
5744
6292
  snapshots.length,
5745
6293
  " stages"
5746
6294
  ] }),
5747
- !expanded && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6295
+ !expanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5748
6296
  "div",
5749
6297
  {
5750
6298
  style: {
@@ -5755,7 +6303,7 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5755
6303
  marginLeft: 8
5756
6304
  },
5757
6305
  children: [
5758
- snapshots.map((snap, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6306
+ snapshots.map((snap, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5759
6307
  "div",
5760
6308
  {
5761
6309
  style: {
@@ -5770,7 +6318,7 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5770
6318
  },
5771
6319
  i
5772
6320
  )),
5773
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6321
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5774
6322
  "div",
5775
6323
  {
5776
6324
  style: {
@@ -5788,7 +6336,7 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5788
6336
  ]
5789
6337
  }
5790
6338
  ),
5791
- expanded && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { padding: "0 12px 8px" }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6339
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { padding: "0 12px 8px" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5792
6340
  GanttTimeline,
5793
6341
  {
5794
6342
  snapshots,
@@ -5799,21 +6347,21 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5799
6347
  });
5800
6348
 
5801
6349
  // src/components/ExplainableShell/ExplainableShell.tsx
5802
- var import_jsx_runtime26 = require("react/jsx-runtime");
5803
- var HLinePill = (0, import_react31.memo)(function HLinePill2({
6350
+ var import_jsx_runtime27 = require("react/jsx-runtime");
6351
+ var HLinePill = (0, import_react32.memo)(function HLinePill2({
5804
6352
  label,
5805
6353
  detail,
5806
6354
  expanded,
5807
6355
  onClick
5808
6356
  }) {
5809
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: {
6357
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: {
5810
6358
  display: "flex",
5811
6359
  alignItems: "center",
5812
6360
  gap: 0,
5813
6361
  padding: "0"
5814
6362
  }, children: [
5815
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } }),
5816
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6363
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } }),
6364
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5817
6365
  "button",
5818
6366
  {
5819
6367
  onClick,
@@ -5837,31 +6385,31 @@ var HLinePill = (0, import_react31.memo)(function HLinePill2({
5837
6385
  transition: "color 0.15s ease"
5838
6386
  },
5839
6387
  children: [
5840
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontSize: 7 }, children: expanded ? "\u25BC" : "\u25B6" }),
6388
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontSize: 7 }, children: expanded ? "\u25BC" : "\u25B6" }),
5841
6389
  label,
5842
- detail && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontWeight: 400, opacity: 0.5, fontSize: 9 }, children: detail })
6390
+ detail && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontWeight: 400, opacity: 0.5, fontSize: 9 }, children: detail })
5843
6391
  ]
5844
6392
  }
5845
6393
  ),
5846
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } })
6394
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } })
5847
6395
  ] });
5848
6396
  });
5849
- var VLinePill = (0, import_react31.memo)(function VLinePill2({
6397
+ var VLinePill = (0, import_react32.memo)(function VLinePill2({
5850
6398
  label,
5851
6399
  expanded,
5852
6400
  side = "right",
5853
6401
  onClick
5854
6402
  }) {
5855
6403
  const arrow = side === "right" ? expanded ? "\u25B6" : "\u25C0" : expanded ? "\u25C0" : "\u25B6";
5856
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: {
6404
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: {
5857
6405
  display: "flex",
5858
6406
  flexDirection: "column",
5859
6407
  alignItems: "center",
5860
6408
  gap: 0,
5861
6409
  padding: "0"
5862
6410
  }, children: [
5863
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } }),
5864
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6411
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } }),
6412
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5865
6413
  "button",
5866
6414
  {
5867
6415
  onClick,
@@ -5886,12 +6434,12 @@ var VLinePill = (0, import_react31.memo)(function VLinePill2({
5886
6434
  transition: "color 0.15s ease"
5887
6435
  },
5888
6436
  children: [
5889
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontSize: 7, writingMode: "horizontal-tb" }, children: arrow }),
6437
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontSize: 7, writingMode: "horizontal-tb" }, children: arrow }),
5890
6438
  label
5891
6439
  ]
5892
6440
  }
5893
6441
  ),
5894
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } })
6442
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } })
5895
6443
  ] });
5896
6444
  });
5897
6445
  function detectKeyedSteps(data) {
@@ -5928,9 +6476,9 @@ function KeyedRecorderView({
5928
6476
  snapshots,
5929
6477
  selectedIndex
5930
6478
  }) {
5931
- const [showAggregate, setShowAggregate] = (0, import_react31.useState)(false);
5932
- const detected = (0, import_react31.useMemo)(() => detectKeyedSteps(data), [data]);
5933
- const visibleKeys = (0, import_react31.useMemo)(() => {
6479
+ const [showAggregate, setShowAggregate] = (0, import_react32.useState)(false);
6480
+ const detected = (0, import_react32.useMemo)(() => detectKeyedSteps(data), [data]);
6481
+ const visibleKeys = (0, import_react32.useMemo)(() => {
5934
6482
  const keys = /* @__PURE__ */ new Set();
5935
6483
  for (let i = 0; i <= selectedIndex && i < snapshots.length; i++) {
5936
6484
  const snap = snapshots[i];
@@ -5945,7 +6493,7 @@ function KeyedRecorderView({
5945
6493
  }, [snapshots, selectedIndex, detected?.keyType]);
5946
6494
  const isAtEnd = selectedIndex >= snapshots.length - 1;
5947
6495
  if (!detected) {
5948
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", height: "100%" }, children: typeof data === "string" ? data : JSON.stringify(data, null, 2) });
6496
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", height: "100%" }, children: typeof data === "string" ? data : JSON.stringify(data, null, 2) });
5949
6497
  }
5950
6498
  const steps = detected.steps;
5951
6499
  const hints = extractRenderHints(data);
@@ -5959,13 +6507,13 @@ function KeyedRecorderView({
5959
6507
  }
5960
6508
  }
5961
6509
  const grandTotal = hints?.grandTotal ?? 0;
5962
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
5963
- description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { padding: "6px 12px", fontSize: 11, color: theme.textMuted, fontStyle: "italic", borderBottom: `1px solid ${theme.border}`, flexShrink: 0 }, children: description }),
5964
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
6510
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
6511
+ description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { padding: "6px 12px", fontSize: 11, color: theme.textMuted, fontStyle: "italic", borderBottom: `1px solid ${theme.border}`, flexShrink: 0 }, children: description }),
6512
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
5965
6513
  preferredOperation === "aggregate" ? (
5966
6514
  /* AGGREGATE: collect silently during scrub, button at end to reveal total */
5967
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
5968
- isAtEnd ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { marginBottom: 16 }, children: !showAggregate ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6515
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6516
+ isAtEnd ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { marginBottom: 16 }, children: !showAggregate ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5969
6517
  "button",
5970
6518
  {
5971
6519
  onClick: () => setShowAggregate(true),
@@ -5983,35 +6531,35 @@ function KeyedRecorderView({
5983
6531
  },
5984
6532
  children: "Aggregate \u2014 Show Grand Total"
5985
6533
  }
5986
- ) : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { padding: "14px 16px", background: `color-mix(in srgb, ${theme.success} 12%, transparent)`, borderRadius: 8, border: `1px solid ${theme.success}44` }, children: [
5987
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Aggregate \u2014 grand total" }),
5988
- numFieldKey && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { fontSize: 26, fontWeight: 700, color: theme.success }, children: [
6534
+ ) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { padding: "14px 16px", background: `color-mix(in srgb, ${theme.success} 12%, transparent)`, borderRadius: 8, border: `1px solid ${theme.success}44` }, children: [
6535
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Aggregate \u2014 grand total" }),
6536
+ numFieldKey && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { fontSize: 26, fontWeight: 700, color: theme.success }, children: [
5989
6537
  grandTotal < 1 ? grandTotal.toFixed(3) : grandTotal.toFixed(1),
5990
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
6538
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
5991
6539
  numFieldKey,
5992
6540
  " \xB7 ",
5993
6541
  allKeys.length,
5994
6542
  " steps"
5995
6543
  ] })
5996
6544
  ] })
5997
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.textMuted} 6%, transparent)`, borderRadius: 6, marginBottom: 16, border: `1px dashed ${theme.border}` }, children: [
5998
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600 }, children: "Collecting data..." }),
5999
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
6545
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.textMuted} 6%, transparent)`, borderRadius: 6, marginBottom: 16, border: `1px dashed ${theme.border}` }, children: [
6546
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600 }, children: "Collecting data..." }),
6547
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
6000
6548
  visibleEntries.length,
6001
6549
  " of ",
6002
6550
  allKeys.length,
6003
6551
  " steps collected. Scrub to end to aggregate."
6004
6552
  ] })
6005
6553
  ] }),
6006
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
6554
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
6007
6555
  ] })
6008
6556
  ) : preferredOperation === "accumulate" ? (
6009
6557
  /* ACCUMULATE: running total grows with slider — IS the total at end, no button */
6010
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6011
- numFieldKey && visibleEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.primary} 8%, transparent)`, borderRadius: 6, marginBottom: 16 }, children: [
6012
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4, fontWeight: 600 }, children: "Accumulate \u2014 running total up to this step" }),
6013
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontWeight: 700, fontSize: 18, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
6014
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
6558
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6559
+ numFieldKey && visibleEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.primary} 8%, transparent)`, borderRadius: 6, marginBottom: 16 }, children: [
6560
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4, fontWeight: 600 }, children: "Accumulate \u2014 running total up to this step" }),
6561
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontWeight: 700, fontSize: 18, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
6562
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
6015
6563
  numFieldKey,
6016
6564
  " \xB7 ",
6017
6565
  visibleEntries.length,
@@ -6020,27 +6568,27 @@ function KeyedRecorderView({
6020
6568
  " steps"
6021
6569
  ] })
6022
6570
  ] }),
6023
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
6571
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
6024
6572
  ] })
6025
6573
  ) : (
6026
6574
  /* TRANSLATE: per-step entries prominent, no totals */
6027
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Translate \u2014 per-step detail" })
6575
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Translate \u2014 per-step detail" })
6028
6576
  ),
6029
6577
  visibleEntries.map((key) => {
6030
6578
  const entry = steps[key];
6031
6579
  const label = entry.stageName ?? key;
6032
6580
  const numVal = numFieldKey ? entry[numFieldKey] : void 0;
6033
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "4px 0", fontSize: 12, fontFamily: theme.fontMono, borderBottom: `1px solid ${theme.border}22` }, children: [
6034
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
6035
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
6036
- numVal !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
6581
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "4px 0", fontSize: 12, fontFamily: theme.fontMono, borderBottom: `1px solid ${theme.border}22` }, children: [
6582
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
6583
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
6584
+ numVal !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
6037
6585
  ] }, key);
6038
6586
  }),
6039
- visibleEntries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", padding: "8px 0" }, children: "Scrub the slider to reveal entries..." })
6587
+ visibleEntries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", padding: "8px 0" }, children: "Scrub the slider to reveal entries..." })
6040
6588
  ] })
6041
6589
  ] });
6042
6590
  }
6043
- var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
6591
+ var DetailsContent = (0, import_react32.memo)(function DetailsContent2({
6044
6592
  snapshots,
6045
6593
  selectedIndex,
6046
6594
  narrativeEntries,
@@ -6052,27 +6600,27 @@ var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
6052
6600
  {
6053
6601
  id: "memory",
6054
6602
  name: "Memory",
6055
- render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: fillHeight ? { height: "100%" } : void 0 })
6603
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: fillHeight ? { height: "100%" } : void 0 })
6056
6604
  },
6057
6605
  {
6058
6606
  id: "narrative",
6059
6607
  name: "Narrative",
6060
- render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries, size, style: fillHeight ? { height: "100%" } : void 0 })
6608
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries, size, style: fillHeight ? { height: "100%" } : void 0 })
6061
6609
  }
6062
6610
  ];
6063
6611
  const allViews = [...builtInViews, ...extraViews ?? []];
6064
- const [activeViewId, setActiveViewId] = (0, import_react31.useState)(allViews[0]?.id ?? "memory");
6612
+ const [activeViewId, setActiveViewId] = (0, import_react32.useState)(allViews[0]?.id ?? "memory");
6065
6613
  const viewIds = allViews.map((v2) => v2.id).join(",");
6066
- (0, import_react31.useEffect)(() => {
6614
+ (0, import_react32.useEffect)(() => {
6067
6615
  if (!allViews.find((v2) => v2.id === activeViewId)) {
6068
6616
  setActiveViewId(allViews[0]?.id ?? "memory");
6069
6617
  }
6070
6618
  }, [viewIds]);
6071
6619
  const activeView = allViews.find((v2) => v2.id === activeViewId) ?? allViews[0];
6072
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
6073
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
6620
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
6621
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
6074
6622
  const active = view.id === activeViewId;
6075
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6623
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6076
6624
  "button",
6077
6625
  {
6078
6626
  onClick: () => setActiveViewId(view.id),
@@ -6096,7 +6644,7 @@ var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
6096
6644
  view.id
6097
6645
  );
6098
6646
  }) }),
6099
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
6647
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
6100
6648
  ] });
6101
6649
  });
6102
6650
  function resolveSubflowFromRuntime(parentSnapshots, subflowId, narrativeEntries) {
@@ -6113,7 +6661,7 @@ function resolveSubflowFromRuntime(parentSnapshots, subflowId, narrativeEntries)
6113
6661
  if (sfSnapshots.length === 0) return null;
6114
6662
  return { subflowId, label, spec: null, snapshots: sfSnapshots, narrative: sfNarrative };
6115
6663
  }
6116
- var RightPanel = (0, import_react31.memo)(function RightPanel2({
6664
+ var RightPanel = (0, import_react32.memo)(function RightPanel2({
6117
6665
  mode,
6118
6666
  onModeChange,
6119
6667
  snapshots,
@@ -6127,15 +6675,17 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6127
6675
  size,
6128
6676
  onNavigateToStage,
6129
6677
  dataTrace,
6130
- onInspectorTabChange
6678
+ onInspectorTabChange,
6679
+ inspectorTab,
6680
+ traceContent
6131
6681
  }) {
6132
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6133
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: {
6682
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6683
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: {
6134
6684
  display: "flex",
6135
6685
  borderBottom: `1px solid ${theme.border}`,
6136
6686
  flexShrink: 0,
6137
6687
  background: theme.bgSecondary
6138
- }, children: ["insights", "what"].map((m) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6688
+ }, children: ["insights", "what"].map((m) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6139
6689
  "button",
6140
6690
  {
6141
6691
  onClick: () => onModeChange(m),
@@ -6157,7 +6707,7 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6157
6707
  },
6158
6708
  m
6159
6709
  )) }),
6160
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: mode === "insights" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6710
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: mode === "insights" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6161
6711
  InsightPanel,
6162
6712
  {
6163
6713
  mode: "tabs",
@@ -6166,16 +6716,16 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6166
6716
  id: tab.id,
6167
6717
  name: insightName(tab.name),
6168
6718
  render: () => {
6169
- if (tab.id === "narrative") return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, runtimeSnapshot, size, style: { height: "100%" } });
6719
+ if (tab.id === "narrative") return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, runtimeSnapshot, size, style: { height: "100%" } });
6170
6720
  const customView = recorderViews?.find((v2) => v2.id === tab.id);
6171
6721
  if (customView?.render) return customView.render({ snapshots, selectedIndex });
6172
6722
  const autoView = autoRecorderViews.find((v2) => v2.id === tab.id);
6173
- if (autoView) return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(KeyedRecorderView, { data: autoView.data, description: autoView.description, preferredOperation: autoView.preferredOperation, snapshots, selectedIndex });
6723
+ if (autoView) return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(KeyedRecorderView, { data: autoView.data, description: autoView.description, preferredOperation: autoView.preferredOperation, snapshots, selectedIndex });
6174
6724
  return null;
6175
6725
  }
6176
6726
  }))
6177
6727
  }
6178
- ) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6728
+ ) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6179
6729
  InspectorPanel,
6180
6730
  {
6181
6731
  snapshots,
@@ -6183,6 +6733,8 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6183
6733
  dataTraceFrames: dataTrace.frames,
6184
6734
  dataTraceNote: dataTrace.readsAvailable ? void 0 : "\u26A0 reads were not recorded (readTracking off) \u2014 dependencies are unknowable, not absent.",
6185
6735
  onTabChange: onInspectorTabChange,
6736
+ tab: inspectorTab,
6737
+ traceContent,
6186
6738
  selectedStageId: snapshots[selectedIndex]?.runtimeStageId,
6187
6739
  onNavigateToStage
6188
6740
  }
@@ -6223,7 +6775,7 @@ function ExplainableShell({
6223
6775
  className,
6224
6776
  style
6225
6777
  }) {
6226
- const derivedFromRuntime = (0, import_react31.useMemo)(() => {
6778
+ const derivedFromRuntime = (0, import_react32.useMemo)(() => {
6227
6779
  if (!runtimeSnapshot) return null;
6228
6780
  try {
6229
6781
  const snaps = toVisualizationSnapshots(runtimeSnapshot, narrativeEntries);
@@ -6234,7 +6786,7 @@ function ExplainableShell({
6234
6786
  }, [runtimeSnapshot, narrativeEntries]);
6235
6787
  const snapshots = snapshotsProp ?? derivedFromRuntime?.snapshots ?? [];
6236
6788
  const resultData = resultDataProp ?? derivedFromRuntime?.resultData ?? null;
6237
- const tracedFlowRenderer = (0, import_react31.useMemo)(() => {
6789
+ const tracedFlowRenderer = (0, import_react32.useMemo)(() => {
6238
6790
  if (!traceGraph) return void 0;
6239
6791
  return ({ selectedIndex, snapshots: snapshots2, onNodeClick, sliceCone: sliceCone2 }) => {
6240
6792
  const activeRsid = snapshots2[selectedIndex]?.runtimeStageId;
@@ -6255,7 +6807,7 @@ function ExplainableShell({
6255
6807
  ...traceTheme.current !== void 0 && { active: traceTheme.current },
6256
6808
  ...traceTheme.mode !== void 0 && { default: traceTheme.mode === "dark" ? "#94a3b8" : "#64748b" }
6257
6809
  };
6258
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6810
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6259
6811
  TracedFlow,
6260
6812
  {
6261
6813
  graph: traceGraph,
@@ -6275,10 +6827,10 @@ function ExplainableShell({
6275
6827
  const leftLabel = panelLabels?.topology ?? "Topology";
6276
6828
  const rightLabel = panelLabels?.details ?? "Details";
6277
6829
  const bottomLabel = panelLabels?.timeline ?? "Timeline";
6278
- const shellRef = (0, import_react31.useRef)(null);
6279
- const [isNarrow, setIsNarrow] = (0, import_react31.useState)(false);
6280
- const [isMedium, setIsMedium] = (0, import_react31.useState)(false);
6281
- (0, import_react31.useEffect)(() => {
6830
+ const shellRef = (0, import_react32.useRef)(null);
6831
+ const [isNarrow, setIsNarrow] = (0, import_react32.useState)(false);
6832
+ const [isMedium, setIsMedium] = (0, import_react32.useState)(false);
6833
+ (0, import_react32.useEffect)(() => {
6282
6834
  const el = shellRef.current;
6283
6835
  if (!el) return;
6284
6836
  const ro = new ResizeObserver(([entry]) => {
@@ -6290,14 +6842,14 @@ function ExplainableShell({
6290
6842
  ro.observe(el);
6291
6843
  return () => ro.disconnect();
6292
6844
  }, []);
6293
- const autoRecorderViews = (0, import_react31.useMemo)(() => {
6845
+ const autoRecorderViews = (0, import_react32.useMemo)(() => {
6294
6846
  const recorders = runtimeSnapshot?.recorders;
6295
6847
  if (!recorders?.length) return [];
6296
6848
  const explicitIds = new Set((recorderViews ?? []).map((v2) => v2.id));
6297
6849
  return recorders.filter((r) => !explicitIds.has(r.id)).map((r) => ({ id: r.id, name: r.name, description: r.description, preferredOperation: r.preferredOperation, data: r.data }));
6298
6850
  }, [runtimeSnapshot, recorderViews]);
6299
6851
  const hasNarrative = !!narrativeEntries?.length;
6300
- const allTabs = (0, import_react31.useMemo)(() => {
6852
+ const allTabs = (0, import_react32.useMemo)(() => {
6301
6853
  const tabs2 = [
6302
6854
  { id: "result", name: "Result", description: "Final output and console logs" },
6303
6855
  { id: "memory", name: "Memory", description: "Accumulator \u2014 progressive shared state at each stage" }
@@ -6316,39 +6868,40 @@ function ExplainableShell({
6316
6868
  }, [hasNarrative, recorderViews, autoRecorderViews, hideTabsProp]);
6317
6869
  const validTabIds = new Set(allTabs.map((t) => t.id));
6318
6870
  const resolvedDefault = defaultTab && validTabIds.has(defaultTab) ? defaultTab : allTabs[0]?.id ?? "result";
6319
- const [activeTab, setActiveTab] = (0, import_react31.useState)(resolvedDefault);
6320
- const [snapshotIdx, setSnapshotIdx] = (0, import_react31.useState)(0);
6321
- const [drillDownStack, setDrillDownStack] = (0, import_react31.useState)([]);
6322
- const [rightExpanded, setRightExpanded] = (0, import_react31.useState)(defaultExpanded?.details ?? true);
6323
- const [rightPanelMode, setRightPanelMode] = (0, import_react31.useState)("insights");
6324
- const [inspectorTab, setInspectorTab] = (0, import_react31.useState)("state");
6325
- const [leftExpanded, setLeftExpanded] = (0, import_react31.useState)(defaultExpanded?.topology ?? false);
6326
- const [timelineExpanded, setTimelineExpanded] = (0, import_react31.useState)(defaultExpanded?.timeline ?? false);
6327
- (0, import_react31.useEffect)(() => {
6871
+ const [activeTab, setActiveTab] = (0, import_react32.useState)(resolvedDefault);
6872
+ const [snapshotIdx, setSnapshotIdx] = (0, import_react32.useState)(0);
6873
+ const [drillDownStack, setDrillDownStack] = (0, import_react32.useState)([]);
6874
+ const [rightExpanded, setRightExpanded] = (0, import_react32.useState)(defaultExpanded?.details ?? true);
6875
+ const [rightPanelMode, setRightPanelMode] = (0, import_react32.useState)("insights");
6876
+ const [inspectorTab, setInspectorTab] = (0, import_react32.useState)("state");
6877
+ const [tracing, setTracing] = (0, import_react32.useState)(null);
6878
+ const [leftExpanded, setLeftExpanded] = (0, import_react32.useState)(defaultExpanded?.topology ?? false);
6879
+ const [timelineExpanded, setTimelineExpanded] = (0, import_react32.useState)(defaultExpanded?.timeline ?? false);
6880
+ (0, import_react32.useEffect)(() => {
6328
6881
  if (isNarrow) {
6329
6882
  setLeftExpanded(false);
6330
6883
  setRightExpanded(false);
6331
6884
  setTimelineExpanded(false);
6332
6885
  }
6333
6886
  }, [isNarrow]);
6334
- const triggerReflow = (0, import_react31.useCallback)(() => {
6887
+ const triggerReflow = (0, import_react32.useCallback)(() => {
6335
6888
  requestAnimationFrame(() => window.dispatchEvent(new Event("resize")));
6336
6889
  setTimeout(() => window.dispatchEvent(new Event("resize")), 320);
6337
6890
  }, []);
6338
- const toggleLeft = (0, import_react31.useCallback)((v2) => {
6891
+ const toggleLeft = (0, import_react32.useCallback)((v2) => {
6339
6892
  setLeftExpanded(v2);
6340
6893
  triggerReflow();
6341
6894
  }, [triggerReflow]);
6342
- const toggleRight = (0, import_react31.useCallback)((v2) => {
6895
+ const toggleRight = (0, import_react32.useCallback)((v2) => {
6343
6896
  setRightExpanded(v2);
6344
6897
  triggerReflow();
6345
6898
  }, [triggerReflow]);
6346
- const toggleTimeline = (0, import_react31.useCallback)(() => {
6899
+ const toggleTimeline = (0, import_react32.useCallback)(() => {
6347
6900
  setTimelineExpanded((p) => !p);
6348
6901
  triggerReflow();
6349
6902
  }, [triggerReflow]);
6350
6903
  const isInSubflow = drillDownStack.length > 0;
6351
- const currentLevel = (0, import_react31.useMemo)(() => {
6904
+ const currentLevel = (0, import_react32.useMemo)(() => {
6352
6905
  if (drillDownStack.length > 0) {
6353
6906
  const top = drillDownStack[drillDownStack.length - 1];
6354
6907
  return { spec: top.spec, snapshots: top.snapshots, narrative: top.narrative };
@@ -6357,11 +6910,32 @@ function ExplainableShell({
6357
6910
  }, [drillDownStack, snapshots]);
6358
6911
  const activeSnapshots = currentLevel.snapshots;
6359
6912
  const safeIdx = activeSnapshots.length > 0 ? Math.max(0, Math.min(snapshotIdx, activeSnapshots.length - 1)) : 0;
6360
- const shellDataTrace = (0, import_react31.useMemo)(
6913
+ const shellDataTrace = (0, import_react32.useMemo)(
6361
6914
  () => runtimeSnapshot?.commitLog ? buildDataTrace(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, activeSnapshots[safeIdx]?.runtimeStageId ?? "") : { frames: [], readsAvailable: true },
6362
6915
  [runtimeSnapshot, activeSnapshots, safeIdx]
6363
6916
  );
6364
- const sliceCone = (0, import_react31.useMemo)(() => {
6917
+ const traceWalk = (0, import_react32.useMemo)(() => {
6918
+ if (!tracing || !runtimeSnapshot?.commitLog) return null;
6919
+ const scope = tracing.via.length > 0 ? tracing.via[tracing.via.length - 1] : tracing;
6920
+ return buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, scope.key, {
6921
+ beforeCommitIdx: scope.beforeCommitIdx
6922
+ });
6923
+ }, [tracing, runtimeSnapshot]);
6924
+ const traceStopIndices = (0, import_react32.useMemo)(() => {
6925
+ if (!traceWalk || traceWalk.missing || isInSubflow) return [];
6926
+ const idxByRsid = new Map(activeSnapshots.map((sn, i) => [sn.runtimeStageId, i]));
6927
+ return traceWalk.stops.map((stop) => idxByRsid.get(stop.runtimeStageId)).filter((i) => i !== void 0).sort((a, b) => a - b);
6928
+ }, [traceWalk, activeSnapshots, isInSubflow]);
6929
+ const sliceCone = (0, import_react32.useMemo)(() => {
6930
+ if (traceWalk && !traceWalk.missing && traceWalk.stops.length >= 2) {
6931
+ const cone2 = /* @__PURE__ */ new Map();
6932
+ for (const stop of traceWalk.stops) {
6933
+ const stagePart = stop.runtimeStageId.split("#")[0];
6934
+ const prev = cone2.get(stagePart);
6935
+ if (prev === void 0 || stop.depth < prev) cone2.set(stagePart, stop.depth);
6936
+ }
6937
+ return cone2;
6938
+ }
6365
6939
  if (rightPanelMode !== "what" || inspectorTab !== "trace") return void 0;
6366
6940
  if (shellDataTrace.frames.length < 2) return void 0;
6367
6941
  const cone = /* @__PURE__ */ new Map();
@@ -6371,49 +6945,98 @@ function ExplainableShell({
6371
6945
  if (prev === void 0 || f.depth < prev) cone.set(stagePart, f.depth);
6372
6946
  }
6373
6947
  return cone;
6374
- }, [rightPanelMode, inspectorTab, shellDataTrace]);
6948
+ }, [traceWalk, rightPanelMode, inspectorTab, shellDataTrace]);
6375
6949
  const activeNarrativeEntries = isInSubflow ? currentLevel.narrative : narrativeEntries;
6376
- const breadcrumbs = (0, import_react31.useMemo)(() => {
6950
+ const breadcrumbs = (0, import_react32.useMemo)(() => {
6377
6951
  const root = { label: title || "Flowchart", spec: null, description: void 0 };
6378
6952
  return [root, ...drillDownStack.map((e) => ({ label: e.label, spec: e.spec, description: void 0 }))];
6379
6953
  }, [title, drillDownStack]);
6380
- const showTreeSidebar = (0, import_react31.useMemo)(() => {
6954
+ const showTreeSidebar = (0, import_react32.useMemo)(() => {
6381
6955
  if (traceGraph?.nodes?.length) {
6382
6956
  return traceGraph.nodes.some((n) => n.data?.isSubflow === true);
6383
6957
  }
6384
6958
  return false;
6385
6959
  }, [traceGraph]);
6386
- const rootOverlay = (0, import_react31.useMemo)(() => {
6960
+ const rootOverlay = (0, import_react32.useMemo)(() => {
6387
6961
  if (isInSubflow || !snapshots.length) return { activeStage: void 0, doneStages: void 0 };
6388
6962
  const doneStages = new Set(snapshots.slice(0, safeIdx).map((s) => s.stageLabel));
6389
6963
  const activeStage = snapshots[safeIdx]?.stageLabel ?? null;
6390
6964
  return { activeStage, doneStages };
6391
6965
  }, [isInSubflow, snapshots, safeIdx]);
6392
- const handleTabChange = (0, import_react31.useCallback)((tab) => {
6966
+ const handleTabChange = (0, import_react32.useCallback)((tab) => {
6393
6967
  setActiveTab(tab);
6394
6968
  setDrillDownStack([]);
6395
6969
  }, []);
6396
- const handleSnapshotChange = (0, import_react31.useCallback)((idx) => {
6970
+ const handleSnapshotChange = (0, import_react32.useCallback)((idx) => {
6397
6971
  if (typeof idx === "number") setSnapshotIdx(idx);
6398
6972
  }, []);
6399
- const handleDrillDown = (0, import_react31.useCallback)(
6973
+ const jumpToAnchor = (0, import_react32.useCallback)(
6974
+ (walk) => {
6975
+ const anchor = walk.stops[0];
6976
+ if (!anchor) return;
6977
+ const idx = activeSnapshots.findIndex((sn) => sn.runtimeStageId === anchor.runtimeStageId);
6978
+ if (idx >= 0) setSnapshotIdx(idx);
6979
+ },
6980
+ [activeSnapshots]
6981
+ );
6982
+ const handleStartTracing = (0, import_react32.useCallback)(
6983
+ (key) => {
6984
+ if (!runtimeSnapshot?.commitLog || isInSubflow) return;
6985
+ const log = runtimeSnapshot.commitLog;
6986
+ const cursorRsid = activeSnapshots[safeIdx]?.runtimeStageId;
6987
+ const cursorCommitIdx = log.findIndex((c) => c.runtimeStageId === cursorRsid);
6988
+ const beforeCommitIdx = cursorCommitIdx >= 0 ? cursorCommitIdx + 1 : void 0;
6989
+ setTracing({ key, beforeCommitIdx, via: [] });
6990
+ setRightPanelMode("what");
6991
+ setInspectorTab("trace");
6992
+ jumpToAnchor(
6993
+ buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, key, { beforeCommitIdx })
6994
+ );
6995
+ },
6996
+ [runtimeSnapshot, isInSubflow, activeSnapshots, safeIdx, jumpToAnchor]
6997
+ );
6998
+ const handleFollowIngredient = (0, import_react32.useCallback)(
6999
+ (ing) => {
7000
+ if (!tracing || !runtimeSnapshot?.commitLog || ing.writerCommitIdx === null) return;
7001
+ const scope = { key: ing.key, beforeCommitIdx: ing.writerCommitIdx + 1 };
7002
+ setTracing({ ...tracing, via: [...tracing.via, scope] });
7003
+ jumpToAnchor(
7004
+ buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, scope.key, {
7005
+ beforeCommitIdx: scope.beforeCommitIdx
7006
+ })
7007
+ );
7008
+ },
7009
+ [tracing, runtimeSnapshot, jumpToAnchor]
7010
+ );
7011
+ const handleShowAllIngredients = (0, import_react32.useCallback)(() => {
7012
+ if (!tracing || !runtimeSnapshot?.commitLog) return;
7013
+ setTracing({ ...tracing, via: [] });
7014
+ jumpToAnchor(
7015
+ buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, tracing.key, {
7016
+ beforeCommitIdx: tracing.beforeCommitIdx
7017
+ })
7018
+ );
7019
+ }, [tracing, runtimeSnapshot, jumpToAnchor]);
7020
+ const handleExitTracing = (0, import_react32.useCallback)(() => setTracing(null), []);
7021
+ const handleDrillDown = (0, import_react32.useCallback)(
6400
7022
  (nodeName) => {
6401
7023
  const entry = resolveSubflowFromRuntime(activeSnapshots, nodeName, narrativeEntries);
6402
7024
  if (entry) {
7025
+ setTracing(null);
6403
7026
  setDrillDownStack((prev) => [...prev, { ...entry, parentSnapshotIdx: snapshotIdx }]);
6404
7027
  setSnapshotIdx(0);
6405
7028
  }
6406
7029
  },
6407
7030
  [activeSnapshots, narrativeEntries, snapshotIdx]
6408
7031
  );
6409
- const handleBreadcrumbNavigate = (0, import_react31.useCallback)((level) => {
7032
+ const handleBreadcrumbNavigate = (0, import_react32.useCallback)((level) => {
6410
7033
  setDrillDownStack((prev) => {
6411
7034
  const popped = level === 0 ? prev[0] : prev[level];
6412
7035
  if (popped) setSnapshotIdx(popped.parentSnapshotIdx);
6413
7036
  return level === 0 ? [] : prev.slice(0, level);
6414
7037
  });
6415
7038
  }, []);
6416
- const handleNodeClick = (0, import_react31.useCallback)(
7039
+ const handleNodeClick = (0, import_react32.useCallback)(
6417
7040
  (indexOrId) => {
6418
7041
  if (typeof indexOrId === "number") {
6419
7042
  setSnapshotIdx(indexOrId);
@@ -6429,7 +7052,7 @@ function ExplainableShell({
6429
7052
  },
6430
7053
  [activeSnapshots, narrativeEntries, handleDrillDown]
6431
7054
  );
6432
- const handleTreeNodeSelect = (0, import_react31.useCallback)(
7055
+ const handleTreeNodeSelect = (0, import_react32.useCallback)(
6433
7056
  (name, isSubflow) => {
6434
7057
  if (isSubflow) {
6435
7058
  setDrillDownStack([]);
@@ -6446,33 +7069,112 @@ function ExplainableShell({
6446
7069
  },
6447
7070
  [snapshots, narrativeEntries, snapshotIdx]
6448
7071
  );
7072
+ const navigateToStage = (0, import_react32.useCallback)(
7073
+ (id) => {
7074
+ const idx = activeSnapshots.findIndex((sn) => sn.runtimeStageId === id);
7075
+ if (idx >= 0) setSnapshotIdx(idx);
7076
+ },
7077
+ [activeSnapshots]
7078
+ );
7079
+ const activeViaKey = tracing && tracing.via.length > 0 ? tracing.via[tracing.via.length - 1].key : null;
7080
+ const stepNumberOf = (0, import_react32.useCallback)(
7081
+ (rsid) => {
7082
+ const i = activeSnapshots.findIndex((sn) => sn.runtimeStageId === rsid);
7083
+ return i >= 0 ? i + 1 : null;
7084
+ },
7085
+ [activeSnapshots]
7086
+ );
7087
+ const tracingRail = (0, import_react32.useMemo)(() => {
7088
+ if (!tracing || !traceWalk || traceWalk.missing || traceStopIndices.length === 0) return null;
7089
+ const cursorRsid = activeSnapshots[safeIdx]?.runtimeStageId;
7090
+ const walkIdx = traceWalk.stops.findIndex((st) => st.runtimeStageId === cursorRsid);
7091
+ return {
7092
+ tracedKey: tracing.key,
7093
+ viaKey: activeViaKey,
7094
+ stopIndices: traceStopIndices,
7095
+ stopOrdinal: walkIdx >= 0 ? walkIdx + 1 : 1,
7096
+ totalStops: traceWalk.stops.length,
7097
+ onExit: handleExitTracing,
7098
+ onShowAll: activeViaKey ? handleShowAllIngredients : void 0
7099
+ };
7100
+ }, [tracing, traceWalk, traceStopIndices, activeSnapshots, safeIdx, activeViaKey, handleExitTracing, handleShowAllIngredients]);
7101
+ const traceTabContent = (0, import_react32.useMemo)(() => tracing && traceWalk ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7102
+ TraceWalkCard,
7103
+ {
7104
+ walk: traceWalk,
7105
+ cursorRuntimeStageId: activeSnapshots[safeIdx]?.runtimeStageId ?? null,
7106
+ viaKey: activeViaKey,
7107
+ stepNumberOf,
7108
+ previewValueOf: (k) => activeSnapshots[safeIdx]?.memory?.[k],
7109
+ onFollowIngredient: handleFollowIngredient,
7110
+ onJumpToStop: navigateToStage,
7111
+ onShowAll: activeViaKey ? handleShowAllIngredients : void 0,
7112
+ onExit: handleExitTracing
7113
+ }
7114
+ ) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7115
+ !isInSubflow && (shellDataTrace.frames[0]?.keysWritten?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { "data-fp": "trace-entry", style: { padding: "10px 14px 0", fontSize: 12 }, children: [
7116
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { color: theme.textMuted, marginRight: 6 }, children: "Trace a value:" }),
7117
+ shellDataTrace.frames[0].keysWritten.map((k) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7118
+ "button",
7119
+ {
7120
+ "data-fp": "trace-entry-chip",
7121
+ onClick: () => handleStartTracing(k),
7122
+ title: "Where did " + k + " come from? Walk its causes on the timeline.",
7123
+ style: {
7124
+ border: "1px solid var(--fp-accent, #6366f1)",
7125
+ background: "transparent",
7126
+ color: "var(--fp-accent, #6366f1)",
7127
+ borderRadius: 12,
7128
+ padding: "2px 10px",
7129
+ margin: "0 6px 6px 0",
7130
+ fontSize: 11,
7131
+ fontWeight: 600,
7132
+ fontFamily: "monospace",
7133
+ cursor: "pointer"
7134
+ },
7135
+ children: k
7136
+ },
7137
+ k
7138
+ ))
7139
+ ] }),
7140
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7141
+ DataTracePanel,
7142
+ {
7143
+ frames: shellDataTrace.frames,
7144
+ note: shellDataTrace.readsAvailable ? void 0 : "\u26A0 reads were not recorded (readTracking off) \u2014 dependencies are unknowable, not absent.",
7145
+ selectedStageId: activeSnapshots[safeIdx]?.runtimeStageId,
7146
+ onFrameClick: navigateToStage,
7147
+ fromStageName: activeSnapshots[safeIdx]?.stageName
7148
+ }
7149
+ )
7150
+ ] }), [tracing, traceWalk, activeSnapshots, safeIdx, activeViaKey, stepNumberOf, handleFollowIngredient, navigateToStage, handleShowAllIngredients, handleExitTracing, handleStartTracing, isInSubflow, shellDataTrace]);
6449
7151
  const tabLabels = new Map(allTabs.map((t) => [t.id, t.name]));
6450
7152
  if (unstyled) {
6451
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className, style, "data-fp": "explainable-shell", children: [
6452
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { "data-fp": "shell-tabs", children: allTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { "data-fp": "shell-tab", "data-active": tab.id === activeTab, onClick: () => handleTabChange(tab.id), children: tab.name }, tab.id)) }),
6453
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
6454
- activeTab === "result" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
6455
- (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6456
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
6457
- isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
7153
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className, style, "data-fp": "explainable-shell", children: [
7154
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { "data-fp": "shell-tabs", children: allTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { "data-fp": "shell-tab", "data-active": tab.id === activeTab, onClick: () => handleTabChange(tab.id), children: tab.name }, tab.id)) }),
7155
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
7156
+ activeTab === "result" && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
7157
+ (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7158
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true, tracing: tracingRail }),
7159
+ isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
6458
7160
  traceGraph && effectiveRenderFlowchart?.({ spec: null, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId, ...sliceCone && { sliceCone } }),
6459
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
6460
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, unstyled: true }),
6461
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
7161
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
7162
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, unstyled: true }),
7163
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
6462
7164
  ] })
6463
7165
  ] })
6464
7166
  ] });
6465
7167
  }
6466
7168
  const showTopology = !!effectiveRenderFlowchart && !!traceGraph;
6467
- const detailsContent = (0, import_react31.useMemo)(() => {
7169
+ const detailsContent = (0, import_react32.useMemo)(() => {
6468
7170
  if (activeTab === "result") {
6469
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
7171
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
6470
7172
  }
6471
7173
  if (activeTab === "memory") {
6472
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, size, style: { height: "100%" } });
7174
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, size, style: { height: "100%" } });
6473
7175
  }
6474
7176
  if (activeTab === "narrative") {
6475
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, size, style: { height: "100%" } });
7177
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, size, style: { height: "100%" } });
6476
7178
  }
6477
7179
  const customView = recorderViews?.find((v2) => v2.id === activeTab);
6478
7180
  if (customView?.render) {
@@ -6480,7 +7182,7 @@ function ExplainableShell({
6480
7182
  }
6481
7183
  const autoView = autoRecorderViews.find((v2) => v2.id === activeTab);
6482
7184
  if (autoView) {
6483
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7185
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6484
7186
  KeyedRecorderView,
6485
7187
  {
6486
7188
  data: autoView.data,
@@ -6493,8 +7195,8 @@ function ExplainableShell({
6493
7195
  }
6494
7196
  return null;
6495
7197
  }, [activeTab, resultData, logs, hideConsole, size, activeSnapshots, safeIdx, activeNarrativeEntries, recorderViews, autoRecorderViews]);
6496
- const detailsPanel = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
6497
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: {
7198
+ const detailsPanel = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
7199
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: {
6498
7200
  display: "flex",
6499
7201
  borderBottom: `1px solid ${theme.border}`,
6500
7202
  background: theme.bgSecondary,
@@ -6502,7 +7204,7 @@ function ExplainableShell({
6502
7204
  overflowX: "auto"
6503
7205
  }, children: allTabs.map((tab) => {
6504
7206
  const active = tab.id === activeTab;
6505
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7207
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6506
7208
  "button",
6507
7209
  {
6508
7210
  onClick: () => handleTabChange(tab.id),
@@ -6526,9 +7228,9 @@ function ExplainableShell({
6526
7228
  tab.id
6527
7229
  );
6528
7230
  }) }),
6529
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: detailsContent })
7231
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: detailsContent })
6530
7232
  ] });
6531
- const shellThemeVars = (0, import_react31.useMemo)(() => {
7233
+ const shellThemeVars = (0, import_react32.useMemo)(() => {
6532
7234
  if (!traceTheme) return {};
6533
7235
  const base = traceTheme.mode ? tokensToCSSVars(traceTheme.mode === "light" ? coolLight : coolDark) : {};
6534
7236
  return {
@@ -6537,7 +7239,7 @@ function ExplainableShell({
6537
7239
  ...traceTheme.current !== void 0 && { ["--fp-node-cursor"]: traceTheme.current }
6538
7240
  };
6539
7241
  }, [traceTheme]);
6540
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
7242
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6541
7243
  "div",
6542
7244
  {
6543
7245
  ref: shellRef,
@@ -6556,20 +7258,21 @@ function ExplainableShell({
6556
7258
  },
6557
7259
  "data-fp": "explainable-shell",
6558
7260
  children: [
6559
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7261
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6560
7262
  TimeTravelControls,
6561
7263
  {
6562
7264
  snapshots: activeSnapshots,
6563
7265
  selectedIndex: safeIdx,
6564
7266
  onIndexChange: handleSnapshotChange,
6565
- size
7267
+ size,
7268
+ tracing: tracingRail
6566
7269
  }
6567
7270
  ),
6568
- isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
6569
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: isNarrow ? (
7271
+ isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
7272
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: isNarrow ? (
6570
7273
  /* ── Mobile: stacked vertical ── */
6571
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6572
- showTopology && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
7274
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7275
+ showTopology && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
6573
7276
  spec: null,
6574
7277
  snapshots: activeSnapshots,
6575
7278
  selectedIndex: safeIdx,
@@ -6577,9 +7280,9 @@ function ExplainableShell({
6577
7280
  showStageId,
6578
7281
  ...sliceCone && { sliceCone }
6579
7282
  }) }),
6580
- showTreeSidebar && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6581
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
6582
- leftExpanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { maxHeight: 180, overflow: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7283
+ showTreeSidebar && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7284
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
7285
+ leftExpanded && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { maxHeight: 180, overflow: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6583
7286
  SubflowTree,
6584
7287
  {
6585
7288
  graph: traceGraph ?? { nodes: [], edges: [] },
@@ -6589,17 +7292,17 @@ function ExplainableShell({
6589
7292
  }
6590
7293
  ) })
6591
7294
  ] }),
6592
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
6593
- rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { maxHeight: 350, flexShrink: 0, overflow: "hidden" }, children: detailsPanel }),
6594
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
6595
- timelineExpanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
7295
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
7296
+ rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { maxHeight: 350, flexShrink: 0, overflow: "hidden" }, children: detailsPanel }),
7297
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
7298
+ timelineExpanded && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
6596
7299
  ] })
6597
7300
  ) : (
6598
7301
  /* ── Desktop: two-column — Flowchart | Right Panel ── */
6599
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6600
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
6601
- showTreeSidebar && (leftExpanded ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { width: 180, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
6602
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7302
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7303
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
7304
+ showTreeSidebar && (leftExpanded ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { width: 180, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
7305
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6603
7306
  SubflowTree,
6604
7307
  {
6605
7308
  graph: traceGraph ?? { nodes: [], edges: [] },
@@ -6608,24 +7311,26 @@ function ExplainableShell({
6608
7311
  onNodeSelect: handleTreeNodeSelect
6609
7312
  }
6610
7313
  ) }),
6611
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VLinePill, { label: "Topology", expanded: true, side: "left", onClick: () => toggleLeft(false) })
6612
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VLinePill, { label: "Topology", expanded: false, side: "left", onClick: () => toggleLeft(true) })),
6613
- showTopology ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "hidden", minWidth: 0 }, children: effectiveRenderFlowchart({
7314
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VLinePill, { label: "Topology", expanded: true, side: "left", onClick: () => toggleLeft(false) })
7315
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VLinePill, { label: "Topology", expanded: false, side: "left", onClick: () => toggleLeft(true) })),
7316
+ showTopology ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "hidden", minWidth: 0 }, children: effectiveRenderFlowchart({
6614
7317
  spec: null,
6615
7318
  snapshots: activeSnapshots,
6616
7319
  selectedIndex: safeIdx,
6617
7320
  onNodeClick: handleNodeClick,
6618
7321
  showStageId,
6619
7322
  ...sliceCone && { sliceCone }
6620
- }) }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1 } }),
6621
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VLinePill, { label: "Details", expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
6622
- rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { width: "42%", minWidth: 320, maxWidth: 550, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7323
+ }) }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1 } }),
7324
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VLinePill, { label: "Details", expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
7325
+ rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { width: "42%", minWidth: 320, maxWidth: 550, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6623
7326
  RightPanel,
6624
7327
  {
6625
7328
  mode: rightPanelMode,
6626
7329
  onModeChange: setRightPanelMode,
6627
7330
  dataTrace: shellDataTrace,
6628
7331
  onInspectorTabChange: setInspectorTab,
7332
+ inspectorTab,
7333
+ traceContent: traceTabContent,
6629
7334
  snapshots: activeSnapshots,
6630
7335
  selectedIndex: safeIdx,
6631
7336
  runtimeSnapshot,
@@ -6635,14 +7340,11 @@ function ExplainableShell({
6635
7340
  recorderViews,
6636
7341
  autoRecorderViews,
6637
7342
  size,
6638
- onNavigateToStage: (id) => {
6639
- const idx = activeSnapshots.findIndex((s) => s.runtimeStageId === id);
6640
- if (idx >= 0) setSnapshotIdx(idx);
6641
- }
7343
+ onNavigateToStage: navigateToStage
6642
7344
  }
6643
7345
  ) })
6644
7346
  ] }),
6645
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7347
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6646
7348
  CompactTimeline,
6647
7349
  {
6648
7350
  snapshots: activeSnapshots,
@@ -6659,8 +7361,8 @@ function ExplainableShell({
6659
7361
 
6660
7362
  // src/components/TraceViewer/TraceViewer.tsx
6661
7363
  var React = __toESM(require("react"), 1);
6662
- var import_react32 = require("react");
6663
- var import_jsx_runtime27 = require("react/jsx-runtime");
7364
+ var import_react33 = require("react");
7365
+ var import_jsx_runtime28 = require("react/jsx-runtime");
6664
7366
  function parseTrace(input) {
6665
7367
  if (input == null) {
6666
7368
  return {
@@ -6723,11 +7425,11 @@ function TraceViewer({
6723
7425
  recorderViews,
6724
7426
  renderFlowchart
6725
7427
  }) {
6726
- const parsed = (0, import_react32.useMemo)(() => parseTrace(trace), [trace]);
7428
+ const parsed = (0, import_react33.useMemo)(() => parseTrace(trace), [trace]);
6727
7429
  React.useEffect(() => {
6728
7430
  if (!parsed.ok && onError) onError(parsed.error);
6729
7431
  }, [parsed, onError]);
6730
- const snapshots = (0, import_react32.useMemo)(() => {
7432
+ const snapshots = (0, import_react33.useMemo)(() => {
6731
7433
  if (!parsed.ok || !parsed.trace.snapshot) return [];
6732
7434
  try {
6733
7435
  return toVisualizationSnapshots(
@@ -6741,7 +7443,7 @@ function TraceViewer({
6741
7443
  if (!parsed.ok || snapshots.length === 0) {
6742
7444
  return fallback ?? null;
6743
7445
  }
6744
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7446
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6745
7447
  ExplainableShell,
6746
7448
  {
6747
7449
  snapshots,
@@ -6778,13 +7480,16 @@ function TraceViewer({
6778
7480
  SubflowTree,
6779
7481
  TimeTravelControls,
6780
7482
  TraceViewer,
7483
+ TraceWalkCard,
6781
7484
  buildEntryRangeIndex,
7485
+ buildTraceWalk,
6782
7486
  computeRevealedEntryCount,
6783
7487
  coolDark,
6784
7488
  coolLight,
6785
7489
  createSnapshots,
6786
7490
  defaultTokens,
6787
7491
  extractSubflowNarrative,
7492
+ formatTraceWalk,
6788
7493
  mergeWritePatch,
6789
7494
  rawDefaults,
6790
7495
  subflowResultToSnapshots,