footprint-explainable-ui 0.27.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,
@@ -3398,15 +4106,15 @@ var SubflowTree = (0, import_react13.memo)(function SubflowTree2({
3398
4106
  );
3399
4107
  });
3400
4108
 
3401
- // 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({
4109
+ // src/components/FlowchartView/SubflowBreadcrumb.tsx
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" };
@@ -5092,33 +5800,34 @@ function TracedFlow({
5092
5800
  nodeTypes: userNodeTypes,
5093
5801
  edgeTypes: userEdgeTypes,
5094
5802
  coActiveStageIds,
5803
+ sliceCone,
5095
5804
  children,
5096
5805
  className,
5097
5806
  style
5098
5807
  }) {
5099
5808
  const layout = layoutProp ?? dagreTraceLayout;
5100
- (0, import_react25.useEffect)(() => {
5809
+ (0, import_react27.useEffect)(() => {
5101
5810
  if (layoutProp === dagreTraceLayout) {
5102
5811
  devWarn(
5103
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."
5104
5813
  );
5105
5814
  }
5106
5815
  }, [layoutProp]);
5107
- const colors = (0, import_react25.useMemo)(
5816
+ const colors = (0, import_react27.useMemo)(
5108
5817
  () => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
5109
5818
  [colorOverrides]
5110
5819
  );
5111
- const mergedNodeTypes = (0, import_react25.useMemo)(
5820
+ const mergedNodeTypes = (0, import_react27.useMemo)(
5112
5821
  () => userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES,
5113
5822
  [userNodeTypes]
5114
5823
  );
5115
- const mergedEdgeTypes = (0, import_react25.useMemo)(
5824
+ const mergedEdgeTypes = (0, import_react27.useMemo)(
5116
5825
  () => userEdgeTypes ? { ...DEFAULT_EDGE_TYPES, ...userEdgeTypes } : DEFAULT_EDGE_TYPES,
5117
5826
  [userEdgeTypes]
5118
5827
  );
5119
5828
  const drill = useSubflowDrill(graph, onSubflowChange);
5120
- const groupedSet = (0, import_react25.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
5121
- const filteredGraph = (0, import_react25.useMemo)(() => {
5829
+ const groupedSet = (0, import_react27.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
5830
+ const filteredGraph = (0, import_react27.useMemo)(() => {
5122
5831
  const base = filterGraphForDrill(graph, drill.currentSubflowId);
5123
5832
  if (groupedSet.size === 0) return base;
5124
5833
  const baseIds = new Set(base.nodes.map((n) => n.id));
@@ -5133,12 +5842,12 @@ function TracedFlow({
5133
5842
  );
5134
5843
  return { nodes: [...base.nodes, ...extraNodes], edges: [...base.edges, ...extraEdges] };
5135
5844
  }, [graph, drill.currentSubflowId, groupedSet]);
5136
- const breadcrumb = (0, import_react25.useMemo)(
5845
+ const breadcrumb = (0, import_react27.useMemo)(
5137
5846
  () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),
5138
5847
  [graph, drill.currentSubflowId]
5139
5848
  );
5140
- const [measuredSizes, setMeasuredSizes] = (0, import_react25.useState)(null);
5141
- const positioned = (0, import_react25.useMemo)(() => {
5849
+ const [measuredSizes, setMeasuredSizes] = (0, import_react27.useState)(null);
5850
+ const positioned = (0, import_react27.useMemo)(() => {
5142
5851
  const nodeSize = measuredSizes ? (n) => measuredSizes.get(n.id) : void 0;
5143
5852
  const sizeOpts = nodeSize ? { nodeSize } : {};
5144
5853
  const dagreBase = withForkCentering(
@@ -5162,7 +5871,7 @@ function TracedFlow({
5162
5871
  }
5163
5872
  return realBase(filteredGraph);
5164
5873
  }, [filteredGraph, layout, layoutProp, groupedSet, mainChartBox, measuredSizes]);
5165
- const slice = (0, import_react25.useMemo)(() => {
5874
+ const slice = (0, import_react27.useMemo)(() => {
5166
5875
  const empty = {
5167
5876
  doneStageIds: /* @__PURE__ */ new Set(),
5168
5877
  activeStageId: null,
@@ -5174,7 +5883,7 @@ function TracedFlow({
5174
5883
  const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);
5175
5884
  return aggregateMountStatus(sliceOverlay(overlay, idx), graph, drill.currentSubflowId);
5176
5885
  }, [overlay, scrubIndex, graph, drill.currentSubflowId]);
5177
- const reactFlowNodes = (0, import_react25.useMemo)(
5886
+ const reactFlowNodes = (0, import_react27.useMemo)(
5178
5887
  () => positioned.nodes.map(
5179
5888
  (n) => toStageNodeWithOverlay(
5180
5889
  n,
@@ -5187,13 +5896,45 @@ function TracedFlow({
5187
5896
  ),
5188
5897
  [positioned.nodes, slice, coActiveStageIds]
5189
5898
  );
5190
- const reactFlowEdges = (0, import_react25.useMemo)(
5899
+ const reactFlowEdges = (0, import_react27.useMemo)(
5191
5900
  () => positioned.edges.map(
5192
5901
  (e) => styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors)
5193
5902
  ),
5194
5903
  [positioned.edges, slice, colors]
5195
5904
  );
5196
- const handleNodeClick = (0, import_react25.useCallback)(
5905
+ const [coneRevealed, setConeRevealed] = (0, import_react27.useState)(false);
5906
+ (0, import_react27.useEffect)(() => {
5907
+ if (!sliceCone) return;
5908
+ setConeRevealed(false);
5909
+ const raf = requestAnimationFrame(() => setConeRevealed(true));
5910
+ return () => cancelAnimationFrame(raf);
5911
+ }, [sliceCone]);
5912
+ const conedNodes = (0, import_react27.useMemo)(() => {
5913
+ if (!sliceCone || sliceCone.size === 0) return reactFlowNodes;
5914
+ return reactFlowNodes.map((n) => {
5915
+ const depth = sliceCone.get(n.id);
5916
+ if (depth === void 0) {
5917
+ return { ...n, style: { ...n.style, opacity: 0.22, transition: "opacity 260ms ease" } };
5918
+ }
5919
+ return {
5920
+ ...n,
5921
+ style: {
5922
+ ...n.style,
5923
+ opacity: coneRevealed ? 1 : 0.22,
5924
+ transition: "opacity 320ms ease",
5925
+ transitionDelay: `${depth * 90}ms`
5926
+ }
5927
+ };
5928
+ });
5929
+ }, [reactFlowNodes, sliceCone, coneRevealed]);
5930
+ const conedEdges = (0, import_react27.useMemo)(() => {
5931
+ if (!sliceCone || sliceCone.size === 0) return reactFlowEdges;
5932
+ return reactFlowEdges.map((e) => {
5933
+ const inCone = sliceCone.has(e.source) && sliceCone.has(e.target);
5934
+ return inCone ? e : { ...e, style: { ...e.style, opacity: 0.12, transition: "opacity 260ms ease" } };
5935
+ });
5936
+ }, [reactFlowEdges, sliceCone]);
5937
+ const handleNodeClick = (0, import_react27.useCallback)(
5197
5938
  (_, node) => {
5198
5939
  const data = node.data ?? {};
5199
5940
  if (data.isSubflow && data.subflowId && !groupedSet.has(data.subflowId)) {
@@ -5203,14 +5944,14 @@ function TracedFlow({
5203
5944
  },
5204
5945
  [drill, onNodeClick, groupedSet]
5205
5946
  );
5206
- const wrapperRef = (0, import_react25.useRef)(null);
5207
- 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);
5208
5949
  useChartAutoRefit(wrapperRef, rfInstance, {
5209
5950
  // Re-fit on drill AND after the measured-size re-layout settles.
5210
5951
  refitKey: `${drill.currentSubflowId ?? ""}:${measuredSizes ? "measured" : "estimated"}`,
5211
5952
  padding: 0.18
5212
5953
  });
5213
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
5954
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5214
5955
  "div",
5215
5956
  {
5216
5957
  ref: wrapperRef,
@@ -5224,18 +5965,18 @@ function TracedFlow({
5224
5965
  ...style
5225
5966
  },
5226
5967
  children: [
5227
- breadcrumb.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5968
+ breadcrumb.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5228
5969
  SubflowBreadcrumbBar,
5229
5970
  {
5230
5971
  entries: breadcrumb,
5231
5972
  onNavigate: drill.setCurrentSubflowId
5232
5973
  }
5233
5974
  ),
5234
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
5235
- 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,
5236
5977
  {
5237
- nodes: reactFlowNodes,
5238
- edges: reactFlowEdges,
5978
+ nodes: conedNodes,
5979
+ edges: conedEdges,
5239
5980
  nodeTypes: mergedNodeTypes,
5240
5981
  edgeTypes: mergedEdgeTypes,
5241
5982
  onNodeClick: handleNodeClick,
@@ -5245,8 +5986,8 @@ function TracedFlow({
5245
5986
  minZoom: 0.1,
5246
5987
  proOptions: { hideAttribution: true },
5247
5988
  children: [
5248
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MeasuredNodeSizes, { onSizes: setMeasuredSizes }),
5249
- /* @__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 }),
5250
5991
  children
5251
5992
  ]
5252
5993
  }
@@ -5257,182 +5998,27 @@ function TracedFlow({
5257
5998
  }
5258
5999
 
5259
6000
  // src/components/InspectorPanel/InspectorPanel.tsx
5260
- var import_react28 = require("react");
5261
-
5262
- // src/components/DataTracePanel/DataTracePanel.tsx
5263
- var import_react27 = require("react");
5264
- var import_jsx_runtime22 = require("react/jsx-runtime");
5265
- var DataTracePanel = (0, import_react27.memo)(function DataTracePanel2({
5266
- frames,
5267
- selectedStageId,
5268
- onFrameClick,
5269
- fromStageName,
5270
- note
5271
- }) {
5272
- const noteLine = note ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", marginBottom: 8 }, children: note }) : null;
5273
- if (frames.length === 0) {
5274
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
5275
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5276
- "div",
5277
- {
5278
- style: {
5279
- fontSize: 11,
5280
- color: theme.textMuted,
5281
- textTransform: "uppercase",
5282
- letterSpacing: "0.5px",
5283
- fontWeight: 600,
5284
- marginBottom: 6
5285
- },
5286
- children: "Backward causal chain"
5287
- }
5288
- ),
5289
- /* @__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." }),
5290
- noteLine,
5291
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: theme.textMuted, fontSize: 12 }, children: "Select a stage above to see its dependency chain." })
5292
- ] });
5293
- }
5294
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "8px 0", fontSize: 13 }, children: [
5295
- note && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { padding: "4px 12px 0", fontSize: 11, color: theme.textMuted, fontStyle: "italic" }, children: note }),
5296
- fromStageName && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "4px 12px 8px" }, children: [
5297
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5298
- "div",
5299
- {
5300
- style: {
5301
- fontSize: 11,
5302
- color: theme.textMuted,
5303
- textTransform: "uppercase",
5304
- letterSpacing: "0.5px",
5305
- fontWeight: 600
5306
- },
5307
- children: [
5308
- "Data trace from ",
5309
- fromStageName
5310
- ]
5311
- }
5312
- ),
5313
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5314
- "div",
5315
- {
5316
- style: {
5317
- fontSize: 11,
5318
- color: theme.textMuted,
5319
- fontStyle: "italic",
5320
- marginTop: 3
5321
- },
5322
- children: "Every value here was derived from the stages below."
5323
- }
5324
- )
5325
- ] }),
5326
- frames.map((frame, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5327
- DataTraceFrame,
5328
- {
5329
- frame,
5330
- isFirst: i === 0,
5331
- isLast: i === frames.length - 1,
5332
- isSelected: frame.runtimeStageId === selectedStageId,
5333
- onClick: onFrameClick
5334
- },
5335
- frame.runtimeStageId
5336
- ))
5337
- ] });
5338
- });
5339
- var DataTraceFrame = (0, import_react27.memo)(function DataTraceFrame2({
5340
- frame,
5341
- isFirst,
5342
- isLast,
5343
- isSelected,
5344
- onClick
5345
- }) {
5346
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5347
- "button",
5348
- {
5349
- onClick: () => onClick?.(frame.runtimeStageId),
5350
- style: {
5351
- display: "block",
5352
- width: "100%",
5353
- textAlign: "left",
5354
- border: "none",
5355
- background: isSelected ? "var(--fp-accent-bg, rgba(99,102,241,0.12))" : "transparent",
5356
- padding: "6px 12px 6px 16px",
5357
- cursor: onClick ? "pointer" : "default",
5358
- borderLeft: isSelected ? "3px solid var(--fp-accent, #6366f1)" : "3px solid transparent",
5359
- color: "inherit",
5360
- fontSize: 13
5361
- },
5362
- children: [
5363
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
5364
- !isFirst && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { color: theme.textMuted, fontSize: 11 }, children: "\u2191" }),
5365
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5366
- "span",
5367
- {
5368
- style: {
5369
- fontWeight: isFirst ? 600 : 400,
5370
- color: isFirst ? "var(--fp-accent, #6366f1)" : theme.textPrimary
5371
- },
5372
- children: frame.stageName
5373
- }
5374
- ),
5375
- isLast && !isFirst && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5376
- "span",
5377
- {
5378
- style: {
5379
- fontSize: 10,
5380
- color: theme.textMuted,
5381
- fontStyle: "italic"
5382
- },
5383
- children: "(origin)"
5384
- }
5385
- )
5386
- ] }),
5387
- frame.keysWritten.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5388
- "div",
5389
- {
5390
- style: {
5391
- fontSize: 11,
5392
- color: theme.textMuted,
5393
- paddingLeft: isFirst ? 0 : 18,
5394
- marginTop: 2
5395
- },
5396
- children: [
5397
- "wrote:",
5398
- " ",
5399
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { color: theme.textSecondary }, children: frame.keysWritten.join(", ") })
5400
- ]
5401
- }
5402
- ),
5403
- frame.linkedBy && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5404
- "div",
5405
- {
5406
- style: {
5407
- fontSize: 11,
5408
- color: "var(--fp-accent, #6366f1)",
5409
- paddingLeft: 18,
5410
- marginTop: 1
5411
- },
5412
- children: [
5413
- "\u2190 via ",
5414
- frame.linkedBy
5415
- ]
5416
- }
5417
- )
5418
- ]
5419
- }
5420
- );
5421
- });
5422
-
5423
- // src/components/InspectorPanel/InspectorPanel.tsx
5424
- var import_jsx_runtime23 = require("react/jsx-runtime");
5425
- 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({
5426
6004
  snapshots,
5427
6005
  selectedIndex,
5428
6006
  dataTraceFrames,
5429
6007
  dataTraceNote,
5430
6008
  selectedStageId,
5431
- onNavigateToStage
6009
+ onNavigateToStage,
6010
+ onTabChange,
6011
+ tab: controlledTab,
6012
+ traceContent
5432
6013
  }) {
5433
- const [tab, setTab] = (0, import_react28.useState)("state");
6014
+ const [internalTab, setTabState] = (0, import_react29.useState)("state");
6015
+ const tab = controlledTab ?? internalTab;
6016
+ const setTab = (t) => {
6017
+ setTabState(t);
6018
+ onTabChange?.(t);
6019
+ };
5434
6020
  const currentSnapshot = snapshots[selectedIndex];
5435
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6021
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5436
6022
  "div",
5437
6023
  {
5438
6024
  style: {
@@ -5442,7 +6028,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5442
6028
  overflow: "hidden"
5443
6029
  },
5444
6030
  children: [
5445
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6031
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5446
6032
  "div",
5447
6033
  {
5448
6034
  style: {
@@ -5451,7 +6037,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5451
6037
  flexShrink: 0
5452
6038
  },
5453
6039
  children: [
5454
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6040
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5455
6041
  TabButton,
5456
6042
  {
5457
6043
  active: tab === "state",
@@ -5459,7 +6045,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5459
6045
  label: "State"
5460
6046
  }
5461
6047
  ),
5462
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6048
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5463
6049
  TabButton,
5464
6050
  {
5465
6051
  active: tab === "trace",
@@ -5471,15 +6057,15 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5471
6057
  ]
5472
6058
  }
5473
6059
  ),
5474
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
5475
- 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)(
5476
6062
  MemoryPanel,
5477
6063
  {
5478
6064
  snapshots,
5479
6065
  selectedIndex
5480
6066
  }
5481
6067
  ),
5482
- tab === "trace" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6068
+ tab === "trace" && (traceContent ?? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5483
6069
  DataTracePanel,
5484
6070
  {
5485
6071
  frames: dataTraceFrames,
@@ -5488,7 +6074,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5488
6074
  onFrameClick: onNavigateToStage,
5489
6075
  fromStageName: currentSnapshot?.stageName
5490
6076
  }
5491
- )
6077
+ ))
5492
6078
  ] })
5493
6079
  ]
5494
6080
  }
@@ -5500,7 +6086,7 @@ function TabButton({
5500
6086
  label,
5501
6087
  badge
5502
6088
  }) {
5503
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6089
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5504
6090
  "button",
5505
6091
  {
5506
6092
  onClick,
@@ -5519,7 +6105,7 @@ function TabButton({
5519
6105
  },
5520
6106
  children: [
5521
6107
  label,
5522
- badge && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6108
+ badge && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5523
6109
  "span",
5524
6110
  {
5525
6111
  style: {
@@ -5539,28 +6125,28 @@ function TabButton({
5539
6125
  }
5540
6126
 
5541
6127
  // src/components/InsightPanel/InsightPanel.tsx
5542
- var import_react29 = require("react");
5543
- var import_jsx_runtime24 = require("react/jsx-runtime");
5544
- 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({
5545
6131
  insights,
5546
6132
  expandedId,
5547
6133
  mode
5548
6134
  }) {
5549
6135
  if (insights.length === 0) {
5550
- 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." });
5551
6137
  }
5552
6138
  if (mode === "grid") {
5553
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(InsightGrid, { insights });
6139
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InsightGrid, { insights });
5554
6140
  }
5555
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(InsightTabs, { insights, defaultId: expandedId });
6141
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InsightTabs, { insights, defaultId: expandedId });
5556
6142
  });
5557
- var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
6143
+ var InsightTabs = (0, import_react30.memo)(function InsightTabs2({
5558
6144
  insights,
5559
6145
  defaultId
5560
6146
  }) {
5561
- const [activeId, setActiveId] = (0, import_react29.useState)(defaultId ?? insights[0]?.id);
6147
+ const [activeId, setActiveId] = (0, import_react30.useState)(defaultId ?? insights[0]?.id);
5562
6148
  const active = insights.find((i) => i.id === activeId) ?? insights[0];
5563
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6149
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5564
6150
  "div",
5565
6151
  {
5566
6152
  style: {
@@ -5570,7 +6156,7 @@ var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
5570
6156
  overflow: "hidden"
5571
6157
  },
5572
6158
  children: [
5573
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6159
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5574
6160
  "div",
5575
6161
  {
5576
6162
  style: {
@@ -5579,7 +6165,7 @@ var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
5579
6165
  flexShrink: 0,
5580
6166
  overflowX: "auto"
5581
6167
  },
5582
- children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6168
+ children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5583
6169
  "button",
5584
6170
  {
5585
6171
  onClick: () => setActiveId(insight.id),
@@ -5600,16 +6186,16 @@ var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
5600
6186
  ))
5601
6187
  }
5602
6188
  ),
5603
- /* @__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() })
5604
6190
  ]
5605
6191
  }
5606
6192
  );
5607
6193
  });
5608
- var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
6194
+ var InsightGrid = (0, import_react30.memo)(function InsightGrid2({
5609
6195
  insights
5610
6196
  }) {
5611
6197
  const cols = insights.length <= 2 ? 1 : 2;
5612
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6198
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5613
6199
  "div",
5614
6200
  {
5615
6201
  style: {
@@ -5620,7 +6206,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5620
6206
  gap: 1,
5621
6207
  background: theme.border
5622
6208
  },
5623
- children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6209
+ children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5624
6210
  "div",
5625
6211
  {
5626
6212
  style: {
@@ -5630,7 +6216,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5630
6216
  overflow: "hidden"
5631
6217
  },
5632
6218
  children: [
5633
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6219
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5634
6220
  "div",
5635
6221
  {
5636
6222
  style: {
@@ -5645,7 +6231,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5645
6231
  },
5646
6232
  children: [
5647
6233
  insight.name,
5648
- insight.summary && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6234
+ insight.summary && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5649
6235
  "span",
5650
6236
  {
5651
6237
  style: {
@@ -5660,7 +6246,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5660
6246
  ]
5661
6247
  }
5662
6248
  ),
5663
- /* @__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() })
5664
6250
  ]
5665
6251
  },
5666
6252
  insight.id
@@ -5670,17 +6256,17 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5670
6256
  });
5671
6257
 
5672
6258
  // src/components/CompactTimeline/CompactTimeline.tsx
5673
- var import_react30 = require("react");
5674
- var import_jsx_runtime25 = require("react/jsx-runtime");
5675
- 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({
5676
6262
  snapshots,
5677
6263
  selectedIndex,
5678
6264
  defaultExpanded = false
5679
6265
  }) {
5680
- const [expanded, setExpanded] = (0, import_react30.useState)(defaultExpanded);
6266
+ const [expanded, setExpanded] = (0, import_react31.useState)(defaultExpanded);
5681
6267
  if (snapshots.length === 0) return null;
5682
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
5683
- /* @__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)(
5684
6270
  "button",
5685
6271
  {
5686
6272
  onClick: () => setExpanded((e) => !e),
@@ -5700,13 +6286,13 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5700
6286
  letterSpacing: "0.5px"
5701
6287
  },
5702
6288
  children: [
5703
- /* @__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" }),
5704
6290
  "Timeline",
5705
- /* @__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: [
5706
6292
  snapshots.length,
5707
6293
  " stages"
5708
6294
  ] }),
5709
- !expanded && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6295
+ !expanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5710
6296
  "div",
5711
6297
  {
5712
6298
  style: {
@@ -5717,7 +6303,7 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5717
6303
  marginLeft: 8
5718
6304
  },
5719
6305
  children: [
5720
- snapshots.map((snap, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6306
+ snapshots.map((snap, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5721
6307
  "div",
5722
6308
  {
5723
6309
  style: {
@@ -5732,7 +6318,7 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5732
6318
  },
5733
6319
  i
5734
6320
  )),
5735
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6321
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5736
6322
  "div",
5737
6323
  {
5738
6324
  style: {
@@ -5750,7 +6336,7 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5750
6336
  ]
5751
6337
  }
5752
6338
  ),
5753
- 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)(
5754
6340
  GanttTimeline,
5755
6341
  {
5756
6342
  snapshots,
@@ -5761,21 +6347,21 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5761
6347
  });
5762
6348
 
5763
6349
  // src/components/ExplainableShell/ExplainableShell.tsx
5764
- var import_jsx_runtime26 = require("react/jsx-runtime");
5765
- 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({
5766
6352
  label,
5767
6353
  detail,
5768
6354
  expanded,
5769
6355
  onClick
5770
6356
  }) {
5771
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: {
6357
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: {
5772
6358
  display: "flex",
5773
6359
  alignItems: "center",
5774
6360
  gap: 0,
5775
6361
  padding: "0"
5776
6362
  }, children: [
5777
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } }),
5778
- /* @__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)(
5779
6365
  "button",
5780
6366
  {
5781
6367
  onClick,
@@ -5799,31 +6385,31 @@ var HLinePill = (0, import_react31.memo)(function HLinePill2({
5799
6385
  transition: "color 0.15s ease"
5800
6386
  },
5801
6387
  children: [
5802
- /* @__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" }),
5803
6389
  label,
5804
- 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 })
5805
6391
  ]
5806
6392
  }
5807
6393
  ),
5808
- /* @__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 } })
5809
6395
  ] });
5810
6396
  });
5811
- var VLinePill = (0, import_react31.memo)(function VLinePill2({
6397
+ var VLinePill = (0, import_react32.memo)(function VLinePill2({
5812
6398
  label,
5813
6399
  expanded,
5814
6400
  side = "right",
5815
6401
  onClick
5816
6402
  }) {
5817
6403
  const arrow = side === "right" ? expanded ? "\u25B6" : "\u25C0" : expanded ? "\u25C0" : "\u25B6";
5818
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: {
6404
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: {
5819
6405
  display: "flex",
5820
6406
  flexDirection: "column",
5821
6407
  alignItems: "center",
5822
6408
  gap: 0,
5823
6409
  padding: "0"
5824
6410
  }, children: [
5825
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } }),
5826
- /* @__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)(
5827
6413
  "button",
5828
6414
  {
5829
6415
  onClick,
@@ -5848,12 +6434,12 @@ var VLinePill = (0, import_react31.memo)(function VLinePill2({
5848
6434
  transition: "color 0.15s ease"
5849
6435
  },
5850
6436
  children: [
5851
- /* @__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 }),
5852
6438
  label
5853
6439
  ]
5854
6440
  }
5855
6441
  ),
5856
- /* @__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 } })
5857
6443
  ] });
5858
6444
  });
5859
6445
  function detectKeyedSteps(data) {
@@ -5890,9 +6476,9 @@ function KeyedRecorderView({
5890
6476
  snapshots,
5891
6477
  selectedIndex
5892
6478
  }) {
5893
- const [showAggregate, setShowAggregate] = (0, import_react31.useState)(false);
5894
- const detected = (0, import_react31.useMemo)(() => detectKeyedSteps(data), [data]);
5895
- 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)(() => {
5896
6482
  const keys = /* @__PURE__ */ new Set();
5897
6483
  for (let i = 0; i <= selectedIndex && i < snapshots.length; i++) {
5898
6484
  const snap = snapshots[i];
@@ -5907,7 +6493,7 @@ function KeyedRecorderView({
5907
6493
  }, [snapshots, selectedIndex, detected?.keyType]);
5908
6494
  const isAtEnd = selectedIndex >= snapshots.length - 1;
5909
6495
  if (!detected) {
5910
- 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) });
5911
6497
  }
5912
6498
  const steps = detected.steps;
5913
6499
  const hints = extractRenderHints(data);
@@ -5921,13 +6507,13 @@ function KeyedRecorderView({
5921
6507
  }
5922
6508
  }
5923
6509
  const grandTotal = hints?.grandTotal ?? 0;
5924
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
5925
- 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 }),
5926
- /* @__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: [
5927
6513
  preferredOperation === "aggregate" ? (
5928
6514
  /* AGGREGATE: collect silently during scrub, button at end to reveal total */
5929
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
5930
- 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)(
5931
6517
  "button",
5932
6518
  {
5933
6519
  onClick: () => setShowAggregate(true),
@@ -5945,35 +6531,35 @@ function KeyedRecorderView({
5945
6531
  },
5946
6532
  children: "Aggregate \u2014 Show Grand Total"
5947
6533
  }
5948
- ) : /* @__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: [
5949
- /* @__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" }),
5950
- 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: [
5951
6537
  grandTotal < 1 ? grandTotal.toFixed(3) : grandTotal.toFixed(1),
5952
- /* @__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: [
5953
6539
  numFieldKey,
5954
6540
  " \xB7 ",
5955
6541
  allKeys.length,
5956
6542
  " steps"
5957
6543
  ] })
5958
6544
  ] })
5959
- ] }) }) : /* @__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: [
5960
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600 }, children: "Collecting data..." }),
5961
- /* @__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: [
5962
6548
  visibleEntries.length,
5963
6549
  " of ",
5964
6550
  allKeys.length,
5965
6551
  " steps collected. Scrub to end to aggregate."
5966
6552
  ] })
5967
6553
  ] }),
5968
- /* @__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" })
5969
6555
  ] })
5970
6556
  ) : preferredOperation === "accumulate" ? (
5971
6557
  /* ACCUMULATE: running total grows with slider — IS the total at end, no button */
5972
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
5973
- 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: [
5974
- /* @__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" }),
5975
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontWeight: 700, fontSize: 18, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
5976
- /* @__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: [
5977
6563
  numFieldKey,
5978
6564
  " \xB7 ",
5979
6565
  visibleEntries.length,
@@ -5982,27 +6568,27 @@ function KeyedRecorderView({
5982
6568
  " steps"
5983
6569
  ] })
5984
6570
  ] }),
5985
- /* @__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" })
5986
6572
  ] })
5987
6573
  ) : (
5988
6574
  /* TRANSLATE: per-step entries prominent, no totals */
5989
- /* @__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" })
5990
6576
  ),
5991
6577
  visibleEntries.map((key) => {
5992
6578
  const entry = steps[key];
5993
6579
  const label = entry.stageName ?? key;
5994
6580
  const numVal = numFieldKey ? entry[numFieldKey] : void 0;
5995
- 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: [
5996
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
5997
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
5998
- 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) })
5999
6585
  ] }, key);
6000
6586
  }),
6001
- 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..." })
6002
6588
  ] })
6003
6589
  ] });
6004
6590
  }
6005
- var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
6591
+ var DetailsContent = (0, import_react32.memo)(function DetailsContent2({
6006
6592
  snapshots,
6007
6593
  selectedIndex,
6008
6594
  narrativeEntries,
@@ -6014,27 +6600,27 @@ var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
6014
6600
  {
6015
6601
  id: "memory",
6016
6602
  name: "Memory",
6017
- 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 })
6018
6604
  },
6019
6605
  {
6020
6606
  id: "narrative",
6021
6607
  name: "Narrative",
6022
- 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 })
6023
6609
  }
6024
6610
  ];
6025
6611
  const allViews = [...builtInViews, ...extraViews ?? []];
6026
- const [activeViewId, setActiveViewId] = (0, import_react31.useState)(allViews[0]?.id ?? "memory");
6612
+ const [activeViewId, setActiveViewId] = (0, import_react32.useState)(allViews[0]?.id ?? "memory");
6027
6613
  const viewIds = allViews.map((v2) => v2.id).join(",");
6028
- (0, import_react31.useEffect)(() => {
6614
+ (0, import_react32.useEffect)(() => {
6029
6615
  if (!allViews.find((v2) => v2.id === activeViewId)) {
6030
6616
  setActiveViewId(allViews[0]?.id ?? "memory");
6031
6617
  }
6032
6618
  }, [viewIds]);
6033
6619
  const activeView = allViews.find((v2) => v2.id === activeViewId) ?? allViews[0];
6034
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
6035
- /* @__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) => {
6036
6622
  const active = view.id === activeViewId;
6037
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6623
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6038
6624
  "button",
6039
6625
  {
6040
6626
  onClick: () => setActiveViewId(view.id),
@@ -6058,7 +6644,7 @@ var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
6058
6644
  view.id
6059
6645
  );
6060
6646
  }) }),
6061
- /* @__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 }) })
6062
6648
  ] });
6063
6649
  });
6064
6650
  function resolveSubflowFromRuntime(parentSnapshots, subflowId, narrativeEntries) {
@@ -6075,7 +6661,7 @@ function resolveSubflowFromRuntime(parentSnapshots, subflowId, narrativeEntries)
6075
6661
  if (sfSnapshots.length === 0) return null;
6076
6662
  return { subflowId, label, spec: null, snapshots: sfSnapshots, narrative: sfNarrative };
6077
6663
  }
6078
- var RightPanel = (0, import_react31.memo)(function RightPanel2({
6664
+ var RightPanel = (0, import_react32.memo)(function RightPanel2({
6079
6665
  mode,
6080
6666
  onModeChange,
6081
6667
  snapshots,
@@ -6087,19 +6673,19 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6087
6673
  recorderViews,
6088
6674
  autoRecorderViews,
6089
6675
  size,
6090
- onNavigateToStage
6676
+ onNavigateToStage,
6677
+ dataTrace,
6678
+ onInspectorTabChange,
6679
+ inspectorTab,
6680
+ traceContent
6091
6681
  }) {
6092
- const dataTrace = (0, import_react31.useMemo)(
6093
- () => runtimeSnapshot?.commitLog ? buildDataTrace(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, snapshots[selectedIndex]?.runtimeStageId ?? "") : { frames: [], readsAvailable: true },
6094
- [runtimeSnapshot, snapshots, selectedIndex]
6095
- );
6096
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6097
- /* @__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: {
6098
6684
  display: "flex",
6099
6685
  borderBottom: `1px solid ${theme.border}`,
6100
6686
  flexShrink: 0,
6101
6687
  background: theme.bgSecondary
6102
- }, children: ["insights", "what"].map((m) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6688
+ }, children: ["insights", "what"].map((m) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6103
6689
  "button",
6104
6690
  {
6105
6691
  onClick: () => onModeChange(m),
@@ -6121,7 +6707,7 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6121
6707
  },
6122
6708
  m
6123
6709
  )) }),
6124
- /* @__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)(
6125
6711
  InsightPanel,
6126
6712
  {
6127
6713
  mode: "tabs",
@@ -6130,22 +6716,25 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6130
6716
  id: tab.id,
6131
6717
  name: insightName(tab.name),
6132
6718
  render: () => {
6133
- 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%" } });
6134
6720
  const customView = recorderViews?.find((v2) => v2.id === tab.id);
6135
6721
  if (customView?.render) return customView.render({ snapshots, selectedIndex });
6136
6722
  const autoView = autoRecorderViews.find((v2) => v2.id === tab.id);
6137
- 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 });
6138
6724
  return null;
6139
6725
  }
6140
6726
  }))
6141
6727
  }
6142
- ) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6728
+ ) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6143
6729
  InspectorPanel,
6144
6730
  {
6145
6731
  snapshots,
6146
6732
  selectedIndex,
6147
6733
  dataTraceFrames: dataTrace.frames,
6148
6734
  dataTraceNote: dataTrace.readsAvailable ? void 0 : "\u26A0 reads were not recorded (readTracking off) \u2014 dependencies are unknowable, not absent.",
6735
+ onTabChange: onInspectorTabChange,
6736
+ tab: inspectorTab,
6737
+ traceContent,
6149
6738
  selectedStageId: snapshots[selectedIndex]?.runtimeStageId,
6150
6739
  onNavigateToStage
6151
6740
  }
@@ -6186,7 +6775,7 @@ function ExplainableShell({
6186
6775
  className,
6187
6776
  style
6188
6777
  }) {
6189
- const derivedFromRuntime = (0, import_react31.useMemo)(() => {
6778
+ const derivedFromRuntime = (0, import_react32.useMemo)(() => {
6190
6779
  if (!runtimeSnapshot) return null;
6191
6780
  try {
6192
6781
  const snaps = toVisualizationSnapshots(runtimeSnapshot, narrativeEntries);
@@ -6197,9 +6786,9 @@ function ExplainableShell({
6197
6786
  }, [runtimeSnapshot, narrativeEntries]);
6198
6787
  const snapshots = snapshotsProp ?? derivedFromRuntime?.snapshots ?? [];
6199
6788
  const resultData = resultDataProp ?? derivedFromRuntime?.resultData ?? null;
6200
- const tracedFlowRenderer = (0, import_react31.useMemo)(() => {
6789
+ const tracedFlowRenderer = (0, import_react32.useMemo)(() => {
6201
6790
  if (!traceGraph) return void 0;
6202
- return ({ selectedIndex, snapshots: snapshots2, onNodeClick }) => {
6791
+ return ({ selectedIndex, snapshots: snapshots2, onNodeClick, sliceCone: sliceCone2 }) => {
6203
6792
  const activeRsid = snapshots2[selectedIndex]?.runtimeStageId;
6204
6793
  let overlayIdx = selectedIndex;
6205
6794
  if (activeRsid && runtimeOverlay) {
@@ -6218,11 +6807,12 @@ function ExplainableShell({
6218
6807
  ...traceTheme.current !== void 0 && { active: traceTheme.current },
6219
6808
  ...traceTheme.mode !== void 0 && { default: traceTheme.mode === "dark" ? "#94a3b8" : "#64748b" }
6220
6809
  };
6221
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6810
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6222
6811
  TracedFlow,
6223
6812
  {
6224
6813
  graph: traceGraph,
6225
6814
  overlay: runtimeOverlay ?? void 0,
6815
+ sliceCone: sliceCone2 ?? void 0,
6226
6816
  colors: traceColors || void 0,
6227
6817
  scrubIndex: overlayIdx,
6228
6818
  onNodeClick: (stageId) => onNodeClick?.(stageId),
@@ -6237,10 +6827,10 @@ function ExplainableShell({
6237
6827
  const leftLabel = panelLabels?.topology ?? "Topology";
6238
6828
  const rightLabel = panelLabels?.details ?? "Details";
6239
6829
  const bottomLabel = panelLabels?.timeline ?? "Timeline";
6240
- const shellRef = (0, import_react31.useRef)(null);
6241
- const [isNarrow, setIsNarrow] = (0, import_react31.useState)(false);
6242
- const [isMedium, setIsMedium] = (0, import_react31.useState)(false);
6243
- (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)(() => {
6244
6834
  const el = shellRef.current;
6245
6835
  if (!el) return;
6246
6836
  const ro = new ResizeObserver(([entry]) => {
@@ -6252,14 +6842,14 @@ function ExplainableShell({
6252
6842
  ro.observe(el);
6253
6843
  return () => ro.disconnect();
6254
6844
  }, []);
6255
- const autoRecorderViews = (0, import_react31.useMemo)(() => {
6845
+ const autoRecorderViews = (0, import_react32.useMemo)(() => {
6256
6846
  const recorders = runtimeSnapshot?.recorders;
6257
6847
  if (!recorders?.length) return [];
6258
6848
  const explicitIds = new Set((recorderViews ?? []).map((v2) => v2.id));
6259
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 }));
6260
6850
  }, [runtimeSnapshot, recorderViews]);
6261
6851
  const hasNarrative = !!narrativeEntries?.length;
6262
- const allTabs = (0, import_react31.useMemo)(() => {
6852
+ const allTabs = (0, import_react32.useMemo)(() => {
6263
6853
  const tabs2 = [
6264
6854
  { id: "result", name: "Result", description: "Final output and console logs" },
6265
6855
  { id: "memory", name: "Memory", description: "Accumulator \u2014 progressive shared state at each stage" }
@@ -6278,38 +6868,40 @@ function ExplainableShell({
6278
6868
  }, [hasNarrative, recorderViews, autoRecorderViews, hideTabsProp]);
6279
6869
  const validTabIds = new Set(allTabs.map((t) => t.id));
6280
6870
  const resolvedDefault = defaultTab && validTabIds.has(defaultTab) ? defaultTab : allTabs[0]?.id ?? "result";
6281
- const [activeTab, setActiveTab] = (0, import_react31.useState)(resolvedDefault);
6282
- const [snapshotIdx, setSnapshotIdx] = (0, import_react31.useState)(0);
6283
- const [drillDownStack, setDrillDownStack] = (0, import_react31.useState)([]);
6284
- const [rightExpanded, setRightExpanded] = (0, import_react31.useState)(defaultExpanded?.details ?? true);
6285
- const [rightPanelMode, setRightPanelMode] = (0, import_react31.useState)("insights");
6286
- const [leftExpanded, setLeftExpanded] = (0, import_react31.useState)(defaultExpanded?.topology ?? false);
6287
- const [timelineExpanded, setTimelineExpanded] = (0, import_react31.useState)(defaultExpanded?.timeline ?? false);
6288
- (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)(() => {
6289
6881
  if (isNarrow) {
6290
6882
  setLeftExpanded(false);
6291
6883
  setRightExpanded(false);
6292
6884
  setTimelineExpanded(false);
6293
6885
  }
6294
6886
  }, [isNarrow]);
6295
- const triggerReflow = (0, import_react31.useCallback)(() => {
6887
+ const triggerReflow = (0, import_react32.useCallback)(() => {
6296
6888
  requestAnimationFrame(() => window.dispatchEvent(new Event("resize")));
6297
6889
  setTimeout(() => window.dispatchEvent(new Event("resize")), 320);
6298
6890
  }, []);
6299
- const toggleLeft = (0, import_react31.useCallback)((v2) => {
6891
+ const toggleLeft = (0, import_react32.useCallback)((v2) => {
6300
6892
  setLeftExpanded(v2);
6301
6893
  triggerReflow();
6302
6894
  }, [triggerReflow]);
6303
- const toggleRight = (0, import_react31.useCallback)((v2) => {
6895
+ const toggleRight = (0, import_react32.useCallback)((v2) => {
6304
6896
  setRightExpanded(v2);
6305
6897
  triggerReflow();
6306
6898
  }, [triggerReflow]);
6307
- const toggleTimeline = (0, import_react31.useCallback)(() => {
6899
+ const toggleTimeline = (0, import_react32.useCallback)(() => {
6308
6900
  setTimelineExpanded((p) => !p);
6309
6901
  triggerReflow();
6310
6902
  }, [triggerReflow]);
6311
6903
  const isInSubflow = drillDownStack.length > 0;
6312
- const currentLevel = (0, import_react31.useMemo)(() => {
6904
+ const currentLevel = (0, import_react32.useMemo)(() => {
6313
6905
  if (drillDownStack.length > 0) {
6314
6906
  const top = drillDownStack[drillDownStack.length - 1];
6315
6907
  return { spec: top.spec, snapshots: top.snapshots, narrative: top.narrative };
@@ -6318,48 +6910,133 @@ function ExplainableShell({
6318
6910
  }, [drillDownStack, snapshots]);
6319
6911
  const activeSnapshots = currentLevel.snapshots;
6320
6912
  const safeIdx = activeSnapshots.length > 0 ? Math.max(0, Math.min(snapshotIdx, activeSnapshots.length - 1)) : 0;
6913
+ const shellDataTrace = (0, import_react32.useMemo)(
6914
+ () => runtimeSnapshot?.commitLog ? buildDataTrace(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, activeSnapshots[safeIdx]?.runtimeStageId ?? "") : { frames: [], readsAvailable: true },
6915
+ [runtimeSnapshot, activeSnapshots, safeIdx]
6916
+ );
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
+ }
6939
+ if (rightPanelMode !== "what" || inspectorTab !== "trace") return void 0;
6940
+ if (shellDataTrace.frames.length < 2) return void 0;
6941
+ const cone = /* @__PURE__ */ new Map();
6942
+ for (const f of shellDataTrace.frames) {
6943
+ const stagePart = f.runtimeStageId.split("#")[0];
6944
+ const prev = cone.get(stagePart);
6945
+ if (prev === void 0 || f.depth < prev) cone.set(stagePart, f.depth);
6946
+ }
6947
+ return cone;
6948
+ }, [traceWalk, rightPanelMode, inspectorTab, shellDataTrace]);
6321
6949
  const activeNarrativeEntries = isInSubflow ? currentLevel.narrative : narrativeEntries;
6322
- const breadcrumbs = (0, import_react31.useMemo)(() => {
6950
+ const breadcrumbs = (0, import_react32.useMemo)(() => {
6323
6951
  const root = { label: title || "Flowchart", spec: null, description: void 0 };
6324
6952
  return [root, ...drillDownStack.map((e) => ({ label: e.label, spec: e.spec, description: void 0 }))];
6325
6953
  }, [title, drillDownStack]);
6326
- const showTreeSidebar = (0, import_react31.useMemo)(() => {
6954
+ const showTreeSidebar = (0, import_react32.useMemo)(() => {
6327
6955
  if (traceGraph?.nodes?.length) {
6328
6956
  return traceGraph.nodes.some((n) => n.data?.isSubflow === true);
6329
6957
  }
6330
6958
  return false;
6331
6959
  }, [traceGraph]);
6332
- const rootOverlay = (0, import_react31.useMemo)(() => {
6960
+ const rootOverlay = (0, import_react32.useMemo)(() => {
6333
6961
  if (isInSubflow || !snapshots.length) return { activeStage: void 0, doneStages: void 0 };
6334
6962
  const doneStages = new Set(snapshots.slice(0, safeIdx).map((s) => s.stageLabel));
6335
6963
  const activeStage = snapshots[safeIdx]?.stageLabel ?? null;
6336
6964
  return { activeStage, doneStages };
6337
6965
  }, [isInSubflow, snapshots, safeIdx]);
6338
- const handleTabChange = (0, import_react31.useCallback)((tab) => {
6966
+ const handleTabChange = (0, import_react32.useCallback)((tab) => {
6339
6967
  setActiveTab(tab);
6340
6968
  setDrillDownStack([]);
6341
6969
  }, []);
6342
- const handleSnapshotChange = (0, import_react31.useCallback)((idx) => {
6970
+ const handleSnapshotChange = (0, import_react32.useCallback)((idx) => {
6343
6971
  if (typeof idx === "number") setSnapshotIdx(idx);
6344
6972
  }, []);
6345
- 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)(
6346
7022
  (nodeName) => {
6347
7023
  const entry = resolveSubflowFromRuntime(activeSnapshots, nodeName, narrativeEntries);
6348
7024
  if (entry) {
7025
+ setTracing(null);
6349
7026
  setDrillDownStack((prev) => [...prev, { ...entry, parentSnapshotIdx: snapshotIdx }]);
6350
7027
  setSnapshotIdx(0);
6351
7028
  }
6352
7029
  },
6353
7030
  [activeSnapshots, narrativeEntries, snapshotIdx]
6354
7031
  );
6355
- const handleBreadcrumbNavigate = (0, import_react31.useCallback)((level) => {
7032
+ const handleBreadcrumbNavigate = (0, import_react32.useCallback)((level) => {
6356
7033
  setDrillDownStack((prev) => {
6357
7034
  const popped = level === 0 ? prev[0] : prev[level];
6358
7035
  if (popped) setSnapshotIdx(popped.parentSnapshotIdx);
6359
7036
  return level === 0 ? [] : prev.slice(0, level);
6360
7037
  });
6361
7038
  }, []);
6362
- const handleNodeClick = (0, import_react31.useCallback)(
7039
+ const handleNodeClick = (0, import_react32.useCallback)(
6363
7040
  (indexOrId) => {
6364
7041
  if (typeof indexOrId === "number") {
6365
7042
  setSnapshotIdx(indexOrId);
@@ -6375,7 +7052,7 @@ function ExplainableShell({
6375
7052
  },
6376
7053
  [activeSnapshots, narrativeEntries, handleDrillDown]
6377
7054
  );
6378
- const handleTreeNodeSelect = (0, import_react31.useCallback)(
7055
+ const handleTreeNodeSelect = (0, import_react32.useCallback)(
6379
7056
  (name, isSubflow) => {
6380
7057
  if (isSubflow) {
6381
7058
  setDrillDownStack([]);
@@ -6392,33 +7069,112 @@ function ExplainableShell({
6392
7069
  },
6393
7070
  [snapshots, narrativeEntries, snapshotIdx]
6394
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]);
6395
7151
  const tabLabels = new Map(allTabs.map((t) => [t.id, t.name]));
6396
7152
  if (unstyled) {
6397
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className, style, "data-fp": "explainable-shell", children: [
6398
- /* @__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)) }),
6399
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
6400
- activeTab === "result" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
6401
- (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6402
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
6403
- isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
6404
- traceGraph && effectiveRenderFlowchart?.({ spec: null, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId }),
6405
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
6406
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, unstyled: true }),
6407
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
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 }),
7160
+ traceGraph && effectiveRenderFlowchart?.({ spec: null, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId, ...sliceCone && { sliceCone } }),
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 })
6408
7164
  ] })
6409
7165
  ] })
6410
7166
  ] });
6411
7167
  }
6412
7168
  const showTopology = !!effectiveRenderFlowchart && !!traceGraph;
6413
- const detailsContent = (0, import_react31.useMemo)(() => {
7169
+ const detailsContent = (0, import_react32.useMemo)(() => {
6414
7170
  if (activeTab === "result") {
6415
- 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 });
6416
7172
  }
6417
7173
  if (activeTab === "memory") {
6418
- 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%" } });
6419
7175
  }
6420
7176
  if (activeTab === "narrative") {
6421
- 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%" } });
6422
7178
  }
6423
7179
  const customView = recorderViews?.find((v2) => v2.id === activeTab);
6424
7180
  if (customView?.render) {
@@ -6426,7 +7182,7 @@ function ExplainableShell({
6426
7182
  }
6427
7183
  const autoView = autoRecorderViews.find((v2) => v2.id === activeTab);
6428
7184
  if (autoView) {
6429
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7185
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6430
7186
  KeyedRecorderView,
6431
7187
  {
6432
7188
  data: autoView.data,
@@ -6439,8 +7195,8 @@ function ExplainableShell({
6439
7195
  }
6440
7196
  return null;
6441
7197
  }, [activeTab, resultData, logs, hideConsole, size, activeSnapshots, safeIdx, activeNarrativeEntries, recorderViews, autoRecorderViews]);
6442
- const detailsPanel = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
6443
- /* @__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: {
6444
7200
  display: "flex",
6445
7201
  borderBottom: `1px solid ${theme.border}`,
6446
7202
  background: theme.bgSecondary,
@@ -6448,7 +7204,7 @@ function ExplainableShell({
6448
7204
  overflowX: "auto"
6449
7205
  }, children: allTabs.map((tab) => {
6450
7206
  const active = tab.id === activeTab;
6451
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7207
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6452
7208
  "button",
6453
7209
  {
6454
7210
  onClick: () => handleTabChange(tab.id),
@@ -6472,9 +7228,9 @@ function ExplainableShell({
6472
7228
  tab.id
6473
7229
  );
6474
7230
  }) }),
6475
- /* @__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 })
6476
7232
  ] });
6477
- const shellThemeVars = (0, import_react31.useMemo)(() => {
7233
+ const shellThemeVars = (0, import_react32.useMemo)(() => {
6478
7234
  if (!traceTheme) return {};
6479
7235
  const base = traceTheme.mode ? tokensToCSSVars(traceTheme.mode === "light" ? coolLight : coolDark) : {};
6480
7236
  return {
@@ -6483,7 +7239,7 @@ function ExplainableShell({
6483
7239
  ...traceTheme.current !== void 0 && { ["--fp-node-cursor"]: traceTheme.current }
6484
7240
  };
6485
7241
  }, [traceTheme]);
6486
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
7242
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6487
7243
  "div",
6488
7244
  {
6489
7245
  ref: shellRef,
@@ -6502,29 +7258,31 @@ function ExplainableShell({
6502
7258
  },
6503
7259
  "data-fp": "explainable-shell",
6504
7260
  children: [
6505
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7261
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6506
7262
  TimeTravelControls,
6507
7263
  {
6508
7264
  snapshots: activeSnapshots,
6509
7265
  selectedIndex: safeIdx,
6510
7266
  onIndexChange: handleSnapshotChange,
6511
- size
7267
+ size,
7268
+ tracing: tracingRail
6512
7269
  }
6513
7270
  ),
6514
- isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
6515
- /* @__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 ? (
6516
7273
  /* ── Mobile: stacked vertical ── */
6517
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6518
- 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({
6519
7276
  spec: null,
6520
7277
  snapshots: activeSnapshots,
6521
7278
  selectedIndex: safeIdx,
6522
7279
  onNodeClick: handleNodeClick,
6523
- showStageId
7280
+ showStageId,
7281
+ ...sliceCone && { sliceCone }
6524
7282
  }) }),
6525
- showTreeSidebar && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6526
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
6527
- 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)(
6528
7286
  SubflowTree,
6529
7287
  {
6530
7288
  graph: traceGraph ?? { nodes: [], edges: [] },
@@ -6534,17 +7292,17 @@ function ExplainableShell({
6534
7292
  }
6535
7293
  ) })
6536
7294
  ] }),
6537
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
6538
- rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { maxHeight: 350, flexShrink: 0, overflow: "hidden" }, children: detailsPanel }),
6539
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
6540
- 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 }) })
6541
7299
  ] })
6542
7300
  ) : (
6543
7301
  /* ── Desktop: two-column — Flowchart | Right Panel ── */
6544
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6545
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
6546
- showTreeSidebar && (leftExpanded ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { width: 180, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
6547
- /* @__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)(
6548
7306
  SubflowTree,
6549
7307
  {
6550
7308
  graph: traceGraph ?? { nodes: [], edges: [] },
@@ -6553,21 +7311,26 @@ function ExplainableShell({
6553
7311
  onNodeSelect: handleTreeNodeSelect
6554
7312
  }
6555
7313
  ) }),
6556
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VLinePill, { label: "Topology", expanded: true, side: "left", onClick: () => toggleLeft(false) })
6557
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VLinePill, { label: "Topology", expanded: false, side: "left", onClick: () => toggleLeft(true) })),
6558
- 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({
6559
7317
  spec: null,
6560
7318
  snapshots: activeSnapshots,
6561
7319
  selectedIndex: safeIdx,
6562
7320
  onNodeClick: handleNodeClick,
6563
- showStageId
6564
- }) }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1 } }),
6565
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VLinePill, { label: "Details", expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
6566
- 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)(
7321
+ showStageId,
7322
+ ...sliceCone && { sliceCone }
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)(
6567
7326
  RightPanel,
6568
7327
  {
6569
7328
  mode: rightPanelMode,
6570
7329
  onModeChange: setRightPanelMode,
7330
+ dataTrace: shellDataTrace,
7331
+ onInspectorTabChange: setInspectorTab,
7332
+ inspectorTab,
7333
+ traceContent: traceTabContent,
6571
7334
  snapshots: activeSnapshots,
6572
7335
  selectedIndex: safeIdx,
6573
7336
  runtimeSnapshot,
@@ -6577,14 +7340,11 @@ function ExplainableShell({
6577
7340
  recorderViews,
6578
7341
  autoRecorderViews,
6579
7342
  size,
6580
- onNavigateToStage: (id) => {
6581
- const idx = activeSnapshots.findIndex((s) => s.runtimeStageId === id);
6582
- if (idx >= 0) setSnapshotIdx(idx);
6583
- }
7343
+ onNavigateToStage: navigateToStage
6584
7344
  }
6585
7345
  ) })
6586
7346
  ] }),
6587
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7347
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6588
7348
  CompactTimeline,
6589
7349
  {
6590
7350
  snapshots: activeSnapshots,
@@ -6601,8 +7361,8 @@ function ExplainableShell({
6601
7361
 
6602
7362
  // src/components/TraceViewer/TraceViewer.tsx
6603
7363
  var React = __toESM(require("react"), 1);
6604
- var import_react32 = require("react");
6605
- var import_jsx_runtime27 = require("react/jsx-runtime");
7364
+ var import_react33 = require("react");
7365
+ var import_jsx_runtime28 = require("react/jsx-runtime");
6606
7366
  function parseTrace(input) {
6607
7367
  if (input == null) {
6608
7368
  return {
@@ -6665,11 +7425,11 @@ function TraceViewer({
6665
7425
  recorderViews,
6666
7426
  renderFlowchart
6667
7427
  }) {
6668
- const parsed = (0, import_react32.useMemo)(() => parseTrace(trace), [trace]);
7428
+ const parsed = (0, import_react33.useMemo)(() => parseTrace(trace), [trace]);
6669
7429
  React.useEffect(() => {
6670
7430
  if (!parsed.ok && onError) onError(parsed.error);
6671
7431
  }, [parsed, onError]);
6672
- const snapshots = (0, import_react32.useMemo)(() => {
7432
+ const snapshots = (0, import_react33.useMemo)(() => {
6673
7433
  if (!parsed.ok || !parsed.trace.snapshot) return [];
6674
7434
  try {
6675
7435
  return toVisualizationSnapshots(
@@ -6683,7 +7443,7 @@ function TraceViewer({
6683
7443
  if (!parsed.ok || snapshots.length === 0) {
6684
7444
  return fallback ?? null;
6685
7445
  }
6686
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7446
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6687
7447
  ExplainableShell,
6688
7448
  {
6689
7449
  snapshots,
@@ -6720,13 +7480,16 @@ function TraceViewer({
6720
7480
  SubflowTree,
6721
7481
  TimeTravelControls,
6722
7482
  TraceViewer,
7483
+ TraceWalkCard,
6723
7484
  buildEntryRangeIndex,
7485
+ buildTraceWalk,
6724
7486
  computeRevealedEntryCount,
6725
7487
  coolDark,
6726
7488
  coolLight,
6727
7489
  createSnapshots,
6728
7490
  defaultTokens,
6729
7491
  extractSubflowNarrative,
7492
+ formatTraceWalk,
6730
7493
  mergeWritePatch,
6731
7494
  rawDefaults,
6732
7495
  subflowResultToSnapshots,