footprint-explainable-ui 0.28.0 → 0.30.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,41 @@ 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 forkPrompt = isTracing && (tracing.forkCount ?? 0) >= 2 && !!tracing.onForkPrompt;
2093
+ const canPrev = isTracing ? forkPrompt || earlierStop !== null : selectedIndex > 0;
2094
+ const canNext = isTracing ? laterStop !== null : selectedIndex < total - 1;
2095
+ const goPrev = (0, import_react10.useCallback)(() => {
2096
+ setPlaying(false);
2097
+ if (isTracing) {
2098
+ if (forkPrompt) {
2099
+ tracing.onForkPrompt();
2100
+ return;
2101
+ }
2102
+ if (earlierStop !== null) onIndexChange(earlierStop);
2103
+ } else if (selectedIndex > 0) onIndexChange(selectedIndex - 1);
2104
+ }, [isTracing, forkPrompt, tracing, earlierStop, selectedIndex, onIndexChange]);
2105
+ const goNext = (0, import_react10.useCallback)(() => {
2106
+ setPlaying(false);
2107
+ if (isTracing) {
2108
+ if (laterStop !== null) onIndexChange(laterStop);
2109
+ } else if (selectedIndex < total - 1) onIndexChange(selectedIndex + 1);
2110
+ }, [isTracing, laterStop, selectedIndex, total, onIndexChange]);
2076
2111
  (0, import_react10.useEffect)(() => {
2077
- if (!playing || !autoPlayable) return;
2112
+ if (!playing || !autoPlayable || isTracing) return;
2078
2113
  if (selectedIndex >= total - 1) {
2079
2114
  setPlaying(false);
2080
2115
  return;
@@ -2090,7 +2125,7 @@ function TimeTravelControls({
2090
2125
  return () => {
2091
2126
  if (playRef.current) clearTimeout(playRef.current);
2092
2127
  };
2093
- }, [playing, selectedIndex, snapshots, total, onIndexChange, autoPlayable]);
2128
+ }, [playing, selectedIndex, snapshots, total, onIndexChange, autoPlayable, isTracing]);
2094
2129
  const togglePlay = (0, import_react10.useCallback)(() => {
2095
2130
  if (playing) {
2096
2131
  setPlaying(false);
@@ -2103,20 +2138,22 @@ function TimeTravelControls({
2103
2138
  (e) => {
2104
2139
  if (e.key === "ArrowLeft" && canPrev && !playing) {
2105
2140
  e.preventDefault();
2106
- setPlaying(false);
2107
- onIndexChange(selectedIndex - 1);
2141
+ goPrev();
2108
2142
  } else if (e.key === "ArrowRight" && canNext && !playing) {
2109
2143
  e.preventDefault();
2110
- setPlaying(false);
2111
- onIndexChange(selectedIndex + 1);
2112
- } else if (e.key === " " && autoPlayable) {
2144
+ goNext();
2145
+ } else if (e.key === "Escape" && isTracing) {
2146
+ e.preventDefault();
2147
+ tracing.onExit();
2148
+ } else if (e.key === " " && autoPlayable && !isTracing) {
2113
2149
  e.preventDefault();
2114
2150
  togglePlay();
2115
2151
  }
2116
2152
  },
2117
- [canPrev, canNext, playing, selectedIndex, onIndexChange, autoPlayable, togglePlay]
2153
+ [canPrev, canNext, playing, goPrev, goNext, autoPlayable, togglePlay, isTracing, tracing]
2118
2154
  );
2119
2155
  const fs = fontSize[size];
2156
+ const tracingColor = "var(--fp-tracing, #0d9488)";
2120
2157
  if (unstyled) {
2121
2158
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2122
2159
  "div",
@@ -2124,60 +2161,77 @@ function TimeTravelControls({
2124
2161
  className,
2125
2162
  style,
2126
2163
  "data-fp": "time-travel-controls",
2164
+ "data-tracing": isTracing || void 0,
2127
2165
  role: "toolbar",
2128
- "aria-label": "Time travel controls",
2166
+ "aria-label": isTracing ? `Tracing ${tracing.tracedKey}` : "Time travel controls",
2129
2167
  tabIndex: 0,
2130
2168
  onKeyDown: handleKeyDown,
2131
2169
  children: [
2170
+ isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { "data-fp": "tt-tracing-header", children: [
2171
+ "Tracing ",
2172
+ tracing.tracedKey,
2173
+ tracing.viaKey && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2174
+ " ",
2175
+ "\u25B8 via ",
2176
+ tracing.viaKey,
2177
+ " ",
2178
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-fp": "tt-show-all", onClick: tracing.onShowAll, children: "show all" })
2179
+ ] }),
2180
+ " \xB7 ",
2181
+ "stop ",
2182
+ tracing.stopOrdinal,
2183
+ " of ",
2184
+ tracing.totalStops,
2185
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-fp": "tt-exit-tracing", onClick: tracing.onExit, "aria-label": "Exit tracing", children: "Done" })
2186
+ ] }),
2132
2187
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2133
2188
  "button",
2134
2189
  {
2135
2190
  "data-fp": "tt-prev",
2136
2191
  disabled: !canPrev || playing,
2137
- onClick: () => {
2138
- setPlaying(false);
2139
- onIndexChange(selectedIndex - 1);
2140
- },
2141
- "aria-label": "Previous stage",
2142
- children: "Prev"
2192
+ onClick: goPrev,
2193
+ "aria-label": isTracing ? forkPrompt ? "Choose cause" : "Earlier cause" : "Previous stage",
2194
+ children: isTracing ? forkPrompt ? "Choose cause\u2026" : "Earlier cause" : "Prev"
2143
2195
  }
2144
2196
  ),
2145
- autoPlayable && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-fp": "tt-play", onClick: togglePlay, "aria-label": playing ? "Pause" : "Play", children: playing ? "Pause" : "Play" }),
2197
+ 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
2198
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2147
2199
  "button",
2148
2200
  {
2149
2201
  "data-fp": "tt-next",
2150
2202
  disabled: !canNext || playing,
2151
- onClick: () => {
2152
- setPlaying(false);
2153
- onIndexChange(selectedIndex + 1);
2154
- },
2155
- "aria-label": "Next stage",
2156
- children: "Next"
2203
+ onClick: goNext,
2204
+ "aria-label": isTracing ? "Toward result" : "Next stage",
2205
+ children: isTracing ? "Toward result" : "Next"
2157
2206
  }
2158
2207
  ),
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);
2208
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "data-fp": "tt-ticks", children: snapshots.map((snap, i) => {
2209
+ const isStop = !stopSet || stopSet.has(i);
2210
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2211
+ "button",
2212
+ {
2213
+ "data-fp": "tt-tick",
2214
+ "data-active": i === selectedIndex,
2215
+ "data-done": i < selectedIndex,
2216
+ "data-stop": isTracing ? isStop : void 0,
2217
+ disabled: isTracing && !isStop,
2218
+ onClick: () => {
2219
+ setPlaying(false);
2220
+ onIndexChange(i);
2221
+ },
2222
+ title: snap.stageLabel
2168
2223
  },
2169
- title: snap.stageLabel
2170
- },
2171
- i
2172
- )) })
2224
+ i
2225
+ );
2226
+ }) })
2173
2227
  ]
2174
2228
  }
2175
2229
  );
2176
2230
  }
2177
2231
  const btnStyle = (disabled) => ({
2178
2232
  background: theme.bgTertiary,
2179
- border: `1px solid ${theme.border}`,
2180
- color: disabled ? theme.textMuted : theme.textPrimary,
2233
+ border: `1px solid ${isTracing ? tracingColor : theme.border}`,
2234
+ color: disabled ? theme.textMuted : isTracing ? tracingColor : theme.textPrimary,
2181
2235
  borderRadius: "6px",
2182
2236
  padding: "4px 12px",
2183
2237
  fontSize: fs.body,
@@ -2193,7 +2247,7 @@ function TimeTravelControls({
2193
2247
  style: {
2194
2248
  padding: "6px 12px",
2195
2249
  background: theme.bgSecondary,
2196
- borderBottom: `1px solid ${theme.border}`,
2250
+ borderBottom: isTracing ? `2px solid ${tracingColor}` : `1px solid ${theme.border}`,
2197
2251
  display: "flex",
2198
2252
  alignItems: "center",
2199
2253
  gap: 6,
@@ -2201,25 +2255,86 @@ function TimeTravelControls({
2201
2255
  ...style
2202
2256
  },
2203
2257
  "data-fp": "time-travel-controls",
2258
+ "data-tracing": isTracing || void 0,
2204
2259
  role: "toolbar",
2205
- "aria-label": "Time travel controls",
2260
+ "aria-label": isTracing ? `Tracing ${tracing.tracedKey}` : "Time travel controls",
2206
2261
  tabIndex: 0,
2207
2262
  onKeyDown: handleKeyDown,
2208
2263
  children: [
2264
+ isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2265
+ "span",
2266
+ {
2267
+ "data-fp": "tt-tracing-header",
2268
+ style: {
2269
+ display: "flex",
2270
+ alignItems: "center",
2271
+ gap: 6,
2272
+ flexShrink: 0,
2273
+ fontSize: fs.body
2274
+ },
2275
+ children: [
2276
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2277
+ "span",
2278
+ {
2279
+ style: {
2280
+ fontSize: 10,
2281
+ fontWeight: 700,
2282
+ letterSpacing: "0.06em",
2283
+ textTransform: "uppercase",
2284
+ color: "#fff",
2285
+ background: tracingColor,
2286
+ borderRadius: 4,
2287
+ padding: "2px 7px"
2288
+ },
2289
+ children: "Tracing"
2290
+ }
2291
+ ),
2292
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontFamily: "monospace", fontWeight: 600, color: tracingColor }, children: tracing.tracedKey }),
2293
+ tracing.viaKey && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: { color: theme.textMuted }, children: [
2294
+ "\u25B8 via",
2295
+ " ",
2296
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontFamily: "monospace", color: theme.textSecondary }, children: tracing.viaKey }),
2297
+ " ",
2298
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2299
+ "button",
2300
+ {
2301
+ "data-fp": "tt-show-all",
2302
+ onClick: tracing.onShowAll,
2303
+ style: {
2304
+ border: "none",
2305
+ background: "transparent",
2306
+ color: tracingColor,
2307
+ cursor: "pointer",
2308
+ fontSize: fs.body,
2309
+ textDecoration: "underline",
2310
+ padding: 0
2311
+ },
2312
+ children: "show all"
2313
+ }
2314
+ )
2315
+ ] }),
2316
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: { color: theme.textMuted }, children: [
2317
+ "\xB7 stop ",
2318
+ tracing.stopOrdinal,
2319
+ " of ",
2320
+ tracing.totalStops
2321
+ ] })
2322
+ ]
2323
+ }
2324
+ ),
2209
2325
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2210
2326
  "button",
2211
2327
  {
2212
2328
  style: btnStyle(!canPrev || playing),
2213
2329
  disabled: !canPrev || playing,
2214
- onClick: () => {
2215
- setPlaying(false);
2216
- onIndexChange(selectedIndex - 1);
2217
- },
2218
- "aria-label": "Previous stage",
2219
- children: "\u25C0"
2330
+ onClick: goPrev,
2331
+ "aria-label": isTracing ? forkPrompt ? "Choose cause" : "Earlier cause" : "Previous stage",
2332
+ title: isTracing ? forkPrompt ? "This stop is a fork \u2014 choose which cause to follow" : "Earlier cause" : "Previous stage",
2333
+ "data-fp": "tt-prev",
2334
+ children: isTracing ? forkPrompt ? "\u2442 choose cause\u2026" : "\u25C0 earlier cause" : "\u25C0"
2220
2335
  }
2221
2336
  ),
2222
- autoPlayable && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2337
+ autoPlayable && !isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2223
2338
  "button",
2224
2339
  {
2225
2340
  onClick: togglePlay,
@@ -2247,12 +2362,11 @@ function TimeTravelControls({
2247
2362
  {
2248
2363
  style: btnStyle(!canNext || playing),
2249
2364
  disabled: !canNext || playing,
2250
- onClick: () => {
2251
- setPlaying(false);
2252
- onIndexChange(selectedIndex + 1);
2253
- },
2254
- "aria-label": "Next stage",
2255
- children: "\u25B6"
2365
+ onClick: goNext,
2366
+ "aria-label": isTracing ? "Toward result" : "Next stage",
2367
+ title: isTracing ? "Toward result" : "Next stage",
2368
+ "data-fp": "tt-next",
2369
+ children: isTracing ? "toward result \u25B6" : "\u25B6"
2256
2370
  }
2257
2371
  ),
2258
2372
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -2268,6 +2382,8 @@ function TimeTravelControls({
2268
2382
  children: snapshots.map((snap, i) => {
2269
2383
  const isActive = i === selectedIndex;
2270
2384
  const isDone = i < selectedIndex;
2385
+ const isStop = !stopSet || stopSet.has(i);
2386
+ const unlandable = isTracing && !isStop;
2271
2387
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2272
2388
  "button",
2273
2389
  {
@@ -2275,15 +2391,19 @@ function TimeTravelControls({
2275
2391
  setPlaying(false);
2276
2392
  onIndexChange(i);
2277
2393
  },
2278
- title: snap.stageLabel,
2394
+ disabled: unlandable,
2395
+ title: unlandable ? `${snap.stageLabel} (not part of this trace)` : snap.stageLabel,
2396
+ "data-fp": "tt-tick",
2397
+ "data-stop": isTracing ? isStop : void 0,
2398
+ "data-active": isActive || void 0,
2279
2399
  style: {
2280
2400
  flex: 1,
2281
- height: isActive ? 14 : 8,
2401
+ height: isActive ? 14 : unlandable ? 4 : 8,
2282
2402
  borderRadius: 3,
2283
2403
  border: "none",
2284
- cursor: "pointer",
2285
- background: isActive ? theme.primary : isDone ? theme.success : theme.bgTertiary,
2286
- opacity: isDone || isActive ? 1 : 0.4,
2404
+ cursor: unlandable ? "default" : "pointer",
2405
+ background: isTracing ? isActive ? tracingColor : isStop ? "color-mix(in srgb, " + tracingColor + " 55%, transparent)" : theme.bgTertiary : isActive ? theme.primary : isDone ? theme.success : theme.bgTertiary,
2406
+ opacity: unlandable ? 0.3 : isTracing || isDone || isActive ? 1 : 0.4,
2287
2407
  transition: "all 0.15s ease"
2288
2408
  }
2289
2409
  },
@@ -2291,6 +2411,16 @@ function TimeTravelControls({
2291
2411
  );
2292
2412
  })
2293
2413
  }
2414
+ ),
2415
+ isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2416
+ "button",
2417
+ {
2418
+ "data-fp": "tt-exit-tracing",
2419
+ onClick: tracing.onExit,
2420
+ "aria-label": "Exit tracing",
2421
+ style: { ...btnStyle(false), background: "transparent" },
2422
+ children: "Done \u2715"
2423
+ }
2294
2424
  )
2295
2425
  ]
2296
2426
  }
@@ -2298,7 +2428,7 @@ function TimeTravelControls({
2298
2428
  }
2299
2429
 
2300
2430
  // src/components/ExplainableShell/ExplainableShell.tsx
2301
- var import_react31 = require("react");
2431
+ var import_react32 = require("react");
2302
2432
 
2303
2433
  // src/components/ExplainableShell/_internal/dataTrace.ts
2304
2434
  function readsByStep(tree) {
@@ -2361,6 +2491,648 @@ function buildDataTrace(commitLog, executionTree, targetRuntimeStageId, maxDepth
2361
2491
  return { frames, readsAvailable };
2362
2492
  }
2363
2493
 
2494
+ // src/components/ExplainableShell/_internal/traceWalk.ts
2495
+ var DEFAULT_MAX_DEPTH = 10;
2496
+ var DEFAULT_MAX_FRAMES = 50;
2497
+ function buildTraceWalk(commitLog, executionTree, key, opts) {
2498
+ const log = commitLog ?? [];
2499
+ const cutoff = opts?.beforeCommitIdx ?? log.length;
2500
+ const maxDepth = opts?.maxDepth ?? DEFAULT_MAX_DEPTH;
2501
+ const maxFrames = opts?.maxFrames ?? DEFAULT_MAX_FRAMES;
2502
+ const writerOf = (k, beforeIdx) => {
2503
+ for (let i = Math.min(beforeIdx, log.length) - 1; i >= 0; i--) {
2504
+ if (log[i].trace.some((t) => t.path === k)) return i;
2505
+ }
2506
+ return -1;
2507
+ };
2508
+ const anchorIdx = writerOf(key, cutoff);
2509
+ if (anchorIdx < 0) {
2510
+ const firstEver = log.findIndex((c) => c.trace.some((t) => t.path === key));
2511
+ const missing = firstEver < 0 ? { reason: "never-written" } : {
2512
+ reason: "not-yet-written",
2513
+ firstWriteCommitIdx: firstEver,
2514
+ firstWriterRuntimeStageId: log[firstEver].runtimeStageId,
2515
+ firstWriterStageName: log[firstEver].stage
2516
+ };
2517
+ return { key, stops: [], missing, inputTermini: [], readsAvailable: true, truncated: false };
2518
+ }
2519
+ const slice = buildDataTrace(
2520
+ log.slice(0, anchorIdx + 1),
2521
+ executionTree,
2522
+ log[anchorIdx].runtimeStageId,
2523
+ maxDepth,
2524
+ maxFrames + 1
2525
+ );
2526
+ const truncated = slice.frames.length > maxFrames;
2527
+ const frames = truncated ? slice.frames.slice(0, maxFrames) : slice.frames;
2528
+ const idxOf = /* @__PURE__ */ new Map();
2529
+ for (let i = 0; i < log.length; i++) idxOf.set(log[i].runtimeStageId, i);
2530
+ const readsOf = readKeysByStep(executionTree);
2531
+ const inputTermini = [];
2532
+ const terminiSeen = /* @__PURE__ */ new Set();
2533
+ const stops = frames.map((f) => {
2534
+ const commitIdx = idxOf.get(f.runtimeStageId) ?? -1;
2535
+ const ingredients = (readsOf.get(f.runtimeStageId) ?? []).map((k) => {
2536
+ const w = writerOf(k, commitIdx);
2537
+ if (w < 0 && !terminiSeen.has(k)) {
2538
+ terminiSeen.add(k);
2539
+ inputTermini.push(k);
2540
+ }
2541
+ return {
2542
+ key: k,
2543
+ writerRuntimeStageId: w >= 0 ? log[w].runtimeStageId : null,
2544
+ writerStageName: w >= 0 ? log[w].stage : null,
2545
+ writerCommitIdx: w >= 0 ? w : null
2546
+ };
2547
+ });
2548
+ return {
2549
+ runtimeStageId: f.runtimeStageId,
2550
+ stageId: f.stageId,
2551
+ stageName: f.stageName,
2552
+ commitIdx,
2553
+ contributedKeys: [],
2554
+ keysWritten: f.keysWritten,
2555
+ ingredients,
2556
+ depth: f.depth,
2557
+ loopPass: 0
2558
+ };
2559
+ });
2560
+ const stopById = new Map(stops.map((s) => [s.runtimeStageId, s]));
2561
+ const contributed = /* @__PURE__ */ new Map();
2562
+ contributed.set(log[anchorIdx].runtimeStageId, /* @__PURE__ */ new Set([key]));
2563
+ for (const s of stops) {
2564
+ for (const ing of s.ingredients) {
2565
+ if (!ing.writerRuntimeStageId || !stopById.has(ing.writerRuntimeStageId)) continue;
2566
+ const set = contributed.get(ing.writerRuntimeStageId) ?? /* @__PURE__ */ new Set();
2567
+ set.add(ing.key);
2568
+ contributed.set(ing.writerRuntimeStageId, set);
2569
+ }
2570
+ }
2571
+ for (const s of stops) s.contributedKeys = [...contributed.get(s.runtimeStageId) ?? []];
2572
+ stops.sort((a, b) => b.commitIdx - a.commitIdx);
2573
+ const byStagePart = /* @__PURE__ */ new Map();
2574
+ for (const s of stops) {
2575
+ const part = s.runtimeStageId.split("#")[0];
2576
+ const arr = byStagePart.get(part) ?? [];
2577
+ arr.push(s);
2578
+ byStagePart.set(part, arr);
2579
+ }
2580
+ for (const arr of byStagePart.values()) {
2581
+ if (arr.length < 2) continue;
2582
+ for (let i = 0; i < arr.length; i++) arr[i].loopPass = arr.length - i;
2583
+ }
2584
+ return { key, stops, missing: null, inputTermini, readsAvailable: slice.readsAvailable, truncated };
2585
+ }
2586
+ function readKeysByStep(tree) {
2587
+ const byStep = /* @__PURE__ */ new Map();
2588
+ const root = tree;
2589
+ if (!root) return byStep;
2590
+ const visited = /* @__PURE__ */ new Set();
2591
+ const stack = [root];
2592
+ while (stack.length > 0) {
2593
+ const node = stack.pop();
2594
+ if (visited.has(node)) continue;
2595
+ visited.add(node);
2596
+ if (node.runtimeStageId && node.stageReads) {
2597
+ const keys = Object.keys(node.stageReads);
2598
+ if (keys.length > 0) byStep.set(node.runtimeStageId, keys);
2599
+ }
2600
+ if (node.next) stack.push(node.next);
2601
+ if (node.children) for (const c of node.children) stack.push(c);
2602
+ }
2603
+ return byStep;
2604
+ }
2605
+ function formatTraceWalk(walk, stepNumberOf) {
2606
+ const lines = [];
2607
+ if (walk.missing) {
2608
+ if (walk.missing.reason === "never-written") {
2609
+ lines.push(
2610
+ `\`${walk.key}\` was never written in this run \u2014 it arrived with the run's inputs.`
2611
+ );
2612
+ } else {
2613
+ const at = walk.missing.firstWriterRuntimeStageId ? stepNumberOf(walk.missing.firstWriterRuntimeStageId) : null;
2614
+ lines.push(
2615
+ `\`${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})` : ""}.` : ".")
2616
+ );
2617
+ }
2618
+ return lines.join("\n");
2619
+ }
2620
+ lines.push(`Tracing \`${walk.key}\` \u2014 ${walk.stops.length} stops, newest first.`);
2621
+ walk.stops.forEach((stop, i) => {
2622
+ const step = stepNumberOf(stop.runtimeStageId);
2623
+ const pass = stop.loopPass > 0 ? ` (pass ${stop.loopPass})` : "";
2624
+ const made = stop.ingredients.length > 0 ? ` \xB7 made from: ${stop.ingredients.map(
2625
+ (ing) => ing.writerRuntimeStageId ? `${ing.key} (\u2190 ${ing.writerStageName}${stepNumberOf(ing.writerRuntimeStageId) ? `, step ${stepNumberOf(ing.writerRuntimeStageId)}` : ""})` : `${ing.key} (run input \u2014 never written)`
2626
+ ).join(", ")}` : walk.readsAvailable ? " \xB7 reads nothing \u2014 origin" : "";
2627
+ lines.push(
2628
+ `stop ${i + 1}/${walk.stops.length} \xB7 ${step ? `step ${step} \xB7 ` : ""}${stop.stageName}${pass} wrote \`${stop.contributedKeys.join("`, `")}\`${made}`
2629
+ );
2630
+ });
2631
+ if (walk.inputTermini.length > 0) {
2632
+ lines.push(`run inputs (never written): ${walk.inputTermini.join(", ")}`);
2633
+ }
2634
+ if (!walk.readsAvailable) {
2635
+ lines.push("\u26A0 reads were not recorded \u2014 dependencies are unknowable, not absent.");
2636
+ }
2637
+ if (walk.truncated) {
2638
+ lines.push("\u26A0 walk truncated at its frame budget \u2014 the earliest stop may not be the true origin.");
2639
+ }
2640
+ return lines.join("\n");
2641
+ }
2642
+
2643
+ // src/components/DataTracePanel/TraceWalkCard.tsx
2644
+ var import_react11 = require("react");
2645
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2646
+ var CHIP_COLORS = ["#0d9488", "#d97706", "#7c3aed", "#e11d48"];
2647
+ var TraceWalkCard = (0, import_react11.memo)(function TraceWalkCard2({
2648
+ walk,
2649
+ cursorRuntimeStageId,
2650
+ viaKey,
2651
+ stepNumberOf,
2652
+ previewValueOf,
2653
+ onFollowIngredient,
2654
+ onJumpToStop,
2655
+ onShowAll,
2656
+ onExit,
2657
+ forkChooserOpen,
2658
+ onContinueTimeOrder,
2659
+ canContinueTimeOrder = true
2660
+ }) {
2661
+ const [copied, setCopied] = (0, import_react11.useState)(false);
2662
+ const accent = "var(--fp-accent, #6366f1)";
2663
+ const tracingColor = "var(--fp-tracing, #0d9488)";
2664
+ const currentIdx = (0, import_react11.useMemo)(() => {
2665
+ if (!cursorRuntimeStageId) return 0;
2666
+ const i = walk.stops.findIndex((s) => s.runtimeStageId === cursorRuntimeStageId);
2667
+ return i >= 0 ? i : 0;
2668
+ }, [walk, cursorRuntimeStageId]);
2669
+ const current = walk.stops[currentIdx];
2670
+ const followableCount = current ? current.ingredients.filter((ing) => ing.writerRuntimeStageId !== null).length : 0;
2671
+ const chooserVisible = !!forkChooserOpen && followableCount >= 2;
2672
+ const copyStory = () => {
2673
+ const text = formatTraceWalk(walk, stepNumberOf);
2674
+ void navigator.clipboard?.writeText(text).then(() => {
2675
+ setCopied(true);
2676
+ setTimeout(() => setCopied(false), 1600);
2677
+ });
2678
+ };
2679
+ if (walk.missing) {
2680
+ 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: [
2681
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CardHeader, { label: `Why this value \u2014 \`${walk.key}\``, onExit }),
2682
+ /* @__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: [
2683
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { style: { color: accent }, children: walk.key }),
2684
+ " was ",
2685
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: "never written in this run" }),
2686
+ " \u2014 it arrived with the run's inputs."
2687
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2688
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { style: { color: accent }, children: walk.key }),
2689
+ " has ",
2690
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: "not been written yet at this moment" }),
2691
+ " \u2014 its first write happens later",
2692
+ walk.missing.firstWriterStageName && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2693
+ ", at ",
2694
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: walk.missing.firstWriterStageName }),
2695
+ walk.missing.firstWriterRuntimeStageId && stepNumberOf(walk.missing.firstWriterRuntimeStageId) && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2696
+ " (step ",
2697
+ stepNumberOf(walk.missing.firstWriterRuntimeStageId),
2698
+ ")"
2699
+ ] })
2700
+ ] }),
2701
+ "."
2702
+ ] }) })
2703
+ ] });
2704
+ }
2705
+ if (!current) return null;
2706
+ const step = stepNumberOf(current.runtimeStageId);
2707
+ const preview = previewValueOf ? previewValue(previewValueOf(current.contributedKeys[0] ?? walk.key)) : null;
2708
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-fp": "trace-walk-card", style: { padding: "10px 14px 14px", fontSize: 13, lineHeight: 1.5 }, children: [
2709
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2710
+ CardHeader,
2711
+ {
2712
+ label: `Why this value \u2014 stop ${currentIdx + 1} of ${walk.stops.length}`,
2713
+ onExit
2714
+ }
2715
+ ),
2716
+ viaKey && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-fp": "twc-breadcrumb", style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
2717
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { style: { color: accent }, children: walk.key }),
2718
+ " \u25B8 via ",
2719
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: viaKey }),
2720
+ onShowAll && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2721
+ " \xB7 ",
2722
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2723
+ "button",
2724
+ {
2725
+ onClick: onShowAll,
2726
+ style: { border: "none", background: "transparent", color: accent, cursor: "pointer", fontSize: 11, textDecoration: "underline", padding: 0 },
2727
+ children: "show all ingredients"
2728
+ }
2729
+ )
2730
+ ] })
2731
+ ] }),
2732
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-fp": "twc-stop-headline", style: { marginTop: 10, fontWeight: 600, color: theme.textPrimary }, children: [
2733
+ step && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted, fontWeight: 500 }, children: [
2734
+ "Step ",
2735
+ step,
2736
+ " \xB7 "
2737
+ ] }),
2738
+ current.stageName,
2739
+ current.loopPass > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted, fontWeight: 500 }, children: [
2740
+ " (pass ",
2741
+ current.loopPass,
2742
+ ")"
2743
+ ] })
2744
+ ] }),
2745
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginTop: 2, color: theme.textSecondary }, children: [
2746
+ "wrote",
2747
+ " ",
2748
+ current.contributedKeys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("code", { style: { color: accent }, children: [
2749
+ i > 0 && ", ",
2750
+ k
2751
+ ] }, k)),
2752
+ preview !== null && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted }, children: [
2753
+ " = ",
2754
+ preview
2755
+ ] })
2756
+ ] }),
2757
+ chooserVisible && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2758
+ "div",
2759
+ {
2760
+ "data-fp": "twc-fork-chooser",
2761
+ style: {
2762
+ marginTop: 10,
2763
+ padding: "10px 12px",
2764
+ border: `1.5px solid ${tracingColor}`,
2765
+ borderRadius: 8,
2766
+ background: `color-mix(in srgb, ${tracingColor} 8%, transparent)`
2767
+ },
2768
+ children: [
2769
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { fontWeight: 600, fontSize: 12, color: theme.textPrimary }, children: [
2770
+ "This value was made from ",
2771
+ current.ingredients.length,
2772
+ " ingredients \u2014 which one should the walk follow?"
2773
+ ] }),
2774
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, marginTop: 8 }, children: current.ingredients.map((ing, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2775
+ IngredientChip,
2776
+ {
2777
+ ing,
2778
+ color: i < CHIP_COLORS.length ? CHIP_COLORS[i] : theme.textMuted,
2779
+ step: ing.writerRuntimeStageId ? stepNumberOf(ing.writerRuntimeStageId) : null,
2780
+ onFollow: onFollowIngredient
2781
+ },
2782
+ ing.key
2783
+ )) }),
2784
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2785
+ "button",
2786
+ {
2787
+ "data-fp": "twc-continue-time",
2788
+ onClick: canContinueTimeOrder ? onContinueTimeOrder : void 0,
2789
+ disabled: !canContinueTimeOrder,
2790
+ title: canContinueTimeOrder ? void 0 : "This is the walk's earliest stop \u2014 there is nothing earlier to visit",
2791
+ style: {
2792
+ display: "block",
2793
+ width: "100%",
2794
+ marginTop: 8,
2795
+ border: `1px solid ${theme.border}`,
2796
+ background: theme.bgTertiary,
2797
+ color: theme.textPrimary,
2798
+ borderRadius: 6,
2799
+ padding: "5px 10px",
2800
+ fontSize: 11,
2801
+ fontWeight: 600,
2802
+ cursor: "pointer"
2803
+ },
2804
+ children: "visit all, oldest cause last (time order)"
2805
+ }
2806
+ )
2807
+ ]
2808
+ }
2809
+ ),
2810
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 10 }, children: chooserVisible ? null : current.ingredients.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2811
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { fontSize: 11, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.5px", fontWeight: 600 }, children: [
2812
+ "Made from ",
2813
+ current.ingredients.length,
2814
+ " ingredient",
2815
+ current.ingredients.length > 1 ? "s" : ""
2816
+ ] }),
2817
+ /* @__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)(
2818
+ IngredientChip,
2819
+ {
2820
+ ing,
2821
+ color: i < CHIP_COLORS.length ? CHIP_COLORS[i] : theme.textMuted,
2822
+ step: ing.writerRuntimeStageId ? stepNumberOf(ing.writerRuntimeStageId) : null,
2823
+ onFollow: onFollowIngredient
2824
+ },
2825
+ ing.key
2826
+ )) })
2827
+ ] }) : 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." }) }),
2828
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginTop: 14 }, children: [
2829
+ /* @__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" }),
2830
+ walk.stops.map((s, i) => {
2831
+ const isCurrent = i === currentIdx;
2832
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2833
+ "button",
2834
+ {
2835
+ "data-fp": "twc-itinerary-row",
2836
+ "data-current": isCurrent || void 0,
2837
+ onClick: () => onJumpToStop?.(s.runtimeStageId),
2838
+ style: {
2839
+ display: "block",
2840
+ width: "100%",
2841
+ textAlign: "left",
2842
+ border: "none",
2843
+ borderLeft: isCurrent ? `3px solid ${accent}` : "3px solid transparent",
2844
+ background: isCurrent ? "var(--fp-accent-bg, rgba(99,102,241,0.12))" : "transparent",
2845
+ padding: "4px 8px",
2846
+ cursor: onJumpToStop ? "pointer" : "default",
2847
+ color: "inherit",
2848
+ fontSize: 12
2849
+ },
2850
+ children: [
2851
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted }, children: [
2852
+ i + 1,
2853
+ "."
2854
+ ] }),
2855
+ " ",
2856
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { style: { color: accent }, children: s.contributedKeys.join(", ") }),
2857
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { color: theme.textMuted }, children: " \u2190 " }),
2858
+ s.stageName,
2859
+ s.loopPass > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted }, children: [
2860
+ " (pass ",
2861
+ s.loopPass,
2862
+ ")"
2863
+ ] }),
2864
+ stepNumberOf(s.runtimeStageId) && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: theme.textMuted }, children: [
2865
+ " \xB7 step ",
2866
+ stepNumberOf(s.runtimeStageId)
2867
+ ] }),
2868
+ s.ingredients.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: { color: "#d97706", fontWeight: 600 }, children: [
2869
+ " \u2442 ",
2870
+ s.ingredients.length
2871
+ ] })
2872
+ ]
2873
+ },
2874
+ s.runtimeStageId
2875
+ );
2876
+ })
2877
+ ] }),
2878
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { marginTop: 12, display: "flex", flexDirection: "column", gap: 4 }, children: [
2879
+ walk.inputTermini.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-fp": "twc-run-inputs", style: { fontSize: 11, color: theme.textMuted }, children: [
2880
+ "\u2691 run inputs (never written): ",
2881
+ walk.inputTermini.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("code", { children: [
2882
+ i > 0 && ", ",
2883
+ k
2884
+ ] }, k))
2885
+ ] }),
2886
+ 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." }),
2887
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2888
+ "button",
2889
+ {
2890
+ "data-fp": "twc-copy-story",
2891
+ onClick: copyStory,
2892
+ style: {
2893
+ alignSelf: "flex-start",
2894
+ marginTop: 4,
2895
+ border: `1px solid ${theme.border}`,
2896
+ background: theme.bgTertiary,
2897
+ color: theme.textPrimary,
2898
+ borderRadius: 6,
2899
+ padding: "4px 10px",
2900
+ fontSize: 11,
2901
+ fontWeight: 600,
2902
+ cursor: "pointer"
2903
+ },
2904
+ children: copied ? "Copied \u2713" : "Copy story"
2905
+ }
2906
+ )
2907
+ ] })
2908
+ ] });
2909
+ });
2910
+ function CardHeader({ label, onExit }) {
2911
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
2912
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { fontSize: 11, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.5px", fontWeight: 600 }, children: label }),
2913
+ onExit && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2914
+ "button",
2915
+ {
2916
+ "data-fp": "twc-exit",
2917
+ onClick: onExit,
2918
+ "aria-label": "Exit tracing",
2919
+ style: { border: "none", background: "transparent", color: theme.textMuted, cursor: "pointer", fontSize: 12 },
2920
+ children: "Done \u2715"
2921
+ }
2922
+ )
2923
+ ] });
2924
+ }
2925
+ function IngredientChip({
2926
+ ing,
2927
+ color,
2928
+ step,
2929
+ onFollow
2930
+ }) {
2931
+ const terminus = !ing.writerRuntimeStageId;
2932
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2933
+ "button",
2934
+ {
2935
+ "data-fp": "twc-ingredient",
2936
+ "data-terminus": terminus || void 0,
2937
+ disabled: terminus || !onFollow,
2938
+ onClick: () => onFollow?.(ing),
2939
+ 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`,
2940
+ style: {
2941
+ display: "inline-flex",
2942
+ alignItems: "center",
2943
+ gap: 4,
2944
+ border: `1px solid ${terminus ? theme.border : color}`,
2945
+ background: "transparent",
2946
+ color: terminus ? theme.textMuted : color,
2947
+ borderRadius: 12,
2948
+ padding: "3px 10px",
2949
+ fontSize: 11,
2950
+ fontWeight: 600,
2951
+ cursor: terminus || !onFollow ? "default" : "pointer"
2952
+ },
2953
+ children: [
2954
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: ing.key }),
2955
+ 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: [
2956
+ "\u2190 ",
2957
+ ing.writerStageName,
2958
+ step && ` \xB7 step ${step}`
2959
+ ] })
2960
+ ]
2961
+ }
2962
+ );
2963
+ }
2964
+ function previewValue(v2) {
2965
+ if (v2 === void 0) return null;
2966
+ try {
2967
+ const s = typeof v2 === "string" ? JSON.stringify(v2) : JSON.stringify(v2);
2968
+ if (s === void 0) return null;
2969
+ return s.length > 60 ? `${s.slice(0, 57)}\u2026` : s;
2970
+ } catch {
2971
+ return null;
2972
+ }
2973
+ }
2974
+
2975
+ // src/components/DataTracePanel/DataTracePanel.tsx
2976
+ var import_react12 = require("react");
2977
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2978
+ var DataTracePanel = (0, import_react12.memo)(function DataTracePanel2({
2979
+ frames,
2980
+ selectedStageId,
2981
+ onFrameClick,
2982
+ fromStageName,
2983
+ note
2984
+ }) {
2985
+ const noteLine = note ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", marginBottom: 8 }, children: note }) : null;
2986
+ if (frames.length === 0) {
2987
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
2988
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2989
+ "div",
2990
+ {
2991
+ style: {
2992
+ fontSize: 11,
2993
+ color: theme.textMuted,
2994
+ textTransform: "uppercase",
2995
+ letterSpacing: "0.5px",
2996
+ fontWeight: 600,
2997
+ marginBottom: 6
2998
+ },
2999
+ children: "Backward causal chain"
3000
+ }
3001
+ ),
3002
+ /* @__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." }),
3003
+ noteLine,
3004
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { color: theme.textMuted, fontSize: 12 }, children: "Select a stage above to see its dependency chain." })
3005
+ ] });
3006
+ }
3007
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { padding: "8px 0", fontSize: 13 }, children: [
3008
+ note && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { padding: "4px 12px 0", fontSize: 11, color: theme.textMuted, fontStyle: "italic" }, children: note }),
3009
+ fromStageName && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { padding: "4px 12px 8px" }, children: [
3010
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3011
+ "div",
3012
+ {
3013
+ style: {
3014
+ fontSize: 11,
3015
+ color: theme.textMuted,
3016
+ textTransform: "uppercase",
3017
+ letterSpacing: "0.5px",
3018
+ fontWeight: 600
3019
+ },
3020
+ children: [
3021
+ "Data trace from ",
3022
+ fromStageName
3023
+ ]
3024
+ }
3025
+ ),
3026
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3027
+ "div",
3028
+ {
3029
+ style: {
3030
+ fontSize: 11,
3031
+ color: theme.textMuted,
3032
+ fontStyle: "italic",
3033
+ marginTop: 3
3034
+ },
3035
+ children: "Every value here was derived from the stages below."
3036
+ }
3037
+ )
3038
+ ] }),
3039
+ frames.map((frame, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3040
+ DataTraceFrame,
3041
+ {
3042
+ frame,
3043
+ isFirst: i === 0,
3044
+ isLast: i === frames.length - 1,
3045
+ isSelected: frame.runtimeStageId === selectedStageId,
3046
+ onClick: onFrameClick
3047
+ },
3048
+ frame.runtimeStageId
3049
+ ))
3050
+ ] });
3051
+ });
3052
+ var DataTraceFrame = (0, import_react12.memo)(function DataTraceFrame2({
3053
+ frame,
3054
+ isFirst,
3055
+ isLast,
3056
+ isSelected,
3057
+ onClick
3058
+ }) {
3059
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3060
+ "button",
3061
+ {
3062
+ onClick: () => onClick?.(frame.runtimeStageId),
3063
+ style: {
3064
+ display: "block",
3065
+ width: "100%",
3066
+ textAlign: "left",
3067
+ border: "none",
3068
+ background: isSelected ? "var(--fp-accent-bg, rgba(99,102,241,0.12))" : "transparent",
3069
+ padding: "6px 12px 6px 16px",
3070
+ cursor: onClick ? "pointer" : "default",
3071
+ borderLeft: isSelected ? "3px solid var(--fp-accent, #6366f1)" : "3px solid transparent",
3072
+ color: "inherit",
3073
+ fontSize: 13
3074
+ },
3075
+ children: [
3076
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
3077
+ !isFirst && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { color: theme.textMuted, fontSize: 11 }, children: "\u2191" }),
3078
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3079
+ "span",
3080
+ {
3081
+ style: {
3082
+ fontWeight: isFirst ? 600 : 400,
3083
+ color: isFirst ? "var(--fp-accent, #6366f1)" : theme.textPrimary
3084
+ },
3085
+ children: frame.stageName
3086
+ }
3087
+ ),
3088
+ isLast && !isFirst && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3089
+ "span",
3090
+ {
3091
+ style: {
3092
+ fontSize: 10,
3093
+ color: theme.textMuted,
3094
+ fontStyle: "italic"
3095
+ },
3096
+ children: "(origin)"
3097
+ }
3098
+ )
3099
+ ] }),
3100
+ frame.keysWritten.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3101
+ "div",
3102
+ {
3103
+ style: {
3104
+ fontSize: 11,
3105
+ color: theme.textMuted,
3106
+ paddingLeft: isFirst ? 0 : 18,
3107
+ marginTop: 2
3108
+ },
3109
+ children: [
3110
+ "wrote:",
3111
+ " ",
3112
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { color: theme.textSecondary }, children: frame.keysWritten.join(", ") })
3113
+ ]
3114
+ }
3115
+ ),
3116
+ frame.linkedBy && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3117
+ "div",
3118
+ {
3119
+ style: {
3120
+ fontSize: 11,
3121
+ color: "var(--fp-accent, #6366f1)",
3122
+ paddingLeft: 18,
3123
+ marginTop: 1
3124
+ },
3125
+ children: [
3126
+ "\u2190 via ",
3127
+ frame.linkedBy
3128
+ ]
3129
+ }
3130
+ )
3131
+ ]
3132
+ }
3133
+ );
3134
+ });
3135
+
2364
3136
  // src/utils/narrativeSync.ts
2365
3137
  function buildEntryRangeIndex(entries) {
2366
3138
  const ranges = /* @__PURE__ */ new Map();
@@ -2682,7 +3454,7 @@ function createSnapshots(stages) {
2682
3454
  }
2683
3455
 
2684
3456
  // src/components/MemoryPanel/MemoryPanel.tsx
2685
- var import_jsx_runtime11 = require("react/jsx-runtime");
3457
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2686
3458
  function MemoryPanel({
2687
3459
  snapshots,
2688
3460
  selectedIndex,
@@ -2694,12 +3466,12 @@ function MemoryPanel({
2694
3466
  const prevMemory = selectedIndex > 0 ? snapshots[selectedIndex - 1]?.memory ?? null : null;
2695
3467
  const currMemory = snapshots[selectedIndex]?.memory ?? {};
2696
3468
  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 })
3469
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className, style, "data-fp": "memory-panel", children: [
3470
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MemoryInspector, { snapshots, selectedIndex, unstyled: true }),
3471
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScopeDiff, { previous: prevMemory, current: currMemory, unstyled: true })
2700
3472
  ] });
2701
3473
  }
2702
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3474
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2703
3475
  "div",
2704
3476
  {
2705
3477
  className,
@@ -2711,19 +3483,19 @@ function MemoryPanel({
2711
3483
  },
2712
3484
  "data-fp": "memory-panel",
2713
3485
  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 }) })
3486
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MemoryInspector, { snapshots, selectedIndex, size }),
3487
+ /* @__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
3488
  ]
2717
3489
  }
2718
3490
  );
2719
3491
  }
2720
3492
 
2721
3493
  // src/components/NarrativePanel/NarrativePanel.tsx
2722
- var import_react12 = require("react");
3494
+ var import_react14 = require("react");
2723
3495
 
2724
3496
  // src/components/StoryNarrative/StoryNarrative.tsx
2725
- var import_react11 = require("react");
2726
- var import_jsx_runtime12 = require("react/jsx-runtime");
3497
+ var import_react13 = require("react");
3498
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2727
3499
  var ENTRY_ICONS = {
2728
3500
  stage: { icon: "\u25B8", color: theme.primary, label: "Stage" },
2729
3501
  step: { icon: "\xB7", color: theme.textMuted, label: "Data operation" },
@@ -2746,7 +3518,7 @@ function StoryNarrative({
2746
3518
  const fs = fontSize[size];
2747
3519
  const pad = padding[size];
2748
3520
  const revealedCount = revealedEntryCount;
2749
- const revealed = (0, import_react11.useMemo)(() => {
3521
+ const revealed = (0, import_react13.useMemo)(() => {
2750
3522
  const raw = entries.slice(0, revealedCount);
2751
3523
  return raw.filter((e) => {
2752
3524
  const sfId = e.subflowId;
@@ -2755,7 +3527,7 @@ function StoryNarrative({
2755
3527
  return false;
2756
3528
  });
2757
3529
  }, [entries, revealedCount]);
2758
- const futureCount = (0, import_react11.useMemo)(() => {
3530
+ const futureCount = (0, import_react13.useMemo)(() => {
2759
3531
  let count = 0;
2760
3532
  for (let i = revealedCount; i < entries.length; i++) {
2761
3533
  const e = entries[i];
@@ -2763,11 +3535,11 @@ function StoryNarrative({
2763
3535
  }
2764
3536
  return count;
2765
3537
  }, [entries, revealedCount]);
2766
- const latestRef = (0, import_react11.useRef)(null);
2767
- (0, import_react11.useEffect)(() => {
3538
+ const latestRef = (0, import_react13.useRef)(null);
3539
+ (0, import_react13.useEffect)(() => {
2768
3540
  latestRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" });
2769
3541
  }, [revealed.length]);
2770
- const numberedEntries = (0, import_react11.useMemo)(() => {
3542
+ const numberedEntries = (0, import_react13.useMemo)(() => {
2771
3543
  let counter = 0;
2772
3544
  const subflowSeen = /* @__PURE__ */ new Set();
2773
3545
  let prevType = "";
@@ -2815,13 +3587,13 @@ function StoryNarrative({
2815
3587
  });
2816
3588
  }, [revealed]);
2817
3589
  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) => {
3590
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className, style: outerStyle, "data-fp": "story-narrative", role: "log", children: numberedEntries.map((entry, i) => {
2819
3591
  if (entry.isSubflowExit) return null;
2820
3592
  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);
3593
+ 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
3594
  }) });
2823
3595
  }
2824
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3596
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2825
3597
  "div",
2826
3598
  {
2827
3599
  className,
@@ -2846,7 +3618,7 @@ function StoryNarrative({
2846
3618
  const isSubflow = entry.isSubflow;
2847
3619
  const isLast = i === numberedEntries.length - 1;
2848
3620
  const headingType = entry.headingType;
2849
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3621
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2850
3622
  "div",
2851
3623
  {
2852
3624
  ref: isLast ? latestRef : void 0,
@@ -2859,7 +3631,7 @@ function StoryNarrative({
2859
3631
  marginTop: isHeading && i > 0 ? 8 : 0
2860
3632
  },
2861
3633
  children: [
2862
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3634
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2863
3635
  "span",
2864
3636
  {
2865
3637
  style: {
@@ -2875,7 +3647,7 @@ function StoryNarrative({
2875
3647
  children: meta.icon
2876
3648
  }
2877
3649
  ),
2878
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3650
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2879
3651
  "span",
2880
3652
  {
2881
3653
  style: {
@@ -2885,15 +3657,15 @@ function StoryNarrative({
2885
3657
  lineHeight: 1.6,
2886
3658
  fontFamily: entry.type === "step" ? theme.fontMono : theme.fontSans
2887
3659
  },
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: [
3660
+ children: entry.heading && headingType ? entry.text.startsWith("[") ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3661
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("strong", { children: [
2890
3662
  entry.heading,
2891
3663
  "."
2892
3664
  ] }),
2893
3665
  " ",
2894
3666
  entry.text
2895
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2896
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("strong", { children: [
3667
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3668
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("strong", { children: [
2897
3669
  entry.heading,
2898
3670
  ". [",
2899
3671
  headingType,
@@ -2910,7 +3682,7 @@ function StoryNarrative({
2910
3682
  i
2911
3683
  );
2912
3684
  }),
2913
- futureCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: {
3685
+ futureCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: {
2914
3686
  opacity: 0.3,
2915
3687
  fontSize: fs.small,
2916
3688
  color: theme.textMuted,
@@ -2928,7 +3700,7 @@ function StoryNarrative({
2928
3700
  }
2929
3701
 
2930
3702
  // src/components/NarrativePanel/NarrativePanel.tsx
2931
- var import_jsx_runtime13 = require("react/jsx-runtime");
3703
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2932
3704
  function safeJsonStringify(value) {
2933
3705
  const seen = /* @__PURE__ */ new WeakSet();
2934
3706
  const MAX_CHARS = 5e5;
@@ -2966,7 +3738,7 @@ function NarrativePanel({
2966
3738
  }) {
2967
3739
  const fs = fontSize[size];
2968
3740
  const pad = padding[size];
2969
- const narrative = (0, import_react12.useMemo)(() => {
3741
+ const narrative = (0, import_react14.useMemo)(() => {
2970
3742
  const lines = [];
2971
3743
  for (const snap of snapshots) {
2972
3744
  const stageLines = (snap.narrative ?? "").split("\n").filter(Boolean);
@@ -2974,7 +3746,7 @@ function NarrativePanel({
2974
3746
  }
2975
3747
  return lines;
2976
3748
  }, [snapshots]);
2977
- const revealedCount = (0, import_react12.useMemo)(() => {
3749
+ const revealedCount = (0, import_react14.useMemo)(() => {
2978
3750
  if (snapshots.length === 0 || narrative.length === 0) return narrative.length;
2979
3751
  const stageBoundaries = [];
2980
3752
  for (let i = 0; i < narrative.length; i++) {
@@ -2991,17 +3763,17 @@ function NarrativePanel({
2991
3763
  const endIdx = groupsToShow < stageBoundaries.length ? stageBoundaries[groupsToShow] : narrative.length;
2992
3764
  return Math.max(1, endIdx);
2993
3765
  }, [snapshots.length, selectedIndex, narrative]);
2994
- const rangeIndex = (0, import_react12.useMemo)(
3766
+ const rangeIndex = (0, import_react14.useMemo)(
2995
3767
  () => narrativeEntries?.length ? buildEntryRangeIndex(narrativeEntries) : void 0,
2996
3768
  [narrativeEntries]
2997
3769
  );
2998
- const revealedEntryCount = (0, import_react12.useMemo)(
3770
+ const revealedEntryCount = (0, import_react14.useMemo)(
2999
3771
  () => narrativeEntries?.length ? computeRevealedEntryCount(narrativeEntries, snapshots, selectedIndex, rangeIndex) : 0,
3000
3772
  [narrativeEntries, snapshots, selectedIndex, rangeIndex]
3001
3773
  );
3002
3774
  const hasStructured = narrativeEntries && narrativeEntries.length > 0;
3003
- const [copied, setCopied] = (0, import_react12.useState)(false);
3004
- const buildLLMNarrative = (0, import_react12.useCallback)(() => {
3775
+ const [copied, setCopied] = (0, import_react14.useState)(false);
3776
+ const buildLLMNarrative = (0, import_react14.useCallback)(() => {
3005
3777
  if (!narrativeEntries?.length) {
3006
3778
  return narrative.join("\n");
3007
3779
  }
@@ -3113,16 +3885,16 @@ function NarrativePanel({
3113
3885
  }
3114
3886
  return sections.join("\n");
3115
3887
  }, [narrativeEntries, narrative, runtimeSnapshot, spec]);
3116
- const handleCopy = (0, import_react12.useCallback)(async () => {
3888
+ const handleCopy = (0, import_react14.useCallback)(async () => {
3117
3889
  const text = buildLLMNarrative();
3118
3890
  await navigator.clipboard.writeText(text);
3119
3891
  setCopied(true);
3120
3892
  setTimeout(() => setCopied(false), 2e3);
3121
3893
  }, [buildLLMNarrative]);
3122
3894
  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 }) });
3895
+ 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
3896
  }
3125
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3897
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3126
3898
  "div",
3127
3899
  {
3128
3900
  className,
@@ -3134,7 +3906,7 @@ function NarrativePanel({
3134
3906
  },
3135
3907
  "data-fp": "narrative-panel",
3136
3908
  children: [
3137
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3909
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3138
3910
  "div",
3139
3911
  {
3140
3912
  style: {
@@ -3148,8 +3920,8 @@ function NarrativePanel({
3148
3920
  alignItems: "center"
3149
3921
  },
3150
3922
  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)(
3923
+ /* @__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." }),
3924
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3153
3925
  "button",
3154
3926
  {
3155
3927
  onClick: handleCopy,
@@ -3172,7 +3944,7 @@ function NarrativePanel({
3172
3944
  ]
3173
3945
  }
3174
3946
  ),
3175
- hasStructured ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3947
+ hasStructured ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3176
3948
  StoryNarrative,
3177
3949
  {
3178
3950
  entries: narrativeEntries,
@@ -3180,7 +3952,7 @@ function NarrativePanel({
3180
3952
  size,
3181
3953
  style: { flex: 1 }
3182
3954
  }
3183
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3955
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3184
3956
  NarrativeTrace,
3185
3957
  {
3186
3958
  narrative,
@@ -3195,8 +3967,8 @@ function NarrativePanel({
3195
3967
  }
3196
3968
 
3197
3969
  // src/components/FlowchartView/SubflowTree.tsx
3198
- var import_react13 = require("react");
3199
- var import_jsx_runtime14 = require("react/jsx-runtime");
3970
+ var import_react15 = require("react");
3971
+ var import_jsx_runtime16 = require("react/jsx-runtime");
3200
3972
  function graphToSubflowEntries(graph) {
3201
3973
  if (!graph?.nodes?.length) return [];
3202
3974
  const entries = [];
@@ -3212,25 +3984,25 @@ function graphToSubflowEntries(graph) {
3212
3984
  }
3213
3985
  return entries;
3214
3986
  }
3215
- var TreeNode = (0, import_react13.memo)(function TreeNode2({
3987
+ var TreeNode = (0, import_react15.memo)(function TreeNode2({
3216
3988
  entry,
3217
3989
  depth,
3218
3990
  activeStage,
3219
3991
  doneStages,
3220
3992
  onNodeSelect
3221
3993
  }) {
3222
- const [expanded, setExpanded] = (0, import_react13.useState)(true);
3994
+ const [expanded, setExpanded] = (0, import_react15.useState)(true);
3223
3995
  const hasChildren = entry.children && entry.children.length > 0;
3224
3996
  const isActive = activeStage === entry.name;
3225
3997
  const isDone = doneStages?.has(entry.name);
3226
- const handleClick = (0, import_react13.useCallback)(() => {
3998
+ const handleClick = (0, import_react15.useCallback)(() => {
3227
3999
  if (hasChildren) {
3228
4000
  setExpanded((prev) => !prev);
3229
4001
  }
3230
4002
  onNodeSelect?.(entry.name, !!entry.isSubflow);
3231
4003
  }, [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)(
4004
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
4005
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3234
4006
  "button",
3235
4007
  {
3236
4008
  onClick: handleClick,
@@ -3261,7 +4033,7 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3261
4033
  }
3262
4034
  },
3263
4035
  children: [
3264
- hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4036
+ hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3265
4037
  "span",
3266
4038
  {
3267
4039
  style: {
@@ -3276,8 +4048,8 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3276
4048
  },
3277
4049
  children: "\u25B6"
3278
4050
  }
3279
- ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { width: 12, flexShrink: 0 } }),
3280
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4051
+ ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { width: 12, flexShrink: 0 } }),
4052
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3281
4053
  "span",
3282
4054
  {
3283
4055
  style: {
@@ -3289,8 +4061,8 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3289
4061
  }
3290
4062
  }
3291
4063
  ),
3292
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { style: { display: "flex", flexDirection: "column", minWidth: 0 }, children: [
3293
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
4064
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: { display: "flex", flexDirection: "column", minWidth: 0 }, children: [
4065
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3294
4066
  "span",
3295
4067
  {
3296
4068
  style: {
@@ -3302,11 +4074,11 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3302
4074
  },
3303
4075
  children: [
3304
4076
  entry.name,
3305
- entry.isSubflow && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { opacity: 0.5, marginLeft: 4, fontSize: 10 }, children: "\u229E" })
4077
+ entry.isSubflow && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { opacity: 0.5, marginLeft: 4, fontSize: 10 }, children: "\u229E" })
3306
4078
  ]
3307
4079
  }
3308
4080
  ),
3309
- entry.description && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4081
+ entry.description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3310
4082
  "span",
3311
4083
  {
3312
4084
  style: {
@@ -3323,7 +4095,7 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3323
4095
  ]
3324
4096
  }
3325
4097
  ),
3326
- hasChildren && expanded && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { children: entry.children.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4098
+ hasChildren && expanded && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { children: entry.children.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3327
4099
  TreeNode2,
3328
4100
  {
3329
4101
  entry: child,
@@ -3336,8 +4108,8 @@ var TreeNode = (0, import_react13.memo)(function TreeNode2({
3336
4108
  )) })
3337
4109
  ] });
3338
4110
  });
3339
- var SectionLabel = (0, import_react13.memo)(function SectionLabel2({ children }) {
3340
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4111
+ var SectionLabel = (0, import_react15.memo)(function SectionLabel2({ children }) {
4112
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3341
4113
  "div",
3342
4114
  {
3343
4115
  style: {
@@ -3352,7 +4124,7 @@ var SectionLabel = (0, import_react13.memo)(function SectionLabel2({ children })
3352
4124
  }
3353
4125
  );
3354
4126
  });
3355
- var SubflowTree = (0, import_react13.memo)(function SubflowTree2({
4127
+ var SubflowTree = (0, import_react15.memo)(function SubflowTree2({
3356
4128
  graph,
3357
4129
  activeStage,
3358
4130
  doneStages,
@@ -3361,9 +4133,9 @@ var SubflowTree = (0, import_react13.memo)(function SubflowTree2({
3361
4133
  className,
3362
4134
  style
3363
4135
  }) {
3364
- const subflowStages = (0, import_react13.useMemo)(() => graphToSubflowEntries(graph), [graph]);
4136
+ const subflowStages = (0, import_react15.useMemo)(() => graphToSubflowEntries(graph), [graph]);
3365
4137
  if (subflowStages.length === 0) return null;
3366
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
4138
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3367
4139
  "div",
3368
4140
  {
3369
4141
  className,
@@ -3381,8 +4153,8 @@ var SubflowTree = (0, import_react13.memo)(function SubflowTree2({
3381
4153
  ...style
3382
4154
  },
3383
4155
  children: [
3384
- !unstyled && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionLabel, { children: "Subflows" }),
3385
- subflowStages.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4156
+ !unstyled && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SectionLabel, { children: "Subflows" }),
4157
+ subflowStages.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3386
4158
  TreeNode,
3387
4159
  {
3388
4160
  entry,
@@ -3399,14 +4171,14 @@ var SubflowTree = (0, import_react13.memo)(function SubflowTree2({
3399
4171
  });
3400
4172
 
3401
4173
  // 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({
4174
+ var import_react16 = require("react");
4175
+ var import_jsx_runtime17 = require("react/jsx-runtime");
4176
+ var SubflowBreadcrumb = (0, import_react16.memo)(function SubflowBreadcrumb2({
3405
4177
  breadcrumbs,
3406
4178
  onNavigate
3407
4179
  }) {
3408
4180
  if (breadcrumbs.length <= 1) return null;
3409
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4181
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3410
4182
  "div",
3411
4183
  {
3412
4184
  style: {
@@ -3423,10 +4195,10 @@ var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
3423
4195
  },
3424
4196
  children: breadcrumbs.map((crumb, i) => {
3425
4197
  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)(
4198
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
4199
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { color: theme.textMuted, fontSize: 10 }, children: "\u203A" }),
4200
+ isLast ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4201
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3430
4202
  "span",
3431
4203
  {
3432
4204
  style: {
@@ -3436,7 +4208,7 @@ var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
3436
4208
  children: crumb.label
3437
4209
  }
3438
4210
  ),
3439
- crumb.description && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4211
+ crumb.description && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3440
4212
  "span",
3441
4213
  {
3442
4214
  style: {
@@ -3450,7 +4222,7 @@ var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
3450
4222
  ]
3451
4223
  }
3452
4224
  )
3453
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4225
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3454
4226
  "button",
3455
4227
  {
3456
4228
  onClick: () => onNavigate(i),
@@ -3482,8 +4254,8 @@ var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
3482
4254
  });
3483
4255
 
3484
4256
  // src/components/FlowchartView/TracedFlow.tsx
3485
- var import_react25 = require("react");
3486
- var import_react26 = require("@xyflow/react");
4257
+ var import_react27 = require("react");
4258
+ var import_react28 = require("@xyflow/react");
3487
4259
 
3488
4260
  // src/components/FlowchartView/_internal/dagreTraceLayout.ts
3489
4261
  var import_dagre = __toESM(require("dagre"), 1);
@@ -3824,9 +4596,9 @@ function sliceOverlay(overlay, index) {
3824
4596
  }
3825
4597
 
3826
4598
  // 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");
4599
+ var import_react17 = require("react");
4600
+ var import_react18 = require("@xyflow/react");
4601
+ var import_jsx_runtime18 = require("react/jsx-runtime");
3830
4602
  var KEYFRAMES_ID = "fp-stage-node-keyframes";
3831
4603
  var KEYFRAMES_CSS = `
3832
4604
  @media (prefers-reduced-motion: no-preference) {
@@ -3852,128 +4624,128 @@ function StageIcon({ type, color }) {
3852
4624
  // LLM / AI call — brain/sparkle
3853
4625
  case "llm":
3854
4626
  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" })
4627
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4628
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: color, strokeWidth: "1.5" }),
4629
+ /* @__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" }),
4630
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "9.5", r: "1", fill: color }),
4631
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "3.5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4632
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "12.5", y1: "4", x2: "11.2", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4633
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "3.5", y1: "4", x2: "4.8", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
3862
4634
  ] });
3863
4635
  // Tool / function call — gear
3864
4636
  case "tool":
3865
4637
  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" }),
4638
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4639
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "8", r: "3", stroke: color, strokeWidth: "1.5" }),
3868
4640
  [0, 45, 90, 135, 180, 225, 270, 315].map((angle) => {
3869
4641
  const rad = angle * Math.PI / 180;
3870
4642
  const x1 = 8 + Math.cos(rad) * 4.5;
3871
4643
  const y1 = 8 + Math.sin(rad) * 4.5;
3872
4644
  const x2 = 8 + Math.cos(rad) * 6;
3873
4645
  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);
4646
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1, y1, x2, y2, stroke: color, strokeWidth: "1.5", strokeLinecap: "round" }, angle);
3875
4647
  })
3876
4648
  ] });
3877
4649
  // RAG / retrieval — magnifying glass + doc
3878
4650
  case "rag":
3879
4651
  case "search":
3880
4652
  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" })
4653
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4654
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "7", cy: "7", r: "4", stroke: color, strokeWidth: "1.5" }),
4655
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "10", y1: "10", x2: "13.5", y2: "13.5", stroke: color, strokeWidth: "1.5", strokeLinecap: "round" }),
4656
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5.5", y1: "6", x2: "8.5", y2: "6", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4657
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5.5", y1: "8", x2: "7.5", y2: "8", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
3886
4658
  ] });
3887
4659
  // Parse / process — diamond with arrows
3888
4660
  case "parse":
3889
4661
  case "process":
3890
4662
  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)" }) });
4663
+ 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
4664
  // Start / seed — play triangle
3893
4665
  case "start":
3894
4666
  case "seed":
3895
4667
  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" }) });
4668
+ 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
4669
  // End / finalize — stop square
3898
4670
  case "end":
3899
4671
  case "finalize":
3900
4672
  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" }) });
4673
+ 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
4674
  // Agent — person silhouette
3903
4675
  case "agent":
3904
4676
  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" })
4677
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4678
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "5", r: "2.5", stroke: color, strokeWidth: "1.5" }),
4679
+ /* @__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
4680
  ] });
3909
4681
  // Swarm — multi-agent
3910
4682
  case "swarm":
3911
4683
  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" })
4684
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4685
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "5", cy: "5", r: "2", stroke: color, strokeWidth: "1.2" }),
4686
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "11", cy: "5", r: "2", stroke: color, strokeWidth: "1.2" }),
4687
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "11", r: "2", stroke: color, strokeWidth: "1.2" }),
4688
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5", y1: "7", x2: "8", y2: "9", stroke: color, strokeWidth: "1", opacity: "0.5" }),
4689
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "11", y1: "7", x2: "8", y2: "9", stroke: color, strokeWidth: "1", opacity: "0.5" })
3918
4690
  ] });
3919
4691
  // Guard / guardrail — shield
3920
4692
  case "guard":
3921
4693
  case "guardrail":
3922
4694
  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" })
4695
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4696
+ /* @__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" }),
4697
+ /* @__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
4698
  ] });
3927
4699
  // Stream — wave
3928
4700
  case "stream":
3929
4701
  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" })
4702
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4703
+ /* @__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" }),
4704
+ /* @__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
4705
  ] });
3934
4706
  // Memory / state — database cylinder
3935
4707
  case "memory":
3936
4708
  case "state":
3937
4709
  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" })
4710
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4711
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ellipse", { cx: "8", cy: "4.5", rx: "5", ry: "2", stroke: color, strokeWidth: "1.3" }),
4712
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "3", y1: "4.5", x2: "3", y2: "11.5", stroke: color, strokeWidth: "1.3" }),
4713
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "13", y1: "4.5", x2: "13", y2: "11.5", stroke: color, strokeWidth: "1.3" }),
4714
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ellipse", { cx: "8", cy: "11.5", rx: "5", ry: "2", stroke: color, strokeWidth: "1.3" })
3943
4715
  ] });
3944
4716
  // System prompt — document with lines
3945
4717
  case "system-prompt":
3946
4718
  case "prompt":
3947
4719
  case "instructions":
3948
4720
  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" })
4721
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4722
+ /* @__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" }),
4723
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5.5", y1: "5", x2: "10.5", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4724
+ /* @__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" }),
4725
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5.5", y1: "10", x2: "8.5", y2: "10", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
3954
4726
  ] });
3955
4727
  // Messages / conversation — chat bubble
3956
4728
  case "messages":
3957
4729
  case "chat":
3958
4730
  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" })
4731
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4732
+ /* @__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" }),
4733
+ /* @__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" }),
4734
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5", y1: "6", x2: "11", y2: "6", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
4735
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("line", { x1: "5", y1: "8.5", x2: "9", y2: "8.5", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
3964
4736
  ] });
3965
4737
  // Loop — circular arrow
3966
4738
  case "loop":
3967
4739
  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" })
4740
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4741
+ /* @__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" }),
4742
+ /* @__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
4743
  ] });
3972
4744
  // Lazy / service — cloud (deferred resolution, loaded on demand)
3973
4745
  case "lazy":
3974
4746
  case "service":
3975
4747
  case "cloud":
3976
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4748
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3977
4749
  "path",
3978
4750
  {
3979
4751
  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 +4758,22 @@ function StageIcon({ type, color }) {
3986
4758
  // Decision — diamond (already handled by isDecider shape)
3987
4759
  case "decision":
3988
4760
  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 })
4761
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { ...props, children: [
4762
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M8 2L14 8L8 14L2 8Z", stroke: color, strokeWidth: "1.5", fill: "none" }),
4763
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("circle", { cx: "8", cy: "8", r: "1.5", fill: color })
3992
4764
  ] });
3993
4765
  default:
3994
4766
  return null;
3995
4767
  }
3996
4768
  }
3997
- var StageNode = (0, import_react15.memo)(function StageNode2({
4769
+ var StageNode = (0, import_react17.memo)(function StageNode2({
3998
4770
  data
3999
4771
  }) {
4000
4772
  const { label, active, done, error, linked, icon, stepNumbers, dimmed, isSubflow, isLazy, isDecider, isFork, description, stageId, showStageId } = data;
4001
4773
  const effectiveIcon = icon || (isLazy ? "lazy" : void 0);
4002
4774
  const isLazyUnresolved = isLazy && !done && !active;
4003
- const injectedRef = (0, import_react15.useRef)(false);
4004
- (0, import_react15.useEffect)(() => {
4775
+ const injectedRef = (0, import_react17.useRef)(false);
4776
+ (0, import_react17.useEffect)(() => {
4005
4777
  if (injectedRef.current) return;
4006
4778
  if (typeof document !== "undefined" && !document.getElementById(KEYFRAMES_ID)) {
4007
4779
  const styleEl = document.createElement("style");
@@ -4022,9 +4794,9 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4022
4794
  const borderColor = active ? theme.nodeCursor : isHero && done ? theme.nodeMain : done ? theme.nodeVisited : error ? theme.error : restingBorder;
4023
4795
  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
4796
  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)(
4797
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4798
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react18.Handle, { type: "target", position: import_react18.Position.Top, style: { opacity: 0 } }),
4799
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { width: "100%", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4028
4800
  "div",
4029
4801
  {
4030
4802
  style: {
@@ -4037,7 +4809,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4037
4809
  opacity: isMuted ? 0.5 : void 0
4038
4810
  },
4039
4811
  children: [
4040
- stepNumbers && stepNumbers.length > 0 && isOnPath && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4812
+ stepNumbers && stepNumbers.length > 0 && isOnPath && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4041
4813
  "div",
4042
4814
  {
4043
4815
  style: {
@@ -4052,7 +4824,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4052
4824
  const isLatest = i === stepNumbers.length - 1;
4053
4825
  const badgeBg = isLatest && active ? theme.nodeCursor : theme.nodeVisited;
4054
4826
  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)(
4827
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4056
4828
  "div",
4057
4829
  {
4058
4830
  style: {
@@ -4075,7 +4847,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4075
4847
  })
4076
4848
  }
4077
4849
  ),
4078
- linked && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4850
+ linked && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4079
4851
  "div",
4080
4852
  {
4081
4853
  style: {
@@ -4089,7 +4861,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4089
4861
  }
4090
4862
  }
4091
4863
  ),
4092
- active && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4864
+ active && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4093
4865
  "div",
4094
4866
  {
4095
4867
  style: {
@@ -4103,7 +4875,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4103
4875
  }
4104
4876
  }
4105
4877
  ),
4106
- active && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4878
+ active && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4107
4879
  "div",
4108
4880
  {
4109
4881
  style: {
@@ -4123,8 +4895,8 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4123
4895
  children: "NOW"
4124
4896
  }
4125
4897
  ),
4126
- isDecider ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { position: "relative", width: 120, height: 72 }, children: [
4127
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4898
+ isDecider ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { position: "relative", width: 120, height: 72 }, children: [
4899
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4128
4900
  "div",
4129
4901
  {
4130
4902
  style: {
@@ -4138,7 +4910,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4138
4910
  }
4139
4911
  }
4140
4912
  ),
4141
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4913
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4142
4914
  "div",
4143
4915
  {
4144
4916
  style: {
@@ -4154,7 +4926,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4154
4926
  }
4155
4927
  }
4156
4928
  ),
4157
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4929
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4158
4930
  "div",
4159
4931
  {
4160
4932
  style: {
@@ -4169,10 +4941,10 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4169
4941
  zIndex: 1
4170
4942
  },
4171
4943
  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)(
4944
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
4945
+ effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StageIcon, { type: effectiveIcon, color: textColor }),
4946
+ !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontSize: 9, color: textColor }, children: "\u25C7" }),
4947
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4176
4948
  "span",
4177
4949
  {
4178
4950
  style: {
@@ -4185,7 +4957,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4185
4957
  }
4186
4958
  )
4187
4959
  ] }),
4188
- description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4960
+ description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4189
4961
  "span",
4190
4962
  {
4191
4963
  style: {
@@ -4201,7 +4973,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4201
4973
  children: description
4202
4974
  }
4203
4975
  ),
4204
- showStageId && stageId && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4976
+ showStageId && stageId && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4205
4977
  "span",
4206
4978
  {
4207
4979
  style: {
@@ -4223,7 +4995,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4223
4995
  )
4224
4996
  ] }) : (
4225
4997
  /* Standard rectangular node */
4226
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
4998
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4227
4999
  "div",
4228
5000
  {
4229
5001
  style: {
@@ -4242,10 +5014,10 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4242
5014
  justifyContent: "center"
4243
5015
  },
4244
5016
  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)(
5017
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
5018
+ effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StageIcon, { type: effectiveIcon, color: textColor }),
5019
+ done && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontSize: 10, color: textColor }, children: "\u2713" }),
5020
+ active && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4249
5021
  "span",
4250
5022
  {
4251
5023
  style: {
@@ -4258,8 +5030,8 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4258
5030
  }
4259
5031
  }
4260
5032
  ),
4261
- error && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontSize: 10, color: textColor }, children: "\u2717" }),
4262
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5033
+ error && !effectiveIcon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontSize: 10, color: textColor }, children: "\u2717" }),
5034
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4263
5035
  "span",
4264
5036
  {
4265
5037
  style: {
@@ -4271,7 +5043,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4271
5043
  children: label
4272
5044
  }
4273
5045
  ),
4274
- isSubflow && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5046
+ isSubflow && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4275
5047
  "span",
4276
5048
  {
4277
5049
  style: {
@@ -4286,7 +5058,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4286
5058
  opacity: 0.7,
4287
5059
  flexShrink: 0
4288
5060
  },
4289
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5061
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4290
5062
  "span",
4291
5063
  {
4292
5064
  style: {
@@ -4300,7 +5072,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4300
5072
  }
4301
5073
  )
4302
5074
  ] }),
4303
- description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5075
+ description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4304
5076
  "span",
4305
5077
  {
4306
5078
  style: {
@@ -4316,7 +5088,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4316
5088
  children: description
4317
5089
  }
4318
5090
  ),
4319
- showStageId && stageId && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5091
+ showStageId && stageId && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4320
5092
  "span",
4321
5093
  {
4322
5094
  style: {
@@ -4340,7 +5112,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
4340
5112
  ]
4341
5113
  }
4342
5114
  ) }),
4343
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react16.Handle, { type: "source", position: import_react16.Position.Bottom, style: { opacity: 0 } })
5115
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react18.Handle, { type: "source", position: import_react18.Position.Bottom, style: { opacity: 0 } })
4344
5116
  ] });
4345
5117
  });
4346
5118
 
@@ -4392,18 +5164,18 @@ function aggregateMountStatus(slice, graph, currentSubflowId) {
4392
5164
  }
4393
5165
 
4394
5166
  // src/components/FlowchartView/_internal/useSubflowDrill.ts
4395
- var import_react17 = require("react");
5167
+ var import_react19 = require("react");
4396
5168
  function useSubflowDrill(graph, onSubflowChange) {
4397
- const [currentSubflowId, setCurrentSubflowId] = (0, import_react17.useState)(null);
4398
- const lastGraphRef = (0, import_react17.useRef)(null);
5169
+ const [currentSubflowId, setCurrentSubflowId] = (0, import_react19.useState)(null);
5170
+ const lastGraphRef = (0, import_react19.useRef)(null);
4399
5171
  if (lastGraphRef.current !== graph) {
4400
5172
  lastGraphRef.current = graph;
4401
5173
  if (currentSubflowId !== null && !graph.nodes.some((n) => n.data?.subflowId === currentSubflowId)) {
4402
5174
  queueMicrotask(() => setCurrentSubflowId(null));
4403
5175
  }
4404
5176
  }
4405
- const lastNotifiedRef = (0, import_react17.useRef)(void 0);
4406
- (0, import_react17.useEffect)(() => {
5177
+ const lastNotifiedRef = (0, import_react19.useRef)(void 0);
5178
+ (0, import_react19.useEffect)(() => {
4407
5179
  if (lastNotifiedRef.current === currentSubflowId) return;
4408
5180
  lastNotifiedRef.current = currentSubflowId;
4409
5181
  if (currentSubflowId === null) {
@@ -4413,22 +5185,22 @@ function useSubflowDrill(graph, onSubflowChange) {
4413
5185
  if (mount) onSubflowChange?.(mount.id);
4414
5186
  }
4415
5187
  }, [currentSubflowId, graph, onSubflowChange]);
4416
- const drillInto = (0, import_react17.useCallback)((subflowId) => {
5188
+ const drillInto = (0, import_react19.useCallback)((subflowId) => {
4417
5189
  setCurrentSubflowId(subflowId);
4418
5190
  }, []);
4419
- const drillUp = (0, import_react17.useCallback)(() => {
5191
+ const drillUp = (0, import_react19.useCallback)(() => {
4420
5192
  setCurrentSubflowId(null);
4421
5193
  }, []);
4422
5194
  return { currentSubflowId, drillInto, drillUp, setCurrentSubflowId };
4423
5195
  }
4424
5196
 
4425
5197
  // src/components/FlowchartView/_internal/useChartAutoRefit.ts
4426
- var import_react18 = require("react");
5198
+ var import_react20 = require("react");
4427
5199
  function useChartAutoRefit(wrapperRef, rfInstance, options = {}) {
4428
5200
  const duration = options.duration ?? 200;
4429
5201
  const padding2 = options.padding ?? 0.1;
4430
5202
  const refitKey = options.refitKey;
4431
- (0, import_react18.useEffect)(() => {
5203
+ (0, import_react20.useEffect)(() => {
4432
5204
  const el = wrapperRef.current;
4433
5205
  if (!el || !rfInstance) return;
4434
5206
  let raf = 0;
@@ -4447,7 +5219,7 @@ function useChartAutoRefit(wrapperRef, rfInstance, options = {}) {
4447
5219
  cancelAnimationFrame(raf);
4448
5220
  };
4449
5221
  }, [rfInstance, wrapperRef, duration, padding2]);
4450
- (0, import_react18.useEffect)(() => {
5222
+ (0, import_react20.useEffect)(() => {
4451
5223
  if (!rfInstance) return;
4452
5224
  let raf2 = 0;
4453
5225
  const raf1 = requestAnimationFrame(() => {
@@ -4463,9 +5235,9 @@ function useChartAutoRefit(wrapperRef, rfInstance, options = {}) {
4463
5235
  }
4464
5236
 
4465
5237
  // src/components/FlowchartView/SubflowBreadcrumbBar.tsx
4466
- var import_jsx_runtime17 = require("react/jsx-runtime");
5238
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4467
5239
  function SubflowBreadcrumbBar({ entries, onNavigate }) {
4468
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5240
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4469
5241
  "div",
4470
5242
  {
4471
5243
  style: {
@@ -4481,12 +5253,12 @@ function SubflowBreadcrumbBar({ entries, onNavigate }) {
4481
5253
  "aria-label": "Subflow breadcrumb",
4482
5254
  children: entries.map((entry, i) => {
4483
5255
  const isLast = i === entries.length - 1;
4484
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5256
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4485
5257
  "span",
4486
5258
  {
4487
5259
  style: { display: "inline-flex", alignItems: "center", gap: 6 },
4488
5260
  children: [
4489
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5261
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4490
5262
  "button",
4491
5263
  {
4492
5264
  type: "button",
@@ -4506,7 +5278,7 @@ function SubflowBreadcrumbBar({ entries, onNavigate }) {
4506
5278
  children: entry.label
4507
5279
  }
4508
5280
  ),
4509
- !isLast && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { color: theme.textMuted }, children: "\u203A" })
5281
+ !isLast && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { color: theme.textMuted }, children: "\u203A" })
4510
5282
  ]
4511
5283
  },
4512
5284
  entry.subflowId ?? "__top__"
@@ -4517,12 +5289,12 @@ function SubflowBreadcrumbBar({ entries, onNavigate }) {
4517
5289
  }
4518
5290
 
4519
5291
  // src/components/GroupContainerNode/GroupContainerNode.tsx
4520
- var import_react19 = require("@xyflow/react");
4521
- var import_jsx_runtime18 = require("react/jsx-runtime");
5292
+ var import_react21 = require("@xyflow/react");
5293
+ var import_jsx_runtime20 = require("react/jsx-runtime");
4522
5294
  function GroupContainerNode({ data }) {
4523
5295
  const d = data;
4524
5296
  const borderColor = d.error ? theme.error : d.active ? theme.primary : d.done ? theme.nodeVisited : theme.border;
4525
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5297
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4526
5298
  "div",
4527
5299
  {
4528
5300
  style: {
@@ -4538,7 +5310,7 @@ function GroupContainerNode({ data }) {
4538
5310
  position: "relative"
4539
5311
  },
4540
5312
  children: [
4541
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5313
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4542
5314
  "div",
4543
5315
  {
4544
5316
  style: {
@@ -4552,20 +5324,20 @@ function GroupContainerNode({ data }) {
4552
5324
  letterSpacing: 0.2
4553
5325
  },
4554
5326
  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 })
5327
+ d.icon ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { "aria-hidden": true, children: d.icon }) : null,
5328
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: d.label })
4557
5329
  ]
4558
5330
  }
4559
5331
  ),
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 } })
5332
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react21.Handle, { type: "target", position: import_react21.Position.Top, style: { opacity: 0 } }),
5333
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react21.Handle, { type: "source", position: import_react21.Position.Bottom, style: { opacity: 0 } })
4562
5334
  ]
4563
5335
  }
4564
5336
  );
4565
5337
  }
4566
5338
 
4567
5339
  // src/components/LoopBackEdge/LoopBackEdge.tsx
4568
- var import_react20 = require("@xyflow/react");
5340
+ var import_react22 = require("@xyflow/react");
4569
5341
 
4570
5342
  // src/components/FlowchartView/_internal/loopRouting.ts
4571
5343
  var LOOP_LANE_GAP = 56;
@@ -4784,7 +5556,7 @@ function wrapInMainChartBox(graph, opts) {
4784
5556
  }
4785
5557
 
4786
5558
  // src/components/LoopBackEdge/LoopBackEdge.tsx
4787
- var import_jsx_runtime19 = require("react/jsx-runtime");
5559
+ var import_jsx_runtime21 = require("react/jsx-runtime");
4788
5560
  var LOOP_DASH = "5 5";
4789
5561
  var LOOP_STROKE_OPACITY_CAP = 0.55;
4790
5562
  var LOOP_STROKE_WIDTH = 1.5;
@@ -4805,7 +5577,7 @@ function centerY(node) {
4805
5577
  return node.internals.positionAbsolute.y + (node.measured.height ?? 0) / 2;
4806
5578
  }
4807
5579
  function LoopBackEdge({ id, source, target, markerEnd, style }) {
4808
- const path = (0, import_react20.useStore)((s) => {
5580
+ const path = (0, import_react22.useStore)((s) => {
4809
5581
  const src = s.nodeLookup.get(source);
4810
5582
  const tgt = s.nodeLookup.get(target);
4811
5583
  if (!src || !tgt) return "";
@@ -4823,8 +5595,8 @@ function LoopBackEdge({ id, source, target, markerEnd, style }) {
4823
5595
  );
4824
5596
  });
4825
5597
  if (!path) return null;
4826
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4827
- import_react20.BaseEdge,
5598
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5599
+ import_react22.BaseEdge,
4828
5600
  {
4829
5601
  id,
4830
5602
  path,
@@ -4836,8 +5608,8 @@ function LoopBackEdge({ id, source, target, markerEnd, style }) {
4836
5608
  }
4837
5609
 
4838
5610
  // src/components/SmartStepEdge/SmartStepEdge.tsx
4839
- var import_react21 = require("@xyflow/react");
4840
- var import_react22 = require("@xyflow/react");
5611
+ var import_react23 = require("@xyflow/react");
5612
+ var import_react24 = require("@xyflow/react");
4841
5613
 
4842
5614
  // src/components/FlowchartView/_internal/stepRouting.ts
4843
5615
  function staggeredBendY(sourceBottom, targetTop, others, minGapFromTarget = 8) {
@@ -4861,7 +5633,7 @@ function resolveStepBendY(forkBend, staggeredBend) {
4861
5633
  }
4862
5634
 
4863
5635
  // src/components/SmartStepEdge/SmartStepEdge.tsx
4864
- var import_jsx_runtime20 = require("react/jsx-runtime");
5636
+ var import_jsx_runtime22 = require("react/jsx-runtime");
4865
5637
  function SmartStepEdge({
4866
5638
  id,
4867
5639
  source,
@@ -4875,7 +5647,7 @@ function SmartStepEdge({
4875
5647
  markerEnd,
4876
5648
  style
4877
5649
  }) {
4878
- const bendY = (0, import_react21.useStore)((s) => {
5650
+ const bendY = (0, import_react23.useStore)((s) => {
4879
5651
  const src = s.nodeLookup.get(source);
4880
5652
  const tgt = s.nodeLookup.get(target);
4881
5653
  if (!src || !tgt) return null;
@@ -4901,23 +5673,23 @@ function SmartStepEdge({
4901
5673
  const staggered = staggeredBendY(sourceBottom, targetTop, others);
4902
5674
  return resolveStepBendY(fan, staggered);
4903
5675
  });
4904
- const [path] = (0, import_react21.getSmoothStepPath)({
5676
+ const [path] = (0, import_react23.getSmoothStepPath)({
4905
5677
  sourceX,
4906
5678
  sourceY,
4907
- sourcePosition: sourcePosition ?? import_react22.Position.Bottom,
5679
+ sourcePosition: sourcePosition ?? import_react24.Position.Bottom,
4908
5680
  targetX,
4909
5681
  targetY,
4910
- targetPosition: targetPosition ?? import_react22.Position.Top,
5682
+ targetPosition: targetPosition ?? import_react24.Position.Top,
4911
5683
  // Override the bend only for a staggered edge; otherwise let getSmoothStepPath
4912
5684
  // use its default centerY (== the built-in `smoothstep` path, byte-for-byte).
4913
5685
  ...bendY !== null ? { centerY: bendY } : {}
4914
5686
  });
4915
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react21.BaseEdge, { id, path, markerEnd, style });
5687
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react23.BaseEdge, { id, path, markerEnd, style });
4916
5688
  }
4917
5689
 
4918
5690
  // src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
4919
- var import_react23 = require("react");
4920
- var import_react24 = require("@xyflow/react");
5691
+ var import_react25 = require("react");
5692
+ var import_react26 = require("@xyflow/react");
4921
5693
 
4922
5694
  // src/components/FlowchartView/_internal/measuredFootprints.ts
4923
5695
  function extractMeasuredFootprints(entries) {
@@ -4946,12 +5718,12 @@ function MeasuredNodeSizes({
4946
5718
  onSizes,
4947
5719
  includeHiddenNodes = false
4948
5720
  }) {
4949
- const initialized = (0, import_react24.useNodesInitialized)({ includeHiddenNodes });
4950
- const sizes = (0, import_react24.useStore)(
5721
+ const initialized = (0, import_react26.useNodesInitialized)({ includeHiddenNodes });
5722
+ const sizes = (0, import_react26.useStore)(
4951
5723
  (s) => extractMeasuredFootprints(s.nodeLookup),
4952
5724
  sameFootprints
4953
5725
  );
4954
- (0, import_react23.useEffect)(() => {
5726
+ (0, import_react25.useEffect)(() => {
4955
5727
  if (!initialized || sizes.size === 0) return;
4956
5728
  onSizes(sizes);
4957
5729
  }, [initialized, sizes, onSizes]);
@@ -4959,7 +5731,7 @@ function MeasuredNodeSizes({
4959
5731
  }
4960
5732
 
4961
5733
  // src/components/FlowchartView/TracedFlow.tsx
4962
- var import_jsx_runtime21 = require("react/jsx-runtime");
5734
+ var import_jsx_runtime23 = require("react/jsx-runtime");
4963
5735
  var DEFAULT_COLORS = {
4964
5736
  default: rawDefaults.colors.textMuted,
4965
5737
  done: rawDefaults.colors.success,
@@ -5067,7 +5839,7 @@ function styleEdgeWithOverlay(edge, doneStageIds, activeStageId, colors) {
5067
5839
  type: kind === "loop" ? "loopBack" : "smartStep",
5068
5840
  animated: isLeadingEdge,
5069
5841
  style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },
5070
- markerEnd: { type: import_react26.MarkerType.ArrowClosed, color, width: 16, height: 16 }
5842
+ markerEnd: { type: import_react28.MarkerType.ArrowClosed, color, width: 16, height: 16 }
5071
5843
  };
5072
5844
  if (kind === "loop") {
5073
5845
  styled.style = { ...styled.style, strokeDasharray: "4 3" };
@@ -5098,28 +5870,28 @@ function TracedFlow({
5098
5870
  style
5099
5871
  }) {
5100
5872
  const layout = layoutProp ?? dagreTraceLayout;
5101
- (0, import_react25.useEffect)(() => {
5873
+ (0, import_react27.useEffect)(() => {
5102
5874
  if (layoutProp === dagreTraceLayout) {
5103
5875
  devWarn(
5104
5876
  () => "[footprint-explainable-ui] <TracedFlow layout={dagreTraceLayout}> bypasses the built-in measure-then-layout pipeline (content-exact sizing, fork/merge centering, straight spines). OMIT the `layout` prop to use it \u2014 passing the raw dagreTraceLayout silently forfeits every layout improvement eui ships."
5105
5877
  );
5106
5878
  }
5107
5879
  }, [layoutProp]);
5108
- const colors = (0, import_react25.useMemo)(
5880
+ const colors = (0, import_react27.useMemo)(
5109
5881
  () => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
5110
5882
  [colorOverrides]
5111
5883
  );
5112
- const mergedNodeTypes = (0, import_react25.useMemo)(
5884
+ const mergedNodeTypes = (0, import_react27.useMemo)(
5113
5885
  () => userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES,
5114
5886
  [userNodeTypes]
5115
5887
  );
5116
- const mergedEdgeTypes = (0, import_react25.useMemo)(
5888
+ const mergedEdgeTypes = (0, import_react27.useMemo)(
5117
5889
  () => userEdgeTypes ? { ...DEFAULT_EDGE_TYPES, ...userEdgeTypes } : DEFAULT_EDGE_TYPES,
5118
5890
  [userEdgeTypes]
5119
5891
  );
5120
5892
  const drill = useSubflowDrill(graph, onSubflowChange);
5121
- const groupedSet = (0, import_react25.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
5122
- const filteredGraph = (0, import_react25.useMemo)(() => {
5893
+ const groupedSet = (0, import_react27.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
5894
+ const filteredGraph = (0, import_react27.useMemo)(() => {
5123
5895
  const base = filterGraphForDrill(graph, drill.currentSubflowId);
5124
5896
  if (groupedSet.size === 0) return base;
5125
5897
  const baseIds = new Set(base.nodes.map((n) => n.id));
@@ -5134,12 +5906,12 @@ function TracedFlow({
5134
5906
  );
5135
5907
  return { nodes: [...base.nodes, ...extraNodes], edges: [...base.edges, ...extraEdges] };
5136
5908
  }, [graph, drill.currentSubflowId, groupedSet]);
5137
- const breadcrumb = (0, import_react25.useMemo)(
5909
+ const breadcrumb = (0, import_react27.useMemo)(
5138
5910
  () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),
5139
5911
  [graph, drill.currentSubflowId]
5140
5912
  );
5141
- const [measuredSizes, setMeasuredSizes] = (0, import_react25.useState)(null);
5142
- const positioned = (0, import_react25.useMemo)(() => {
5913
+ const [measuredSizes, setMeasuredSizes] = (0, import_react27.useState)(null);
5914
+ const positioned = (0, import_react27.useMemo)(() => {
5143
5915
  const nodeSize = measuredSizes ? (n) => measuredSizes.get(n.id) : void 0;
5144
5916
  const sizeOpts = nodeSize ? { nodeSize } : {};
5145
5917
  const dagreBase = withForkCentering(
@@ -5163,7 +5935,7 @@ function TracedFlow({
5163
5935
  }
5164
5936
  return realBase(filteredGraph);
5165
5937
  }, [filteredGraph, layout, layoutProp, groupedSet, mainChartBox, measuredSizes]);
5166
- const slice = (0, import_react25.useMemo)(() => {
5938
+ const slice = (0, import_react27.useMemo)(() => {
5167
5939
  const empty = {
5168
5940
  doneStageIds: /* @__PURE__ */ new Set(),
5169
5941
  activeStageId: null,
@@ -5175,7 +5947,7 @@ function TracedFlow({
5175
5947
  const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);
5176
5948
  return aggregateMountStatus(sliceOverlay(overlay, idx), graph, drill.currentSubflowId);
5177
5949
  }, [overlay, scrubIndex, graph, drill.currentSubflowId]);
5178
- const reactFlowNodes = (0, import_react25.useMemo)(
5950
+ const reactFlowNodes = (0, import_react27.useMemo)(
5179
5951
  () => positioned.nodes.map(
5180
5952
  (n) => toStageNodeWithOverlay(
5181
5953
  n,
@@ -5188,20 +5960,20 @@ function TracedFlow({
5188
5960
  ),
5189
5961
  [positioned.nodes, slice, coActiveStageIds]
5190
5962
  );
5191
- const reactFlowEdges = (0, import_react25.useMemo)(
5963
+ const reactFlowEdges = (0, import_react27.useMemo)(
5192
5964
  () => positioned.edges.map(
5193
5965
  (e) => styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors)
5194
5966
  ),
5195
5967
  [positioned.edges, slice, colors]
5196
5968
  );
5197
- const [coneRevealed, setConeRevealed] = (0, import_react25.useState)(false);
5198
- (0, import_react25.useEffect)(() => {
5969
+ const [coneRevealed, setConeRevealed] = (0, import_react27.useState)(false);
5970
+ (0, import_react27.useEffect)(() => {
5199
5971
  if (!sliceCone) return;
5200
5972
  setConeRevealed(false);
5201
5973
  const raf = requestAnimationFrame(() => setConeRevealed(true));
5202
5974
  return () => cancelAnimationFrame(raf);
5203
5975
  }, [sliceCone]);
5204
- const conedNodes = (0, import_react25.useMemo)(() => {
5976
+ const conedNodes = (0, import_react27.useMemo)(() => {
5205
5977
  if (!sliceCone || sliceCone.size === 0) return reactFlowNodes;
5206
5978
  return reactFlowNodes.map((n) => {
5207
5979
  const depth = sliceCone.get(n.id);
@@ -5219,14 +5991,14 @@ function TracedFlow({
5219
5991
  };
5220
5992
  });
5221
5993
  }, [reactFlowNodes, sliceCone, coneRevealed]);
5222
- const conedEdges = (0, import_react25.useMemo)(() => {
5994
+ const conedEdges = (0, import_react27.useMemo)(() => {
5223
5995
  if (!sliceCone || sliceCone.size === 0) return reactFlowEdges;
5224
5996
  return reactFlowEdges.map((e) => {
5225
5997
  const inCone = sliceCone.has(e.source) && sliceCone.has(e.target);
5226
5998
  return inCone ? e : { ...e, style: { ...e.style, opacity: 0.12, transition: "opacity 260ms ease" } };
5227
5999
  });
5228
6000
  }, [reactFlowEdges, sliceCone]);
5229
- const handleNodeClick = (0, import_react25.useCallback)(
6001
+ const handleNodeClick = (0, import_react27.useCallback)(
5230
6002
  (_, node) => {
5231
6003
  const data = node.data ?? {};
5232
6004
  if (data.isSubflow && data.subflowId && !groupedSet.has(data.subflowId)) {
@@ -5236,14 +6008,14 @@ function TracedFlow({
5236
6008
  },
5237
6009
  [drill, onNodeClick, groupedSet]
5238
6010
  );
5239
- const wrapperRef = (0, import_react25.useRef)(null);
5240
- const [rfInstance, setRfInstance] = (0, import_react25.useState)(null);
6011
+ const wrapperRef = (0, import_react27.useRef)(null);
6012
+ const [rfInstance, setRfInstance] = (0, import_react27.useState)(null);
5241
6013
  useChartAutoRefit(wrapperRef, rfInstance, {
5242
6014
  // Re-fit on drill AND after the measured-size re-layout settles.
5243
6015
  refitKey: `${drill.currentSubflowId ?? ""}:${measuredSizes ? "measured" : "estimated"}`,
5244
6016
  padding: 0.18
5245
6017
  });
5246
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
6018
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5247
6019
  "div",
5248
6020
  {
5249
6021
  ref: wrapperRef,
@@ -5257,15 +6029,15 @@ function TracedFlow({
5257
6029
  ...style
5258
6030
  },
5259
6031
  children: [
5260
- breadcrumb.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6032
+ breadcrumb.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5261
6033
  SubflowBreadcrumbBar,
5262
6034
  {
5263
6035
  entries: breadcrumb,
5264
6036
  onNavigate: drill.setCurrentSubflowId
5265
6037
  }
5266
6038
  ),
5267
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
5268
- import_react26.ReactFlow,
6039
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6040
+ import_react28.ReactFlow,
5269
6041
  {
5270
6042
  nodes: conedNodes,
5271
6043
  edges: conedEdges,
@@ -5278,8 +6050,8 @@ function TracedFlow({
5278
6050
  minZoom: 0.1,
5279
6051
  proOptions: { hideAttribution: true },
5280
6052
  children: [
5281
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MeasuredNodeSizes, { onSizes: setMeasuredSizes }),
5282
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react26.Background, { variant: import_react26.BackgroundVariant.Dots, gap: 20, size: 1 }),
6053
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(MeasuredNodeSizes, { onSizes: setMeasuredSizes }),
6054
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.Background, { variant: import_react28.BackgroundVariant.Dots, gap: 20, size: 1 }),
5283
6055
  children
5284
6056
  ]
5285
6057
  }
@@ -5290,187 +6062,27 @@ function TracedFlow({
5290
6062
  }
5291
6063
 
5292
6064
  // src/components/InspectorPanel/InspectorPanel.tsx
5293
- var import_react28 = require("react");
5294
-
5295
- // src/components/DataTracePanel/DataTracePanel.tsx
5296
- var import_react27 = require("react");
5297
- var import_jsx_runtime22 = require("react/jsx-runtime");
5298
- var DataTracePanel = (0, import_react27.memo)(function DataTracePanel2({
5299
- frames,
5300
- selectedStageId,
5301
- onFrameClick,
5302
- fromStageName,
5303
- note
5304
- }) {
5305
- const noteLine = note ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", marginBottom: 8 }, children: note }) : null;
5306
- if (frames.length === 0) {
5307
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
5308
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5309
- "div",
5310
- {
5311
- style: {
5312
- fontSize: 11,
5313
- color: theme.textMuted,
5314
- textTransform: "uppercase",
5315
- letterSpacing: "0.5px",
5316
- fontWeight: 600,
5317
- marginBottom: 6
5318
- },
5319
- children: "Backward causal chain"
5320
- }
5321
- ),
5322
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: theme.textSecondary, marginBottom: 10 }, children: "Trace any value back to the stage that created it \u2014 and everything upstream that influenced it." }),
5323
- noteLine,
5324
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: theme.textMuted, fontSize: 12 }, children: "Select a stage above to see its dependency chain." })
5325
- ] });
5326
- }
5327
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "8px 0", fontSize: 13 }, children: [
5328
- note && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { padding: "4px 12px 0", fontSize: 11, color: theme.textMuted, fontStyle: "italic" }, children: note }),
5329
- fromStageName && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "4px 12px 8px" }, children: [
5330
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5331
- "div",
5332
- {
5333
- style: {
5334
- fontSize: 11,
5335
- color: theme.textMuted,
5336
- textTransform: "uppercase",
5337
- letterSpacing: "0.5px",
5338
- fontWeight: 600
5339
- },
5340
- children: [
5341
- "Data trace from ",
5342
- fromStageName
5343
- ]
5344
- }
5345
- ),
5346
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5347
- "div",
5348
- {
5349
- style: {
5350
- fontSize: 11,
5351
- color: theme.textMuted,
5352
- fontStyle: "italic",
5353
- marginTop: 3
5354
- },
5355
- children: "Every value here was derived from the stages below."
5356
- }
5357
- )
5358
- ] }),
5359
- frames.map((frame, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5360
- DataTraceFrame,
5361
- {
5362
- frame,
5363
- isFirst: i === 0,
5364
- isLast: i === frames.length - 1,
5365
- isSelected: frame.runtimeStageId === selectedStageId,
5366
- onClick: onFrameClick
5367
- },
5368
- frame.runtimeStageId
5369
- ))
5370
- ] });
5371
- });
5372
- var DataTraceFrame = (0, import_react27.memo)(function DataTraceFrame2({
5373
- frame,
5374
- isFirst,
5375
- isLast,
5376
- isSelected,
5377
- onClick
5378
- }) {
5379
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5380
- "button",
5381
- {
5382
- onClick: () => onClick?.(frame.runtimeStageId),
5383
- style: {
5384
- display: "block",
5385
- width: "100%",
5386
- textAlign: "left",
5387
- border: "none",
5388
- background: isSelected ? "var(--fp-accent-bg, rgba(99,102,241,0.12))" : "transparent",
5389
- padding: "6px 12px 6px 16px",
5390
- cursor: onClick ? "pointer" : "default",
5391
- borderLeft: isSelected ? "3px solid var(--fp-accent, #6366f1)" : "3px solid transparent",
5392
- color: "inherit",
5393
- fontSize: 13
5394
- },
5395
- children: [
5396
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
5397
- !isFirst && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { color: theme.textMuted, fontSize: 11 }, children: "\u2191" }),
5398
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5399
- "span",
5400
- {
5401
- style: {
5402
- fontWeight: isFirst ? 600 : 400,
5403
- color: isFirst ? "var(--fp-accent, #6366f1)" : theme.textPrimary
5404
- },
5405
- children: frame.stageName
5406
- }
5407
- ),
5408
- isLast && !isFirst && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5409
- "span",
5410
- {
5411
- style: {
5412
- fontSize: 10,
5413
- color: theme.textMuted,
5414
- fontStyle: "italic"
5415
- },
5416
- children: "(origin)"
5417
- }
5418
- )
5419
- ] }),
5420
- frame.keysWritten.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5421
- "div",
5422
- {
5423
- style: {
5424
- fontSize: 11,
5425
- color: theme.textMuted,
5426
- paddingLeft: isFirst ? 0 : 18,
5427
- marginTop: 2
5428
- },
5429
- children: [
5430
- "wrote:",
5431
- " ",
5432
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { color: theme.textSecondary }, children: frame.keysWritten.join(", ") })
5433
- ]
5434
- }
5435
- ),
5436
- frame.linkedBy && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
5437
- "div",
5438
- {
5439
- style: {
5440
- fontSize: 11,
5441
- color: "var(--fp-accent, #6366f1)",
5442
- paddingLeft: 18,
5443
- marginTop: 1
5444
- },
5445
- children: [
5446
- "\u2190 via ",
5447
- frame.linkedBy
5448
- ]
5449
- }
5450
- )
5451
- ]
5452
- }
5453
- );
5454
- });
5455
-
5456
- // src/components/InspectorPanel/InspectorPanel.tsx
5457
- var import_jsx_runtime23 = require("react/jsx-runtime");
5458
- var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
6065
+ var import_react29 = require("react");
6066
+ var import_jsx_runtime24 = require("react/jsx-runtime");
6067
+ var InspectorPanel = (0, import_react29.memo)(function InspectorPanel2({
5459
6068
  snapshots,
5460
6069
  selectedIndex,
5461
6070
  dataTraceFrames,
5462
6071
  dataTraceNote,
5463
6072
  selectedStageId,
5464
6073
  onNavigateToStage,
5465
- onTabChange
6074
+ onTabChange,
6075
+ tab: controlledTab,
6076
+ traceContent
5466
6077
  }) {
5467
- const [tab, setTabState] = (0, import_react28.useState)("state");
6078
+ const [internalTab, setTabState] = (0, import_react29.useState)("state");
6079
+ const tab = controlledTab ?? internalTab;
5468
6080
  const setTab = (t) => {
5469
6081
  setTabState(t);
5470
6082
  onTabChange?.(t);
5471
6083
  };
5472
6084
  const currentSnapshot = snapshots[selectedIndex];
5473
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6085
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5474
6086
  "div",
5475
6087
  {
5476
6088
  style: {
@@ -5480,7 +6092,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5480
6092
  overflow: "hidden"
5481
6093
  },
5482
6094
  children: [
5483
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6095
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5484
6096
  "div",
5485
6097
  {
5486
6098
  style: {
@@ -5489,7 +6101,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5489
6101
  flexShrink: 0
5490
6102
  },
5491
6103
  children: [
5492
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6104
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5493
6105
  TabButton,
5494
6106
  {
5495
6107
  active: tab === "state",
@@ -5497,7 +6109,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5497
6109
  label: "State"
5498
6110
  }
5499
6111
  ),
5500
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6112
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5501
6113
  TabButton,
5502
6114
  {
5503
6115
  active: tab === "trace",
@@ -5509,15 +6121,15 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5509
6121
  ]
5510
6122
  }
5511
6123
  ),
5512
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
5513
- tab === "state" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6124
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
6125
+ tab === "state" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5514
6126
  MemoryPanel,
5515
6127
  {
5516
6128
  snapshots,
5517
6129
  selectedIndex
5518
6130
  }
5519
6131
  ),
5520
- tab === "trace" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6132
+ tab === "trace" && (traceContent ?? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5521
6133
  DataTracePanel,
5522
6134
  {
5523
6135
  frames: dataTraceFrames,
@@ -5526,7 +6138,7 @@ var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
5526
6138
  onFrameClick: onNavigateToStage,
5527
6139
  fromStageName: currentSnapshot?.stageName
5528
6140
  }
5529
- )
6141
+ ))
5530
6142
  ] })
5531
6143
  ]
5532
6144
  }
@@ -5538,7 +6150,7 @@ function TabButton({
5538
6150
  label,
5539
6151
  badge
5540
6152
  }) {
5541
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
6153
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5542
6154
  "button",
5543
6155
  {
5544
6156
  onClick,
@@ -5557,7 +6169,7 @@ function TabButton({
5557
6169
  },
5558
6170
  children: [
5559
6171
  label,
5560
- badge && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6172
+ badge && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5561
6173
  "span",
5562
6174
  {
5563
6175
  style: {
@@ -5577,28 +6189,28 @@ function TabButton({
5577
6189
  }
5578
6190
 
5579
6191
  // src/components/InsightPanel/InsightPanel.tsx
5580
- var import_react29 = require("react");
5581
- var import_jsx_runtime24 = require("react/jsx-runtime");
5582
- var InsightPanel = (0, import_react29.memo)(function InsightPanel2({
6192
+ var import_react30 = require("react");
6193
+ var import_jsx_runtime25 = require("react/jsx-runtime");
6194
+ var InsightPanel = (0, import_react30.memo)(function InsightPanel2({
5583
6195
  insights,
5584
6196
  expandedId,
5585
6197
  mode
5586
6198
  }) {
5587
6199
  if (insights.length === 0) {
5588
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { padding: 12, color: theme.textMuted, fontSize: 13 }, children: "No insights available. Attach recorders to see data." });
6200
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { padding: 12, color: theme.textMuted, fontSize: 13 }, children: "No insights available. Attach recorders to see data." });
5589
6201
  }
5590
6202
  if (mode === "grid") {
5591
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(InsightGrid, { insights });
6203
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InsightGrid, { insights });
5592
6204
  }
5593
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(InsightTabs, { insights, defaultId: expandedId });
6205
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InsightTabs, { insights, defaultId: expandedId });
5594
6206
  });
5595
- var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
6207
+ var InsightTabs = (0, import_react30.memo)(function InsightTabs2({
5596
6208
  insights,
5597
6209
  defaultId
5598
6210
  }) {
5599
- const [activeId, setActiveId] = (0, import_react29.useState)(defaultId ?? insights[0]?.id);
6211
+ const [activeId, setActiveId] = (0, import_react30.useState)(defaultId ?? insights[0]?.id);
5600
6212
  const active = insights.find((i) => i.id === activeId) ?? insights[0];
5601
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6213
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5602
6214
  "div",
5603
6215
  {
5604
6216
  style: {
@@ -5608,7 +6220,7 @@ var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
5608
6220
  overflow: "hidden"
5609
6221
  },
5610
6222
  children: [
5611
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6223
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5612
6224
  "div",
5613
6225
  {
5614
6226
  style: {
@@ -5617,7 +6229,7 @@ var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
5617
6229
  flexShrink: 0,
5618
6230
  overflowX: "auto"
5619
6231
  },
5620
- children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6232
+ children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5621
6233
  "button",
5622
6234
  {
5623
6235
  onClick: () => setActiveId(insight.id),
@@ -5638,16 +6250,16 @@ var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
5638
6250
  ))
5639
6251
  }
5640
6252
  ),
5641
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: active?.render() })
6253
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: active?.render() })
5642
6254
  ]
5643
6255
  }
5644
6256
  );
5645
6257
  });
5646
- var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
6258
+ var InsightGrid = (0, import_react30.memo)(function InsightGrid2({
5647
6259
  insights
5648
6260
  }) {
5649
6261
  const cols = insights.length <= 2 ? 1 : 2;
5650
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6262
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5651
6263
  "div",
5652
6264
  {
5653
6265
  style: {
@@ -5658,7 +6270,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5658
6270
  gap: 1,
5659
6271
  background: theme.border
5660
6272
  },
5661
- children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6273
+ children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5662
6274
  "div",
5663
6275
  {
5664
6276
  style: {
@@ -5668,7 +6280,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5668
6280
  overflow: "hidden"
5669
6281
  },
5670
6282
  children: [
5671
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
6283
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5672
6284
  "div",
5673
6285
  {
5674
6286
  style: {
@@ -5683,7 +6295,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5683
6295
  },
5684
6296
  children: [
5685
6297
  insight.name,
5686
- insight.summary && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6298
+ insight.summary && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5687
6299
  "span",
5688
6300
  {
5689
6301
  style: {
@@ -5698,7 +6310,7 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5698
6310
  ]
5699
6311
  }
5700
6312
  ),
5701
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: insight.render() })
6313
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: insight.render() })
5702
6314
  ]
5703
6315
  },
5704
6316
  insight.id
@@ -5708,17 +6320,17 @@ var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
5708
6320
  });
5709
6321
 
5710
6322
  // src/components/CompactTimeline/CompactTimeline.tsx
5711
- var import_react30 = require("react");
5712
- var import_jsx_runtime25 = require("react/jsx-runtime");
5713
- var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
6323
+ var import_react31 = require("react");
6324
+ var import_jsx_runtime26 = require("react/jsx-runtime");
6325
+ var CompactTimeline = (0, import_react31.memo)(function CompactTimeline2({
5714
6326
  snapshots,
5715
6327
  selectedIndex,
5716
6328
  defaultExpanded = false
5717
6329
  }) {
5718
- const [expanded, setExpanded] = (0, import_react30.useState)(defaultExpanded);
6330
+ const [expanded, setExpanded] = (0, import_react31.useState)(defaultExpanded);
5719
6331
  if (snapshots.length === 0) return null;
5720
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
5721
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6332
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
6333
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5722
6334
  "button",
5723
6335
  {
5724
6336
  onClick: () => setExpanded((e) => !e),
@@ -5738,13 +6350,13 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5738
6350
  letterSpacing: "0.5px"
5739
6351
  },
5740
6352
  children: [
5741
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { style: { fontSize: 10 }, children: expanded ? "\u25BC" : "\u25B8" }),
6353
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontSize: 10 }, children: expanded ? "\u25BC" : "\u25B8" }),
5742
6354
  "Timeline",
5743
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { style: { fontWeight: 400, fontSize: 10 }, children: [
6355
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { style: { fontWeight: 400, fontSize: 10 }, children: [
5744
6356
  snapshots.length,
5745
6357
  " stages"
5746
6358
  ] }),
5747
- !expanded && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6359
+ !expanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5748
6360
  "div",
5749
6361
  {
5750
6362
  style: {
@@ -5755,7 +6367,7 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5755
6367
  marginLeft: 8
5756
6368
  },
5757
6369
  children: [
5758
- snapshots.map((snap, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6370
+ snapshots.map((snap, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5759
6371
  "div",
5760
6372
  {
5761
6373
  style: {
@@ -5770,7 +6382,7 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5770
6382
  },
5771
6383
  i
5772
6384
  )),
5773
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6385
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5774
6386
  "div",
5775
6387
  {
5776
6388
  style: {
@@ -5788,7 +6400,7 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5788
6400
  ]
5789
6401
  }
5790
6402
  ),
5791
- expanded && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { padding: "0 12px 8px" }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6403
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { padding: "0 12px 8px" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5792
6404
  GanttTimeline,
5793
6405
  {
5794
6406
  snapshots,
@@ -5799,21 +6411,21 @@ var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
5799
6411
  });
5800
6412
 
5801
6413
  // src/components/ExplainableShell/ExplainableShell.tsx
5802
- var import_jsx_runtime26 = require("react/jsx-runtime");
5803
- var HLinePill = (0, import_react31.memo)(function HLinePill2({
6414
+ var import_jsx_runtime27 = require("react/jsx-runtime");
6415
+ var HLinePill = (0, import_react32.memo)(function HLinePill2({
5804
6416
  label,
5805
6417
  detail,
5806
6418
  expanded,
5807
6419
  onClick
5808
6420
  }) {
5809
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: {
6421
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: {
5810
6422
  display: "flex",
5811
6423
  alignItems: "center",
5812
6424
  gap: 0,
5813
6425
  padding: "0"
5814
6426
  }, children: [
5815
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } }),
5816
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6427
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } }),
6428
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5817
6429
  "button",
5818
6430
  {
5819
6431
  onClick,
@@ -5837,31 +6449,31 @@ var HLinePill = (0, import_react31.memo)(function HLinePill2({
5837
6449
  transition: "color 0.15s ease"
5838
6450
  },
5839
6451
  children: [
5840
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontSize: 7 }, children: expanded ? "\u25BC" : "\u25B6" }),
6452
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontSize: 7 }, children: expanded ? "\u25BC" : "\u25B6" }),
5841
6453
  label,
5842
- detail && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontWeight: 400, opacity: 0.5, fontSize: 9 }, children: detail })
6454
+ detail && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontWeight: 400, opacity: 0.5, fontSize: 9 }, children: detail })
5843
6455
  ]
5844
6456
  }
5845
6457
  ),
5846
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } })
6458
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } })
5847
6459
  ] });
5848
6460
  });
5849
- var VLinePill = (0, import_react31.memo)(function VLinePill2({
6461
+ var VLinePill = (0, import_react32.memo)(function VLinePill2({
5850
6462
  label,
5851
6463
  expanded,
5852
6464
  side = "right",
5853
6465
  onClick
5854
6466
  }) {
5855
6467
  const arrow = side === "right" ? expanded ? "\u25B6" : "\u25C0" : expanded ? "\u25C0" : "\u25B6";
5856
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: {
6468
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: {
5857
6469
  display: "flex",
5858
6470
  flexDirection: "column",
5859
6471
  alignItems: "center",
5860
6472
  gap: 0,
5861
6473
  padding: "0"
5862
6474
  }, children: [
5863
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } }),
5864
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
6475
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } }),
6476
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5865
6477
  "button",
5866
6478
  {
5867
6479
  onClick,
@@ -5886,12 +6498,12 @@ var VLinePill = (0, import_react31.memo)(function VLinePill2({
5886
6498
  transition: "color 0.15s ease"
5887
6499
  },
5888
6500
  children: [
5889
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontSize: 7, writingMode: "horizontal-tb" }, children: arrow }),
6501
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontSize: 7, writingMode: "horizontal-tb" }, children: arrow }),
5890
6502
  label
5891
6503
  ]
5892
6504
  }
5893
6505
  ),
5894
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } })
6506
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } })
5895
6507
  ] });
5896
6508
  });
5897
6509
  function detectKeyedSteps(data) {
@@ -5928,9 +6540,9 @@ function KeyedRecorderView({
5928
6540
  snapshots,
5929
6541
  selectedIndex
5930
6542
  }) {
5931
- const [showAggregate, setShowAggregate] = (0, import_react31.useState)(false);
5932
- const detected = (0, import_react31.useMemo)(() => detectKeyedSteps(data), [data]);
5933
- const visibleKeys = (0, import_react31.useMemo)(() => {
6543
+ const [showAggregate, setShowAggregate] = (0, import_react32.useState)(false);
6544
+ const detected = (0, import_react32.useMemo)(() => detectKeyedSteps(data), [data]);
6545
+ const visibleKeys = (0, import_react32.useMemo)(() => {
5934
6546
  const keys = /* @__PURE__ */ new Set();
5935
6547
  for (let i = 0; i <= selectedIndex && i < snapshots.length; i++) {
5936
6548
  const snap = snapshots[i];
@@ -5945,7 +6557,7 @@ function KeyedRecorderView({
5945
6557
  }, [snapshots, selectedIndex, detected?.keyType]);
5946
6558
  const isAtEnd = selectedIndex >= snapshots.length - 1;
5947
6559
  if (!detected) {
5948
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", height: "100%" }, children: typeof data === "string" ? data : JSON.stringify(data, null, 2) });
6560
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", height: "100%" }, children: typeof data === "string" ? data : JSON.stringify(data, null, 2) });
5949
6561
  }
5950
6562
  const steps = detected.steps;
5951
6563
  const hints = extractRenderHints(data);
@@ -5959,13 +6571,13 @@ function KeyedRecorderView({
5959
6571
  }
5960
6572
  }
5961
6573
  const grandTotal = hints?.grandTotal ?? 0;
5962
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
5963
- description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { padding: "6px 12px", fontSize: 11, color: theme.textMuted, fontStyle: "italic", borderBottom: `1px solid ${theme.border}`, flexShrink: 0 }, children: description }),
5964
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
6574
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
6575
+ 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 }),
6576
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
5965
6577
  preferredOperation === "aggregate" ? (
5966
6578
  /* AGGREGATE: collect silently during scrub, button at end to reveal total */
5967
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
5968
- isAtEnd ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { marginBottom: 16 }, children: !showAggregate ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6579
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6580
+ isAtEnd ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { marginBottom: 16 }, children: !showAggregate ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5969
6581
  "button",
5970
6582
  {
5971
6583
  onClick: () => setShowAggregate(true),
@@ -5983,35 +6595,35 @@ function KeyedRecorderView({
5983
6595
  },
5984
6596
  children: "Aggregate \u2014 Show Grand Total"
5985
6597
  }
5986
- ) : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { padding: "14px 16px", background: `color-mix(in srgb, ${theme.success} 12%, transparent)`, borderRadius: 8, border: `1px solid ${theme.success}44` }, children: [
5987
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Aggregate \u2014 grand total" }),
5988
- numFieldKey && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { fontSize: 26, fontWeight: 700, color: theme.success }, children: [
6598
+ ) : /* @__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: [
6599
+ /* @__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" }),
6600
+ numFieldKey && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { fontSize: 26, fontWeight: 700, color: theme.success }, children: [
5989
6601
  grandTotal < 1 ? grandTotal.toFixed(3) : grandTotal.toFixed(1),
5990
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
6602
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
5991
6603
  numFieldKey,
5992
6604
  " \xB7 ",
5993
6605
  allKeys.length,
5994
6606
  " steps"
5995
6607
  ] })
5996
6608
  ] })
5997
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.textMuted} 6%, transparent)`, borderRadius: 6, marginBottom: 16, border: `1px dashed ${theme.border}` }, children: [
5998
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600 }, children: "Collecting data..." }),
5999
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
6609
+ ] }) }) : /* @__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: [
6610
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600 }, children: "Collecting data..." }),
6611
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
6000
6612
  visibleEntries.length,
6001
6613
  " of ",
6002
6614
  allKeys.length,
6003
6615
  " steps collected. Scrub to end to aggregate."
6004
6616
  ] })
6005
6617
  ] }),
6006
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
6618
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
6007
6619
  ] })
6008
6620
  ) : preferredOperation === "accumulate" ? (
6009
6621
  /* ACCUMULATE: running total grows with slider — IS the total at end, no button */
6010
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6011
- numFieldKey && visibleEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.primary} 8%, transparent)`, borderRadius: 6, marginBottom: 16 }, children: [
6012
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4, fontWeight: 600 }, children: "Accumulate \u2014 running total up to this step" }),
6013
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontWeight: 700, fontSize: 18, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
6014
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
6622
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6623
+ 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: [
6624
+ /* @__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" }),
6625
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontWeight: 700, fontSize: 18, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
6626
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
6015
6627
  numFieldKey,
6016
6628
  " \xB7 ",
6017
6629
  visibleEntries.length,
@@ -6020,27 +6632,27 @@ function KeyedRecorderView({
6020
6632
  " steps"
6021
6633
  ] })
6022
6634
  ] }),
6023
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
6635
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
6024
6636
  ] })
6025
6637
  ) : (
6026
6638
  /* TRANSLATE: per-step entries prominent, no totals */
6027
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Translate \u2014 per-step detail" })
6639
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Translate \u2014 per-step detail" })
6028
6640
  ),
6029
6641
  visibleEntries.map((key) => {
6030
6642
  const entry = steps[key];
6031
6643
  const label = entry.stageName ?? key;
6032
6644
  const numVal = numFieldKey ? entry[numFieldKey] : void 0;
6033
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "4px 0", fontSize: 12, fontFamily: theme.fontMono, borderBottom: `1px solid ${theme.border}22` }, children: [
6034
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
6035
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
6036
- numVal !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
6645
+ 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: [
6646
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
6647
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
6648
+ numVal !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
6037
6649
  ] }, key);
6038
6650
  }),
6039
- visibleEntries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", padding: "8px 0" }, children: "Scrub the slider to reveal entries..." })
6651
+ visibleEntries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", padding: "8px 0" }, children: "Scrub the slider to reveal entries..." })
6040
6652
  ] })
6041
6653
  ] });
6042
6654
  }
6043
- var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
6655
+ var DetailsContent = (0, import_react32.memo)(function DetailsContent2({
6044
6656
  snapshots,
6045
6657
  selectedIndex,
6046
6658
  narrativeEntries,
@@ -6052,27 +6664,27 @@ var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
6052
6664
  {
6053
6665
  id: "memory",
6054
6666
  name: "Memory",
6055
- render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: fillHeight ? { height: "100%" } : void 0 })
6667
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: fillHeight ? { height: "100%" } : void 0 })
6056
6668
  },
6057
6669
  {
6058
6670
  id: "narrative",
6059
6671
  name: "Narrative",
6060
- render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries, size, style: fillHeight ? { height: "100%" } : void 0 })
6672
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries, size, style: fillHeight ? { height: "100%" } : void 0 })
6061
6673
  }
6062
6674
  ];
6063
6675
  const allViews = [...builtInViews, ...extraViews ?? []];
6064
- const [activeViewId, setActiveViewId] = (0, import_react31.useState)(allViews[0]?.id ?? "memory");
6676
+ const [activeViewId, setActiveViewId] = (0, import_react32.useState)(allViews[0]?.id ?? "memory");
6065
6677
  const viewIds = allViews.map((v2) => v2.id).join(",");
6066
- (0, import_react31.useEffect)(() => {
6678
+ (0, import_react32.useEffect)(() => {
6067
6679
  if (!allViews.find((v2) => v2.id === activeViewId)) {
6068
6680
  setActiveViewId(allViews[0]?.id ?? "memory");
6069
6681
  }
6070
6682
  }, [viewIds]);
6071
6683
  const activeView = allViews.find((v2) => v2.id === activeViewId) ?? allViews[0];
6072
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
6073
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
6684
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
6685
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
6074
6686
  const active = view.id === activeViewId;
6075
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6687
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6076
6688
  "button",
6077
6689
  {
6078
6690
  onClick: () => setActiveViewId(view.id),
@@ -6096,7 +6708,7 @@ var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
6096
6708
  view.id
6097
6709
  );
6098
6710
  }) }),
6099
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
6711
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
6100
6712
  ] });
6101
6713
  });
6102
6714
  function resolveSubflowFromRuntime(parentSnapshots, subflowId, narrativeEntries) {
@@ -6113,7 +6725,7 @@ function resolveSubflowFromRuntime(parentSnapshots, subflowId, narrativeEntries)
6113
6725
  if (sfSnapshots.length === 0) return null;
6114
6726
  return { subflowId, label, spec: null, snapshots: sfSnapshots, narrative: sfNarrative };
6115
6727
  }
6116
- var RightPanel = (0, import_react31.memo)(function RightPanel2({
6728
+ var RightPanel = (0, import_react32.memo)(function RightPanel2({
6117
6729
  mode,
6118
6730
  onModeChange,
6119
6731
  snapshots,
@@ -6127,15 +6739,17 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6127
6739
  size,
6128
6740
  onNavigateToStage,
6129
6741
  dataTrace,
6130
- onInspectorTabChange
6742
+ onInspectorTabChange,
6743
+ inspectorTab,
6744
+ traceContent
6131
6745
  }) {
6132
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6133
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: {
6746
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6747
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: {
6134
6748
  display: "flex",
6135
6749
  borderBottom: `1px solid ${theme.border}`,
6136
6750
  flexShrink: 0,
6137
6751
  background: theme.bgSecondary
6138
- }, children: ["insights", "what"].map((m) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6752
+ }, children: ["insights", "what"].map((m) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6139
6753
  "button",
6140
6754
  {
6141
6755
  onClick: () => onModeChange(m),
@@ -6157,7 +6771,7 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6157
6771
  },
6158
6772
  m
6159
6773
  )) }),
6160
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: mode === "insights" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6774
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: mode === "insights" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6161
6775
  InsightPanel,
6162
6776
  {
6163
6777
  mode: "tabs",
@@ -6166,16 +6780,16 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6166
6780
  id: tab.id,
6167
6781
  name: insightName(tab.name),
6168
6782
  render: () => {
6169
- if (tab.id === "narrative") return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, runtimeSnapshot, size, style: { height: "100%" } });
6783
+ if (tab.id === "narrative") return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, runtimeSnapshot, size, style: { height: "100%" } });
6170
6784
  const customView = recorderViews?.find((v2) => v2.id === tab.id);
6171
6785
  if (customView?.render) return customView.render({ snapshots, selectedIndex });
6172
6786
  const autoView = autoRecorderViews.find((v2) => v2.id === tab.id);
6173
- if (autoView) return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(KeyedRecorderView, { data: autoView.data, description: autoView.description, preferredOperation: autoView.preferredOperation, snapshots, selectedIndex });
6787
+ if (autoView) return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(KeyedRecorderView, { data: autoView.data, description: autoView.description, preferredOperation: autoView.preferredOperation, snapshots, selectedIndex });
6174
6788
  return null;
6175
6789
  }
6176
6790
  }))
6177
6791
  }
6178
- ) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6792
+ ) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6179
6793
  InspectorPanel,
6180
6794
  {
6181
6795
  snapshots,
@@ -6183,6 +6797,8 @@ var RightPanel = (0, import_react31.memo)(function RightPanel2({
6183
6797
  dataTraceFrames: dataTrace.frames,
6184
6798
  dataTraceNote: dataTrace.readsAvailable ? void 0 : "\u26A0 reads were not recorded (readTracking off) \u2014 dependencies are unknowable, not absent.",
6185
6799
  onTabChange: onInspectorTabChange,
6800
+ tab: inspectorTab,
6801
+ traceContent,
6186
6802
  selectedStageId: snapshots[selectedIndex]?.runtimeStageId,
6187
6803
  onNavigateToStage
6188
6804
  }
@@ -6223,7 +6839,7 @@ function ExplainableShell({
6223
6839
  className,
6224
6840
  style
6225
6841
  }) {
6226
- const derivedFromRuntime = (0, import_react31.useMemo)(() => {
6842
+ const derivedFromRuntime = (0, import_react32.useMemo)(() => {
6227
6843
  if (!runtimeSnapshot) return null;
6228
6844
  try {
6229
6845
  const snaps = toVisualizationSnapshots(runtimeSnapshot, narrativeEntries);
@@ -6234,7 +6850,7 @@ function ExplainableShell({
6234
6850
  }, [runtimeSnapshot, narrativeEntries]);
6235
6851
  const snapshots = snapshotsProp ?? derivedFromRuntime?.snapshots ?? [];
6236
6852
  const resultData = resultDataProp ?? derivedFromRuntime?.resultData ?? null;
6237
- const tracedFlowRenderer = (0, import_react31.useMemo)(() => {
6853
+ const tracedFlowRenderer = (0, import_react32.useMemo)(() => {
6238
6854
  if (!traceGraph) return void 0;
6239
6855
  return ({ selectedIndex, snapshots: snapshots2, onNodeClick, sliceCone: sliceCone2 }) => {
6240
6856
  const activeRsid = snapshots2[selectedIndex]?.runtimeStageId;
@@ -6255,7 +6871,7 @@ function ExplainableShell({
6255
6871
  ...traceTheme.current !== void 0 && { active: traceTheme.current },
6256
6872
  ...traceTheme.mode !== void 0 && { default: traceTheme.mode === "dark" ? "#94a3b8" : "#64748b" }
6257
6873
  };
6258
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
6874
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6259
6875
  TracedFlow,
6260
6876
  {
6261
6877
  graph: traceGraph,
@@ -6275,10 +6891,10 @@ function ExplainableShell({
6275
6891
  const leftLabel = panelLabels?.topology ?? "Topology";
6276
6892
  const rightLabel = panelLabels?.details ?? "Details";
6277
6893
  const bottomLabel = panelLabels?.timeline ?? "Timeline";
6278
- const shellRef = (0, import_react31.useRef)(null);
6279
- const [isNarrow, setIsNarrow] = (0, import_react31.useState)(false);
6280
- const [isMedium, setIsMedium] = (0, import_react31.useState)(false);
6281
- (0, import_react31.useEffect)(() => {
6894
+ const shellRef = (0, import_react32.useRef)(null);
6895
+ const [isNarrow, setIsNarrow] = (0, import_react32.useState)(false);
6896
+ const [isMedium, setIsMedium] = (0, import_react32.useState)(false);
6897
+ (0, import_react32.useEffect)(() => {
6282
6898
  const el = shellRef.current;
6283
6899
  if (!el) return;
6284
6900
  const ro = new ResizeObserver(([entry]) => {
@@ -6290,14 +6906,14 @@ function ExplainableShell({
6290
6906
  ro.observe(el);
6291
6907
  return () => ro.disconnect();
6292
6908
  }, []);
6293
- const autoRecorderViews = (0, import_react31.useMemo)(() => {
6909
+ const autoRecorderViews = (0, import_react32.useMemo)(() => {
6294
6910
  const recorders = runtimeSnapshot?.recorders;
6295
6911
  if (!recorders?.length) return [];
6296
6912
  const explicitIds = new Set((recorderViews ?? []).map((v2) => v2.id));
6297
6913
  return recorders.filter((r) => !explicitIds.has(r.id)).map((r) => ({ id: r.id, name: r.name, description: r.description, preferredOperation: r.preferredOperation, data: r.data }));
6298
6914
  }, [runtimeSnapshot, recorderViews]);
6299
6915
  const hasNarrative = !!narrativeEntries?.length;
6300
- const allTabs = (0, import_react31.useMemo)(() => {
6916
+ const allTabs = (0, import_react32.useMemo)(() => {
6301
6917
  const tabs2 = [
6302
6918
  { id: "result", name: "Result", description: "Final output and console logs" },
6303
6919
  { id: "memory", name: "Memory", description: "Accumulator \u2014 progressive shared state at each stage" }
@@ -6316,39 +6932,45 @@ function ExplainableShell({
6316
6932
  }, [hasNarrative, recorderViews, autoRecorderViews, hideTabsProp]);
6317
6933
  const validTabIds = new Set(allTabs.map((t) => t.id));
6318
6934
  const resolvedDefault = defaultTab && validTabIds.has(defaultTab) ? defaultTab : allTabs[0]?.id ?? "result";
6319
- const [activeTab, setActiveTab] = (0, import_react31.useState)(resolvedDefault);
6320
- const [snapshotIdx, setSnapshotIdx] = (0, import_react31.useState)(0);
6321
- const [drillDownStack, setDrillDownStack] = (0, import_react31.useState)([]);
6322
- const [rightExpanded, setRightExpanded] = (0, import_react31.useState)(defaultExpanded?.details ?? true);
6323
- const [rightPanelMode, setRightPanelMode] = (0, import_react31.useState)("insights");
6324
- const [inspectorTab, setInspectorTab] = (0, import_react31.useState)("state");
6325
- const [leftExpanded, setLeftExpanded] = (0, import_react31.useState)(defaultExpanded?.topology ?? false);
6326
- const [timelineExpanded, setTimelineExpanded] = (0, import_react31.useState)(defaultExpanded?.timeline ?? false);
6327
- (0, import_react31.useEffect)(() => {
6935
+ const [activeTab, setActiveTab] = (0, import_react32.useState)(resolvedDefault);
6936
+ const [snapshotIdx, setSnapshotIdx] = (0, import_react32.useState)(0);
6937
+ const [drillDownStack, setDrillDownStack] = (0, import_react32.useState)([]);
6938
+ const [rightExpanded, setRightExpanded] = (0, import_react32.useState)(defaultExpanded?.details ?? true);
6939
+ const [rightPanelMode, setRightPanelMode] = (0, import_react32.useState)("insights");
6940
+ const [inspectorTab, setInspectorTab] = (0, import_react32.useState)("state");
6941
+ const [tracing, setTracing] = (0, import_react32.useState)(null);
6942
+ const [forkChooserOpen, setForkChooserOpen] = (0, import_react32.useState)(false);
6943
+ const [traceSearch, setTraceSearch] = (0, import_react32.useState)("");
6944
+ (0, import_react32.useEffect)(() => {
6945
+ setForkChooserOpen(false);
6946
+ }, [snapshotIdx]);
6947
+ const [leftExpanded, setLeftExpanded] = (0, import_react32.useState)(defaultExpanded?.topology ?? false);
6948
+ const [timelineExpanded, setTimelineExpanded] = (0, import_react32.useState)(defaultExpanded?.timeline ?? false);
6949
+ (0, import_react32.useEffect)(() => {
6328
6950
  if (isNarrow) {
6329
6951
  setLeftExpanded(false);
6330
6952
  setRightExpanded(false);
6331
6953
  setTimelineExpanded(false);
6332
6954
  }
6333
6955
  }, [isNarrow]);
6334
- const triggerReflow = (0, import_react31.useCallback)(() => {
6956
+ const triggerReflow = (0, import_react32.useCallback)(() => {
6335
6957
  requestAnimationFrame(() => window.dispatchEvent(new Event("resize")));
6336
6958
  setTimeout(() => window.dispatchEvent(new Event("resize")), 320);
6337
6959
  }, []);
6338
- const toggleLeft = (0, import_react31.useCallback)((v2) => {
6960
+ const toggleLeft = (0, import_react32.useCallback)((v2) => {
6339
6961
  setLeftExpanded(v2);
6340
6962
  triggerReflow();
6341
6963
  }, [triggerReflow]);
6342
- const toggleRight = (0, import_react31.useCallback)((v2) => {
6964
+ const toggleRight = (0, import_react32.useCallback)((v2) => {
6343
6965
  setRightExpanded(v2);
6344
6966
  triggerReflow();
6345
6967
  }, [triggerReflow]);
6346
- const toggleTimeline = (0, import_react31.useCallback)(() => {
6968
+ const toggleTimeline = (0, import_react32.useCallback)(() => {
6347
6969
  setTimelineExpanded((p) => !p);
6348
6970
  triggerReflow();
6349
6971
  }, [triggerReflow]);
6350
6972
  const isInSubflow = drillDownStack.length > 0;
6351
- const currentLevel = (0, import_react31.useMemo)(() => {
6973
+ const currentLevel = (0, import_react32.useMemo)(() => {
6352
6974
  if (drillDownStack.length > 0) {
6353
6975
  const top = drillDownStack[drillDownStack.length - 1];
6354
6976
  return { spec: top.spec, snapshots: top.snapshots, narrative: top.narrative };
@@ -6357,11 +6979,47 @@ function ExplainableShell({
6357
6979
  }, [drillDownStack, snapshots]);
6358
6980
  const activeSnapshots = currentLevel.snapshots;
6359
6981
  const safeIdx = activeSnapshots.length > 0 ? Math.max(0, Math.min(snapshotIdx, activeSnapshots.length - 1)) : 0;
6360
- const shellDataTrace = (0, import_react31.useMemo)(
6982
+ const shellDataTrace = (0, import_react32.useMemo)(
6361
6983
  () => runtimeSnapshot?.commitLog ? buildDataTrace(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, activeSnapshots[safeIdx]?.runtimeStageId ?? "") : { frames: [], readsAvailable: true },
6362
6984
  [runtimeSnapshot, activeSnapshots, safeIdx]
6363
6985
  );
6364
- const sliceCone = (0, import_react31.useMemo)(() => {
6986
+ const allTracedKeys = (0, import_react32.useMemo)(() => {
6987
+ const log = runtimeSnapshot?.commitLog;
6988
+ if (!log?.length) return [];
6989
+ const seen = /* @__PURE__ */ new Set();
6990
+ const keys = [];
6991
+ for (const c of log) {
6992
+ for (const t of c.trace ?? []) {
6993
+ if (!seen.has(t.path)) {
6994
+ seen.add(t.path);
6995
+ keys.push(t.path);
6996
+ }
6997
+ }
6998
+ }
6999
+ return keys;
7000
+ }, [runtimeSnapshot]);
7001
+ const traceWalk = (0, import_react32.useMemo)(() => {
7002
+ if (!tracing || !runtimeSnapshot?.commitLog) return null;
7003
+ const scope = tracing.via.length > 0 ? tracing.via[tracing.via.length - 1] : tracing;
7004
+ return buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, scope.key, {
7005
+ beforeCommitIdx: scope.beforeCommitIdx
7006
+ });
7007
+ }, [tracing, runtimeSnapshot]);
7008
+ const traceStopIndices = (0, import_react32.useMemo)(() => {
7009
+ if (!traceWalk || traceWalk.missing || isInSubflow) return [];
7010
+ const idxByRsid = new Map(activeSnapshots.map((sn, i) => [sn.runtimeStageId, i]));
7011
+ return traceWalk.stops.map((stop) => idxByRsid.get(stop.runtimeStageId)).filter((i) => i !== void 0).sort((a, b) => a - b);
7012
+ }, [traceWalk, activeSnapshots, isInSubflow]);
7013
+ const sliceCone = (0, import_react32.useMemo)(() => {
7014
+ if (traceWalk && !traceWalk.missing && traceWalk.stops.length >= 2) {
7015
+ const cone2 = /* @__PURE__ */ new Map();
7016
+ for (const stop of traceWalk.stops) {
7017
+ const stagePart = stop.runtimeStageId.split("#")[0];
7018
+ const prev = cone2.get(stagePart);
7019
+ if (prev === void 0 || stop.depth < prev) cone2.set(stagePart, stop.depth);
7020
+ }
7021
+ return cone2;
7022
+ }
6365
7023
  if (rightPanelMode !== "what" || inspectorTab !== "trace") return void 0;
6366
7024
  if (shellDataTrace.frames.length < 2) return void 0;
6367
7025
  const cone = /* @__PURE__ */ new Map();
@@ -6371,49 +7029,112 @@ function ExplainableShell({
6371
7029
  if (prev === void 0 || f.depth < prev) cone.set(stagePart, f.depth);
6372
7030
  }
6373
7031
  return cone;
6374
- }, [rightPanelMode, inspectorTab, shellDataTrace]);
7032
+ }, [traceWalk, rightPanelMode, inspectorTab, shellDataTrace]);
6375
7033
  const activeNarrativeEntries = isInSubflow ? currentLevel.narrative : narrativeEntries;
6376
- const breadcrumbs = (0, import_react31.useMemo)(() => {
7034
+ const breadcrumbs = (0, import_react32.useMemo)(() => {
6377
7035
  const root = { label: title || "Flowchart", spec: null, description: void 0 };
6378
7036
  return [root, ...drillDownStack.map((e) => ({ label: e.label, spec: e.spec, description: void 0 }))];
6379
7037
  }, [title, drillDownStack]);
6380
- const showTreeSidebar = (0, import_react31.useMemo)(() => {
7038
+ const showTreeSidebar = (0, import_react32.useMemo)(() => {
6381
7039
  if (traceGraph?.nodes?.length) {
6382
7040
  return traceGraph.nodes.some((n) => n.data?.isSubflow === true);
6383
7041
  }
6384
7042
  return false;
6385
7043
  }, [traceGraph]);
6386
- const rootOverlay = (0, import_react31.useMemo)(() => {
7044
+ const rootOverlay = (0, import_react32.useMemo)(() => {
6387
7045
  if (isInSubflow || !snapshots.length) return { activeStage: void 0, doneStages: void 0 };
6388
7046
  const doneStages = new Set(snapshots.slice(0, safeIdx).map((s) => s.stageLabel));
6389
7047
  const activeStage = snapshots[safeIdx]?.stageLabel ?? null;
6390
7048
  return { activeStage, doneStages };
6391
7049
  }, [isInSubflow, snapshots, safeIdx]);
6392
- const handleTabChange = (0, import_react31.useCallback)((tab) => {
7050
+ const handleTabChange = (0, import_react32.useCallback)((tab) => {
6393
7051
  setActiveTab(tab);
6394
7052
  setDrillDownStack([]);
6395
7053
  }, []);
6396
- const handleSnapshotChange = (0, import_react31.useCallback)((idx) => {
7054
+ const handleSnapshotChange = (0, import_react32.useCallback)((idx) => {
6397
7055
  if (typeof idx === "number") setSnapshotIdx(idx);
6398
7056
  }, []);
6399
- const handleDrillDown = (0, import_react31.useCallback)(
7057
+ const jumpToAnchor = (0, import_react32.useCallback)(
7058
+ (walk) => {
7059
+ const anchor = walk.stops[0];
7060
+ if (!anchor) return;
7061
+ const idx = activeSnapshots.findIndex((sn) => sn.runtimeStageId === anchor.runtimeStageId);
7062
+ if (idx >= 0) setSnapshotIdx(idx);
7063
+ },
7064
+ [activeSnapshots]
7065
+ );
7066
+ const handleStartTracing = (0, import_react32.useCallback)(
7067
+ (key) => {
7068
+ if (!runtimeSnapshot?.commitLog || isInSubflow) return;
7069
+ const log = runtimeSnapshot.commitLog;
7070
+ const cursorRsid = activeSnapshots[safeIdx]?.runtimeStageId;
7071
+ const cursorCommitIdx = log.findIndex((c) => c.runtimeStageId === cursorRsid);
7072
+ const beforeCommitIdx = cursorCommitIdx >= 0 ? cursorCommitIdx + 1 : void 0;
7073
+ setTracing({ key, beforeCommitIdx, via: [] });
7074
+ setForkChooserOpen(false);
7075
+ setTraceSearch("");
7076
+ setRightPanelMode("what");
7077
+ setInspectorTab("trace");
7078
+ jumpToAnchor(
7079
+ buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, key, { beforeCommitIdx })
7080
+ );
7081
+ },
7082
+ [runtimeSnapshot, isInSubflow, activeSnapshots, safeIdx, jumpToAnchor]
7083
+ );
7084
+ const handleFollowIngredient = (0, import_react32.useCallback)(
7085
+ (ing) => {
7086
+ if (!tracing || !runtimeSnapshot?.commitLog || ing.writerCommitIdx === null) return;
7087
+ const scope = { key: ing.key, beforeCommitIdx: ing.writerCommitIdx + 1 };
7088
+ setTracing({ ...tracing, via: [...tracing.via, scope] });
7089
+ setForkChooserOpen(false);
7090
+ jumpToAnchor(
7091
+ buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, scope.key, {
7092
+ beforeCommitIdx: scope.beforeCommitIdx
7093
+ })
7094
+ );
7095
+ },
7096
+ [tracing, runtimeSnapshot, jumpToAnchor]
7097
+ );
7098
+ const handleShowAllIngredients = (0, import_react32.useCallback)(() => {
7099
+ if (!tracing || !runtimeSnapshot?.commitLog) return;
7100
+ setTracing({ ...tracing, via: [] });
7101
+ setForkChooserOpen(false);
7102
+ jumpToAnchor(
7103
+ buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, tracing.key, {
7104
+ beforeCommitIdx: tracing.beforeCommitIdx
7105
+ })
7106
+ );
7107
+ }, [tracing, runtimeSnapshot, jumpToAnchor]);
7108
+ const handleExitTracing = (0, import_react32.useCallback)(() => {
7109
+ setTracing(null);
7110
+ setForkChooserOpen(false);
7111
+ }, []);
7112
+ const handleForkPrompt = (0, import_react32.useCallback)(() => setForkChooserOpen(true), []);
7113
+ const handleContinueTimeOrder = (0, import_react32.useCallback)(() => {
7114
+ const earlier = traceStopIndices.filter((i) => i < safeIdx);
7115
+ if (earlier.length > 0) setSnapshotIdx(earlier[earlier.length - 1]);
7116
+ setForkChooserOpen(false);
7117
+ }, [traceStopIndices, safeIdx]);
7118
+ const handleDrillDown = (0, import_react32.useCallback)(
6400
7119
  (nodeName) => {
6401
7120
  const entry = resolveSubflowFromRuntime(activeSnapshots, nodeName, narrativeEntries);
6402
7121
  if (entry) {
7122
+ setTracing(null);
7123
+ setForkChooserOpen(false);
6403
7124
  setDrillDownStack((prev) => [...prev, { ...entry, parentSnapshotIdx: snapshotIdx }]);
6404
7125
  setSnapshotIdx(0);
6405
7126
  }
6406
7127
  },
6407
7128
  [activeSnapshots, narrativeEntries, snapshotIdx]
6408
7129
  );
6409
- const handleBreadcrumbNavigate = (0, import_react31.useCallback)((level) => {
7130
+ const handleBreadcrumbNavigate = (0, import_react32.useCallback)((level) => {
6410
7131
  setDrillDownStack((prev) => {
6411
7132
  const popped = level === 0 ? prev[0] : prev[level];
6412
7133
  if (popped) setSnapshotIdx(popped.parentSnapshotIdx);
6413
7134
  return level === 0 ? [] : prev.slice(0, level);
6414
7135
  });
6415
7136
  }, []);
6416
- const handleNodeClick = (0, import_react31.useCallback)(
7137
+ const handleNodeClick = (0, import_react32.useCallback)(
6417
7138
  (indexOrId) => {
6418
7139
  if (typeof indexOrId === "number") {
6419
7140
  setSnapshotIdx(indexOrId);
@@ -6429,7 +7150,7 @@ function ExplainableShell({
6429
7150
  },
6430
7151
  [activeSnapshots, narrativeEntries, handleDrillDown]
6431
7152
  );
6432
- const handleTreeNodeSelect = (0, import_react31.useCallback)(
7153
+ const handleTreeNodeSelect = (0, import_react32.useCallback)(
6433
7154
  (name, isSubflow) => {
6434
7155
  if (isSubflow) {
6435
7156
  setDrillDownStack([]);
@@ -6446,33 +7167,170 @@ function ExplainableShell({
6446
7167
  },
6447
7168
  [snapshots, narrativeEntries, snapshotIdx]
6448
7169
  );
7170
+ const navigateToStage = (0, import_react32.useCallback)(
7171
+ (id) => {
7172
+ const idx = activeSnapshots.findIndex((sn) => sn.runtimeStageId === id);
7173
+ if (idx >= 0) setSnapshotIdx(idx);
7174
+ },
7175
+ [activeSnapshots]
7176
+ );
7177
+ const activeViaKey = tracing && tracing.via.length > 0 ? tracing.via[tracing.via.length - 1].key : null;
7178
+ const stepNumberOf = (0, import_react32.useCallback)(
7179
+ (rsid) => {
7180
+ const i = activeSnapshots.findIndex((sn) => sn.runtimeStageId === rsid);
7181
+ return i >= 0 ? i + 1 : null;
7182
+ },
7183
+ [activeSnapshots]
7184
+ );
7185
+ const tracingRail = (0, import_react32.useMemo)(() => {
7186
+ if (!tracing || !traceWalk || traceWalk.missing || traceStopIndices.length === 0) return null;
7187
+ const cursorRsid = activeSnapshots[safeIdx]?.runtimeStageId;
7188
+ const walkIdx = traceWalk.stops.findIndex((st) => st.runtimeStageId === cursorRsid);
7189
+ const currentStop = traceWalk.stops[walkIdx >= 0 ? walkIdx : 0];
7190
+ return {
7191
+ tracedKey: tracing.key,
7192
+ viaKey: activeViaKey,
7193
+ stopIndices: traceStopIndices,
7194
+ stopOrdinal: walkIdx >= 0 ? walkIdx + 1 : 1,
7195
+ totalStops: traceWalk.stops.length,
7196
+ onExit: handleExitTracing,
7197
+ onShowAll: activeViaKey ? handleShowAllIngredients : void 0,
7198
+ // Followable ingredients only — termini can't be chosen, so a stop of
7199
+ // run-inputs must not prompt (matches the card's chooser gate).
7200
+ forkCount: currentStop?.ingredients.filter((ing) => ing.writerRuntimeStageId !== null).length ?? 0,
7201
+ onForkPrompt: handleForkPrompt
7202
+ };
7203
+ }, [tracing, traceWalk, traceStopIndices, activeSnapshots, safeIdx, activeViaKey, handleExitTracing, handleShowAllIngredients, handleForkPrompt]);
7204
+ const traceTabContent = (0, import_react32.useMemo)(() => {
7205
+ if (tracing && traceWalk) {
7206
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7207
+ TraceWalkCard,
7208
+ {
7209
+ walk: traceWalk,
7210
+ cursorRuntimeStageId: activeSnapshots[safeIdx]?.runtimeStageId ?? null,
7211
+ viaKey: activeViaKey,
7212
+ stepNumberOf,
7213
+ previewValueOf: (k) => activeSnapshots[safeIdx]?.memory?.[k],
7214
+ onFollowIngredient: handleFollowIngredient,
7215
+ onJumpToStop: navigateToStage,
7216
+ onShowAll: activeViaKey ? handleShowAllIngredients : void 0,
7217
+ onExit: handleExitTracing,
7218
+ forkChooserOpen,
7219
+ onContinueTimeOrder: handleContinueTimeOrder,
7220
+ canContinueTimeOrder: traceStopIndices.some((i) => i < safeIdx)
7221
+ }
7222
+ );
7223
+ }
7224
+ const chipStyle = {
7225
+ border: "1px solid var(--fp-accent, #6366f1)",
7226
+ background: "transparent",
7227
+ color: "var(--fp-accent, #6366f1)",
7228
+ borderRadius: 12,
7229
+ padding: "2px 10px",
7230
+ margin: "0 6px 6px 0",
7231
+ fontSize: 11,
7232
+ fontWeight: 600,
7233
+ fontFamily: "monospace",
7234
+ cursor: "pointer"
7235
+ };
7236
+ const query = traceSearch.trim().toLowerCase();
7237
+ const matchedKeys = query ? allTracedKeys.filter((k) => k.toLowerCase().includes(query)) : allTracedKeys;
7238
+ const shownKeys = matchedKeys.slice(0, 12);
7239
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7240
+ !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: [
7241
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { color: theme.textMuted, marginRight: 6 }, children: "This step wrote:" }),
7242
+ shellDataTrace.frames[0].keysWritten.map((k) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7243
+ "button",
7244
+ {
7245
+ "data-fp": "trace-entry-chip",
7246
+ onClick: () => handleStartTracing(k),
7247
+ title: "Where did " + k + " come from? Walk its causes on the timeline.",
7248
+ style: chipStyle,
7249
+ children: k
7250
+ },
7251
+ k
7252
+ ))
7253
+ ] }),
7254
+ !isInSubflow && allTracedKeys.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { "data-fp": "trace-any", style: { padding: "6px 14px 0", fontSize: 12 }, children: [
7255
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { color: theme.textMuted, marginBottom: 4 }, children: "Trace any variable:" }),
7256
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7257
+ "input",
7258
+ {
7259
+ "data-fp": "trace-search",
7260
+ value: traceSearch,
7261
+ onChange: (e) => setTraceSearch(e.target.value),
7262
+ placeholder: "search any variable...",
7263
+ style: {
7264
+ display: "block",
7265
+ width: "100%",
7266
+ boxSizing: "border-box",
7267
+ background: theme.bgTertiary,
7268
+ border: `1px solid ${theme.border}`,
7269
+ borderRadius: 6,
7270
+ color: theme.textPrimary,
7271
+ fontSize: 11,
7272
+ fontFamily: "monospace",
7273
+ padding: "4px 8px",
7274
+ marginBottom: 6
7275
+ }
7276
+ }
7277
+ ),
7278
+ shownKeys.map((k) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7279
+ "button",
7280
+ {
7281
+ "data-fp": "trace-any-chip",
7282
+ onClick: () => handleStartTracing(k),
7283
+ title: "Where did " + k + " come from? Walk its causes on the timeline.",
7284
+ style: chipStyle,
7285
+ children: k
7286
+ },
7287
+ k
7288
+ )),
7289
+ query === "" && matchedKeys.length > shownKeys.length && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { style: { color: theme.textMuted, fontSize: 11 }, children: [
7290
+ "+",
7291
+ matchedKeys.length - shownKeys.length,
7292
+ " more \u2014 type to search"
7293
+ ] })
7294
+ ] }),
7295
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7296
+ DataTracePanel,
7297
+ {
7298
+ frames: shellDataTrace.frames,
7299
+ note: shellDataTrace.readsAvailable ? void 0 : "\u26A0 reads were not recorded (readTracking off) \u2014 dependencies are unknowable, not absent.",
7300
+ selectedStageId: activeSnapshots[safeIdx]?.runtimeStageId,
7301
+ onFrameClick: navigateToStage,
7302
+ fromStageName: activeSnapshots[safeIdx]?.stageName
7303
+ }
7304
+ )
7305
+ ] });
7306
+ }, [tracing, traceWalk, activeSnapshots, safeIdx, activeViaKey, stepNumberOf, handleFollowIngredient, navigateToStage, handleShowAllIngredients, handleExitTracing, handleStartTracing, isInSubflow, shellDataTrace, forkChooserOpen, handleContinueTimeOrder, traceStopIndices, traceSearch, allTracedKeys]);
6449
7307
  const tabLabels = new Map(allTabs.map((t) => [t.id, t.name]));
6450
7308
  if (unstyled) {
6451
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className, style, "data-fp": "explainable-shell", children: [
6452
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { "data-fp": "shell-tabs", children: allTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { "data-fp": "shell-tab", "data-active": tab.id === activeTab, onClick: () => handleTabChange(tab.id), children: tab.name }, tab.id)) }),
6453
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
6454
- activeTab === "result" && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
6455
- (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6456
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
6457
- isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
7309
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className, style, "data-fp": "explainable-shell", children: [
7310
+ /* @__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)) }),
7311
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
7312
+ activeTab === "result" && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
7313
+ (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7314
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true, tracing: tracingRail }),
7315
+ isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
6458
7316
  traceGraph && effectiveRenderFlowchart?.({ spec: null, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick, showStageId, ...sliceCone && { sliceCone } }),
6459
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
6460
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, unstyled: true }),
6461
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
7317
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
7318
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, unstyled: true }),
7319
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
6462
7320
  ] })
6463
7321
  ] })
6464
7322
  ] });
6465
7323
  }
6466
7324
  const showTopology = !!effectiveRenderFlowchart && !!traceGraph;
6467
- const detailsContent = (0, import_react31.useMemo)(() => {
7325
+ const detailsContent = (0, import_react32.useMemo)(() => {
6468
7326
  if (activeTab === "result") {
6469
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
7327
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
6470
7328
  }
6471
7329
  if (activeTab === "memory") {
6472
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, size, style: { height: "100%" } });
7330
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, size, style: { height: "100%" } });
6473
7331
  }
6474
7332
  if (activeTab === "narrative") {
6475
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, size, style: { height: "100%" } });
7333
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, size, style: { height: "100%" } });
6476
7334
  }
6477
7335
  const customView = recorderViews?.find((v2) => v2.id === activeTab);
6478
7336
  if (customView?.render) {
@@ -6480,7 +7338,7 @@ function ExplainableShell({
6480
7338
  }
6481
7339
  const autoView = autoRecorderViews.find((v2) => v2.id === activeTab);
6482
7340
  if (autoView) {
6483
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7341
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6484
7342
  KeyedRecorderView,
6485
7343
  {
6486
7344
  data: autoView.data,
@@ -6493,8 +7351,8 @@ function ExplainableShell({
6493
7351
  }
6494
7352
  return null;
6495
7353
  }, [activeTab, resultData, logs, hideConsole, size, activeSnapshots, safeIdx, activeNarrativeEntries, recorderViews, autoRecorderViews]);
6496
- const detailsPanel = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
6497
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: {
7354
+ const detailsPanel = /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
7355
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: {
6498
7356
  display: "flex",
6499
7357
  borderBottom: `1px solid ${theme.border}`,
6500
7358
  background: theme.bgSecondary,
@@ -6502,7 +7360,7 @@ function ExplainableShell({
6502
7360
  overflowX: "auto"
6503
7361
  }, children: allTabs.map((tab) => {
6504
7362
  const active = tab.id === activeTab;
6505
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7363
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6506
7364
  "button",
6507
7365
  {
6508
7366
  onClick: () => handleTabChange(tab.id),
@@ -6526,9 +7384,9 @@ function ExplainableShell({
6526
7384
  tab.id
6527
7385
  );
6528
7386
  }) }),
6529
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: detailsContent })
7387
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: detailsContent })
6530
7388
  ] });
6531
- const shellThemeVars = (0, import_react31.useMemo)(() => {
7389
+ const shellThemeVars = (0, import_react32.useMemo)(() => {
6532
7390
  if (!traceTheme) return {};
6533
7391
  const base = traceTheme.mode ? tokensToCSSVars(traceTheme.mode === "light" ? coolLight : coolDark) : {};
6534
7392
  return {
@@ -6537,7 +7395,7 @@ function ExplainableShell({
6537
7395
  ...traceTheme.current !== void 0 && { ["--fp-node-cursor"]: traceTheme.current }
6538
7396
  };
6539
7397
  }, [traceTheme]);
6540
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
7398
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6541
7399
  "div",
6542
7400
  {
6543
7401
  ref: shellRef,
@@ -6556,20 +7414,21 @@ function ExplainableShell({
6556
7414
  },
6557
7415
  "data-fp": "explainable-shell",
6558
7416
  children: [
6559
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7417
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6560
7418
  TimeTravelControls,
6561
7419
  {
6562
7420
  snapshots: activeSnapshots,
6563
7421
  selectedIndex: safeIdx,
6564
7422
  onIndexChange: handleSnapshotChange,
6565
- size
7423
+ size,
7424
+ tracing: tracingRail
6566
7425
  }
6567
7426
  ),
6568
- isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
6569
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: isNarrow ? (
7427
+ isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
7428
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: isNarrow ? (
6570
7429
  /* ── Mobile: stacked vertical ── */
6571
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6572
- showTopology && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
7430
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7431
+ showTopology && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
6573
7432
  spec: null,
6574
7433
  snapshots: activeSnapshots,
6575
7434
  selectedIndex: safeIdx,
@@ -6577,9 +7436,9 @@ function ExplainableShell({
6577
7436
  showStageId,
6578
7437
  ...sliceCone && { sliceCone }
6579
7438
  }) }),
6580
- showTreeSidebar && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6581
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
6582
- leftExpanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { maxHeight: 180, overflow: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7439
+ showTreeSidebar && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7440
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
7441
+ leftExpanded && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { maxHeight: 180, overflow: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6583
7442
  SubflowTree,
6584
7443
  {
6585
7444
  graph: traceGraph ?? { nodes: [], edges: [] },
@@ -6589,17 +7448,17 @@ function ExplainableShell({
6589
7448
  }
6590
7449
  ) })
6591
7450
  ] }),
6592
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
6593
- rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { maxHeight: 350, flexShrink: 0, overflow: "hidden" }, children: detailsPanel }),
6594
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
6595
- timelineExpanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
7451
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
7452
+ rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { maxHeight: 350, flexShrink: 0, overflow: "hidden" }, children: detailsPanel }),
7453
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
7454
+ timelineExpanded && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
6596
7455
  ] })
6597
7456
  ) : (
6598
7457
  /* ── Desktop: two-column — Flowchart | Right Panel ── */
6599
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
6600
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
6601
- showTreeSidebar && (leftExpanded ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { style: { width: 180, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
6602
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7458
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
7459
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
7460
+ showTreeSidebar && (leftExpanded ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { style: { width: 180, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
7461
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6603
7462
  SubflowTree,
6604
7463
  {
6605
7464
  graph: traceGraph ?? { nodes: [], edges: [] },
@@ -6608,24 +7467,26 @@ function ExplainableShell({
6608
7467
  onNodeSelect: handleTreeNodeSelect
6609
7468
  }
6610
7469
  ) }),
6611
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VLinePill, { label: "Topology", expanded: true, side: "left", onClick: () => toggleLeft(false) })
6612
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VLinePill, { label: "Topology", expanded: false, side: "left", onClick: () => toggleLeft(true) })),
6613
- showTopology ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, overflow: "hidden", minWidth: 0 }, children: effectiveRenderFlowchart({
7470
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VLinePill, { label: "Topology", expanded: true, side: "left", onClick: () => toggleLeft(false) })
7471
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VLinePill, { label: "Topology", expanded: false, side: "left", onClick: () => toggleLeft(true) })),
7472
+ showTopology ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1, overflow: "hidden", minWidth: 0 }, children: effectiveRenderFlowchart({
6614
7473
  spec: null,
6615
7474
  snapshots: activeSnapshots,
6616
7475
  selectedIndex: safeIdx,
6617
7476
  onNodeClick: handleNodeClick,
6618
7477
  showStageId,
6619
7478
  ...sliceCone && { sliceCone }
6620
- }) }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1 } }),
6621
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VLinePill, { label: "Details", expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
6622
- rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { width: "42%", minWidth: 320, maxWidth: 550, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7479
+ }) }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { flex: 1 } }),
7480
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(VLinePill, { label: "Details", expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
7481
+ rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { width: "42%", minWidth: 320, maxWidth: 550, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6623
7482
  RightPanel,
6624
7483
  {
6625
7484
  mode: rightPanelMode,
6626
7485
  onModeChange: setRightPanelMode,
6627
7486
  dataTrace: shellDataTrace,
6628
7487
  onInspectorTabChange: setInspectorTab,
7488
+ inspectorTab,
7489
+ traceContent: traceTabContent,
6629
7490
  snapshots: activeSnapshots,
6630
7491
  selectedIndex: safeIdx,
6631
7492
  runtimeSnapshot,
@@ -6635,14 +7496,11 @@ function ExplainableShell({
6635
7496
  recorderViews,
6636
7497
  autoRecorderViews,
6637
7498
  size,
6638
- onNavigateToStage: (id) => {
6639
- const idx = activeSnapshots.findIndex((s) => s.runtimeStageId === id);
6640
- if (idx >= 0) setSnapshotIdx(idx);
6641
- }
7499
+ onNavigateToStage: navigateToStage
6642
7500
  }
6643
7501
  ) })
6644
7502
  ] }),
6645
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
7503
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6646
7504
  CompactTimeline,
6647
7505
  {
6648
7506
  snapshots: activeSnapshots,
@@ -6659,8 +7517,8 @@ function ExplainableShell({
6659
7517
 
6660
7518
  // src/components/TraceViewer/TraceViewer.tsx
6661
7519
  var React = __toESM(require("react"), 1);
6662
- var import_react32 = require("react");
6663
- var import_jsx_runtime27 = require("react/jsx-runtime");
7520
+ var import_react33 = require("react");
7521
+ var import_jsx_runtime28 = require("react/jsx-runtime");
6664
7522
  function parseTrace(input) {
6665
7523
  if (input == null) {
6666
7524
  return {
@@ -6723,11 +7581,11 @@ function TraceViewer({
6723
7581
  recorderViews,
6724
7582
  renderFlowchart
6725
7583
  }) {
6726
- const parsed = (0, import_react32.useMemo)(() => parseTrace(trace), [trace]);
7584
+ const parsed = (0, import_react33.useMemo)(() => parseTrace(trace), [trace]);
6727
7585
  React.useEffect(() => {
6728
7586
  if (!parsed.ok && onError) onError(parsed.error);
6729
7587
  }, [parsed, onError]);
6730
- const snapshots = (0, import_react32.useMemo)(() => {
7588
+ const snapshots = (0, import_react33.useMemo)(() => {
6731
7589
  if (!parsed.ok || !parsed.trace.snapshot) return [];
6732
7590
  try {
6733
7591
  return toVisualizationSnapshots(
@@ -6741,7 +7599,7 @@ function TraceViewer({
6741
7599
  if (!parsed.ok || snapshots.length === 0) {
6742
7600
  return fallback ?? null;
6743
7601
  }
6744
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
7602
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
6745
7603
  ExplainableShell,
6746
7604
  {
6747
7605
  snapshots,
@@ -6778,13 +7636,16 @@ function TraceViewer({
6778
7636
  SubflowTree,
6779
7637
  TimeTravelControls,
6780
7638
  TraceViewer,
7639
+ TraceWalkCard,
6781
7640
  buildEntryRangeIndex,
7641
+ buildTraceWalk,
6782
7642
  computeRevealedEntryCount,
6783
7643
  coolDark,
6784
7644
  coolLight,
6785
7645
  createSnapshots,
6786
7646
  defaultTokens,
6787
7647
  extractSubflowNarrative,
7648
+ formatTraceWalk,
6788
7649
  mergeWritePatch,
6789
7650
  rawDefaults,
6790
7651
  subflowResultToSnapshots,