@principal-ai/subsystems-react 0.20.6 → 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 (73) 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/index.d.ts +5 -5
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +2 -2
  11. package/dist/index.js.map +1 -1
  12. package/dist/pierre/PierreWalkthroughCodeView.d.ts +22 -0
  13. package/dist/pierre/PierreWalkthroughCodeView.d.ts.map +1 -0
  14. package/dist/pierre/PierreWalkthroughCodeView.js +198 -0
  15. package/dist/pierre/PierreWalkthroughCodeView.js.map +1 -0
  16. package/dist/pierre/index.d.ts +2 -2
  17. package/dist/pierre/index.js +1 -1
  18. package/dist/pierre/pierreFileLang.d.ts +1 -1
  19. package/dist/pierre/pierreFileLang.js +1 -1
  20. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts +14 -2
  21. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
  22. package/dist/stories/Subsystem/ComponentGraph/fixtures.js +86 -20
  23. package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
  24. package/dist/subsystem/FileDrawer.d.ts +2 -2
  25. package/dist/subsystem/FileDrawer.js +2 -2
  26. package/dist/subsystem/SubsystemComponentGraph.d.ts +25 -24
  27. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  28. package/dist/subsystem/SubsystemComponentGraph.js +204 -199
  29. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  30. package/dist/subsystem/formatDeclaration.d.ts +2 -1
  31. package/dist/subsystem/formatDeclaration.d.ts.map +1 -1
  32. package/dist/subsystem/formatDeclaration.js +57 -33
  33. package/dist/subsystem/formatDeclaration.js.map +1 -1
  34. package/dist/subsystem/model.d.ts +85 -35
  35. package/dist/subsystem/model.d.ts.map +1 -1
  36. package/dist/subsystem/model.js +85 -6
  37. package/dist/subsystem/model.js.map +1 -1
  38. package/dist/subsystem/nodes.d.ts.map +1 -1
  39. package/dist/subsystem/nodes.js +30 -13
  40. package/dist/subsystem/nodes.js.map +1 -1
  41. package/dist/subsystem/tokenizeComponent.js +2 -2
  42. package/dist/subsystem/tokenizeComponent.js.map +1 -1
  43. package/package.json +3 -3
  44. package/src/graphify/anchor.test.ts +31 -2
  45. package/src/graphify/anchor.ts +46 -0
  46. package/src/graphify/consolidated.ts +43 -1
  47. package/src/index.ts +13 -5
  48. package/src/pierre/{PierreThroughlineCodeView.tsx → PierreWalkthroughCodeView.tsx} +39 -47
  49. package/src/pierre/index.ts +2 -2
  50. package/src/pierre/pierreFileLang.ts +1 -1
  51. package/src/stories/Pierre/CodeView.stories.tsx +3 -3
  52. package/src/stories/Subsystem/ComponentDeclarationAudit.stories.tsx +14 -14
  53. package/src/stories/Subsystem/ComponentGraph/Appearance.stories.tsx +13 -15
  54. package/src/stories/Subsystem/ComponentGraph/Basics.stories.tsx +8 -8
  55. package/src/stories/Subsystem/ComponentGraph/Captures.stories.tsx +14 -14
  56. package/src/stories/Subsystem/ComponentGraph/CustomEntities.stories.tsx +11 -10
  57. package/src/stories/Subsystem/ComponentGraph/DetailPanel.stories.tsx +13 -14
  58. package/src/stories/Subsystem/ComponentGraph/Flows.stories.tsx +31 -66
  59. package/src/stories/Subsystem/ComponentGraph/FrameworkStereotype.stories.tsx +2 -2
  60. package/src/stories/Subsystem/ComponentGraph/GraphTitle.stories.tsx +4 -4
  61. package/src/stories/Subsystem/ComponentGraph/Processes.stories.tsx +3 -3
  62. package/src/stories/Subsystem/ComponentGraph/Proposed.stories.tsx +1 -1
  63. package/src/stories/Subsystem/ComponentGraph/Scenarios.stories.tsx +518 -33
  64. package/src/stories/Subsystem/ComponentGraph/Spotlights.stories.tsx +13 -13
  65. package/src/stories/Subsystem/ComponentGraph/fixtures.ts +105 -21
  66. package/src/subsystem/FileDrawer.tsx +2 -2
  67. package/src/subsystem/SubsystemComponentGraph.tsx +268 -259
  68. package/src/subsystem/formatDeclaration.test.ts +76 -1
  69. package/src/subsystem/formatDeclaration.ts +57 -33
  70. package/src/subsystem/model.test.ts +27 -15
  71. package/src/subsystem/model.ts +175 -45
  72. package/src/subsystem/nodes.tsx +47 -13
  73. package/src/subsystem/tokenizeComponent.ts +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principal-ai/subsystems-react",
3
- "version": "0.20.6",
3
+ "version": "0.21.0",
4
4
  "description": "React UI for Subsystem Models — graph, Pierre code views, and session-event feeds",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  "peerDependencies": {
38
38
  "@pierre/diffs": ">=1.1.20",
39
39
  "@principal-ade/industry-theme": "^0.1.7",
40
- "@principal-ai/subsystems-core": ">=0.30.0",
40
+ "@principal-ai/subsystems-core": ">=0.32.0",
41
41
  "react": "^18.0.0 || ^19.0.0",
42
42
  "react-dom": "^18.0.0 || ^19.0.0"
43
43
  },
@@ -45,7 +45,7 @@
45
45
  "@pierre/diffs": "1.3.6",
46
46
  "@principal-ade/industry-theme": "0.1.7",
47
47
  "@principal-ai/agent-monitoring": "^0.3.38",
48
- "@principal-ai/subsystems-core": "0.31.0",
48
+ "@principal-ai/subsystems-core": "0.32.0",
49
49
  "@storybook/addon-docs": "10.1.2",
50
50
  "@storybook/addon-links": "10.1.2",
51
51
  "@storybook/addon-onboarding": "10.1.2",
@@ -5,7 +5,7 @@ import {
5
5
  makeGraphifyId,
6
6
  normalizeGraphifyId,
7
7
  } from './ids';
8
- import { resolveComponentAnchor, symbolLabelVariants } from './anchor';
8
+ import { resolveComponentAnchor, symbolLabelVariants, findUniqueDefinitionBySymbol } from './anchor';
9
9
 
10
10
  function node(
11
11
  id: string,
@@ -31,7 +31,7 @@ describe('makeGraphifyId', () => {
31
31
  'packages/subsystems-studio/src/mainview/views/SubsystemModelView',
32
32
  );
33
33
  expect(makeGraphifyId(stem, 'SubsystemModelView')).toBe(
34
- 'packages_trail_viewer_src_mainview_views_subsystemmodelview_subsystemmodelview',
34
+ 'packages_subsystems_studio_src_mainview_views_subsystemmodelview_subsystemmodelview',
35
35
  );
36
36
  });
37
37
 
@@ -122,3 +122,32 @@ describe('resolveComponentAnchor', () => {
122
122
  expect(r.resolution).toBe('missing');
123
123
  });
124
124
  });
125
+
126
+ describe('findUniqueDefinitionBySymbol', () => {
127
+ test('unique when one defining file', () => {
128
+ const nodes = [
129
+ node('a', 'HostInfo', 'src/a.ts', 'L1'),
130
+ node('b', 'Other', 'src/b.ts', 'L1'),
131
+ ];
132
+ const r = findUniqueDefinitionBySymbol(nodes, 'HostInfo');
133
+ expect(r.status).toBe('unique');
134
+ if (r.status === 'unique') expect(r.node.source_file).toBe('src/a.ts');
135
+ });
136
+
137
+ test('ambiguous when same symbol in two files', () => {
138
+ const nodes = [
139
+ node('a', 'Foo()', 'src/a.ts', 'L1'),
140
+ node('b', 'Foo()', 'src/b.ts', 'L1'),
141
+ ];
142
+ const r = findUniqueDefinitionBySymbol(nodes, 'Foo');
143
+ expect(r.status).toBe('ambiguous');
144
+ });
145
+
146
+ test('none when symbol absent', () => {
147
+ const r = findUniqueDefinitionBySymbol(
148
+ [node('a', 'Bar', 'src/a.ts')],
149
+ 'Foo',
150
+ );
151
+ expect(r.status).toBe('none');
152
+ });
153
+ });
@@ -158,3 +158,49 @@ export function resolveComponentAnchor(
158
158
  triedIds,
159
159
  };
160
160
  }
161
+
162
+ export type UniqueDefinitionBySymbolResult =
163
+ | { status: 'unique'; node: GraphifyNode }
164
+ | { status: 'ambiguous'; candidates: GraphifyNode[] }
165
+ | { status: 'none' };
166
+
167
+ /**
168
+ * Corpus-wide definition lookup by symbol label only (no claimed file).
169
+ * Used when the model’s file path is missing and we want a deterministic
170
+ * relocate if exactly one defining file still declares the symbol.
171
+ *
172
+ * Unique means a single `source_file` among matching definition nodes.
173
+ */
174
+ export function findUniqueDefinitionBySymbol(
175
+ nodes: readonly GraphifyNode[],
176
+ symbol: string,
177
+ ): UniqueDefinitionBySymbolResult {
178
+ const trimmed = symbol.trim();
179
+ if (!trimmed) return { status: 'none' };
180
+
181
+ const hits: GraphifyNode[] = [];
182
+ for (const node of nodes) {
183
+ if (!isDefinition(node)) continue;
184
+ if (!labelMatchesSymbol(String(node.label ?? ''), trimmed)) continue;
185
+ hits.push(node);
186
+ }
187
+ if (hits.length === 0) return { status: 'none' };
188
+
189
+ const byFile = new Map<string, GraphifyNode[]>();
190
+ for (const n of hits) {
191
+ const sf = normalizeSourcePath(String(n.source_file ?? ''));
192
+ if (!sf) continue;
193
+ const list = byFile.get(sf) ?? [];
194
+ list.push(n);
195
+ byFile.set(sf, list);
196
+ }
197
+ if (byFile.size === 0) return { status: 'none' };
198
+ if (byFile.size > 1) {
199
+ return {
200
+ status: 'ambiguous',
201
+ candidates: hits.slice(0, 12),
202
+ };
203
+ }
204
+ const only = [...byFile.values()][0]!;
205
+ return { status: 'unique', node: only[0]! };
206
+ }
@@ -161,6 +161,25 @@ export interface GraphifyFunctionDetail {
161
161
  callees: GraphifyCallInfo[];
162
162
  }
163
163
 
164
+ /** One generic type parameter, e.g. `T` or `K extends keyof StudioMessages`. */
165
+ export interface GraphifyTypeParamInfo {
166
+ name: string;
167
+ /** Constraint written after `extends` (or language equivalent). */
168
+ constraint?: string;
169
+ }
170
+
171
+ /** A callable/function type: `(params) => returnType`. */
172
+ export interface GraphifyCallableTypeInfo {
173
+ parameters?: GraphifyParamInfo[];
174
+ returnType?: string;
175
+ }
176
+
177
+ /** One enum member, with its optional literal value. */
178
+ export interface GraphifyEnumMemberInfo {
179
+ name: string;
180
+ value?: string;
181
+ }
182
+
164
183
  /** A type-like node (interface/struct): revealed by incoming `implements` edges. */
165
184
  export interface GraphifyTypeDetail {
166
185
  kind: 'type';
@@ -170,6 +189,22 @@ export interface GraphifyTypeDetail {
170
189
  usedBy: GraphifyReferenceInfo[];
171
190
  /** Nodes that `inherits`/`implements` this type. */
172
191
  implementors: string[];
192
+ /** Generic type parameters, e.g. `<K extends keyof StudioMessages>`. */
193
+ generics?: GraphifyTypeParamInfo[];
194
+ /** Callable type — `(params) => returnType` (TS/Go/Rust fn, Java lambda). */
195
+ signature?: GraphifyCallableTypeInfo;
196
+ /** Enum members (name, optional literal value). */
197
+ enumMembers?: GraphifyEnumMemberInfo[];
198
+ /** Alias whose RHS is a plain reference, e.g. `StudioMessages[K]`. */
199
+ aliasOf?: string;
200
+ /** Simple union of alternatives, e.g. `'started' | 'stopped'`. */
201
+ unionOf?: string[];
202
+ /**
203
+ * Verbatim RHS — the escape hatch for shapes the structured fields can't
204
+ * express (mapped/conditional/template-literal/infer types, `typeof`/utility
205
+ * compositions, C pointers, Rust trait objects). Wins over every shape above.
206
+ */
207
+ rhs?: string;
173
208
  }
174
209
 
175
210
  /** A module/file-like node: a `contains` target with a filename label. */
@@ -221,6 +256,13 @@ export interface GraphifyStoreDetail {
221
256
  kind: 'store';
222
257
  /** The retained state members (module-level consts or class fields). */
223
258
  properties: GraphifyPropertyInfo[];
259
+ /**
260
+ * Where the retained state physically lives / who mediates access. Authored
261
+ * — graphify cannot infer it: `memory` = process-lifetime RAM, `disk` =
262
+ * this process reads/writes the filesystem, `external` = mediated by another
263
+ * system (db/service; carries no `process`).
264
+ */
265
+ storage?: 'memory' | 'disk' | 'external';
224
266
  }
225
267
 
226
268
  /** A standalone method selected from its owning class. */
@@ -235,7 +277,7 @@ export interface GraphifyMethodDetail {
235
277
  }
236
278
 
237
279
  /**
238
- * The drill-down payload for a subsystem component.
280
+ * The structured declaration payload for a subsystem component (click panel).
239
281
  *
240
282
  * The discriminant is derived from graph structure, not read off the node:
241
283
  * method edges → class; `()` label + no method edges → function; incoming
package/src/index.ts CHANGED
@@ -86,7 +86,7 @@ export type { UseElkLayoutOptions, UseElkLayoutResult } from './hooks/useElkLayo
86
86
 
87
87
  // Subsystem component graph
88
88
  export { SubsystemComponentGraph } from './subsystem/SubsystemComponentGraph';
89
- export type { SubsystemComponentGraphProps, ThroughlineViewerContext } from './subsystem/SubsystemComponentGraph';
89
+ export type { SubsystemComponentGraphProps, WalkthroughViewerContext } from './subsystem/SubsystemComponentGraph';
90
90
  export type {
91
91
  ComponentVerificationState,
92
92
  ComponentVerificationPhase,
@@ -114,14 +114,19 @@ export type { GraphLayoutCoverProps } from './subsystem/GraphLayoutCover';
114
114
  export type {
115
115
  SubsystemComponent,
116
116
  SubsystemComponentEdge,
117
- SubsystemThroughline,
118
- SubsystemThroughlineStep,
117
+ SubsystemRelation,
118
+ SubsystemRelationType,
119
+ SubsystemWalkthrough,
120
+ SubsystemWalkthroughStep,
121
+ SubsystemWalkthroughMechanism,
119
122
  SubsystemModelDocument,
120
123
  SubsystemComponentConstruct,
121
124
  SubsystemComponentRole,
122
125
  SubsystemFramework,
123
126
  SubsystemStereotype,
124
127
  SubsystemEdgeMechanism,
128
+ SubsystemConstructDeclaration,
129
+ SubsystemDeclarationProvenance,
125
130
  } from './subsystem/model';
126
131
  export {
127
132
  constructBadgeLabel,
@@ -129,6 +134,9 @@ export {
129
134
  rightBadgeColor,
130
135
  deriveNameFromSymbol,
131
136
  nodeMinWidthForBadges,
137
+ deriveGraphEdges,
138
+ derivedGraphEdgeId,
139
+ walkthroughStepGraphEdgeId,
132
140
  ROLE_COLOR,
133
141
  ROLE_LABEL,
134
142
  PROPOSED_COLOR,
@@ -146,11 +154,11 @@ export {
146
154
  } from './subsystem/declarationRef';
147
155
 
148
156
  // Pierre code views (@pierre/diffs wrappers)
149
- export { PierreFileView, PierreSnippetView, PierreThroughlineCodeView, sliceSnippetWindow, resolvePierreSyntaxThemeName } from './pierre';
157
+ export { PierreFileView, PierreSnippetView, PierreWalkthroughCodeView, sliceSnippetWindow, resolvePierreSyntaxThemeName } from './pierre';
150
158
  export type {
151
159
  PierreFileViewProps,
152
160
  PierreSnippetViewProps,
153
- PierreThroughlineCodeViewProps,
161
+ PierreWalkthroughCodeViewProps,
154
162
  SnippetSlice,
155
163
  PierreSyntaxThemeName,
156
164
  } from './pierre';
@@ -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,