@principal-ai/subsystems-react 0.20.5 → 0.21.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 (87) hide show
  1. package/README.md +1 -1
  2. package/dist/graphify/anchor.d.ts +17 -0
  3. package/dist/graphify/anchor.d.ts.map +1 -1
  4. package/dist/graphify/anchor.js +41 -0
  5. package/dist/graphify/anchor.js.map +1 -1
  6. package/dist/graphify/consolidated.d.ts +40 -1
  7. package/dist/graphify/consolidated.d.ts.map +1 -1
  8. package/dist/graphify/construct.d.ts +23 -0
  9. package/dist/graphify/construct.d.ts.map +1 -0
  10. package/dist/graphify/construct.js +77 -0
  11. package/dist/graphify/construct.js.map +1 -0
  12. package/dist/graphify/index.d.ts +2 -2
  13. package/dist/graphify/index.d.ts.map +1 -1
  14. package/dist/graphify/index.js +1 -1
  15. package/dist/graphify/index.js.map +1 -1
  16. package/dist/index.d.ts +7 -7
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +3 -3
  19. package/dist/index.js.map +1 -1
  20. package/dist/pierre/PierreWalkthroughCodeView.d.ts +22 -0
  21. package/dist/pierre/PierreWalkthroughCodeView.d.ts.map +1 -0
  22. package/dist/pierre/PierreWalkthroughCodeView.js +198 -0
  23. package/dist/pierre/PierreWalkthroughCodeView.js.map +1 -0
  24. package/dist/pierre/index.d.ts +2 -2
  25. package/dist/pierre/index.js +1 -1
  26. package/dist/pierre/pierreFileLang.d.ts +1 -1
  27. package/dist/pierre/pierreFileLang.js +1 -1
  28. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts +14 -2
  29. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
  30. package/dist/stories/Subsystem/ComponentGraph/fixtures.js +86 -20
  31. package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
  32. package/dist/subsystem/ComponentDeclaration.js +1 -1
  33. package/dist/subsystem/ComponentDeclaration.js.map +1 -1
  34. package/dist/subsystem/FileDrawer.d.ts +2 -2
  35. package/dist/subsystem/FileDrawer.js +2 -2
  36. package/dist/subsystem/SubsystemComponentGraph.d.ts +25 -24
  37. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  38. package/dist/subsystem/SubsystemComponentGraph.js +220 -194
  39. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  40. package/dist/subsystem/formatDeclaration.d.ts +2 -1
  41. package/dist/subsystem/formatDeclaration.d.ts.map +1 -1
  42. package/dist/subsystem/formatDeclaration.js +57 -33
  43. package/dist/subsystem/formatDeclaration.js.map +1 -1
  44. package/dist/subsystem/model.d.ts +109 -42
  45. package/dist/subsystem/model.d.ts.map +1 -1
  46. package/dist/subsystem/model.js +107 -5
  47. package/dist/subsystem/model.js.map +1 -1
  48. package/dist/subsystem/nodes.d.ts.map +1 -1
  49. package/dist/subsystem/nodes.js +43 -18
  50. package/dist/subsystem/nodes.js.map +1 -1
  51. package/dist/subsystem/tokenizeComponent.js +2 -2
  52. package/dist/subsystem/tokenizeComponent.js.map +1 -1
  53. package/package.json +3 -3
  54. package/src/graphify/anchor.test.ts +31 -2
  55. package/src/graphify/anchor.ts +46 -0
  56. package/src/graphify/consolidated.ts +43 -1
  57. package/src/graphify/{kind.test.ts → construct.test.ts} +20 -20
  58. package/src/graphify/{kind.ts → construct.ts} +17 -17
  59. package/src/graphify/index.ts +5 -2
  60. package/src/index.ts +20 -9
  61. package/src/pierre/{PierreThroughlineCodeView.tsx → PierreWalkthroughCodeView.tsx} +39 -47
  62. package/src/pierre/index.ts +2 -2
  63. package/src/pierre/pierreFileLang.ts +1 -1
  64. package/src/stories/Pierre/CodeView.stories.tsx +3 -3
  65. package/src/stories/Subsystem/ComponentDeclarationAudit.stories.tsx +14 -14
  66. package/src/stories/Subsystem/ComponentGraph/Appearance.stories.tsx +13 -15
  67. package/src/stories/Subsystem/ComponentGraph/Basics.stories.tsx +8 -8
  68. package/src/stories/Subsystem/ComponentGraph/Captures.stories.tsx +16 -20
  69. package/src/stories/Subsystem/ComponentGraph/CustomEntities.stories.tsx +11 -10
  70. package/src/stories/Subsystem/ComponentGraph/DetailPanel.stories.tsx +13 -14
  71. package/src/stories/Subsystem/ComponentGraph/Flows.stories.tsx +31 -66
  72. package/src/stories/Subsystem/ComponentGraph/FrameworkStereotype.stories.tsx +2 -2
  73. package/src/stories/Subsystem/ComponentGraph/GraphTitle.stories.tsx +4 -4
  74. package/src/stories/Subsystem/ComponentGraph/Processes.stories.tsx +3 -3
  75. package/src/stories/Subsystem/ComponentGraph/Proposed.stories.tsx +254 -0
  76. package/src/stories/Subsystem/ComponentGraph/Scenarios.stories.tsx +518 -33
  77. package/src/stories/Subsystem/ComponentGraph/Spotlights.stories.tsx +13 -13
  78. package/src/stories/Subsystem/ComponentGraph/fixtures.ts +105 -21
  79. package/src/subsystem/ComponentDeclaration.tsx +1 -1
  80. package/src/subsystem/FileDrawer.tsx +2 -2
  81. package/src/subsystem/SubsystemComponentGraph.tsx +284 -254
  82. package/src/subsystem/formatDeclaration.test.ts +76 -1
  83. package/src/subsystem/formatDeclaration.ts +57 -33
  84. package/src/subsystem/model.test.ts +49 -15
  85. package/src/subsystem/model.ts +210 -51
  86. package/src/subsystem/nodes.tsx +63 -22
  87. package/src/subsystem/tokenizeComponent.ts +2 -2
@@ -1,7 +1,7 @@
1
1
  /**
2
- * PierreThroughlineCodeView — multi-file step snippets via `@pierre/diffs` CodeView.
2
+ * PierreWalkthroughCodeView — multi-file step snippets via `@pierre/diffs` CodeView.
3
3
  *
4
- * Renders one sliced window per throughline step in a single virtualized
4
+ * Renders one sliced window per walkthrough step in a single virtualized
5
5
  * scroll; when `stepIndex` changes, scrolls that step's site line into view
6
6
  * and highlights it via CodeView `selectedLines` (same mechanism as
7
7
  * `PierreSnippetView`).
@@ -22,10 +22,10 @@ type CodeViewLineSelection = {
22
22
  id: string;
23
23
  range: { start: number; end: number };
24
24
  };
25
- /** Metadata carried on a throughline step's line annotation. */
26
- type ThroughlineStepAnnotation = { text: string };
25
+ /** Metadata carried on a walkthrough step's line annotation. */
26
+ type WalkthroughStepAnnotation = { text: string };
27
27
  import { useTheme } from '@principal-ade/industry-theme';
28
- import type { SubsystemThroughline } from '../subsystem/model';
28
+ import type { SubsystemWalkthrough } from '../subsystem/model';
29
29
  import { buildPierreOptions, PIERRE_FILE_STYLE } from './pierreBackground';
30
30
  import {
31
31
  pierreCodeViewFileName,
@@ -34,8 +34,8 @@ import {
34
34
  import { resolvePierreSyntaxThemeName } from './pierreSyntaxTheme';
35
35
  import { sliceSnippetWindow, type SnippetSlice } from './sliceSnippet';
36
36
 
37
- export interface PierreThroughlineCodeViewProps {
38
- throughline: SubsystemThroughline;
37
+ export interface PierreWalkthroughCodeViewProps {
38
+ walkthrough: SubsystemWalkthrough;
39
39
  /** Focused step; `null` shows all snippets without scrolling to a step. */
40
40
  stepIndex: number | null;
41
41
  readFile: (path: string) => Promise<string>;
@@ -50,31 +50,31 @@ type FileLoadState =
50
50
  | { status: 'error'; message: string }
51
51
  | { status: 'ready'; byPath: Map<string, string> };
52
52
 
53
- function stepItemId(throughlineId: string, index: number): string {
54
- return `${throughlineId}:${index}`;
53
+ function stepItemId(walkthroughId: string, index: number): string {
54
+ return `${walkthroughId}:${index}`;
55
55
  }
56
56
 
57
- export function PierreThroughlineCodeView({
58
- throughline,
57
+ export function PierreWalkthroughCodeView({
58
+ walkthrough,
59
59
  stepIndex,
60
60
  readFile,
61
61
  contextLines = 8,
62
62
  background,
63
- }: PierreThroughlineCodeViewProps) {
63
+ }: PierreWalkthroughCodeViewProps) {
64
64
  const { theme, mode } = useTheme();
65
65
  const viewRef = useRef<CodeViewHandle<undefined>>(null);
66
66
  const [load, setLoad] = useState<FileLoadState>({ status: 'loading' });
67
67
 
68
68
  const pathsKey = useMemo(() => {
69
- const paths = [...new Set(throughline.steps.map((s) => s.file))];
69
+ const paths = [...new Set(walkthrough.steps.map((s) => s.file))];
70
70
  paths.sort();
71
71
  return paths.join('\0');
72
- }, [throughline.steps]);
72
+ }, [walkthrough.steps]);
73
73
 
74
74
  useEffect(() => {
75
75
  let cancelled = false;
76
76
  setLoad({ status: 'loading' });
77
- const paths = [...new Set(throughline.steps.map((s) => s.file))];
77
+ const paths = [...new Set(walkthrough.steps.map((s) => s.file))];
78
78
  void Promise.all(
79
79
  paths.map(async (path) => {
80
80
  const contents = await readFile(path);
@@ -95,11 +95,11 @@ export function PierreThroughlineCodeView({
95
95
  return () => {
96
96
  cancelled = true;
97
97
  };
98
- }, [throughline.id, pathsKey, readFile]);
98
+ }, [walkthrough.id, pathsKey, readFile]);
99
99
 
100
100
  const slices = useMemo((): SnippetSlice[] => {
101
101
  if (load.status !== 'ready') return [];
102
- return throughline.steps.map((step) => {
102
+ return walkthrough.steps.map((step) => {
103
103
  const contents = load.byPath.get(step.file) ?? '';
104
104
  return sliceSnippetWindow(
105
105
  contents,
@@ -109,15 +109,15 @@ export function PierreThroughlineCodeView({
109
109
  step.line,
110
110
  );
111
111
  });
112
- }, [load, throughline.steps, contextLines]);
112
+ }, [load, walkthrough.steps, contextLines]);
113
113
 
114
- const items = useMemo((): CodeViewItem<ThroughlineStepAnnotation>[] => {
114
+ const items = useMemo((): CodeViewItem<WalkthroughStepAnnotation>[] => {
115
115
  if (load.status !== 'ready' || slices.length === 0) return [];
116
- return throughline.steps.map((step, index) => {
116
+ return walkthrough.steps.map((step, index) => {
117
117
  const slice = slices[index]!;
118
118
  const focus = slice.focusOffset;
119
119
  const annotations:
120
- | LineAnnotation<ThroughlineStepAnnotation>[]
120
+ | LineAnnotation<WalkthroughStepAnnotation>[]
121
121
  | undefined =
122
122
  step.annotation != null && step.annotation.length > 0 && focus != null
123
123
  ? [
@@ -128,26 +128,20 @@ const items = useMemo((): CodeViewItem<ThroughlineStepAnnotation>[] => {
128
128
  ]
129
129
  : undefined;
130
130
  return {
131
- id: stepItemId(throughline.id, index),
131
+ id: stepItemId(walkthrough.id, index),
132
132
  type: 'file' as const,
133
133
  version: 1,
134
134
  annotations,
135
135
  file: {
136
- // Unique per-step name: many throughline steps share one path
137
- // (e.g. seven sites in main.cpp), and identical `name`s have
138
- // correlated with WebKit renderer traps in CodeView.
139
136
  name: pierreCodeViewFileName(step.file, index),
140
137
  contents: slice.contents,
141
- // C-family → plain text: cpp Shiki still traps WebKit even with
142
- // unique names (reproduced on 0.16.67).
143
138
  lang: pierreLangForPath(step.file),
144
- cacheKey: `${throughline.id}:${index}:${step.file}:${step.line}:${slice.sliceStart}-${slice.sliceEnd}`,
139
+ cacheKey: `${walkthrough.id}:${index}:${step.file}:${step.line}:${slice.sliceStart}-${slice.sliceEnd}`,
145
140
  },
146
141
  };
147
142
  });
148
- }, [load, slices, throughline.id, throughline.steps]);
143
+ }, [load, slices, walkthrough.id, walkthrough.steps]);
149
144
 
150
- /** Highlight the focused step's site line (1-based within its sliced window). */
151
145
  const selectedLines = useMemo((): CodeViewLineSelection | null => {
152
146
  if (stepIndex == null || stepIndex < 0 || stepIndex >= slices.length) {
153
147
  return null;
@@ -155,15 +149,15 @@ const items = useMemo((): CodeViewItem<ThroughlineStepAnnotation>[] => {
155
149
  const focus = slices[stepIndex]?.focusOffset;
156
150
  if (focus == null) return null;
157
151
  return {
158
- id: stepItemId(throughline.id, stepIndex),
152
+ id: stepItemId(walkthrough.id, stepIndex),
159
153
  range: { start: focus, end: focus },
160
154
  };
161
- }, [stepIndex, slices, throughline.id]);
155
+ }, [stepIndex, slices, walkthrough.id]);
162
156
 
163
157
  const renderHeaderPrefix = useMemo(() => {
164
158
  return (item: CodeViewItem) => {
165
159
  const index = Number.parseInt(item.id.split(':').pop() ?? '', 10);
166
- const step = throughline.steps[index];
160
+ const step = walkthrough.steps[index];
167
161
  if (!step) return null;
168
162
  const label =
169
163
  step.symbol != null && step.symbol.length > 0
@@ -182,12 +176,12 @@ const items = useMemo((): CodeViewItem<ThroughlineStepAnnotation>[] => {
182
176
  </span>
183
177
  );
184
178
  };
185
- }, [throughline.steps, theme]);
179
+ }, [walkthrough.steps, theme]);
186
180
 
187
181
  const renderHeaderMetadata = useMemo(() => {
188
182
  return (item: CodeViewItem) => {
189
183
  const index = Number.parseInt(item.id.split(':').pop() ?? '', 10);
190
- const step = throughline.steps[index];
184
+ const step = walkthrough.steps[index];
191
185
  if (!step) return null;
192
186
  return (
193
187
  <span
@@ -202,17 +196,17 @@ const items = useMemo((): CodeViewItem<ThroughlineStepAnnotation>[] => {
202
196
  </span>
203
197
  );
204
198
  };
205
- }, [throughline.steps, theme]);
199
+ }, [walkthrough.steps, theme]);
206
200
 
207
201
  const renderAnnotation = useMemo(() => {
208
202
  return (
209
203
  annotation:
210
- | LineAnnotation<ThroughlineStepAnnotation>
211
- | DiffLineAnnotation<ThroughlineStepAnnotation>,
212
- item: CodeViewItem<ThroughlineStepAnnotation>,
204
+ | LineAnnotation<WalkthroughStepAnnotation>
205
+ | DiffLineAnnotation<WalkthroughStepAnnotation>,
206
+ item: CodeViewItem<WalkthroughStepAnnotation>,
213
207
  ) => {
214
208
  const index = Number.parseInt(item.id.split(':').pop() ?? '', 10);
215
- const step = throughline.steps[index];
209
+ const step = walkthrough.steps[index];
216
210
  const text = annotation.metadata?.text;
217
211
  if (!text || !step) return null;
218
212
  return (
@@ -230,7 +224,7 @@ const items = useMemo((): CodeViewItem<ThroughlineStepAnnotation>[] => {
230
224
  </span>
231
225
  );
232
226
  };
233
- }, [throughline.steps, theme]);
227
+ }, [walkthrough.steps, theme]);
234
228
 
235
229
  const options = useMemo((): CodeViewReactOptions => {
236
230
  return {
@@ -248,11 +242,10 @@ const items = useMemo((): CodeViewItem<ThroughlineStepAnnotation>[] => {
248
242
 
249
243
  useEffect(() => {
250
244
  if (load.status !== 'ready' || stepIndex == null) return;
251
- if (stepIndex < 0 || stepIndex >= throughline.steps.length) return;
245
+ if (stepIndex < 0 || stepIndex >= walkthrough.steps.length) return;
252
246
  const focus = slices[stepIndex]?.focusOffset;
253
247
  if (focus == null) return;
254
- // Defer until CodeView has laid out items.
255
- const id = stepItemId(throughline.id, stepIndex);
248
+ const id = stepItemId(walkthrough.id, stepIndex);
256
249
  const t = window.setTimeout(() => {
257
250
  viewRef.current?.scrollTo({
258
251
  type: 'line',
@@ -265,8 +258,8 @@ const items = useMemo((): CodeViewItem<ThroughlineStepAnnotation>[] => {
265
258
  }, [
266
259
  load.status,
267
260
  stepIndex,
268
- throughline.id,
269
- throughline.steps.length,
261
+ walkthrough.id,
262
+ walkthrough.steps.length,
270
263
  slices,
271
264
  items.length,
272
265
  ]);
@@ -286,7 +279,6 @@ const items = useMemo((): CodeViewItem<ThroughlineStepAnnotation>[] => {
286
279
  );
287
280
  }
288
281
 
289
- // Pierre's CodeView prop / item unions blow past TS's complexity limit.
290
282
  const CodeViewLoose = CodeView as unknown as (props: Record<string, unknown>) => ReactElement;
291
283
 
292
284
  return (
@@ -2,8 +2,8 @@ export { PierreFileView } from './PierreFileView';
2
2
  export type { PierreFileViewProps } from './PierreFileView';
3
3
  export { PierreSnippetView } from './PierreSnippetView';
4
4
  export type { PierreSnippetViewProps } from './PierreSnippetView';
5
- export { PierreThroughlineCodeView } from './PierreThroughlineCodeView';
6
- export type { PierreThroughlineCodeViewProps } from './PierreThroughlineCodeView';
5
+ export { PierreWalkthroughCodeView } from './PierreWalkthroughCodeView';
6
+ export type { PierreWalkthroughCodeViewProps } from './PierreWalkthroughCodeView';
7
7
  export { sliceSnippetWindow } from './sliceSnippet';
8
8
  export type { SnippetSlice } from './sliceSnippet';
9
9
  export {
@@ -7,7 +7,7 @@
7
7
  * `file.name`s — so we force plain text for those paths until Pierre/WebKit
8
8
  * is safe with them.
9
9
  *
10
- * Distinct throughline slices of the same path still need unique `file.name`s
10
+ * Distinct walkthrough slices of the same path still need unique `file.name`s
11
11
  * (see `pierreCodeViewFileName`).
12
12
  */
13
13
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Demo: Pierre CodeView with snippets from different files.
3
3
  *
4
- * Throughlines want many short windows across files in one scroll —
4
+ * Walkthroughs want many short windows across files in one scroll —
5
5
  * CodeView is the Pierre primitive for that (virtualized list of file items).
6
6
  */
7
7
  import React, { useMemo, useRef } from 'react';
@@ -54,7 +54,7 @@ const SNIPPETS: SnippetSpec[] = [
54
54
  startLine: 216,
55
55
  endLine: 250,
56
56
  focusLine: 216,
57
- label: '3 · Throughline types',
57
+ label: '3 · Walkthrough types',
58
58
  },
59
59
  ];
60
60
 
@@ -159,7 +159,7 @@ function MultiFileSnippetsDemo() {
159
159
  }}
160
160
  >
161
161
  <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 4 }}>
162
- Throughline steps
162
+ Walkthrough steps
163
163
  </div>
164
164
  <div style={{ fontSize: 12, color: theme.colors.textSecondary, marginBottom: 8 }}>
165
165
  Click a step to scroll + highlight its site line.
@@ -43,7 +43,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
43
43
  file: 'src/event-processing/sink.ts',
44
44
  purl: 'pkg:github/principal-ai/agent-monitoring',
45
45
  symbol: 'flush',
46
- detail: {
46
+ declaration: {
47
47
  kind: 'function',
48
48
  parameters: [],
49
49
  } satisfies GraphifyComponentDetail,
@@ -58,7 +58,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
58
58
  file: 'src/session/SessionReader.ts',
59
59
  purl: 'pkg:github/principal-ai/agent-monitoring',
60
60
  symbol: 'SessionReader.normalize',
61
- detail: {
61
+ declaration: {
62
62
  kind: 'function',
63
63
  parameters: [{ name: 'session', type: 'SessionRecord' }],
64
64
  returnType: 'SessionEvent[]',
@@ -74,7 +74,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
74
74
  file: 'src/event-processing/normalize.ts',
75
75
  purl: 'pkg:github/principal-ai/agent-monitoring',
76
76
  symbol: 'normalizeSession',
77
- detail: {
77
+ declaration: {
78
78
  kind: 'function',
79
79
  parameters: [
80
80
  { name: 'session', type: 'SessionRecord' },
@@ -93,7 +93,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
93
93
  file: 'src/session/merge.ts',
94
94
  purl: 'pkg:github/principal-ai/agent-monitoring',
95
95
  symbol: 'mergeSessions',
96
- detail: {
96
+ declaration: {
97
97
  kind: 'function',
98
98
  parameters: [
99
99
  { name: 'sessions', type: 'SessionRecord[]' },
@@ -114,7 +114,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
114
114
  file: 'src/empty.ts',
115
115
  purl: 'pkg:github/principal-ai/agent-monitoring',
116
116
  symbol: 'EmptyClass',
117
- detail: {
117
+ declaration: {
118
118
  kind: 'class',
119
119
  } satisfies GraphifyComponentDetail,
120
120
  },
@@ -128,7 +128,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
128
128
  file: 'src/config.ts',
129
129
  purl: 'pkg:github/principal-ai/agent-monitoring',
130
130
  symbol: 'Config',
131
- detail: {
131
+ declaration: {
132
132
  kind: 'class',
133
133
  properties: [
134
134
  { name: 'host', type: 'string' },
@@ -147,7 +147,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
147
147
  file: 'src/event-processing/EventProcessor.ts',
148
148
  purl: 'pkg:github/principal-ai/agent-monitoring',
149
149
  symbol: 'EventProcessor',
150
- detail: {
150
+ declaration: {
151
151
  kind: 'class',
152
152
  methods: [
153
153
  { name: 'process', parameters: [{ type: 'RawEvent' }, { type: 'ProcessingOptions' }], returnType: 'ProcessedEvent' },
@@ -174,7 +174,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
174
174
  file: 'src/session/transcript.ts',
175
175
  purl: 'pkg:github/principal-ai/agent-monitoring',
176
176
  symbol: 'SessionRecord',
177
- detail: {
177
+ declaration: {
178
178
  kind: 'type',
179
179
  properties: [
180
180
  { name: 'id', type: 'string' },
@@ -192,7 +192,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
192
192
  file: 'src/types.ts',
193
193
  purl: 'pkg:github/principal-ai/agent-monitoring',
194
194
  symbol: 'BrandedId',
195
- detail: {
195
+ declaration: {
196
196
  kind: 'type',
197
197
  } satisfies GraphifyComponentDetail,
198
198
  },
@@ -206,7 +206,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
206
206
  file: 'src/index.ts',
207
207
  purl: 'pkg:github/principal-ai/agent-monitoring',
208
208
  symbol: 'index',
209
- detail: {
209
+ declaration: {
210
210
  kind: 'module',
211
211
  imports: [
212
212
  { name: './session/SessionReader' },
@@ -237,7 +237,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
237
237
  file: '',
238
238
  purl: 'pkg:npm/@principal-ai/subsystems-studio',
239
239
  symbol: '',
240
- detail: {
240
+ declaration: {
241
241
  kind: 'external',
242
242
  label: 'pkg:npm/@principal-ai/subsystems-studio',
243
243
  } satisfies GraphifyComponentDetail,
@@ -251,7 +251,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
251
251
  construct: 'function',
252
252
  file: 'src/helpers.ts',
253
253
  purl: 'pkg:github/principal-ai/agent-monitoring',
254
- detail: {
254
+ declaration: {
255
255
  kind: 'function',
256
256
  parameters: [{ name: 'input', type: 'string' }],
257
257
  returnType: 'void',
@@ -267,7 +267,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
267
267
  file: 'src/session/SessionReader.ts',
268
268
  purl: 'pkg:github/principal-ai/agent-monitoring',
269
269
  symbol: 'SessionReader.normalize',
270
- detail: {
270
+ declaration: {
271
271
  kind: 'method',
272
272
  hostClass: 'SessionReader',
273
273
  parameters: [{ name: 'session', type: 'SessionRecord' }],
@@ -284,7 +284,7 @@ const cases: { label: string; component: SubsystemComponent }[] = [
284
284
  file: 'src/event-processing/EventProcessor.ts',
285
285
  purl: 'pkg:github/principal-ai/agent-monitoring',
286
286
  symbol: 'EventProcessor.dispose',
287
- detail: {
287
+ declaration: {
288
288
  kind: 'method',
289
289
  hostClass: 'EventProcessor',
290
290
  } satisfies GraphifyComponentDetail,
@@ -5,7 +5,7 @@ import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme
5
5
  import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
6
6
  import type { SubsystemComponent, SubsystemComponentEdge } from '../../../subsystem/model';
7
7
  import type { GraphifyComponentDetail } from '../../../graphify';
8
- import { investigateOnlyComponents, investigateOnlyEdges } from './fixtures';
8
+ import { investigateOnlyComponents, investigateOnlyRelations, investigateOnlyWalkthroughs } from './fixtures';
9
9
 
10
10
  const meta = {
11
11
  title: 'Subsystem/ComponentGraph/Appearance',
@@ -32,7 +32,7 @@ export const NarrowMaxWidth: Story = {
32
32
  <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
33
33
  <SubsystemComponentGraph
34
34
  components={investigateOnlyComponents}
35
- edges={investigateOnlyEdges}
35
+ relations={investigateOnlyRelations} walkthroughs={investigateOnlyWalkthroughs}
36
36
  maxNodeWidth={140}
37
37
  />
38
38
  </div>
@@ -93,7 +93,6 @@ const namingConventionComponents: SubsystemComponent[] = [
93
93
  },
94
94
  ];
95
95
 
96
- const namingConventionEdges: SubsystemComponentEdge[] = [];
97
96
 
98
97
  /** Nodes with compact `maxNodeWidth` so the different conventions visibly wrap
99
98
  * at their word boundaries (camelCase, snake_case, PascalCase, acronyms). */
@@ -102,7 +101,7 @@ export const NamingConventions: Story = {
102
101
  <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
103
102
  <SubsystemComponentGraph
104
103
  components={namingConventionComponents}
105
- edges={namingConventionEdges}
104
+ relations={[]}
106
105
  maxNodeWidth={180}
107
106
  />
108
107
  </div>
@@ -137,7 +136,7 @@ const kindVariationComponents: SubsystemComponent[] = [
137
136
  purpose: 'members only — methods with typed params + returns, a typed field',
138
137
  symbol: 'Transcoder',
139
138
  layer: 1,
140
- detail: {
139
+ declaration: {
141
140
  kind: 'class',
142
141
  methods: [
143
142
  { nodeId: 'tm1', name: 'encode', parameters: [{ type: 'RawFrame' }], returnType: 'Uint8Array' },
@@ -160,7 +159,7 @@ const kindVariationComponents: SubsystemComponent[] = [
160
159
  purpose: 'relationships only — extends + implements, constructed-by comment; empty body elides the braces',
161
160
  symbol: 'HttpTransport',
162
161
  layer: 1,
163
- detail: {
162
+ declaration: {
164
163
  kind: 'class',
165
164
  methods: [],
166
165
  properties: [],
@@ -191,7 +190,7 @@ const kindVariationComponents: SubsystemComponent[] = [
191
190
  purpose: 'signature only — named + positional (type-only) params, array return; no callers/callees comments',
192
191
  symbol: 'normalizeSession',
193
192
  layer: 2,
194
- detail: {
193
+ declaration: {
195
194
  kind: 'function',
196
195
  parameters: [
197
196
  { name: 'session', type: 'SessionRecord' },
@@ -211,7 +210,7 @@ const kindVariationComponents: SubsystemComponent[] = [
211
210
  purpose: 'signature + call relationships — union-typed param, generic return, called-by / calls trailing comments',
212
211
  symbol: 'mergeSessions',
213
212
  layer: 2,
214
- detail: {
213
+ declaration: {
215
214
  kind: 'function',
216
215
  parameters: [
217
216
  { name: 'sessions', type: 'SessionRecord[]' },
@@ -243,7 +242,7 @@ const kindVariationComponents: SubsystemComponent[] = [
243
242
  purpose: 'fields only — typed interface body, nothing else',
244
243
  symbol: 'SessionRecord',
245
244
  layer: 3,
246
- detail: {
245
+ declaration: {
247
246
  kind: 'type',
248
247
  properties: [
249
248
  { name: 'id', type: 'string' },
@@ -262,7 +261,7 @@ const kindVariationComponents: SubsystemComponent[] = [
262
261
  purpose: 'full — fields + implemented-by (clicks through to HttpTransport) + used-by comments',
263
262
  symbol: 'Transport',
264
263
  layer: 3,
265
- detail: {
264
+ declaration: {
266
265
  kind: 'type',
267
266
  properties: [{ name: 'name', type: 'string' }],
268
267
  usedBy: [{ nodeId: 'u1', name: 'main', context: 'parameter_type' }],
@@ -290,7 +289,7 @@ const kindVariationComponents: SubsystemComponent[] = [
290
289
  purpose: 'exports only — export statement + defines comment',
291
290
  symbol: '',
292
291
  layer: 4,
293
- detail: {
292
+ declaration: {
294
293
  kind: 'module',
295
294
  exports: ['extractToolName', 'extractFilePath'],
296
295
  imports: [],
@@ -306,7 +305,7 @@ const kindVariationComponents: SubsystemComponent[] = [
306
305
  purpose: 'full — import statements + re-export statement + defines comment',
307
306
  symbol: '',
308
307
  layer: 4,
309
- detail: {
308
+ declaration: {
310
309
  kind: 'module',
311
310
  exports: ['SessionReader', 'SessionStore'],
312
311
  imports: [{ nodeId: 'i1', name: 'transcript', relation: 'imports_from' }],
@@ -334,14 +333,13 @@ const kindVariationComponents: SubsystemComponent[] = [
334
333
  purpose: 'labeled — the full purl as a quoted string literal',
335
334
  symbol: '',
336
335
  layer: 5,
337
- detail: {
336
+ declaration: {
338
337
  kind: 'external',
339
338
  label: 'pkg:npm/@principal-ai/subsystems-studio',
340
339
  } satisfies GraphifyComponentDetail,
341
340
  },
342
341
  ];
343
342
 
344
- const kindVariationEdges: SubsystemComponentEdge[] = [];
345
343
 
346
344
  function KindVariationsDemo() {
347
345
  const [selected, setSelected] = useState<string | null>(null);
@@ -349,7 +347,7 @@ function KindVariationsDemo() {
349
347
  <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
350
348
  <SubsystemComponentGraph
351
349
  components={kindVariationComponents}
352
- edges={kindVariationEdges}
350
+ relations={[]}
353
351
  onSelect={(id) => setSelected(id)}
354
352
  />
355
353
  <div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
@@ -4,7 +4,7 @@ import type { Meta, StoryObj } from '@storybook/react';
4
4
  import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
5
5
  import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
6
6
  import type { SubsystemComponent, SubsystemComponentEdge } from '../../../subsystem/model';
7
- import { components, edges } from './fixtures';
7
+ import { components, graphSpecFromEdges } from './fixtures';
8
8
 
9
9
  const meta = {
10
10
  title: 'Subsystem/ComponentGraph/Basics',
@@ -33,7 +33,7 @@ const twoNodeComponents = components([
33
33
  ['dst', 'SessionReader', 'class', 'SessionReader.ts', 'pkg:github/principal-ai/agent-monitoring', 'normalizes sessions into events'],
34
34
  ]);
35
35
 
36
- const twoNodeEdges = edges([
36
+ const twoNodeEdges = graphSpecFromEdges([
37
37
  ['src', 'dst', 'imports'],
38
38
  ]);
39
39
 
@@ -44,7 +44,7 @@ function TwoNodeDemo({ showEdgeLabels = true }: { showEdgeLabels?: boolean }) {
44
44
  <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
45
45
  <SubsystemComponentGraph
46
46
  components={twoNodeComponents}
47
- edges={twoNodeEdges}
47
+ relations={twoNodeEdges.relations} walkthroughs={twoNodeEdges.walkthroughs}
48
48
  onSelect={(id) => setSelected(id)}
49
49
  onEdgeSelect={(e) => setSelectedEdge(e)}
50
50
  showEdgeLabels={showEdgeLabels}
@@ -74,7 +74,7 @@ export const TwoNodeNoLabels: Story = {
74
74
  // ---------------------------------------------------------------------------
75
75
  function PlaygroundDemo({ leftCount, rightCount, showEdgeLabels }: { leftCount: number; rightCount: number; showEdgeLabels: boolean }) {
76
76
  const comps: SubsystemComponent[] = [];
77
- const edgeList: SubsystemComponentEdge[] = [];
77
+ const edgeSpec: Array<[string, string, SubsystemComponentEdge['mechanism']]> = [];
78
78
 
79
79
  for (let i = 0; i < leftCount; i++) {
80
80
  comps.push({
@@ -97,16 +97,16 @@ function PlaygroundDemo({ leftCount, rightCount, showEdgeLabels }: { leftCount:
97
97
  });
98
98
  }
99
99
 
100
- let ei = 0;
101
100
  for (let i = 0; i < leftCount; i++) {
102
101
  for (let j = 0; j < rightCount; j++) {
103
- edgeList.push({ id: `e${ei++}`, from: `l${i}`, to: `r${j}`, mechanism: 'imports' });
102
+ edgeSpec.push([`l${i}`, `r${j}`, 'imports']);
104
103
  }
105
104
  }
105
+ const graph = graphSpecFromEdges(edgeSpec);
106
106
 
107
107
  return (
108
108
  <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
109
- <SubsystemComponentGraph components={comps} edges={edgeList} showEdgeLabels={showEdgeLabels} />
109
+ <SubsystemComponentGraph components={comps} relations={graph.relations} walkthroughs={graph.walkthroughs} showEdgeLabels={showEdgeLabels} />
110
110
  </div>
111
111
  );
112
112
  }
@@ -131,7 +131,7 @@ export const Playground: Story = {
131
131
  export const Empty: Story = {
132
132
  render: () => (
133
133
  <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
134
- <SubsystemComponentGraph components={[]} edges={[]} />
134
+ <SubsystemComponentGraph components={[]} relations={[]} />
135
135
  </div>
136
136
  ),
137
137
  };