@principal-ai/subsystems-react 0.55.1 → 0.55.2

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 (105) hide show
  1. package/README.md +2 -1
  2. package/dist/graphify/index.d.ts +2 -0
  3. package/dist/graphify/index.d.ts.map +1 -1
  4. package/dist/graphify/index.js +1 -0
  5. package/dist/graphify/index.js.map +1 -1
  6. package/dist/graphify/symbolFocus.d.ts +49 -0
  7. package/dist/graphify/symbolFocus.d.ts.map +1 -0
  8. package/dist/graphify/symbolFocus.js +139 -0
  9. package/dist/graphify/symbolFocus.js.map +1 -0
  10. package/dist/index.d.ts +5 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/stories/Canvases/Aggregate/aggregateViewFixture.d.ts.map +1 -0
  15. package/dist/stories/Canvases/Aggregate/aggregateViewFixture.js.map +1 -0
  16. package/dist/stories/Canvases/Subsystem/fixtures.d.ts.map +1 -0
  17. package/dist/stories/Canvases/Subsystem/fixtures.js.map +1 -0
  18. package/dist/subsystem/SubsystemComponentGraph.d.ts +35 -1
  19. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  20. package/dist/subsystem/SubsystemComponentGraph.js +248 -33
  21. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  22. package/dist/subsystem/SymbolFocusedView.d.ts +30 -0
  23. package/dist/subsystem/SymbolFocusedView.d.ts.map +1 -0
  24. package/dist/subsystem/SymbolFocusedView.js +24 -0
  25. package/dist/subsystem/SymbolFocusedView.js.map +1 -0
  26. package/dist/subsystem/TrailsPanel.d.ts +16 -1
  27. package/dist/subsystem/TrailsPanel.d.ts.map +1 -1
  28. package/dist/subsystem/TrailsPanel.js +64 -8
  29. package/dist/subsystem/TrailsPanel.js.map +1 -1
  30. package/dist/subsystem/graphChrome.d.ts +13 -0
  31. package/dist/subsystem/graphChrome.d.ts.map +1 -1
  32. package/dist/subsystem/graphChrome.js +19 -1
  33. package/dist/subsystem/graphChrome.js.map +1 -1
  34. package/dist/subsystem/model.d.ts +40 -4
  35. package/dist/subsystem/model.d.ts.map +1 -1
  36. package/dist/subsystem/model.js +38 -7
  37. package/dist/subsystem/model.js.map +1 -1
  38. package/package.json +2 -2
  39. package/src/graphify/index.ts +6 -0
  40. package/src/graphify/symbolFocus.test.ts +163 -0
  41. package/src/graphify/symbolFocus.ts +190 -0
  42. package/src/index.ts +7 -0
  43. package/src/stories/{Subsystem/AggregateGraph → Canvases/Aggregate}/AggregateFrameGraph.stories.tsx +1 -1
  44. package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4CardGrow.stories.tsx +1 -1
  45. package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4Component.stories.tsx +1 -1
  46. package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4Container.stories.tsx +1 -1
  47. package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4NodeGallery.stories.tsx +1 -1
  48. package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4ToComponentDrill.stories.tsx +1 -1
  49. package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4Transition.stories.tsx +1 -1
  50. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/AnimatedProgression.stories.tsx +1 -1
  51. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Appearance.stories.tsx +1 -1
  52. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Basics.stories.tsx +1 -1
  53. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Captures.stories.tsx +1 -1
  54. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Constructs.stories.tsx +1 -1
  55. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/CustomEntities.stories.tsx +1 -1
  56. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Deprecated.stories.tsx +1 -1
  57. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/DetailPanel.stories.tsx +1 -1
  58. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Diagnostics.stories.tsx +1 -1
  59. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/EdgeViews.stories.tsx +1 -1
  60. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/FrameworkStereotype.stories.tsx +1 -1
  61. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/GraphTitle.stories.tsx +1 -1
  62. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Issues.stories.tsx +1 -1
  63. package/src/stories/Canvases/Subsystem/LayoutDirection.stories.tsx +122 -0
  64. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/ModuleBadges.stories.tsx +1 -1
  65. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/ModulePathNesting.stories.tsx +1 -1
  66. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Modules.stories.tsx +1 -1
  67. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/NodeAnatomy.stories.tsx +1 -1
  68. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Packages.stories.tsx +1 -1
  69. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Processes.stories.tsx +1 -1
  70. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Proposed.stories.tsx +1 -1
  71. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/ProposedTrails.stories.tsx +1 -1
  72. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Reorder.stories.tsx +1 -1
  73. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Scenarios.stories.tsx +1 -1
  74. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Spotlights.stories.tsx +1 -1
  75. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/StoreValueType.stories.tsx +1 -1
  76. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/TrailAutoplay.stories.tsx +1 -1
  77. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Trails.stories.tsx +1 -1
  78. package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/WorkspacePackageFrames.stories.tsx +1 -1
  79. package/src/stories/Canvases/SymbolFocusedView/SymbolFocusedView.stories.tsx +163 -0
  80. package/src/stories/{Subsystem → Components}/AgentsPanel.stories.tsx +1 -1
  81. package/src/stories/{Subsystem/ComponentDeclarationAudit.stories.tsx → Components/ComponentDeclaration/Audit.stories.tsx} +4 -4
  82. package/src/stories/{Subsystem/ComponentDeclarationSymbols.stories.tsx → Components/ComponentDeclaration/Symbols.stories.tsx} +5 -5
  83. package/src/stories/{Subsystem → Components}/ConstructsCatalog.stories.tsx +1 -1
  84. package/src/stories/{Subsystem/Sidebar → Components}/GraphSidebar.stories.tsx +4 -4
  85. package/src/stories/{Subsystem/IssueIcons.stories.tsx → Components/IssueList.stories.tsx} +1 -1
  86. package/src/stories/{Subsystem/StoreValueTypeDeclaration.stories.tsx → Components/StoreValueType.stories.tsx} +1 -1
  87. package/src/subsystem/SubsystemComponentGraph.tsx +331 -25
  88. package/src/subsystem/SymbolFocusedView.tsx +80 -0
  89. package/src/subsystem/TrailsPanel.tsx +107 -4
  90. package/src/subsystem/graphChrome.tsx +22 -1
  91. package/src/subsystem/layoutDirection.test.ts +26 -0
  92. package/src/subsystem/model.test.ts +17 -0
  93. package/src/subsystem/model.ts +70 -10
  94. package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.d.ts.map +0 -1
  95. package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.js.map +0 -1
  96. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +0 -1
  97. package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +0 -1
  98. package/src/stories/Subsystem/EgoGraph/EgoGraph.stories.tsx +0 -351
  99. /package/dist/stories/{Subsystem/AggregateGraph → Canvases/Aggregate}/aggregateViewFixture.d.ts +0 -0
  100. /package/dist/stories/{Subsystem/AggregateGraph → Canvases/Aggregate}/aggregateViewFixture.js +0 -0
  101. /package/dist/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/fixtures.d.ts +0 -0
  102. /package/dist/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/fixtures.js +0 -0
  103. /package/src/graphify/__fixtures__/{ego-samples.json → symbol-focused-samples.json} +0 -0
  104. /package/src/stories/{Subsystem/AggregateGraph → Canvases/Aggregate}/aggregateViewFixture.ts +0 -0
  105. /package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/fixtures.ts +0 -0
@@ -1,351 +0,0 @@
1
- /**
2
- * Ego-graph prototype: reuse the subsystem component nodes to render one
3
- * graphify symbol at the center plus its real connections.
4
- *
5
- * The center + neighbors come from `graphify/__fixtures__/ego-samples.json`
6
- * (extracted from this repo's cached graph). Each graphify node is mapped onto
7
- * a `SubsystemComponent`; the graphify edges are passed through the dedicated
8
- * `graphifyRelations` input, so they render with the separate
9
- * `GRAPHIFY_RELATION_COLOR` palette — visually distinct from authored subsystem
10
- * mechanisms — and keep their raw verb as the label (no folding to
11
- * `references`).
12
- */
13
- import React from 'react';
14
- import '@xyflow/react/dist/style.css';
15
- import type { Meta, StoryObj } from '@storybook/react';
16
- import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
17
- import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
18
- import type {
19
- SubsystemComponent,
20
- SubsystemComponentConstruct,
21
- SubsystemGraphifyRelation,
22
- } from '../../../subsystem/model';
23
- import { inferConstructFromGraphify } from '../../../graphify';
24
- import type { GraphifyEdge, GraphifyNode } from '../../../graphify';
25
- import egoSamples from '../../../graphify/__fixtures__/ego-samples.json';
26
-
27
- const meta = {
28
- title: 'Subsystem/EgoGraph',
29
- component: SubsystemComponentGraph,
30
- parameters: { layout: 'fullscreen' },
31
- tags: ['autodocs'],
32
- decorators: [
33
- (Story) => (
34
- <ThemeProvider theme={defaultEditorTheme}>
35
- <Story />
36
- </ThemeProvider>
37
- ),
38
- ],
39
- } satisfies Meta<typeof SubsystemComponentGraph>;
40
-
41
- export default meta;
42
- type Story = StoryObj<typeof meta>;
43
-
44
- // ---------------------------------------------------------------------------
45
- // Fixture shape
46
- // ---------------------------------------------------------------------------
47
-
48
- type FixtureNode = {
49
- id: string;
50
- label: string;
51
- file_type?: string;
52
- source_file?: string;
53
- source_location?: string;
54
- type?: string;
55
- };
56
-
57
- type FixtureEdge = {
58
- source: string;
59
- target: string;
60
- relation: string;
61
- confidence?: string;
62
- context?: string;
63
- source_file?: string;
64
- source_location?: string;
65
- };
66
-
67
- type FixtureCategory = {
68
- center?: FixtureNode;
69
- degree?: number;
70
- neighborCount?: number;
71
- neighbors?: FixtureNode[];
72
- edges?: FixtureEdge[];
73
- };
74
-
75
- type Category = 'class' | 'function' | 'method' | 'type' | 'module';
76
-
77
- const categories = egoSamples.categories as unknown as Record<Category, FixtureCategory>;
78
- const authoredCategories = egoSamples.authoredCategories as unknown as Record<
79
- string,
80
- { component: SubsystemComponent }
81
- >;
82
-
83
- const REPO_PURL = 'pkg:github/principal-ai/subsystem-modeling';
84
-
85
- // ---------------------------------------------------------------------------
86
- // graphify -> subsystem mapping
87
- // ---------------------------------------------------------------------------
88
-
89
- /** The fixture center's category, expressed as a subsystem construct. */
90
- const CENTER_CONSTRUCT: Record<Category, SubsystemComponentConstruct> = {
91
- class: 'class',
92
- function: 'function',
93
- method: 'method',
94
- type: 'interface',
95
- // Subsystem models draw files as module *frames*, not nodes — there is no
96
- // `module` construct. Stand in with `external` so the file node still draws.
97
- module: 'external',
98
- };
99
-
100
- /** Coarse graphify-inferred construct -> subsystem construct. */
101
- const INFERRED_TO_CONSTRUCT: Record<string, SubsystemComponentConstruct> = {
102
- class: 'class',
103
- function: 'function',
104
- method: 'method',
105
- type: 'interface',
106
- module: 'external',
107
- unknown: 'external',
108
- };
109
-
110
- function parseLine(location?: string): number | undefined {
111
- const m = /^L(\d+)$/.exec(location ?? '');
112
- return m ? Number(m[1]) : undefined;
113
- }
114
-
115
- function purlFor(sourceFile?: string): string {
116
- return sourceFile ? `${REPO_PURL}#${sourceFile}` : REPO_PURL;
117
- }
118
-
119
- /**
120
- * Graphify labels carry their own decoration: functions end `name()`, methods
121
- * start `.name()`. A subsystem `symbol` is the bare code identity and the node
122
- * renderer re-derives the `()` / `.` decoration itself, so passing a decorated
123
- * label through would double it (`readFoo()()` → the name printed twice).
124
- * Strip the graphify decoration and hand back a clean symbol.
125
- */
126
- function stripGraphifyDecoration(label: string): string {
127
- let s = label.trim();
128
- if (s.endsWith('()')) s = s.slice(0, -2);
129
- if (s.startsWith('.')) s = s.slice(1);
130
- return s;
131
- }
132
-
133
- function toComponent(
134
- alias: string,
135
- node: FixtureNode,
136
- construct: SubsystemComponentConstruct,
137
- purpose: string,
138
- lineOverride?: number,
139
- ): SubsystemComponent {
140
- const line = lineOverride ?? parseLine(node.source_location);
141
- const symbol = stripGraphifyDecoration(node.label);
142
- return {
143
- alias,
144
- name: symbol,
145
- construct,
146
- symbol,
147
- file: node.source_file ?? '',
148
- purl: purlFor(node.source_file),
149
- purpose,
150
- // `line` also seeds ELK's same-layer ordering (orderByLine).
151
- ...(line != null ? { line } : {}),
152
- ...(line != null
153
- ? {
154
- declarationSpan: {
155
- startLine: line,
156
- endLine: line,
157
- contentHash: 'ego-fixture',
158
- },
159
- }
160
- : {}),
161
- };
162
- }
163
-
164
- interface EgoGraph {
165
- components: SubsystemComponent[];
166
- graphifyRelations: SubsystemGraphifyRelation[];
167
- }
168
-
169
- /** Turn one fixture category into a subsystem graph centered on its symbol. */
170
- function toEgoGraph(cat: FixtureCategory, category: Category): EgoGraph {
171
- const center = cat.center;
172
- if (!center) return { components: [], graphifyRelations: [] };
173
-
174
- const edges = cat.edges ?? [];
175
- const neighbors = cat.neighbors ?? [];
176
-
177
- // graphify file nodes (`inferConstructFromGraphify` → 'module') are not
178
- // symbols — they are the CONTAINER of symbols. The center's own file becomes
179
- // a `module` boundary (a frame around its members) and its `contains` edges
180
- // are dropped: membership is expressed by the frame, exactly as an authored
181
- // model does it. Files reached as neighbors stay as nodes (they are external
182
- // to the center's file), so only the center's file is framed.
183
- const isFileNode = (n: FixtureNode): boolean =>
184
- inferConstructFromGraphify(
185
- n as unknown as GraphifyNode,
186
- edges as unknown as GraphifyEdge[],
187
- ).construct === 'module';
188
-
189
- const centerFile = center.source_file;
190
- const fileNodeIds = new Set(
191
- neighbors.filter((n) => isFileNode(n)).map((n) => n.id),
192
- );
193
- // Neighbors that live in the center's file stay; the file node for that file
194
- // is dropped (its containment is now the frame).
195
- const knotless = neighbors.filter(
196
- (n) => !(fileNodeIds.has(n.id) && n.source_file === centerFile),
197
- );
198
-
199
- const aliasById = new Map<string, string>([[center.id, 'center']]);
200
- knotless.forEach((n, i) => aliasById.set(n.id, `n${i}`));
201
- const aliasFor = (id: string): string | undefined => aliasById.get(id);
202
-
203
- const centerConstruct = CENTER_CONSTRUCT[category];
204
- const framedCenter: SubsystemComponent = {
205
- ...toComponent(
206
- 'center',
207
- center,
208
- centerConstruct,
209
- `graphify center — ${center.label}`,
210
- ),
211
- ...(centerConstruct !== 'external' && centerFile ? { module: centerFile } : {}),
212
- };
213
- const components: SubsystemComponent[] = [framedCenter];
214
-
215
- // `component.line` is the CALL-SITE line, not the declaration line: the
216
- // edge's `source_location` on an edge FROM the center (L115, L119, …), which
217
- // `orderByLine` uses to stack callees in the order the center calls them.
218
- // (The neighbor's own node `source_location` — where it is declared — is
219
- // deliberately ignored here; declaration order would read arbitrarily.)
220
- const callLineByAlias = new Map<string, number>();
221
- for (const e of edges) {
222
- const from = aliasFor(e.source);
223
- const to = aliasFor(e.target);
224
- const line = parseLine(e.source_location);
225
- if (from === 'center' && to && line != null) callLineByAlias.set(to, line);
226
- }
227
-
228
- knotless.forEach((n, i) => {
229
- const inferred = inferConstructFromGraphify(
230
- n as unknown as GraphifyNode,
231
- edges as unknown as GraphifyEdge[],
232
- ).construct;
233
- const construct = INFERRED_TO_CONSTRUCT[inferred] ?? 'external';
234
- const purpose =
235
- inferred === 'module'
236
- ? 'graphify file node in ANOTHER file — kept as a node (outside the center frame)'
237
- : `graphify ${inferred} neighbor (${n.file_type ?? 'code'})`;
238
- // Members of the center's file join the frame; others stand alone.
239
- const module = n.source_file === centerFile ? centerFile : undefined;
240
- const c = toComponent(`n${i}`, n, construct, purpose, callLineByAlias.get(`n${i}`));
241
- components.push(module ? { ...c, module } : c);
242
- });
243
-
244
- // Raw graphify edges — passed straight through (no verb folding). The
245
- // canvas colors them from GRAPHIFY_RELATION_COLOR and draws them dashed.
246
- // `contains` is dropped: the frame carries containment, not an edge.
247
- const graphifyRelations: SubsystemGraphifyRelation[] = edges
248
- .map((e, i): SubsystemGraphifyRelation | null => {
249
- if (e.relation === 'contains') return null;
250
- const from = aliasFor(e.source);
251
- const to = aliasFor(e.target);
252
- if (!from || !to) return null;
253
- return {
254
- id: `g${i}`,
255
- from,
256
- to,
257
- relation: e.relation,
258
- refs: e.source_file ? [e.source_file] : undefined,
259
- line: parseLine(e.source_location),
260
- confidence: e.confidence,
261
- context: e.context,
262
- };
263
- })
264
- .filter((x): x is SubsystemGraphifyRelation => x != null);
265
-
266
- return { components, graphifyRelations };
267
- }
268
-
269
- function EgoDemo({ category, orderByLine }: { category: Category; orderByLine: boolean }) {
270
- const graph = React.useMemo(() => toEgoGraph(categories[category], category), [category]);
271
- const cat = categories[category];
272
- const verbs = [...new Set(graph.graphifyRelations.map((r) => r.relation))];
273
- return (
274
- <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
275
- <SubsystemComponentGraph
276
- components={graph.components}
277
- graphifyRelations={graph.graphifyRelations}
278
- orderByLine={orderByLine}
279
- showSingletonFrames
280
- title={`Ego graph — ${category}`}
281
- description={`graphify center ${cat.center?.label ?? '?'} · ${cat.degree ?? 0} edges · verbs: ${verbs.join(', ')}${orderByLine ? ' · ordered by call-site line' : ''}`}
282
- showEdgeLabels
283
- hideSidebar={false}
284
- />
285
- </div>
286
- );
287
- }
288
-
289
- /** Everything on disk for the center: node + neighbor nodes + raw edges. */
290
- function RawDump({ category }: { category: Category }) {
291
- const cat = categories[category];
292
- return (
293
- <pre
294
- style={{
295
- margin: 0,
296
- padding: 12,
297
- fontSize: 12,
298
- lineHeight: 1.5,
299
- fontFamily: 'monospace',
300
- color: '#ddd',
301
- background: '#111',
302
- height: '100vh',
303
- overflow: 'auto',
304
- boxSizing: 'border-box',
305
- }}
306
- >
307
- {JSON.stringify({ category, ...cat }, null, 2)}
308
- </pre>
309
- );
310
- }
311
-
312
- // ---------------------------------------------------------------------------
313
- // Stories — one per graphify node category
314
- // ---------------------------------------------------------------------------
315
-
316
- export const Class: Story = { render: () => <EgoDemo category="class" orderByLine /> };
317
- export const Function: Story = { render: () => <EgoDemo category="function" orderByLine /> };
318
- export const Method: Story = { render: () => <EgoDemo category="method" orderByLine /> };
319
- export const Type: Story = { render: () => <EgoDemo category="type" orderByLine /> };
320
- export const Module: Story = { render: () => <EgoDemo category="module" orderByLine /> };
321
-
322
- /** Same centers, ELK's default ordering — compare against the line-ordered set. */
323
- export const MethodReorderOff: Story = {
324
- render: () => <EgoDemo category="method" orderByLine={false} />,
325
- };
326
-
327
- /** The raw extracted data behind each center — no rendering involved. */
328
- export const Raw: Story = { render: () => <RawDump category="class" /> };
329
-
330
- // ---------------------------------------------------------------------------
331
- // Authored-only constructs (no graphify node) pulled from the model store
332
- // ---------------------------------------------------------------------------
333
-
334
- const authoredComponents: SubsystemComponent[] = [
335
- authoredCategories.store?.component,
336
- authoredCategories.external?.component,
337
- authoredCategories.custom_entity?.component,
338
- ].filter(Boolean) as SubsystemComponent[];
339
-
340
- /** store / external / custom_entity — authored nodes, no graphify anchor. */
341
- export const AuthoredConstructs: Story = {
342
- render: () => (
343
- <div style={{ width: '100%', height: '100vh' }}>
344
- <SubsystemComponentGraph
345
- components={authoredComponents}
346
- title="Authored-only constructs"
347
- description="store / external / custom_entity — reused cast from stored subsystem models (no graphify node, no edges)."
348
- />
349
- </div>
350
- ),
351
- };