@principal-ai/subsystems-react 0.44.4 → 0.46.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.
Files changed (128) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +8 -8
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +4 -4
  5. package/dist/index.js.map +1 -1
  6. package/dist/pierre/{PierreWalkthroughCodeView.d.ts → PierreTrailCodeView.d.ts} +11 -11
  7. package/dist/pierre/PierreTrailCodeView.d.ts.map +1 -0
  8. package/dist/pierre/{PierreWalkthroughCodeView.js → PierreTrailCodeView.js} +36 -36
  9. package/dist/pierre/PierreTrailCodeView.js.map +1 -0
  10. package/dist/pierre/index.d.ts +2 -2
  11. package/dist/pierre/index.d.ts.map +1 -1
  12. package/dist/pierre/index.js +1 -1
  13. package/dist/pierre/index.js.map +1 -1
  14. package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.d.ts.map +1 -1
  15. package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.js +1 -1
  16. package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.js.map +1 -1
  17. package/dist/stories/Subsystem/C4Graph/c4Fixture.js +1 -1
  18. package/dist/stories/Subsystem/C4Graph/c4Fixture.js.map +1 -1
  19. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts +7 -11
  20. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
  21. package/dist/stories/Subsystem/ComponentGraph/fixtures.js +10 -26
  22. package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
  23. package/dist/subsystem/C4Graph.d.ts +2 -2
  24. package/dist/subsystem/C4Graph.js +2 -2
  25. package/dist/subsystem/ConstructsCatalog.d.ts +2 -3
  26. package/dist/subsystem/ConstructsCatalog.d.ts.map +1 -1
  27. package/dist/subsystem/ConstructsCatalog.js +3 -14
  28. package/dist/subsystem/ConstructsCatalog.js.map +1 -1
  29. package/dist/subsystem/DiagnosticToggle.d.ts +1 -1
  30. package/dist/subsystem/DiagnosticToggle.js +1 -1
  31. package/dist/subsystem/FileDrawer.d.ts +2 -2
  32. package/dist/subsystem/FileDrawer.js +2 -2
  33. package/dist/subsystem/IssueList.d.ts +6 -6
  34. package/dist/subsystem/IssueList.d.ts.map +1 -1
  35. package/dist/subsystem/IssueList.js +9 -9
  36. package/dist/subsystem/IssueList.js.map +1 -1
  37. package/dist/subsystem/SubsystemAggregateGraph.d.ts +3 -3
  38. package/dist/subsystem/SubsystemAggregateGraph.d.ts.map +1 -1
  39. package/dist/subsystem/SubsystemAggregateGraph.js +2 -2
  40. package/dist/subsystem/SubsystemComponentGraph.d.ts +45 -51
  41. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  42. package/dist/subsystem/SubsystemComponentGraph.js +288 -292
  43. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  44. package/dist/subsystem/SubsystemModelTransition.d.ts +10 -10
  45. package/dist/subsystem/SubsystemModelTransition.d.ts.map +1 -1
  46. package/dist/subsystem/SubsystemModelTransition.js +42 -42
  47. package/dist/subsystem/SubsystemModelTransition.js.map +1 -1
  48. package/dist/subsystem/TrailsPanel.d.ts +55 -0
  49. package/dist/subsystem/TrailsPanel.d.ts.map +1 -0
  50. package/dist/subsystem/{WalkthroughsPanel.js → TrailsPanel.js} +51 -51
  51. package/dist/subsystem/TrailsPanel.js.map +1 -0
  52. package/dist/subsystem/declarationRef.d.ts +1 -1
  53. package/dist/subsystem/declarationRef.d.ts.map +1 -1
  54. package/dist/subsystem/model.d.ts +40 -40
  55. package/dist/subsystem/model.d.ts.map +1 -1
  56. package/dist/subsystem/model.js +17 -17
  57. package/dist/subsystem/model.js.map +1 -1
  58. package/dist/subsystem/nodes.d.ts +1 -1
  59. package/dist/subsystem/nodes.js +1 -1
  60. package/dist/subsystem/toC4.d.ts +2 -2
  61. package/dist/subsystem/toC4.d.ts.map +1 -1
  62. package/dist/subsystem/toC4.js +2 -2
  63. package/dist/subsystem/toC4.js.map +1 -1
  64. package/dist/subsystem/trailBrief.d.ts +18 -0
  65. package/dist/subsystem/trailBrief.d.ts.map +1 -0
  66. package/dist/subsystem/{walkthroughBrief.js → trailBrief.js} +8 -8
  67. package/dist/subsystem/trailBrief.js.map +1 -0
  68. package/package.json +3 -3
  69. package/src/index.ts +15 -15
  70. package/src/pierre/{PierreWalkthroughCodeView.tsx → PierreTrailCodeView.tsx} +56 -56
  71. package/src/pierre/index.ts +2 -2
  72. package/src/stories/Pierre/CodeView.stories.tsx +3 -3
  73. package/src/stories/Subsystem/AggregateGraph/AggregateFrameGraph.stories.tsx +1 -1
  74. package/src/stories/Subsystem/AggregateGraph/aggregateViewFixture.ts +1 -1
  75. package/src/stories/Subsystem/C4Graph/c4Fixture.ts +1 -1
  76. package/src/stories/Subsystem/ComponentDeclarationAudit.stories.tsx +8 -8
  77. package/src/stories/Subsystem/ComponentGraph/AnimatedProgression.stories.tsx +13 -13
  78. package/src/stories/Subsystem/ComponentGraph/Appearance.stories.tsx +2 -2
  79. package/src/stories/Subsystem/ComponentGraph/Basics.stories.tsx +5 -5
  80. package/src/stories/Subsystem/ComponentGraph/Captures.stories.tsx +8 -8
  81. package/src/stories/Subsystem/ComponentGraph/CustomEntities.stories.tsx +3 -3
  82. package/src/stories/Subsystem/ComponentGraph/Diagnostics.stories.tsx +6 -6
  83. package/src/stories/Subsystem/ComponentGraph/EdgeViews.stories.tsx +12 -12
  84. package/src/stories/Subsystem/ComponentGraph/Flows.stories.tsx +36 -36
  85. package/src/stories/Subsystem/ComponentGraph/FrameworkStereotype.stories.tsx +7 -7
  86. package/src/stories/Subsystem/ComponentGraph/GraphTitle.stories.tsx +4 -4
  87. package/src/stories/Subsystem/ComponentGraph/IssueOverlay.stories.tsx +8 -8
  88. package/src/stories/Subsystem/ComponentGraph/Issues.stories.tsx +4 -4
  89. package/src/stories/Subsystem/ComponentGraph/ModuleBadges.stories.tsx +3 -3
  90. package/src/stories/Subsystem/ComponentGraph/Modules.stories.tsx +5 -5
  91. package/src/stories/Subsystem/ComponentGraph/Packages.stories.tsx +6 -6
  92. package/src/stories/Subsystem/ComponentGraph/Processes.stories.tsx +3 -3
  93. package/src/stories/Subsystem/ComponentGraph/Proposed.stories.tsx +4 -4
  94. package/src/stories/Subsystem/ComponentGraph/{ProposedWalkthroughs.stories.tsx → ProposedTrails.stories.tsx} +9 -9
  95. package/src/stories/Subsystem/ComponentGraph/Reorder.stories.tsx +19 -19
  96. package/src/stories/Subsystem/ComponentGraph/Scenarios.stories.tsx +21 -21
  97. package/src/stories/Subsystem/ComponentGraph/{WalkthroughAutoplay.stories.tsx → TrailAutoplay.stories.tsx} +22 -22
  98. package/src/stories/Subsystem/ComponentGraph/WorkspacePackageFrames.stories.tsx +3 -3
  99. package/src/stories/Subsystem/ComponentGraph/fixtures.ts +17 -37
  100. package/src/subsystem/C4Graph.tsx +2 -2
  101. package/src/subsystem/ConstructsCatalog.tsx +2 -16
  102. package/src/subsystem/DiagnosticToggle.tsx +1 -1
  103. package/src/subsystem/FileDrawer.tsx +2 -2
  104. package/src/subsystem/IssueList.focus.test.tsx +4 -4
  105. package/src/subsystem/IssueList.icon.test.tsx +3 -3
  106. package/src/subsystem/IssueList.tsx +14 -14
  107. package/src/subsystem/SubsystemAggregateGraph.tsx +3 -3
  108. package/src/subsystem/SubsystemComponentGraph.tsx +380 -393
  109. package/src/subsystem/SubsystemModelTransition.tsx +61 -61
  110. package/src/subsystem/{WalkthroughsPanel.test.tsx → TrailsPanel.test.tsx} +16 -16
  111. package/src/subsystem/{WalkthroughsPanel.tsx → TrailsPanel.tsx} +81 -81
  112. package/src/subsystem/declarationRef.ts +1 -1
  113. package/src/subsystem/formatDeclaration.test.ts +6 -6
  114. package/src/subsystem/model.test.ts +25 -25
  115. package/src/subsystem/model.ts +51 -51
  116. package/src/subsystem/nodes.tsx +1 -1
  117. package/src/subsystem/toC4.test.ts +1 -1
  118. package/src/subsystem/toC4.ts +3 -3
  119. package/src/subsystem/{walkthroughBrief.test.ts → trailBrief.test.ts} +10 -10
  120. package/src/subsystem/{walkthroughBrief.ts → trailBrief.ts} +8 -8
  121. package/dist/pierre/PierreWalkthroughCodeView.d.ts.map +0 -1
  122. package/dist/pierre/PierreWalkthroughCodeView.js.map +0 -1
  123. package/dist/subsystem/WalkthroughsPanel.d.ts +0 -55
  124. package/dist/subsystem/WalkthroughsPanel.d.ts.map +0 -1
  125. package/dist/subsystem/WalkthroughsPanel.js.map +0 -1
  126. package/dist/subsystem/walkthroughBrief.d.ts +0 -18
  127. package/dist/subsystem/walkthroughBrief.d.ts.map +0 -1
  128. package/dist/subsystem/walkthroughBrief.js.map +0 -1
@@ -8,7 +8,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
8
8
  * inside one labeled boundary frame; nodes without one sit outside every
9
9
  * boundary. Clicking a component invokes `onSelect`.
10
10
  *
11
- * When the model has components but no topology or walkthrough edges, the
11
+ * When the model has components but no topology or trail edges, the
12
12
  * canvas is a constructs catalog (list + signature) instead of a graph.
13
13
  *
14
14
  * This is a focused fork of the package's `GraphRenderer` pipeline (same ELK
@@ -20,7 +20,7 @@ import { ReactFlow, ReactFlowProvider, useReactFlow, useViewport, applyNodeChang
20
20
  import { useTheme } from '@principal-ade/industry-theme';
21
21
  import { FileText, X } from 'lucide-react';
22
22
  import { IndustryMarkdownSlide } from 'themed-markdown';
23
- import { buildSubsystemGraph, deriveGraphEdges, isConstructsOnlyModel, moduleGroupNodeId, isWalkthroughMechanism, edgeColor, MECHANISM_DESCRIPTIONS, subsystemGraphLayoutKey, walkthroughStepGraphEdgeId, } from './model';
23
+ import { buildSubsystemGraph, deriveGraphEdges, isConstructsOnlyModel, moduleGroupNodeId, isTrailMechanism, edgeColor, MECHANISM_DESCRIPTIONS, subsystemGraphLayoutKey, trailStepGraphEdgeId, } from './model';
24
24
  import { ConstructsCatalog } from './ConstructsCatalog';
25
25
  import { SubsystemAgentsPanel, } from './AgentsPanel';
26
26
  import { MaintainLivePanel, } from '../components/maintain-events/MaintainLivePanel';
@@ -33,7 +33,7 @@ import { GRAPH_CANVAS_CLASS, GRAPH_NAV_PROPS, GraphChrome, GraphLayerStyle } fro
33
33
  import { ComponentDeclaration } from './ComponentDeclaration';
34
34
  import { FileDrawer, FILE_DRAWER_HEIGHT_MS } from './FileDrawer';
35
35
  import { buildRepoGroups, repoAvatarUrl } from './paths';
36
- import { WalkthroughsPanel, WALKTHROUGH_PLAY_PAUSE_MS } from './WalkthroughsPanel';
36
+ import { TrailsPanel, TRAIL_PLAY_PAUSE_MS } from './TrailsPanel';
37
37
  import { EDGE_LABEL_WIDTH, EDGE_LABEL_HEIGHT, EDGE_LABEL_FONT_SIZE, EDGE_LABEL_CLOUD_PATH, EDGE_LABEL_CLOUD_EXTRA_TOP, } from '../utils/edgeLabel';
38
38
  /** Identifiers a token could match to name this component as a construct. */
39
39
  function constructIdentifiers(comp) {
@@ -112,9 +112,9 @@ function FileOverlayCloseButton({ onClose }) {
112
112
  transition: 'background 120ms ease, color 120ms ease',
113
113
  }, children: _jsx(X, { size: 14 }) }));
114
114
  }
115
- const WalkthroughDrawerContent = memo(function WalkthroughDrawerContent({ render, walkthrough, stepIndex, onOpenFile, proposedAliases, resolveSymbol, onSymbolClick, }) {
115
+ const TrailDrawerContent = memo(function TrailDrawerContent({ render, trail, stepIndex, onOpenFile, proposedAliases, resolveSymbol, onSymbolClick, }) {
116
116
  return (_jsx(_Fragment, { children: render({
117
- walkthrough,
117
+ trail,
118
118
  stepIndex,
119
119
  onOpenFile,
120
120
  proposedAliases,
@@ -122,14 +122,14 @@ const WalkthroughDrawerContent = memo(function WalkthroughDrawerContent({ render
122
122
  onSymbolClick,
123
123
  }) }));
124
124
  });
125
- function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initialWalkthroughId, onReorderWalkthroughs, onSelect, onEdgeSelect, measured: _measured, maxNodeWidth, showEdgeLabels, showSingletonFrames = true, moduleNesting, edgeView, title, hideSidebar, walkthroughStepMode = 'focus', autoPlayWalkthroughs = false, walkthroughAutoPlayIntervalMs = WALKTHROUGH_PLAY_PAUSE_MS, zoomOnWalkthroughFocus = true, walkthroughFocusDurationMs = 300, graphTitle, showWalkthroughTitle = false, description, canvasOverlay, sidebarExtra, sidebarAfterDescription, diagnostic, issues, showIssues, focusIssueCategory, onSelectIssue, onApplyIssueFix, onHoverIssue, renderFileView, renderFileViewer, renderWalkthroughViewer, onFileSelect, componentVerification, onInspectSymbol, boundaryColors, hideDrawer = false, persistKey, liveEvents, agentsPanel }) {
125
+ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrailId, onReorderTrails, onSelect, onEdgeSelect, measured: _measured, maxNodeWidth, showEdgeLabels, showSingletonFrames = true, moduleNesting, edgeView, title, hideSidebar, trailStepMode = 'focus', autoPlayTrails = false, trailAutoPlayIntervalMs = TRAIL_PLAY_PAUSE_MS, zoomOnTrailFocus = true, trailFocusDurationMs = 300, graphTitle, showTrailTitle = false, description, canvasOverlay, sidebarExtra, sidebarAfterDescription, diagnostic, issues, showIssues, focusIssueCategory, onSelectIssue, onApplyIssueFix, onHoverIssue, renderFileViewer, renderTrailViewer, onFileSelect, componentVerification, onInspectSymbol, boundaryColors, hideDrawer = false, persistKey, liveEvents, agentsPanel }) {
126
126
  const { theme } = useTheme();
127
127
  const { fitView, fitBounds, screenToFlowPosition } = useReactFlow();
128
128
  const viewport = useViewport();
129
129
  // Restored once per mount from `localStorage` (see `readViewState`). Each
130
130
  // graph is its own tab/mount, so `persistKey` is stable for a mount.
131
131
  const persisted = useMemo(() => readViewState(persistKey), [persistKey]);
132
- const graphEdges = useMemo(() => deriveGraphEdges({ walkthroughs }), [walkthroughs]);
132
+ const graphEdges = useMemo(() => deriveGraphEdges({ trails }), [trails]);
133
133
  const [built, setBuilt] = useState({
134
134
  nodes: [],
135
135
  edges: [],
@@ -137,9 +137,9 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
137
137
  });
138
138
  const [layoutReady, setLayoutReady] = useState(false);
139
139
  const [selected, setSelected] = useState(null);
140
- /** Bottom drawer: single file or walkthrough multi-snippet mode. */
140
+ /** Bottom drawer: single file or trail multi-snippet mode. */
141
141
  const [drawerTarget, setDrawerTarget] = useState(null);
142
- /** Full-file layer over an open walkthrough drawer — walkthrough stays mounted. */
142
+ /** Full-file layer over an open trail drawer — trail stays mounted. */
143
143
  const [fileOverlay, setFileOverlay] = useState(null);
144
144
  // Mirror so step-focus can decide whether to wait for the drawer open
145
145
  // transition before fitView (avoids framing against full-height canvas).
@@ -214,39 +214,46 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
214
214
  cancelAnimationFrame(raf);
215
215
  };
216
216
  }, [pathFrameRects, screenToFlowPosition]);
217
- // Walkthrough focus — selected flow (or step) is full strength; other
217
+ // Trail focus — selected flow (or step) is full strength; other
218
218
  // opened-flow members stay visible but dimmed; everything else is hidden.
219
219
  // Restored from the persisted view state when a `persistKey` is set.
220
- const [focusedWalkthroughId, setFocusedWalkthroughId] = useState(persisted.focusedWalkthroughId ?? null);
220
+ const [focusedTrailId, setFocusedTrailId] = useState(persisted.focusedTrailId ?? null);
221
221
  // `null` = whole flow focused; a number = that single step's edge focused.
222
222
  const [focusedStepIndex, setFocusedStepIndex] = useState(persisted.focusedStepIndex ?? null);
223
- // Hovered walkthrough in the flows panel: dims every canvas node/edge not
223
+ // Hovered trail in the flows panel: dims every canvas node/edge not
224
224
  // involved in the hover preview (or selected ∪ hovered when a step is
225
225
  // focused). `stepIndex: null` = whole flow (collapsed title hover);
226
226
  // a number = that step. Transient — no drawer. Camera only reframes when
227
227
  // a step is already selected.
228
- const [hoveredWalkthroughStep, setHoveredWalkthroughStep] = useState(null);
229
- // Sidebar bottom half: which panel is shown when walkthroughs exist.
230
- const [sidebarView, setSidebarView] = useState(() => persisted.sidebarView ?? (walkthroughs?.length ? 'walkthroughs' : 'files'));
228
+ const [hoveredTrailStep, setHoveredTrailStep] = useState(null);
229
+ // Sidebar bottom half: which panel is shown when trails exist.
230
+ // The persisted value is membership-checked rather than trusted: a stale
231
+ // localStorage entry from before the walkthrough->trail rename would match
232
+ // neither panel and render a blank sidebar with no selected tab.
233
+ const [sidebarView, setSidebarView] = useState(() => {
234
+ const stored = persisted.sidebarView;
235
+ const restored = stored === 'files' || stored === 'trails' ? stored : 'trails';
236
+ return trails?.length ? restored : 'files';
237
+ });
231
238
  // Diagnostics area tab: issues list vs the Maintain agent pipeline.
232
239
  const [diagnosticsTab, setDiagnosticsTab] = useState(() => persisted.diagnosticsTab ?? 'issues');
233
240
  // One edge source at a time. When the caller doesn't pick, the sidebar's
234
- // Files / Walkthroughs tab picks: Files draws graphify static edges,
235
- // Walkthroughs draws runtime hop edges. Without visible tabs (no walkthroughs,
236
- // or a sidebar-less embed) fall back to walkthrough edges.
237
- const sidebarTabsVisible = !hideSidebar && (walkthroughs?.length ?? 0) > 0;
241
+ // Files / Trails tab picks: Files draws graphify static edges,
242
+ // Trails draws runtime step edges. Without visible tabs (no trails,
243
+ // or a sidebar-less embed) fall back to trail edges.
244
+ const sidebarTabsVisible = !hideSidebar && (trails?.length ?? 0) > 0;
238
245
  const resolvedEdgeView = edgeView ??
239
246
  (sidebarTabsVisible
240
- ? (sidebarView === 'walkthroughs' ? 'walkthroughs' : 'graphify')
241
- : (walkthroughs?.length ?? 0) > 0
242
- ? 'walkthroughs'
247
+ ? (sidebarView === 'trails' ? 'trails' : 'graphify')
248
+ : (trails?.length ?? 0) > 0
249
+ ? 'trails'
243
250
  : (graphifyRelations?.length ?? 0) > 0
244
251
  ? 'graphify'
245
- : 'walkthroughs');
246
- // Walkthrough flows the user has expanded (via the title row). Closed by
252
+ : 'trails');
253
+ // Trail flows the user has expanded (via the title row). Closed by
247
254
  // default so a graph with several flows doesn't dump every step list at once.
248
255
  // Restored from the persisted view state when a `persistKey` is set.
249
- const [expandedWalkthroughs, setExpandedWalkthroughs] = useState(() => new Set(persisted.expandedWalkthroughs ?? []));
256
+ const [expandedTrails, setExpandedTrails] = useState(() => new Set(persisted.expandedTrails ?? []));
250
257
  // Sidebar description visibility. Hidden by default so the files/flows
251
258
  // panel gets the vertical room; the title-row toggle reveals it.
252
259
  const [descriptionVisible, setDescriptionVisible] = useState(false);
@@ -296,20 +303,20 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
296
303
  document.removeEventListener('mouseup', onUp);
297
304
  };
298
305
  }, [sidebarDrag, sidebarMaxWidth, fitView, persistKey]);
299
- // Persist the walkthrough working set per model. Each write merges into the
306
+ // Persist the trail working set per model. Each write merges into the
300
307
  // stored blob, so the three fields never clobber one another.
301
308
  useEffect(() => {
302
309
  if (!persistKey)
303
310
  return;
304
311
  writeViewState(persistKey, {
305
- expandedWalkthroughs: Array.from(expandedWalkthroughs),
312
+ expandedTrails: Array.from(expandedTrails),
306
313
  });
307
- }, [persistKey, expandedWalkthroughs]);
314
+ }, [persistKey, expandedTrails]);
308
315
  useEffect(() => {
309
316
  if (!persistKey)
310
317
  return;
311
- writeViewState(persistKey, { focusedWalkthroughId });
312
- }, [persistKey, focusedWalkthroughId]);
318
+ writeViewState(persistKey, { focusedTrailId });
319
+ }, [persistKey, focusedTrailId]);
313
320
  useEffect(() => {
314
321
  if (!persistKey)
315
322
  return;
@@ -343,60 +350,60 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
343
350
  : drawerTarget?.kind === 'file'
344
351
  ? { file: drawerTarget.file, startLine: drawerTarget.startLine }
345
352
  : null;
346
- const focusedWalkthrough = useMemo(() => {
347
- if (drawerTarget?.kind !== 'walkthrough' || !walkthroughs)
353
+ const focusedTrail = useMemo(() => {
354
+ if (drawerTarget?.kind !== 'trail' || !trails)
348
355
  return null;
349
- return walkthroughs.find((t) => t.id === drawerTarget.walkthroughId) ?? null;
350
- }, [drawerTarget, walkthroughs]);
356
+ return trails.find((t) => t.id === drawerTarget.trailId) ?? null;
357
+ }, [drawerTarget, trails]);
351
358
  // Autoplay focus: a sidebar-less embed has no expanded flow to "open", so
352
359
  // branding every step as a selection would hide all other nodes. Instead the
353
- // autoplay sets this (flow id + step) to frame the hop and dim the rest —
360
+ // autoplay sets this (flow id + step) to frame the step and dim the rest —
354
361
  // same treatment as hover — without hiding anything. Declared before the
355
362
  // overlay memos, which read it to title the canvas chip + step bar.
356
363
  const [autoPlayFocus, setAutoPlayFocus] = useState(null);
357
- // Ref mirror of the drawer's walkthrough id so the symbol resolver stays
364
+ // Ref mirror of the drawer's trail id so the symbol resolver stays
358
365
  // stable across graph re-renders (the drawer is memoized on callback identity).
359
- const drawerWalkthroughIdRef = useRef(null);
360
- drawerWalkthroughIdRef.current = focusedWalkthrough?.id ?? null;
361
- // Walkthrough shown on the canvas title chip (focus, hover highlight, or
366
+ const drawerTrailIdRef = useRef(null);
367
+ drawerTrailIdRef.current = focusedTrail?.id ?? null;
368
+ // Trail shown on the canvas title chip (focus, hover highlight, or
362
369
  // autoplay focus).
363
- const overlayWalkthroughTitle = useMemo(() => {
364
- if (!showWalkthroughTitle || !walkthroughs?.length)
370
+ const overlayTrailTitle = useMemo(() => {
371
+ if (!showTrailTitle || !trails?.length)
365
372
  return null;
366
- const id = focusedWalkthroughId ??
367
- autoPlayFocus?.walkthroughId ??
368
- hoveredWalkthroughStep?.walkthroughId;
373
+ const id = focusedTrailId ??
374
+ autoPlayFocus?.trailId ??
375
+ hoveredTrailStep?.trailId;
369
376
  if (!id)
370
377
  return null;
371
- return walkthroughs.find((t) => t.id === id)?.title ?? null;
378
+ return trails.find((t) => t.id === id)?.title ?? null;
372
379
  }, [
373
- showWalkthroughTitle,
374
- walkthroughs,
375
- focusedWalkthroughId,
380
+ showTrailTitle,
381
+ trails,
382
+ focusedTrailId,
376
383
  autoPlayFocus,
377
- hoveredWalkthroughStep,
384
+ hoveredTrailStep,
378
385
  ]);
379
386
  // Active step for the bottom-of-title progress + annotation chip.
380
- const overlayWalkthroughStep = useMemo(() => {
381
- if (!showWalkthroughTitle || !walkthroughs?.length)
387
+ const overlayTrailStep = useMemo(() => {
388
+ if (!showTrailTitle || !trails?.length)
382
389
  return null;
383
- const tlId = focusedWalkthroughId ??
384
- autoPlayFocus?.walkthroughId ??
385
- hoveredWalkthroughStep?.walkthroughId ??
390
+ const tlId = focusedTrailId ??
391
+ autoPlayFocus?.trailId ??
392
+ hoveredTrailStep?.trailId ??
386
393
  null;
387
394
  let stepIndex = null;
388
- if (focusedWalkthroughId != null) {
395
+ if (focusedTrailId != null) {
389
396
  stepIndex = focusedStepIndex;
390
397
  }
391
398
  else if (autoPlayFocus != null) {
392
399
  stepIndex = autoPlayFocus.stepIndex;
393
400
  }
394
- else if (hoveredWalkthroughStep != null) {
395
- stepIndex = hoveredWalkthroughStep.stepIndex;
401
+ else if (hoveredTrailStep != null) {
402
+ stepIndex = hoveredTrailStep.stepIndex;
396
403
  }
397
404
  if (tlId == null || stepIndex == null)
398
405
  return null;
399
- const tl = walkthroughs.find((t) => t.id === tlId);
406
+ const tl = trails.find((t) => t.id === tlId);
400
407
  const step = tl?.steps[stepIndex];
401
408
  if (!step || !tl)
402
409
  return null;
@@ -406,19 +413,19 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
406
413
  annotation: step.annotation,
407
414
  };
408
415
  }, [
409
- showWalkthroughTitle,
410
- walkthroughs,
411
- focusedWalkthroughId,
416
+ showTrailTitle,
417
+ trails,
418
+ focusedTrailId,
412
419
  focusedStepIndex,
413
420
  autoPlayFocus,
414
- hoveredWalkthroughStep,
421
+ hoveredTrailStep,
415
422
  ]);
416
423
  const drawerTitle = useMemo(() => {
417
424
  if (!drawerTarget)
418
425
  return null;
419
426
  if (drawerTarget.kind === 'file')
420
427
  return drawerTarget.file;
421
- const tl = focusedWalkthrough;
428
+ const tl = focusedTrail;
422
429
  if (!tl)
423
430
  return null;
424
431
  if (drawerTarget.stepIndex == null)
@@ -428,7 +435,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
428
435
  return tl.title;
429
436
  const site = `${step.file.split('/').pop() ?? step.file}:${step.line}`;
430
437
  return `${tl.title} · ${site}`;
431
- }, [drawerTarget, focusedWalkthrough]);
438
+ }, [drawerTarget, focusedTrail]);
432
439
  // Refresh selected component when the components list updates (e.g. verify
433
440
  // writes back declarationRef).
434
441
  useEffect(() => {
@@ -441,12 +448,12 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
441
448
  // Pass 1: build with estimated widths so React Flow can measure the DOM.
442
449
  // The pane stays hidden until Pass 2 completes. Key off layout-affecting
443
450
  // fields only — declarationRef updates after verify must not re-run ELK.
444
- const layoutKey = useMemo(() => subsystemGraphLayoutKey({ components, walkthroughs, graphifyRelations }), [components, walkthroughs, graphifyRelations]);
451
+ const layoutKey = useMemo(() => subsystemGraphLayoutKey({ components, trails, graphifyRelations }), [components, trails, graphifyRelations]);
445
452
  const componentsRef = useRef(components);
446
- const walkthroughsRef = useRef(walkthroughs);
453
+ const trailsRef = useRef(trails);
447
454
  const graphifyRelationsRef = useRef(graphifyRelations);
448
455
  componentsRef.current = components;
449
- walkthroughsRef.current = walkthroughs;
456
+ trailsRef.current = trails;
450
457
  graphifyRelationsRef.current = graphifyRelations;
451
458
  // Track measured dimensions from React Flow's dimension changes.
452
459
  // These arrive as { type: 'dimensions', id, dimensions } in onNodesChange.
@@ -464,7 +471,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
464
471
  pass2GenRef.current += 1;
465
472
  const doc = {
466
473
  components: componentsRef.current,
467
- walkthroughs: walkthroughsRef.current,
474
+ trails: trailsRef.current,
468
475
  };
469
476
  void buildSubsystemGraph(doc, {
470
477
  maxNodeWidth,
@@ -523,7 +530,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
523
530
  const measuredWidths = new Map(leafNodes.map((n) => [n.id, dims.get(n.id).width]));
524
531
  const measuredHeights = new Map(leafNodes.map((n) => [n.id, dims.get(n.id).height]));
525
532
  const gen = ++pass2GenRef.current;
526
- void buildSubsystemGraph({ components, walkthroughs }, { maxNodeWidth, showEdgeLabels, measuredWidths, measuredHeights, showSingletonFrames, moduleNesting, graphifyRelations, orderByLine })
533
+ void buildSubsystemGraph({ components, trails }, { maxNodeWidth, showEdgeLabels, measuredWidths, measuredHeights, showSingletonFrames, moduleNesting, graphifyRelations, orderByLine })
527
534
  .then(({ nodes, edges: e, absoluteRects }) => {
528
535
  if (gen !== pass2GenRef.current)
529
536
  return;
@@ -537,7 +544,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
537
544
  // Reveal Pass 1 layout rather than leaving the cover up forever.
538
545
  setLayoutReady(true);
539
546
  });
540
- }, [built.nodes, components, walkthroughs, graphifyRelations, orderByLine, maxNodeWidth, showEdgeLabels, moduleNesting]);
547
+ }, [built.nodes, components, trails, graphifyRelations, orderByLine, maxNodeWidth, showEdgeLabels, moduleNesting]);
541
548
  // After Pass 1 commits, try Pass 2 immediately with retained measurements.
542
549
  // Same-id live updates often get no new React Flow `dimensions` events, so
543
550
  // waiting only on onNodesChange leaves the cover stuck.
@@ -578,8 +585,8 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
578
585
  }
579
586
  const src = edgeById.get(edgeId);
580
587
  setSelectedEdgeId(edgeId);
581
- // A direct edge selection on the canvas supersedes any walkthrough focus.
582
- setFocusedWalkthroughId(null);
588
+ // A direct edge selection on the canvas supersedes any trail focus.
589
+ setFocusedTrailId(null);
583
590
  setFocusedStepIndex(null);
584
591
  if (src)
585
592
  onEdgeSelect?.(src);
@@ -597,7 +604,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
597
604
  }
598
605
  setSelected(comp);
599
606
  setSelectedEdgeId(null);
600
- setFocusedWalkthroughId(null);
607
+ setFocusedTrailId(null);
601
608
  setFocusedStepIndex(null);
602
609
  onSelect?.(alias);
603
610
  }
@@ -639,9 +646,9 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
639
646
  return null;
640
647
  return moduleGroupNodeId(key);
641
648
  }, [components]);
642
- // A `step` issue target names ONE step of a walkthrough — the walkthrough id in
649
+ // A `step` issue target names ONE step of a trail — the trail id in
643
650
  // `id`, the 0-based step position in `stepIndex`. Validated against the loaded
644
- // walkthroughs so a finding left over from an edited flow resolves to null
651
+ // trails so a finding left over from an edited flow resolves to null
645
652
  // rather than framing whatever now happens to sit at that index.
646
653
  const issueStep = useCallback((issue) => {
647
654
  const target = issue.target;
@@ -649,11 +656,11 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
649
656
  return null;
650
657
  if (target.id == null || target.stepIndex == null)
651
658
  return null;
652
- const walkthrough = walkthroughs?.find((t) => t.id === target.id);
653
- if (!walkthrough?.steps[target.stepIndex])
659
+ const trail = trails?.find((t) => t.id === target.id);
660
+ if (!trail?.steps[target.stepIndex])
654
661
  return null;
655
- return { walkthrough, stepIndex: target.stepIndex };
656
- }, [walkthroughs]);
662
+ return { trail, stepIndex: target.stepIndex };
663
+ }, [trails]);
657
664
  // Per-node diagnostics badge: fold each component-targeted finding that maps
658
665
  // to a verification rung into one badge per node — worst severity wins, the
659
666
  // chip shows the earliest failing rung, and the count tallies the findings.
@@ -731,7 +738,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
731
738
  // target:
732
739
  // component → that node
733
740
  // module → every component in that module
734
- // walkthrough → the flow's nodes + its hop edges
741
+ // trail → the flow's nodes + its step edges
735
742
  // repo → every component of that repo
736
743
  // graph → whole-graph finding; implicates nothing specific
737
744
  // Returns null when nothing is expanded, no expanded layer has findings, or
@@ -766,13 +773,13 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
766
773
  }
767
774
  }
768
775
  }
769
- else if (t.kind === 'walkthrough') {
770
- const wt = (walkthroughs ?? []).find((w) => w.id === t.id || w.title === t.label);
776
+ else if (t.kind === 'trail') {
777
+ const wt = (trails ?? []).find((w) => w.id === t.id || w.title === t.label);
771
778
  if (wt) {
772
779
  for (const s of wt.steps) {
773
780
  nodeIds.add(s.from);
774
781
  nodeIds.add(s.to);
775
- edgeIds.add(walkthroughStepGraphEdgeId(s));
782
+ edgeIds.add(trailStepGraphEdgeId(s));
776
783
  }
777
784
  }
778
785
  }
@@ -793,7 +800,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
793
800
  edgeIds.add(e.id);
794
801
  }
795
802
  return { nodeIds, edgeIds };
796
- }, [issues, expandedIssueCategories, components, walkthroughs, resolveAlias]);
803
+ }, [issues, expandedIssueCategories, components, trails, resolveAlias]);
797
804
  const issueFocusNodeIds = issueFocus?.nodeIds ?? null;
798
805
  const issueFocusEdgeIds = issueFocus?.edgeIds ?? null;
799
806
  // When an edge is selected, dim every other edge + its label to focus it.
@@ -804,61 +811,61 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
804
811
  selectedEdgeIdRef.current = selectedEdgeId;
805
812
  // Ref mirrors of the focused step, so `unfocusIssueTarget` (a useCallback
806
813
  // over early deps) can tell a step focus it still owns from one the user has
807
- // since moved elsewhere in the walkthrough panel.
814
+ // since moved elsewhere in the trail panel.
808
815
  const focusedStepRef = useRef(null);
809
816
  focusedStepRef.current =
810
- focusedWalkthroughId != null && focusedStepIndex != null
811
- ? { walkthroughId: focusedWalkthroughId, stepIndex: focusedStepIndex }
817
+ focusedTrailId != null && focusedStepIndex != null
818
+ ? { trailId: focusedTrailId, stepIndex: focusedStepIndex }
812
819
  : null;
813
- // Edge ids in walkthrough focus (an active flow's edge set, or a single
814
- // step's edge). Used to frame the camera. `null` = no walkthrough focus.
820
+ // Edge ids in trail focus (an active flow's edge set, or a single
821
+ // step's edge). Used to frame the camera. `null` = no trail focus.
815
822
  const focusEdgeIds = useMemo(() => {
816
823
  if (autoPlayFocus) {
817
- const tl = walkthroughs?.find((t) => t.id === autoPlayFocus.walkthroughId);
824
+ const tl = trails?.find((t) => t.id === autoPlayFocus.trailId);
818
825
  const step = tl?.steps[autoPlayFocus.stepIndex];
819
- return step ? new Set([walkthroughStepGraphEdgeId(step)]) : null;
826
+ return step ? new Set([trailStepGraphEdgeId(step)]) : null;
820
827
  }
821
- if (focusedWalkthroughId == null || !walkthroughs)
828
+ if (focusedTrailId == null || !trails)
822
829
  return null;
823
- const tl = walkthroughs.find((t) => t.id === focusedWalkthroughId);
830
+ const tl = trails.find((t) => t.id === focusedTrailId);
824
831
  if (!tl)
825
832
  return null;
826
833
  if (focusedStepIndex != null) {
827
834
  const step = tl.steps[focusedStepIndex];
828
- return step ? new Set([walkthroughStepGraphEdgeId(step)]) : null;
835
+ return step ? new Set([trailStepGraphEdgeId(step)]) : null;
829
836
  }
830
- return new Set(tl.steps.map((s) => walkthroughStepGraphEdgeId(s)));
831
- }, [walkthroughs, focusedWalkthroughId, focusedStepIndex, autoPlayFocus]);
837
+ return new Set(tl.steps.map((s) => trailStepGraphEdgeId(s)));
838
+ }, [trails, focusedTrailId, focusedStepIndex, autoPlayFocus]);
832
839
  // 1-based step numbers per edge of the active flow (focused or
833
840
  // hover/autoplay-highlighted). An edge can appear in more than one step.
834
841
  const selectedFlowStepNos = useMemo(() => {
835
- const activeId = focusedWalkthroughId ?? hoveredWalkthroughStep?.walkthroughId;
836
- if (activeId == null || !walkthroughs)
842
+ const activeId = focusedTrailId ?? hoveredTrailStep?.trailId;
843
+ if (activeId == null || !trails)
837
844
  return null;
838
- const tl = walkthroughs.find((t) => t.id === activeId);
845
+ const tl = trails.find((t) => t.id === activeId);
839
846
  if (!tl)
840
847
  return null;
841
848
  const map = new Map();
842
849
  tl.steps.forEach((s, i) => {
843
- const list = map.get(walkthroughStepGraphEdgeId(s)) ?? [];
850
+ const list = map.get(trailStepGraphEdgeId(s)) ?? [];
844
851
  list.push(i + 1);
845
- map.set(walkthroughStepGraphEdgeId(s), list);
852
+ map.set(trailStepGraphEdgeId(s), list);
846
853
  });
847
854
  return map;
848
- }, [walkthroughs, focusedWalkthroughId, hoveredWalkthroughStep]);
849
- // Union of every expanded (opened) walkthrough's edges — the visible set.
855
+ }, [trails, focusedTrailId, hoveredTrailStep]);
856
+ // Union of every expanded (opened) trail's edges — the visible set.
850
857
  const openedEdgeIds = useMemo(() => {
851
- if (!walkthroughs || expandedWalkthroughs.size === 0)
858
+ if (!trails || expandedTrails.size === 0)
852
859
  return null;
853
860
  const ids = new Set();
854
- for (const tl of walkthroughs) {
855
- if (!expandedWalkthroughs.has(tl.id))
861
+ for (const tl of trails) {
862
+ if (!expandedTrails.has(tl.id))
856
863
  continue;
857
864
  for (const s of tl.steps)
858
- ids.add(walkthroughStepGraphEdgeId(s));
865
+ ids.add(trailStepGraphEdgeId(s));
859
866
  }
860
867
  return ids.size > 0 ? ids : null;
861
- }, [walkthroughs, expandedWalkthroughs]);
868
+ }, [trails, expandedTrails]);
862
869
  const endpointsOf = (edgeIds) => {
863
870
  if (!edgeIds)
864
871
  return null;
@@ -873,22 +880,22 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
873
880
  };
874
881
  // Edge/nodes involved in the hovered step or whole flow.
875
882
  const hoverEdgeIds = useMemo(() => {
876
- if (!hoveredWalkthroughStep || !walkthroughs)
883
+ if (!hoveredTrailStep || !trails)
877
884
  return null;
878
- const tl = walkthroughs.find((t) => t.id === hoveredWalkthroughStep.walkthroughId);
885
+ const tl = trails.find((t) => t.id === hoveredTrailStep.trailId);
879
886
  if (!tl)
880
887
  return null;
881
- if (hoveredWalkthroughStep.stepIndex == null) {
882
- return new Set(tl.steps.map((s) => walkthroughStepGraphEdgeId(s)));
888
+ if (hoveredTrailStep.stepIndex == null) {
889
+ return new Set(tl.steps.map((s) => trailStepGraphEdgeId(s)));
883
890
  }
884
- const step = tl.steps[hoveredWalkthroughStep.stepIndex];
885
- return step ? new Set([walkthroughStepGraphEdgeId(step)]) : null;
886
- }, [walkthroughs, hoveredWalkthroughStep]);
891
+ const step = tl.steps[hoveredTrailStep.stepIndex];
892
+ return step ? new Set([trailStepGraphEdgeId(step)]) : null;
893
+ }, [trails, hoveredTrailStep]);
887
894
  // While hovering with a *step* already selected, brighten the union of
888
895
  // selected + hovered participants. Whole-flow focus (or no focus) keeps
889
896
  // the old hover-replace preview so a step hover still dims the rest.
890
897
  const previewEdgeIds = useMemo(() => {
891
- // Autoplay drives focus without a hover, so its hop is the preview set.
898
+ // Autoplay drives focus without a hover, so its step is the preview set.
892
899
  if (autoPlayFocus)
893
900
  return focusEdgeIds;
894
901
  if (!hoverEdgeIds)
@@ -1028,14 +1035,14 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1028
1035
  };
1029
1036
  // Edges outside the selected view are hidden entirely (labels included).
1030
1037
  // graphify-native edges belong to the graphify view (they are static
1031
- // topology, not runtime hops) regardless of their verb.
1038
+ // topology, not runtime steps) regardless of their verb.
1032
1039
  const edgeInView = (e) => {
1033
1040
  const d = e.data;
1034
1041
  const mechanism = d?.mechanism ?? 'uses';
1035
1042
  if (resolvedEdgeView === 'graphify') {
1036
1043
  return d?.provenance === 'graphify';
1037
1044
  }
1038
- return isWalkthroughMechanism(mechanism);
1045
+ return isTrailMechanism(mechanism);
1039
1046
  };
1040
1047
  if (openedEdgeIds || focusEdgeIds || previewEdgeIds || issueFocusEdgeIds) {
1041
1048
  return baseEdges.map((e) => {
@@ -1090,7 +1097,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1090
1097
  const onNodeClick = useCallback((_e, node) => {
1091
1098
  const comp = node.data?.component;
1092
1099
  setSelectedEdgeId(null);
1093
- setFocusedWalkthroughId(null);
1100
+ setFocusedTrailId(null);
1094
1101
  setFocusedStepIndex(null);
1095
1102
  if (node.type === 'subsystem-component' && comp) {
1096
1103
  // Clicking the already-selected node unselects it (toggle off).
@@ -1112,15 +1119,15 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1112
1119
  const onPaneClick = useCallback(() => {
1113
1120
  setSelected(null);
1114
1121
  setSelectedEdgeId(null);
1115
- setFocusedWalkthroughId(null);
1122
+ setFocusedTrailId(null);
1116
1123
  setFocusedStepIndex(null);
1117
1124
  issueModuleFocusRef.current = null;
1118
1125
  }, []);
1119
1126
  // Sidebar file trees — one per repo on multi-repo graphs, each under its
1120
1127
  // own owner-avatar header. Clicking a header collapses that repo's tree.
1121
1128
  const repoGroups = useMemo(() => buildRepoGroups(components), [components]);
1122
- const hasWalkthroughs = useMemo(() => (walkthroughs?.length ?? 0) > 0, [walkthroughs]);
1123
- // Aliases of proposed components — the flows panel tints walkthrough titles
1129
+ const hasTrails = useMemo(() => (trails?.length ?? 0) > 0, [trails]);
1130
+ // Aliases of proposed components — the flows panel tints trail titles
1124
1131
  // (and steps) that touch one.
1125
1132
  const proposedAliases = useMemo(() => new Set(components.filter((c) => c.proposed).map((c) => c.alias)), [components]);
1126
1133
  // Diagnostics view in the sidebar. Uncontrolled unless the host pins
@@ -1181,7 +1188,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1181
1188
  const [focusedBoundaryKey, setFocusedBoundaryKey] = useState(null);
1182
1189
  const onNodeDoubleClick = useCallback((_e, node) => {
1183
1190
  // Boundary frame → frame its members on the canvas; double-click again to
1184
- // zoom back out. User-initiated, so it ignores the walkthrough zoom gate.
1191
+ // zoom back out. User-initiated, so it ignores the trail zoom gate.
1185
1192
  if (node.type === 'subsystem-group') {
1186
1193
  const key = node.data?.region?.key;
1187
1194
  if (!key)
@@ -1216,7 +1223,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1216
1223
  const startLine = comp.declarationRef?.startLine;
1217
1224
  onOpenDeclarationFile(comp.file, startLine != null ? { startLine } : undefined);
1218
1225
  }, [onOpenDeclarationFile, fitView, focusedBoundaryKey]);
1219
- const onOpenFileFromWalkthrough = useCallback((file, opts) => {
1226
+ const onOpenFileFromTrail = useCallback((file, opts) => {
1220
1227
  setFileOverlay({ file, startLine: opts?.startLine });
1221
1228
  onFileSelect?.(file);
1222
1229
  }, [onFileSelect]);
@@ -1230,14 +1237,14 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1230
1237
  const drawerFillHeight = drawerTarget?.kind === 'file' && drawerTarget.startLine == null;
1231
1238
  const fileOverlayOpen = fileOverlay != null;
1232
1239
  const collapseCanvas = drawerFillHeight || fileOverlayOpen;
1233
- // Drop the full-file overlay when the underlying walkthrough drawer changes
1240
+ // Drop the full-file overlay when the underlying trail drawer changes
1234
1241
  // or closes — open-file keeps the same drawerTarget so the snippets stay mounted.
1235
- const walkthroughDrawerKey = drawerTarget?.kind === 'walkthrough'
1236
- ? `${drawerTarget.walkthroughId}:${drawerTarget.stepIndex}`
1242
+ const trailDrawerKey = drawerTarget?.kind === 'trail'
1243
+ ? `${drawerTarget.trailId}:${drawerTarget.stepIndex}`
1237
1244
  : null;
1238
1245
  useEffect(() => {
1239
1246
  setFileOverlay(null);
1240
- }, [walkthroughDrawerKey]);
1247
+ }, [trailDrawerKey]);
1241
1248
  useEffect(() => {
1242
1249
  if (!fileOverlayOpen)
1243
1250
  return;
@@ -1248,15 +1255,15 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1248
1255
  window.addEventListener('keydown', onKey);
1249
1256
  return () => window.removeEventListener('keydown', onKey);
1250
1257
  }, [fileOverlayOpen, closeFileOverlay]);
1251
- // Camera helper shared by the walkthrough interactions. Fits the union of
1258
+ // Camera helper shared by the trail interactions. Fits the union of
1252
1259
  // the focused edges' endpoint rects AND their routed waypoints — the edge
1253
1260
  // carries its full polyline (`elkPathPoints`, absolute flow coords), so the
1254
- // frame is the line the hop actually traces. That keeps a hop whose route
1261
+ // frame is the line the step actually traces. That keeps a step whose route
1255
1262
  // bulges out around intervening nodes from being clipped at the viewport
1256
1263
  // edge, and it is the edge's own geometry doing the guiding, not fudge
1257
1264
  // padding.
1258
1265
  const fitFocusBounds = useCallback((ids) => {
1259
- if (!zoomOnWalkthroughFocus)
1266
+ if (!zoomOnTrailFocus)
1260
1267
  return;
1261
1268
  const nodeIds = new Set();
1262
1269
  const points = [];
@@ -1306,14 +1313,14 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1306
1313
  };
1307
1314
  fitBounds(bounds, {
1308
1315
  padding: 0.15,
1309
- duration: walkthroughFocusDurationMs,
1316
+ duration: trailFocusDurationMs,
1310
1317
  });
1311
1318
  }, [
1312
1319
  baseEdges,
1313
1320
  built.absoluteRects,
1314
1321
  fitBounds,
1315
- zoomOnWalkthroughFocus,
1316
- walkthroughFocusDurationMs,
1322
+ zoomOnTrailFocus,
1323
+ trailFocusDurationMs,
1317
1324
  ]);
1318
1325
  // A node's laid-out rect in absolute flow coords. `absoluteRects` is the
1319
1326
  // authority; the fallback covers an unparented group node, whose `position` is
@@ -1359,12 +1366,12 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1359
1366
  y: minY,
1360
1367
  width: Math.max(1, maxX - minX),
1361
1368
  height: Math.max(1, maxY - minY),
1362
- }, { padding, duration: walkthroughFocusDurationMs });
1363
- }, [rectForNode, fitBounds, walkthroughFocusDurationMs]);
1364
- // Zoom back out to the full diagram after the last expanded walkthrough
1369
+ }, { padding, duration: trailFocusDurationMs });
1370
+ }, [rectForNode, fitBounds, trailFocusDurationMs]);
1371
+ // Zoom back out to the full diagram after the last expanded trail
1365
1372
  // closes (visibility restores non-flow nodes that were hidden).
1366
1373
  const fitOverview = useCallback(() => {
1367
- if (!zoomOnWalkthroughFocus)
1374
+ if (!zoomOnTrailFocus)
1368
1375
  return;
1369
1376
  fitView({
1370
1377
  padding: 0.1,
@@ -1373,109 +1380,109 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1373
1380
  maxZoom: 2,
1374
1381
  duration: 300,
1375
1382
  });
1376
- }, [fitView, zoomOnWalkthroughFocus]);
1383
+ }, [fitView, zoomOnTrailFocus]);
1377
1384
  // Focus an entire flow: hide everything but the flow's nodes and edges, and
1378
1385
  // frame the flow on the canvas. Selection state is cleared — the graph now
1379
1386
  // reads as the narrative. No drawer: the code view only opens on a step
1380
- // click. A stale walkthrough drawer (from a previously focused flow's step)
1387
+ // click. A stale trail drawer (from a previously focused flow's step)
1381
1388
  // closes; an explicitly opened file drawer stays.
1382
1389
  // In `dim` mode: clear step highlight and leave the full graph visible
1383
1390
  // (no zoom / hide) — matching "step away from a hovered step".
1384
- const focusWalkthroughEdges = useCallback((tl) => {
1391
+ const focusTrailEdges = useCallback((tl) => {
1385
1392
  setSelected(null);
1386
1393
  setSelectedEdgeId(null);
1387
- setHoveredWalkthroughStep(null);
1388
- if (walkthroughStepMode === 'dim') {
1394
+ setHoveredTrailStep(null);
1395
+ if (trailStepMode === 'dim') {
1389
1396
  setFocusedStepIndex(null);
1390
- setFocusedWalkthroughId(null);
1391
- setDrawerTarget((prev) => (prev?.kind === 'walkthrough' ? null : prev));
1397
+ setFocusedTrailId(null);
1398
+ setDrawerTarget((prev) => (prev?.kind === 'trail' ? null : prev));
1392
1399
  return;
1393
1400
  }
1394
1401
  setFocusedStepIndex(null);
1395
- setFocusedWalkthroughId(tl.id);
1396
- fitFocusBounds(new Set(tl.steps.map((s) => walkthroughStepGraphEdgeId(s))));
1397
- setDrawerTarget((prev) => (prev?.kind === 'walkthrough' ? null : prev));
1398
- }, [fitFocusBounds, walkthroughStepMode]);
1399
- const clearWalkthroughFocus = useCallback(() => {
1400
- setFocusedWalkthroughId(null);
1402
+ setFocusedTrailId(tl.id);
1403
+ fitFocusBounds(new Set(tl.steps.map((s) => trailStepGraphEdgeId(s))));
1404
+ setDrawerTarget((prev) => (prev?.kind === 'trail' ? null : prev));
1405
+ }, [fitFocusBounds, trailStepMode]);
1406
+ const clearTrailFocus = useCallback(() => {
1407
+ setFocusedTrailId(null);
1401
1408
  setFocusedStepIndex(null);
1402
- setHoveredWalkthroughStep(null);
1403
- setDrawerTarget((prev) => (prev?.kind === 'walkthrough' ? null : prev));
1409
+ setHoveredTrailStep(null);
1410
+ setDrawerTarget((prev) => (prev?.kind === 'trail' ? null : prev));
1404
1411
  }, []);
1405
- // Host deep-link: opening the graph from a walkthrough row selects that
1412
+ // Host deep-link: opening the graph from a trail row selects that
1406
1413
  // flow — expand its steps, focus its edges, and switch the sidebar to
1407
- // Walkthroughs. Guarded by a ref so a later in-tab selection isn't yanked
1414
+ // Trails. Guarded by a ref so a later in-tab selection isn't yanked
1408
1415
  // back; a remount (or a new id) re-applies it.
1409
- const appliedInitialWalkthroughRef = useRef(null);
1416
+ const appliedInitialTrailRef = useRef(null);
1410
1417
  useEffect(() => {
1411
- if (!initialWalkthroughId)
1418
+ if (!initialTrailId)
1412
1419
  return;
1413
- if (appliedInitialWalkthroughRef.current === initialWalkthroughId)
1420
+ if (appliedInitialTrailRef.current === initialTrailId)
1414
1421
  return;
1415
- if (!layoutReady || !walkthroughs?.length)
1422
+ if (!layoutReady || !trails?.length)
1416
1423
  return;
1417
- const tl = walkthroughs.find((t) => t.id === initialWalkthroughId);
1424
+ const tl = trails.find((t) => t.id === initialTrailId);
1418
1425
  if (!tl)
1419
1426
  return;
1420
- appliedInitialWalkthroughRef.current = initialWalkthroughId;
1421
- setSidebarView('walkthroughs');
1422
- setExpandedWalkthroughs((prev) => new Set(prev).add(tl.id));
1423
- focusWalkthroughEdges(tl);
1424
- }, [initialWalkthroughId, layoutReady, walkthroughs, focusWalkthroughEdges]);
1427
+ appliedInitialTrailRef.current = initialTrailId;
1428
+ setSidebarView('trails');
1429
+ setExpandedTrails((prev) => new Set(prev).add(tl.id));
1430
+ focusTrailEdges(tl);
1431
+ }, [initialTrailId, layoutReady, trails, focusTrailEdges]);
1425
1432
  // Switching sidebar panels also switches the edge vocabulary. Leaving the
1426
- // Walkthroughs panel drops its canvas state (focus, expanded flows, selected
1433
+ // Trails panel drops its canvas state (focus, expanded flows, selected
1427
1434
  // edge) so the Files view's topology edges aren't gated by a flow the user
1428
1435
  // can no longer see or un-dim.
1429
1436
  const changeSidebarView = useCallback((view) => {
1430
1437
  setSidebarView(view);
1431
- if (view === 'walkthroughs')
1438
+ if (view === 'trails')
1432
1439
  return;
1433
- clearWalkthroughFocus();
1434
- setExpandedWalkthroughs(new Set());
1440
+ clearTrailFocus();
1441
+ setExpandedTrails(new Set());
1435
1442
  setSelectedEdgeId(null);
1436
- }, [clearWalkthroughFocus]);
1437
- // Focus a single step's edge on the canvas and open/scroll the walkthrough
1443
+ }, [clearTrailFocus]);
1444
+ // Focus a single step's edge on the canvas and open/scroll the trail
1438
1445
  // drawer to that step's snippet. Clicking the already-focused step clears
1439
1446
  // step focus and returns to whole-flow (high-level) framing.
1440
1447
  // In `dim` mode: only dim non-participants (same as hovering a step) —
1441
1448
  // no camera move, no drawer, no hide.
1442
- const focusWalkthroughStep = useCallback((tl, stepIndex) => {
1449
+ const focusTrailStep = useCallback((tl, stepIndex) => {
1443
1450
  const step = tl.steps[stepIndex];
1444
1451
  if (!step)
1445
1452
  return;
1446
1453
  setSelected(null);
1447
1454
  setSelectedEdgeId(null);
1448
- if (walkthroughStepMode === 'dim') {
1455
+ if (trailStepMode === 'dim') {
1449
1456
  setFocusedStepIndex(null);
1450
- setFocusedWalkthroughId(null);
1451
- setHoveredWalkthroughStep({ walkthroughId: tl.id, stepIndex });
1452
- setDrawerTarget((prev) => (prev?.kind === 'walkthrough' ? null : prev));
1457
+ setFocusedTrailId(null);
1458
+ setHoveredTrailStep({ trailId: tl.id, stepIndex });
1459
+ setDrawerTarget((prev) => (prev?.kind === 'trail' ? null : prev));
1453
1460
  return;
1454
1461
  }
1455
1462
  // Toggle: clicking the selected step unselects it (back to whole flow).
1456
- if (focusedWalkthroughId === tl.id && focusedStepIndex === stepIndex) {
1463
+ if (focusedTrailId === tl.id && focusedStepIndex === stepIndex) {
1457
1464
  setFocusedStepIndex(null);
1458
1465
  // Pointer is still over the row — keep hover preview so dimming doesn't
1459
1466
  // flash off until mouseleave.
1460
- setHoveredWalkthroughStep({ walkthroughId: tl.id, stepIndex });
1461
- setDrawerTarget((prev) => (prev?.kind === 'walkthrough' ? null : prev));
1467
+ setHoveredTrailStep({ trailId: tl.id, stepIndex });
1468
+ setDrawerTarget((prev) => (prev?.kind === 'trail' ? null : prev));
1462
1469
  if (pendingFocusFitRef.current != null) {
1463
1470
  window.clearTimeout(pendingFocusFitRef.current);
1464
1471
  pendingFocusFitRef.current = null;
1465
1472
  }
1466
- fitFocusBounds(new Set(tl.steps.map((s) => walkthroughStepGraphEdgeId(s))));
1473
+ fitFocusBounds(new Set(tl.steps.map((s) => trailStepGraphEdgeId(s))));
1467
1474
  return;
1468
1475
  }
1469
1476
  setFocusedStepIndex(stepIndex);
1470
- setFocusedWalkthroughId(tl.id);
1471
- setHoveredWalkthroughStep(null);
1477
+ setFocusedTrailId(tl.id);
1478
+ setHoveredTrailStep(null);
1472
1479
  // Open the drawer before fitting. If it was closed, wait for its height
1473
1480
  // transition so fitView uses the reduced canvas — not full height.
1474
1481
  const drawerWasOpen = drawerOpenRef.current;
1475
- if (renderWalkthroughViewer) {
1482
+ if (renderTrailViewer) {
1476
1483
  setDrawerTarget({
1477
- kind: 'walkthrough',
1478
- walkthroughId: tl.id,
1484
+ kind: 'trail',
1485
+ trailId: tl.id,
1479
1486
  stepIndex,
1480
1487
  });
1481
1488
  }
@@ -1486,7 +1493,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1486
1493
  startLine: step.line,
1487
1494
  });
1488
1495
  }
1489
- const edgeIds = new Set([walkthroughStepGraphEdgeId(step)]);
1496
+ const edgeIds = new Set([trailStepGraphEdgeId(step)]);
1490
1497
  if (pendingFocusFitRef.current != null) {
1491
1498
  window.clearTimeout(pendingFocusFitRef.current);
1492
1499
  pendingFocusFitRef.current = null;
@@ -1503,9 +1510,9 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1503
1510
  }, [
1504
1511
  fitFocusBounds,
1505
1512
  focusedStepIndex,
1506
- focusedWalkthroughId,
1507
- renderWalkthroughViewer,
1508
- walkthroughStepMode,
1513
+ focusedTrailId,
1514
+ renderTrailViewer,
1515
+ trailStepMode,
1509
1516
  ]);
1510
1517
  useEffect(() => {
1511
1518
  return () => {
@@ -1523,11 +1530,11 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1523
1530
  useEffect(() => {
1524
1531
  const prev = prevPreviewEdgeIdsRef.current;
1525
1532
  prevPreviewEdgeIdsRef.current = previewEdgeIds;
1526
- if (!zoomOnWalkthroughFocus || walkthroughStepMode === 'dim')
1533
+ if (!zoomOnTrailFocus || trailStepMode === 'dim')
1527
1534
  return;
1528
1535
  // Camera follows hover only when a specific step is already focused (or
1529
1536
  // autoplay is driving an auto-focus).
1530
- if (!autoPlayFocus && (focusedWalkthroughId == null || focusedStepIndex == null)) {
1537
+ if (!autoPlayFocus && (focusedTrailId == null || focusedStepIndex == null)) {
1531
1538
  return;
1532
1539
  }
1533
1540
  if (previewEdgeIds) {
@@ -1540,27 +1547,27 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1540
1547
  }, [
1541
1548
  previewEdgeIds,
1542
1549
  focusEdgeIds,
1543
- focusedWalkthroughId,
1550
+ focusedTrailId,
1544
1551
  focusedStepIndex,
1545
1552
  autoPlayFocus,
1546
1553
  fitFocusBounds,
1547
- zoomOnWalkthroughFocus,
1548
- walkthroughStepMode,
1554
+ zoomOnTrailFocus,
1555
+ trailStepMode,
1549
1556
  ]);
1550
- // Graph-only embeds: cycle walkthrough steps. In `focus` mode each step is
1551
- // selected (camera frames it via fitFocusBounds) and, when a walkthrough
1557
+ // Graph-only embeds: cycle trail steps. In `focus` mode each step is
1558
+ // selected (camera frames it via fitFocusBounds) and, when a trail
1552
1559
  // viewer is supplied, its snippet drawer opens; in `dim` mode it only
1553
1560
  // dim-highlights the step (hover-style) with no camera move.
1554
1561
  useEffect(() => {
1555
- if (!autoPlayWalkthroughs || walkthroughs == null || walkthroughs.length === 0)
1562
+ if (!autoPlayTrails || trails == null || trails.length === 0)
1556
1563
  return;
1557
1564
  if (!layoutReady)
1558
1565
  return;
1559
- const playable = walkthroughs.filter((tl) => tl.steps.length > 0);
1566
+ const playable = trails.filter((tl) => tl.steps.length > 0);
1560
1567
  if (playable.length === 0)
1561
1568
  return;
1562
1569
  // Only run the cycles that can actually be shown in the current edge view.
1563
- const inView = playable.filter((tl) => tl.steps.some((s) => isWalkthroughMechanism(s.mechanism)));
1570
+ const inView = playable.filter((tl) => tl.steps.some((s) => isTrailMechanism(s.mechanism)));
1564
1571
  if (inView.length === 0)
1565
1572
  return;
1566
1573
  const cyc = inView;
@@ -1568,8 +1575,8 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1568
1575
  let tlIdx = 0;
1569
1576
  let stepIdx = 0;
1570
1577
  let timer = null;
1571
- const interval = Math.max(400, walkthroughAutoPlayIntervalMs);
1572
- const focusMode = walkthroughStepMode !== 'dim';
1578
+ const interval = Math.max(400, trailAutoPlayIntervalMs);
1579
+ const focusMode = trailStepMode !== 'dim';
1573
1580
  let cleanup = () => { };
1574
1581
  const tick = () => {
1575
1582
  if (cancelled)
@@ -1578,15 +1585,15 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1578
1585
  setSelected(null);
1579
1586
  setSelectedEdgeId(null);
1580
1587
  if (focusMode) {
1581
- setHoveredWalkthroughStep(null);
1582
- setFocusedWalkthroughId(null);
1588
+ setHoveredTrailStep(null);
1589
+ setFocusedTrailId(null);
1583
1590
  setFocusedStepIndex(null);
1584
- setAutoPlayFocus({ walkthroughId: tl.id, stepIndex: stepIdx });
1591
+ setAutoPlayFocus({ trailId: tl.id, stepIndex: stepIdx });
1585
1592
  if (!hideDrawer) {
1586
1593
  const step = tl.steps[stepIdx];
1587
1594
  if (step) {
1588
- if (renderWalkthroughViewer) {
1589
- setDrawerTarget({ kind: 'walkthrough', walkthroughId: tl.id, stepIndex: stepIdx });
1595
+ if (renderTrailViewer) {
1596
+ setDrawerTarget({ kind: 'trail', trailId: tl.id, stepIndex: stepIdx });
1590
1597
  }
1591
1598
  else {
1592
1599
  setDrawerTarget({ kind: 'file', file: step.file, startLine: step.line });
@@ -1596,9 +1603,9 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1596
1603
  }
1597
1604
  else {
1598
1605
  setAutoPlayFocus(null);
1599
- setFocusedWalkthroughId(null);
1606
+ setFocusedTrailId(null);
1600
1607
  setFocusedStepIndex(null);
1601
- setHoveredWalkthroughStep({ walkthroughId: tl.id, stepIndex: stepIdx });
1608
+ setHoveredTrailStep({ trailId: tl.id, stepIndex: stepIdx });
1602
1609
  }
1603
1610
  stepIdx += 1;
1604
1611
  if (stepIdx >= tl.steps.length) {
@@ -1612,28 +1619,28 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1612
1619
  cancelled = true;
1613
1620
  if (timer != null)
1614
1621
  window.clearTimeout(timer);
1615
- setHoveredWalkthroughStep(null);
1616
- setFocusedWalkthroughId(null);
1622
+ setHoveredTrailStep(null);
1623
+ setFocusedTrailId(null);
1617
1624
  setFocusedStepIndex(null);
1618
1625
  setAutoPlayFocus(null);
1619
1626
  };
1620
1627
  return cleanup;
1621
1628
  }, [
1622
- autoPlayWalkthroughs,
1623
- walkthroughs,
1624
- walkthroughAutoPlayIntervalMs,
1629
+ autoPlayTrails,
1630
+ trails,
1631
+ trailAutoPlayIntervalMs,
1625
1632
  layoutReady,
1626
- walkthroughStepMode,
1627
- renderWalkthroughViewer,
1633
+ trailStepMode,
1634
+ renderTrailViewer,
1628
1635
  hideDrawer,
1629
1636
  ]);
1630
- // Arrow keys step through the focused walkthrough once a step is active
1637
+ // Arrow keys step through the focused trail once a step is active
1631
1638
  // (sidebar click or drawer open). Ignores typing targets and chords.
1632
1639
  useEffect(() => {
1633
- if (focusedWalkthroughId == null || focusedStepIndex == null || !walkthroughs) {
1640
+ if (focusedTrailId == null || focusedStepIndex == null || !trails) {
1634
1641
  return;
1635
1642
  }
1636
- const tl = walkthroughs.find((t) => t.id === focusedWalkthroughId);
1643
+ const tl = trails.find((t) => t.id === focusedTrailId);
1637
1644
  if (!tl || tl.steps.length === 0)
1638
1645
  return;
1639
1646
  const onKeyDown = (e) => {
@@ -1660,19 +1667,19 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1660
1667
  if (next === focusedStepIndex)
1661
1668
  return;
1662
1669
  e.preventDefault();
1663
- focusWalkthroughStep(tl, next);
1670
+ focusTrailStep(tl, next);
1664
1671
  };
1665
1672
  window.addEventListener('keydown', onKeyDown);
1666
1673
  return () => window.removeEventListener('keydown', onKeyDown);
1667
1674
  }, [
1668
- focusedWalkthroughId,
1675
+ focusedTrailId,
1669
1676
  focusedStepIndex,
1670
- walkthroughs,
1671
- focusWalkthroughStep,
1677
+ trails,
1678
+ focusTrailStep,
1672
1679
  ]);
1673
- const toggleWalkthroughCollapsed = useCallback((tlId) => {
1674
- const collapsingLast = expandedWalkthroughs.has(tlId) && expandedWalkthroughs.size === 1;
1675
- setExpandedWalkthroughs((prev) => {
1680
+ const toggleTrailCollapsed = useCallback((tlId) => {
1681
+ const collapsingLast = expandedTrails.has(tlId) && expandedTrails.size === 1;
1682
+ setExpandedTrails((prev) => {
1676
1683
  const next = new Set(prev);
1677
1684
  if (next.has(tlId))
1678
1685
  next.delete(tlId);
@@ -1680,7 +1687,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1680
1687
  next.add(tlId);
1681
1688
  return next;
1682
1689
  });
1683
- if (!collapsingLast || !zoomOnWalkthroughFocus)
1690
+ if (!collapsingLast || !zoomOnTrailFocus)
1684
1691
  return;
1685
1692
  // Cancel any pending focus fit so it doesn't fight the overview zoom.
1686
1693
  if (pendingFocusFitRef.current != null) {
@@ -1695,7 +1702,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1695
1702
  pendingFocusFitRef.current = null;
1696
1703
  requestAnimationFrame(() => fitOverview());
1697
1704
  }, drawerWasOpen ? FILE_DRAWER_HEIGHT_MS + 20 : 20);
1698
- }, [expandedWalkthroughs, fitOverview, zoomOnWalkthroughFocus]);
1705
+ }, [expandedTrails, fitOverview, zoomOnTrailFocus]);
1699
1706
  // Detail-panel links: related-name clicks select the matching component —
1700
1707
  // resolved by alias, name, or symbol (call labels may carry a trailing `()`).
1701
1708
  const resolveRelatedComponent = useCallback((ref) => {
@@ -1708,7 +1715,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1708
1715
  return;
1709
1716
  setSelected(comp);
1710
1717
  setSelectedEdgeId(null);
1711
- setFocusedWalkthroughId(null);
1718
+ setFocusedTrailId(null);
1712
1719
  setFocusedStepIndex(null);
1713
1720
  onSelect?.(comp.alias);
1714
1721
  }, [components, onSelect]);
@@ -1723,9 +1730,9 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1723
1730
  if (comp) {
1724
1731
  setSelected(comp);
1725
1732
  setSelectedEdgeId(null);
1726
- setFocusedWalkthroughId(null);
1733
+ setFocusedTrailId(null);
1727
1734
  setFocusedStepIndex(null);
1728
- setHoveredWalkthroughStep(null);
1735
+ setHoveredTrailStep(null);
1729
1736
  issueModuleFocusRef.current = null;
1730
1737
  onSelect?.(comp.alias);
1731
1738
  requestAnimationFrame(() => {
@@ -1740,11 +1747,11 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1740
1747
  }
1741
1748
  else if (step) {
1742
1749
  // A step finding focuses the step itself, through the same entry point
1743
- // the walkthrough panel uses — so the drawer, the step numbering, the
1750
+ // the trail panel uses — so the drawer, the step numbering, the
1744
1751
  // dim-mode hover preview, and the camera all behave identically whether
1745
1752
  // the step was reached from the panel or from a diagnostics card.
1746
1753
  issueModuleFocusRef.current = null;
1747
- focusWalkthroughStep(step.walkthrough, step.stepIndex);
1754
+ focusTrailStep(step.trail, step.stepIndex);
1748
1755
  }
1749
1756
  else {
1750
1757
  // Nothing selectable — but a module target names a boundary frame, so
@@ -1753,9 +1760,9 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1753
1760
  if (moduleNodeId) {
1754
1761
  setSelected(null);
1755
1762
  setSelectedEdgeId(null);
1756
- setFocusedWalkthroughId(null);
1763
+ setFocusedTrailId(null);
1757
1764
  setFocusedStepIndex(null);
1758
- setHoveredWalkthroughStep(null);
1765
+ setHoveredTrailStep(null);
1759
1766
  issueModuleFocusRef.current = moduleNodeId;
1760
1767
  requestAnimationFrame(() => {
1761
1768
  fitNodeRects(new Set([moduleNodeId]), 0.4);
@@ -1767,7 +1774,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1767
1774
  issueComponent,
1768
1775
  issueStep,
1769
1776
  issueModuleNodeId,
1770
- focusWalkthroughStep,
1777
+ focusTrailStep,
1771
1778
  onSelect,
1772
1779
  onSelectIssue,
1773
1780
  fitView,
@@ -1795,13 +1802,13 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1795
1802
  // keeps its step focus in hover state instead (owned by the pointer,
1796
1803
  // not the card), and correctly leaves that alone here.
1797
1804
  const owned = focusedStepRef.current;
1798
- if (owned?.walkthroughId !== step.walkthrough.id ||
1805
+ if (owned?.trailId !== step.trail.id ||
1799
1806
  owned?.stepIndex !== step.stepIndex) {
1800
1807
  return;
1801
1808
  }
1802
- setFocusedWalkthroughId(null);
1809
+ setFocusedTrailId(null);
1803
1810
  setFocusedStepIndex(null);
1804
- setDrawerTarget((prev) => (prev?.kind === 'walkthrough' ? null : prev));
1811
+ setDrawerTarget((prev) => (prev?.kind === 'trail' ? null : prev));
1805
1812
  }
1806
1813
  else if (moduleNodeId) {
1807
1814
  // Only unwind framing this card still owns.
@@ -1817,14 +1824,14 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1817
1824
  fitView({ padding: 0.1, duration: 300, minZoom: 0.05, maxZoom: 2 });
1818
1825
  });
1819
1826
  }, [issueComponent, issueStep, issueModuleNodeId, fitView]);
1820
- // Construct tokens inside a walkthrough snippet. A step's line is an edge
1827
+ // Construct tokens inside a trail snippet. A step's line is an edge
1821
1828
  // between its `from`/`to` components, so a token naming either of those
1822
1829
  // constructs should navigate to that construct's declaration. Index the
1823
- // matchable identifiers per step (`walkthroughId:index`).
1824
- const walkthroughSymbolIndex = useMemo(() => {
1830
+ // matchable identifiers per step (`trailId:index`).
1831
+ const trailSymbolIndex = useMemo(() => {
1825
1832
  const byAlias = new Map(components.map((c) => [c.alias, c]));
1826
1833
  const index = new Map();
1827
- for (const wt of walkthroughs ?? []) {
1834
+ for (const wt of trails ?? []) {
1828
1835
  wt.steps.forEach((step, i) => {
1829
1836
  const tokens = new Map();
1830
1837
  for (const alias of [step.from, step.to]) {
@@ -1838,17 +1845,17 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1838
1845
  });
1839
1846
  }
1840
1847
  return index;
1841
- }, [components, walkthroughs]);
1842
- const walkthroughSymbolIndexRef = useRef(walkthroughSymbolIndex);
1843
- walkthroughSymbolIndexRef.current = walkthroughSymbolIndex;
1844
- // Stable resolver: reads the live index + focused walkthrough from refs so
1845
- // the memoized walkthrough drawer isn't rebuilt on every graph render.
1846
- const resolveWalkthroughSymbol = useCallback((query) => {
1847
- const walkthroughId = drawerWalkthroughIdRef.current;
1848
- if (walkthroughId == null)
1848
+ }, [components, trails]);
1849
+ const trailSymbolIndexRef = useRef(trailSymbolIndex);
1850
+ trailSymbolIndexRef.current = trailSymbolIndex;
1851
+ // Stable resolver: reads the live index + focused trail from refs so
1852
+ // the memoized trail drawer isn't rebuilt on every graph render.
1853
+ const resolveTrailSymbol = useCallback((query) => {
1854
+ const trailId = drawerTrailIdRef.current;
1855
+ if (trailId == null)
1849
1856
  return null;
1850
- return (walkthroughSymbolIndexRef.current
1851
- .get(`${walkthroughId}:${query.stepIndex}`)
1857
+ return (trailSymbolIndexRef.current
1858
+ .get(`${trailId}:${query.stepIndex}`)
1852
1859
  ?.get(query.tokenText) ?? null);
1853
1860
  }, []);
1854
1861
  // A construct token click navigates to that construct's declaration: open
@@ -1894,27 +1901,16 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1894
1901
  return null;
1895
1902
  return components.find((c) => c.alias === hoveredComponentAlias)?.file ?? null;
1896
1903
  }, [components, hoveredComponentAlias]);
1897
- // Drawer content renderer: prefer the path-keyed viewer; fall back to the
1898
- // legacy component-keyed one via a file → first-component lookup.
1899
- const fileViewer = useMemo(() => {
1900
- if (renderFileViewer)
1901
- return renderFileViewer;
1902
- if (renderFileView) {
1903
- const byFile = new Map(components.filter((c) => c.file).map((c) => [c.file, c]));
1904
- return (file, _opts) => {
1905
- const comp = byFile.get(file);
1906
- return comp ? renderFileView(comp) : null;
1907
- };
1908
- }
1909
- return renderFileViewer;
1910
- }, [renderFileViewer, renderFileView, components]);
1904
+ // Drawer content renderer. Path-keyed only — the component-keyed
1905
+ // `renderFileView` variant was removed; nothing in-repo passed it.
1906
+ const fileViewer = renderFileViewer;
1911
1907
  const fileViewerRef = useRef(fileViewer);
1912
1908
  fileViewerRef.current = fileViewer;
1913
1909
  const renderDrawerContent = useCallback((file, opts) => fileViewerRef.current?.(file, opts) ?? null, []);
1914
- const walkthroughViewerRef = useRef(renderWalkthroughViewer);
1915
- walkthroughViewerRef.current = renderWalkthroughViewer;
1916
- const renderWalkthroughDrawerContent = useCallback((ctx) => walkthroughViewerRef.current?.(ctx) ?? null, []);
1917
- return (_jsxs("div", { style: { width: '100%', height: '100%', display: 'flex', flexDirection: 'row', userSelect: sidebarDrag ? 'none' : undefined }, children: [!hideSidebar && (title || description || diagnostic || issuesActive || sidebarExtra || sidebarAfterDescription || treeFilePaths.length > 0 || hasWalkthroughs) && (_jsxs("div", { style: {
1910
+ const trailViewerRef = useRef(renderTrailViewer);
1911
+ trailViewerRef.current = renderTrailViewer;
1912
+ const renderTrailDrawerContent = useCallback((ctx) => trailViewerRef.current?.(ctx) ?? null, []);
1913
+ return (_jsxs("div", { style: { width: '100%', height: '100%', display: 'flex', flexDirection: 'row', userSelect: sidebarDrag ? 'none' : undefined }, children: [!hideSidebar && (title || description || diagnostic || issuesActive || sidebarExtra || sidebarAfterDescription || treeFilePaths.length > 0 || hasTrails) && (_jsxs("div", { style: {
1918
1914
  width: sidebarWidth,
1919
1915
  minWidth: sidebarWidth,
1920
1916
  borderRight: `1px solid ${theme.colors.border}`,
@@ -1960,7 +1956,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1960
1956
  color: descriptionVisible || descToggleHover ? theme.colors.text : (theme.colors.textMuted ?? theme.colors.textSecondary),
1961
1957
  cursor: 'pointer',
1962
1958
  transition: 'background 120ms ease, color 120ms ease',
1963
- }, children: _jsx(FileText, { size: 14 }) }))] })] })), description && descriptionVisible && (_jsx("div", { style: { fontSize: theme.fontSizes[0], lineHeight: 1.5 }, children: _jsx(IndustryMarkdownSlide, { content: description, slideIdPrefix: "subsystem-desc", slideIndex: 0, isVisible: true, theme: theme, disableScroll: true, disableBasePadding: true, enableKeyboardScrolling: false, autoFocusOnVisible: false }) })), sidebarAfterDescription] }), (treeFilePaths.length > 0 || hasWalkthroughs || issuesActive) && (_jsx("div", { style: {
1959
+ }, children: _jsx(FileText, { size: 14 }) }))] })] })), description && descriptionVisible && (_jsx("div", { style: { fontSize: theme.fontSizes[0], lineHeight: 1.5 }, children: _jsx(IndustryMarkdownSlide, { content: description, slideIdPrefix: "subsystem-desc", slideIndex: 0, isVisible: true, theme: theme, disableScroll: true, disableBasePadding: true, enableKeyboardScrolling: false, autoFocusOnVisible: false }) })), sidebarAfterDescription] }), (treeFilePaths.length > 0 || hasTrails || issuesActive) && (_jsx("div", { style: {
1964
1960
  ...(showDesc ? { height: '50%' } : { flex: 1, minHeight: 0 }),
1965
1961
  minHeight: 160,
1966
1962
  flexShrink: 0,
@@ -1986,13 +1982,13 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
1986
1982
  fontFamily: theme.fonts.monospace,
1987
1983
  textTransform: 'capitalize',
1988
1984
  cursor: 'pointer',
1989
- }, children: tab === 'issues' ? 'Issues' : 'Agents' }, tab))) }), diagnosticsTab === 'agents' ? (_jsx(SubsystemAgentsPanel, { ...agentsPanel })) : (_jsx(SubsystemIssueList, { issues: issues ?? [], focusCategory: focusIssueCategory, onSelectIssue: focusIssueTarget, onDeselectIssue: unfocusIssueTarget, onApplyFix: onApplyIssueFix, onHoverIssue: onHoverIssue, onExpandedCategoriesChange: handleExpandedCategoriesChange }))] })) : (_jsx(SubsystemIssueList, { issues: issues ?? [], focusCategory: focusIssueCategory, onSelectIssue: focusIssueTarget, onDeselectIssue: unfocusIssueTarget, onApplyFix: onApplyIssueFix, onHoverIssue: onHoverIssue, onExpandedCategoriesChange: handleExpandedCategoriesChange }))) : (_jsxs(_Fragment, { children: [hasWalkthroughs && (_jsx("div", { role: "tablist", "aria-label": "Sidebar view", style: {
1985
+ }, children: tab === 'issues' ? 'Issues' : 'Agents' }, tab))) }), diagnosticsTab === 'agents' ? (_jsx(SubsystemAgentsPanel, { ...agentsPanel })) : (_jsx(SubsystemIssueList, { issues: issues ?? [], focusCategory: focusIssueCategory, onSelectIssue: focusIssueTarget, onDeselectIssue: unfocusIssueTarget, onApplyFix: onApplyIssueFix, onHoverIssue: onHoverIssue, onExpandedCategoriesChange: handleExpandedCategoriesChange }))] })) : (_jsx(SubsystemIssueList, { issues: issues ?? [], focusCategory: focusIssueCategory, onSelectIssue: focusIssueTarget, onDeselectIssue: unfocusIssueTarget, onApplyFix: onApplyIssueFix, onHoverIssue: onHoverIssue, onExpandedCategoriesChange: handleExpandedCategoriesChange }))) : (_jsxs(_Fragment, { children: [hasTrails && (_jsx("div", { role: "tablist", "aria-label": "Sidebar view", style: {
1990
1986
  display: 'flex',
1991
1987
  width: '100%',
1992
1988
  flexShrink: 0,
1993
1989
  borderBottom: `1px solid ${theme.colors.border}`,
1994
1990
  background: theme.colors.backgroundSecondary ?? theme.colors.background,
1995
- }, children: ['walkthroughs', 'files'].map((view) => (_jsx("button", { type: "button", role: "tab", "aria-selected": sidebarView === view, onClick: () => changeSidebarView(view), style: {
1991
+ }, children: ['trails', 'files'].map((view) => (_jsx("button", { type: "button", role: "tab", "aria-selected": sidebarView === view, onClick: () => changeSidebarView(view), style: {
1996
1992
  flex: 1,
1997
1993
  minWidth: 0,
1998
1994
  padding: '8px 8px',
@@ -2006,7 +2002,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
2006
2002
  fontFamily: theme.fonts.monospace,
2007
2003
  textTransform: 'capitalize',
2008
2004
  cursor: 'pointer',
2009
- }, children: view === 'walkthroughs' ? 'Walkthroughs' : 'Files' }, view))) })), sidebarView === 'walkthroughs' && walkthroughs && walkthroughs.length > 0 ? (_jsx(WalkthroughsPanel, { walkthroughs: walkthroughs, expandedWalkthroughs: expandedWalkthroughs, focusedWalkthroughId: focusedWalkthroughId, focusedStepIndex: focusedStepIndex, hoveredWalkthroughStep: hoveredWalkthroughStep, onToggleCollapsed: toggleWalkthroughCollapsed, onFocusFlow: focusWalkthroughEdges, onClearFocus: clearWalkthroughFocus, onFocusStep: focusWalkthroughStep, onHoverStep: (tl, i) => setHoveredWalkthroughStep({ walkthroughId: tl.id, stepIndex: i }), onHoverFlow: (tl) => setHoveredWalkthroughStep({ walkthroughId: tl.id, stepIndex: null }), onLeaveStep: () => setHoveredWalkthroughStep(null), onReorder: onReorderWalkthroughs, proposedAliases: proposedAliases })) : treeFilePaths.length > 0 ? (_jsx(_Fragment, { children: repoGroups.groups.map((group, i) => {
2005
+ }, children: view === 'trails' ? 'Trails' : 'Files' }, view))) })), sidebarView === 'trails' && trails && trails.length > 0 ? (_jsx(TrailsPanel, { trails: trails, expandedTrails: expandedTrails, focusedTrailId: focusedTrailId, focusedStepIndex: focusedStepIndex, hoveredTrailStep: hoveredTrailStep, onToggleCollapsed: toggleTrailCollapsed, onFocusFlow: focusTrailEdges, onClearFocus: clearTrailFocus, onFocusStep: focusTrailStep, onHoverStep: (tl, i) => setHoveredTrailStep({ trailId: tl.id, stepIndex: i }), onHoverFlow: (tl) => setHoveredTrailStep({ trailId: tl.id, stepIndex: null }), onLeaveStep: () => setHoveredTrailStep(null), onReorder: onReorderTrails, proposedAliases: proposedAliases })) : treeFilePaths.length > 0 ? (_jsx(_Fragment, { children: repoGroups.groups.map((group, i) => {
2010
2006
  const groupKey = group.repoKey ?? '__no-repo__';
2011
2007
  const collapsed = collapsedRepos.has(groupKey);
2012
2008
  return (_jsxs("div", { style: {
@@ -2016,7 +2012,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
2016
2012
  flexDirection: 'column',
2017
2013
  borderTop: i > 0 ? `1px solid ${theme.colors.border}` : undefined,
2018
2014
  }, children: [repoGroups.multiRepo && (_jsx(RepoGroupHeader, { group: group, collapsed: collapsed, onToggle: () => toggleRepoCollapsed(groupKey) })), !collapsed && (_jsx(SubsystemFileTree, { files: group.entries.map((e) => e.displayPath), selectedFile: selected?.file ?? openFile, hoveredFile: hoveredFile, onSelectFile: onTreeSelectFile, hoveredFolder: hoveredBoundaryPath, headerless: repoGroups.multiRepo }))] }, groupKey));
2019
- }) })) : null] })) }))] })), !hideSidebar && (title || description || diagnostic || issuesActive || sidebarExtra || sidebarAfterDescription || treeFilePaths.length > 0 || hasWalkthroughs) && (_jsx("div", { onMouseDown: onSidebarResizeStart, "aria-label": "Resize sidebar", title: "Drag to resize", style: {
2015
+ }) })) : null] })) }))] })), !hideSidebar && (title || description || diagnostic || issuesActive || sidebarExtra || sidebarAfterDescription || treeFilePaths.length > 0 || hasTrails) && (_jsx("div", { onMouseDown: onSidebarResizeStart, "aria-label": "Resize sidebar", title: "Drag to resize", style: {
2020
2016
  width: 3,
2021
2017
  flexShrink: 0,
2022
2018
  cursor: 'col-resize',
@@ -2109,7 +2105,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
2109
2105
  flex: 1,
2110
2106
  minHeight: 0,
2111
2107
  background: theme.colors.background,
2112
- }, children: _jsx(GraphChrome, {}) }, `${baseNodesKey}-${baseEdgesKey}`), (graphTitle || overlayWalkthroughTitle || overlayWalkthroughStep) && (_jsxs("div", { style: {
2108
+ }, children: _jsx(GraphChrome, {}) }, `${baseNodesKey}-${baseEdgesKey}`), (graphTitle || overlayTrailTitle || overlayTrailStep) && (_jsxs("div", { style: {
2113
2109
  position: 'absolute',
2114
2110
  top: 10,
2115
2111
  left: '50%',
@@ -2135,9 +2131,9 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
2135
2131
  border: `1px solid ${theme.colors.border}`,
2136
2132
  borderRadius: 6,
2137
2133
  boxShadow: '0 1px 4px rgba(0,0,0,0.25)',
2138
- }, children: graphTitle })), overlayWalkthroughTitle && (_jsxs("div", { style: {
2134
+ }, children: graphTitle })), overlayTrailTitle && (_jsxs("div", { style: {
2139
2135
  maxWidth: '100%',
2140
- minWidth: overlayWalkthroughStep ? 160 : undefined,
2136
+ minWidth: overlayTrailStep ? 160 : undefined,
2141
2137
  display: 'flex',
2142
2138
  flexDirection: 'column',
2143
2139
  background: theme.colors.backgroundSecondary ?? theme.colors.background,
@@ -2146,9 +2142,9 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
2146
2142
  boxShadow: '0 1px 4px rgba(0,0,0,0.25)',
2147
2143
  overflow: 'hidden',
2148
2144
  opacity: 0.95,
2149
- }, "aria-label": overlayWalkthroughStep
2150
- ? `${overlayWalkthroughTitle}, step ${overlayWalkthroughStep.index} of ${overlayWalkthroughStep.total}`
2151
- : overlayWalkthroughTitle, children: [_jsx("div", { style: {
2145
+ }, "aria-label": overlayTrailStep
2146
+ ? `${overlayTrailTitle}, step ${overlayTrailStep.index} of ${overlayTrailStep.total}`
2147
+ : overlayTrailTitle, children: [_jsx("div", { style: {
2152
2148
  padding: '5px 14px',
2153
2149
  fontSize: theme.fontSizes[2] ?? theme.fontSizes[1],
2154
2150
  fontWeight: 600,
@@ -2158,14 +2154,14 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
2158
2154
  textOverflow: 'ellipsis',
2159
2155
  whiteSpace: 'nowrap',
2160
2156
  textAlign: 'center',
2161
- }, children: overlayWalkthroughTitle }), overlayWalkthroughStep && overlayWalkthroughStep.total > 0 && (_jsx("div", { style: {
2157
+ }, children: overlayTrailTitle }), overlayTrailStep && overlayTrailStep.total > 0 && (_jsx("div", { style: {
2162
2158
  display: 'flex',
2163
2159
  gap: 3,
2164
2160
  padding: '0 6px 5px',
2165
- }, "aria-hidden": "true", children: Array.from({ length: overlayWalkthroughStep.total }, (_, i) => {
2161
+ }, "aria-hidden": "true", children: Array.from({ length: overlayTrailStep.total }, (_, i) => {
2166
2162
  const n = i + 1;
2167
- const active = n === overlayWalkthroughStep.index;
2168
- const done = n < overlayWalkthroughStep.index;
2163
+ const active = n === overlayTrailStep.index;
2164
+ const done = n < overlayTrailStep.index;
2169
2165
  return (_jsx("span", { style: {
2170
2166
  flex: 1,
2171
2167
  height: 2,
@@ -2178,7 +2174,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
2178
2174
  opacity: active ? 1 : done ? 0.75 : 0.4,
2179
2175
  transition: 'opacity 120ms ease, background 120ms ease',
2180
2176
  } }, n));
2181
- }) }))] })), overlayWalkthroughStep?.annotation && (_jsx("div", { style: {
2177
+ }) }))] })), overlayTrailStep?.annotation && (_jsx("div", { style: {
2182
2178
  maxWidth: '100%',
2183
2179
  padding: '6px 14px',
2184
2180
  background: theme.colors.backgroundSecondary ?? theme.colors.background,
@@ -2190,7 +2186,7 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
2190
2186
  fontFamily: theme.fonts.body,
2191
2187
  color: theme.colors.textMuted ?? theme.colors.textSecondary,
2192
2188
  lineHeight: 1.35,
2193
- }, children: overlayWalkthroughStep.annotation }))] })), selected && (_jsx("div", { style: {
2189
+ }, children: overlayTrailStep.annotation }))] })), selected && (_jsx("div", { style: {
2194
2190
  position: 'absolute',
2195
2191
  top: 10,
2196
2192
  right: 10,
@@ -2215,9 +2211,9 @@ function Inner({ components, walkthroughs, graphifyRelations, orderByLine, initi
2215
2211
  drawerTarget.startLine != null &&
2216
2212
  !!selected.file &&
2217
2213
  selected.file === drawerTarget.file &&
2218
- selected.declarationRef?.startLine === drawerTarget.startLine }) }))] }), _jsx(FileDrawer, { title: drawerTitle, onClose: closeDrawer, fillHeight: drawerFillHeight, suppressEscape: fileOverlayOpen, hidden: hideDrawer, children: drawerTarget?.kind === 'walkthrough' &&
2219
- focusedWalkthrough &&
2220
- renderWalkthroughViewer ? (_jsx(WalkthroughDrawerContent, { render: renderWalkthroughDrawerContent, walkthrough: focusedWalkthrough, stepIndex: drawerTarget.stepIndex, onOpenFile: onOpenFileFromWalkthrough, proposedAliases: proposedAliases, resolveSymbol: resolveWalkthroughSymbol, onSymbolClick: openConstructDeclaration })) : drawerTarget?.kind === 'file' ? (_jsx(FileDrawerContent, { render: renderDrawerContent, file: drawerTarget.file, startLine: drawerTarget.startLine })) : null }), fileOverlay && (_jsxs("div", { style: {
2214
+ selected.declarationRef?.startLine === drawerTarget.startLine }) }))] }), _jsx(FileDrawer, { title: drawerTitle, onClose: closeDrawer, fillHeight: drawerFillHeight, suppressEscape: fileOverlayOpen, hidden: hideDrawer, children: drawerTarget?.kind === 'trail' &&
2215
+ focusedTrail &&
2216
+ renderTrailViewer ? (_jsx(TrailDrawerContent, { render: renderTrailDrawerContent, trail: focusedTrail, stepIndex: drawerTarget.stepIndex, onOpenFile: onOpenFileFromTrail, proposedAliases: proposedAliases, resolveSymbol: resolveTrailSymbol, onSymbolClick: openConstructDeclaration })) : drawerTarget?.kind === 'file' ? (_jsx(FileDrawerContent, { render: renderDrawerContent, file: drawerTarget.file, startLine: drawerTarget.startLine })) : null }), fileOverlay && (_jsxs("div", { style: {
2221
2217
  position: 'absolute',
2222
2218
  inset: 0,
2223
2219
  zIndex: 8,
@@ -2304,7 +2300,7 @@ export function SubsystemComponentGraph(props) {
2304
2300
  }, []);
2305
2301
  const constructsOnly = isConstructsOnlyModel({
2306
2302
  components: props.components,
2307
- walkthroughs: props.walkthroughs,
2303
+ trails: props.trails,
2308
2304
  graphifyRelations: props.graphifyRelations,
2309
2305
  });
2310
2306
  return (_jsx("div", { ref: wrapRef, style: {
@@ -2314,6 +2310,6 @@ export function SubsystemComponentGraph(props) {
2314
2310
  minHeight: 0,
2315
2311
  display: 'flex',
2316
2312
  flexDirection: 'column',
2317
- }, children: _jsx("div", { style: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }, children: constructsOnly ? (_jsx(ConstructsCatalog, { components: props.components, onSelect: props.onSelect, title: props.title, hideSidebar: props.hideSidebar, description: props.description, descriptionOpen: props.descriptionOpen, onDescriptionOpenChange: props.onDescriptionOpenChange, diagnostic: props.diagnostic, sidebarExtra: props.sidebarExtra, sidebarAfterDescription: props.sidebarAfterDescription, renderFileViewer: props.renderFileViewer, renderFileView: props.renderFileView, onFileSelect: props.onFileSelect, componentVerification: props.componentVerification, onInspectSymbol: props.onInspectSymbol })) : (_jsx(ReactFlowProvider, { children: _jsx(Inner, { ...props, measured: size }) })) }) }));
2313
+ }, children: _jsx("div", { style: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }, children: constructsOnly ? (_jsx(ConstructsCatalog, { components: props.components, onSelect: props.onSelect, title: props.title, hideSidebar: props.hideSidebar, description: props.description, descriptionOpen: props.descriptionOpen, onDescriptionOpenChange: props.onDescriptionOpenChange, diagnostic: props.diagnostic, sidebarExtra: props.sidebarExtra, sidebarAfterDescription: props.sidebarAfterDescription, renderFileViewer: props.renderFileViewer, onFileSelect: props.onFileSelect, componentVerification: props.componentVerification, onInspectSymbol: props.onInspectSymbol })) : (_jsx(ReactFlowProvider, { children: _jsx(Inner, { ...props, measured: size }) })) }) }));
2318
2314
  }
2319
2315
  //# sourceMappingURL=SubsystemComponentGraph.js.map