@principal-ai/subsystems-react 0.42.0 → 0.43.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/stories/Subsystem/C4Graph/c4Fixture.js +1 -1
- package/dist/stories/Subsystem/C4Graph/c4Fixture.js.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts +6 -9
- package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js +15 -50
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
- package/dist/subsystem/C4Graph.d.ts +2 -3
- package/dist/subsystem/C4Graph.d.ts.map +1 -1
- package/dist/subsystem/C4Graph.js +2 -3
- package/dist/subsystem/C4Graph.js.map +1 -1
- package/dist/subsystem/IssueList.d.ts +5 -5
- package/dist/subsystem/IssueList.d.ts.map +1 -1
- package/dist/subsystem/IssueList.js +9 -18
- package/dist/subsystem/IssueList.js.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.d.ts +16 -12
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +99 -113
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/SubsystemFileTree.d.ts +5 -5
- package/dist/subsystem/SubsystemFileTree.d.ts.map +1 -1
- package/dist/subsystem/SubsystemFileTree.js +13 -49
- package/dist/subsystem/SubsystemFileTree.js.map +1 -1
- package/dist/subsystem/model.d.ts +67 -53
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +305 -55
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/nodes.d.ts.map +1 -1
- package/dist/subsystem/nodes.js +11 -4
- package/dist/subsystem/nodes.js.map +1 -1
- package/dist/subsystem/toC4.d.ts +4 -4
- package/dist/subsystem/toC4.d.ts.map +1 -1
- package/dist/subsystem/toC4.js +3 -7
- package/dist/subsystem/toC4.js.map +1 -1
- package/dist/utils/elkLayout.d.ts.map +1 -1
- package/dist/utils/elkLayout.js +7 -0
- package/dist/utils/elkLayout.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +0 -4
- package/src/stories/Subsystem/AgentsPanel.stories.tsx +3 -5
- package/src/stories/Subsystem/C4Graph/C4Container.stories.tsx +1 -4
- package/src/stories/Subsystem/C4Graph/c4Fixture.ts +1 -1
- package/src/stories/Subsystem/ComponentGraph/Appearance.stories.tsx +2 -4
- package/src/stories/Subsystem/ComponentGraph/Basics.stories.tsx +8 -8
- package/src/stories/Subsystem/ComponentGraph/Captures.stories.tsx +19 -19
- package/src/stories/Subsystem/ComponentGraph/Constructs.stories.tsx +0 -1
- package/src/stories/Subsystem/ComponentGraph/CustomEntities.stories.tsx +3 -3
- package/src/stories/Subsystem/ComponentGraph/DetailPanel.stories.tsx +0 -2
- package/src/stories/Subsystem/ComponentGraph/Diagnostics.stories.tsx +2 -6
- package/src/stories/Subsystem/ComponentGraph/EdgeViews.stories.tsx +21 -21
- package/src/stories/Subsystem/ComponentGraph/Flows.stories.tsx +0 -3
- package/src/stories/Subsystem/ComponentGraph/FrameworkStereotype.stories.tsx +30 -32
- package/src/stories/Subsystem/ComponentGraph/GraphTitle.stories.tsx +4 -4
- package/src/stories/Subsystem/ComponentGraph/IssueOverlay.stories.tsx +1 -26
- package/src/stories/Subsystem/ComponentGraph/Issues.stories.tsx +3 -25
- package/src/stories/Subsystem/ComponentGraph/ModuleBadges.stories.tsx +7 -8
- package/src/stories/Subsystem/ComponentGraph/ModulePathNesting.stories.tsx +116 -0
- package/src/stories/Subsystem/ComponentGraph/Modules.stories.tsx +9 -11
- package/src/stories/Subsystem/ComponentGraph/Packages.stories.tsx +3 -6
- package/src/stories/Subsystem/ComponentGraph/Processes.stories.tsx +3 -3
- package/src/stories/Subsystem/ComponentGraph/Proposed.stories.tsx +8 -6
- package/src/stories/Subsystem/ComponentGraph/ProposedWalkthroughs.stories.tsx +0 -1
- package/src/stories/Subsystem/ComponentGraph/Reorder.stories.tsx +0 -1
- package/src/stories/Subsystem/ComponentGraph/Scenarios.stories.tsx +26 -28
- package/src/stories/Subsystem/ComponentGraph/WalkthroughAutoplay.stories.tsx +0 -1
- package/src/stories/Subsystem/ComponentGraph/WorkspacePackageFrames.stories.tsx +2 -3
- package/src/stories/Subsystem/ComponentGraph/fixtures.ts +18 -58
- package/src/stories/Subsystem/EgoGraph/EgoGraph.stories.tsx +0 -2
- package/src/subsystem/C4Graph.tsx +2 -3
- package/src/subsystem/IssueList.tsx +12 -22
- package/src/subsystem/SubsystemComponentGraph.tsx +117 -135
- package/src/subsystem/SubsystemFileTree.tsx +17 -50
- package/src/subsystem/model.test.ts +155 -24
- package/src/subsystem/model.ts +352 -108
- package/src/subsystem/nodes.tsx +13 -3
- package/src/subsystem/toC4.test.ts +5 -12
- package/src/subsystem/toC4.ts +5 -9
- package/src/utils/elkLayout.ts +10 -0
|
@@ -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 { SubsystemIssueList, type SubsystemIssue } from '../../../subsystem/IssueList';
|
|
7
|
-
import { components,
|
|
7
|
+
import { components, graphSpecFromHops } from './fixtures';
|
|
8
8
|
|
|
9
9
|
const meta = {
|
|
10
10
|
title: 'Subsystem/ComponentGraph/Issues',
|
|
@@ -47,13 +47,6 @@ const ISSUES: SubsystemIssue[] = [
|
|
|
47
47
|
message: 'Named parameter types are not present in the graphify cache.',
|
|
48
48
|
target: { kind: 'component', id: 'entry', label: 'checkoutApi' },
|
|
49
49
|
},
|
|
50
|
-
{
|
|
51
|
-
id: 'i4',
|
|
52
|
-
severity: 'error',
|
|
53
|
-
kind: 'topology_broken_endpoint',
|
|
54
|
-
message: 'Relationship endpoint "store" does not resolve to a component.',
|
|
55
|
-
target: { kind: 'relation', id: 'r1', label: 'checkoutApi → cartStore', detail: 'writes' },
|
|
56
|
-
},
|
|
57
50
|
{
|
|
58
51
|
id: 'i5',
|
|
59
52
|
severity: 'info',
|
|
@@ -132,21 +125,7 @@ const ISSUES: SubsystemIssue[] = [
|
|
|
132
125
|
message: 'Graphify cache missing for pkg:github/you/your-app — build it to verify constructs and anchors',
|
|
133
126
|
target: { kind: 'repo', id: 'pkg:github/you/your-app', label: 'pkg:github/you/your-app' },
|
|
134
127
|
},
|
|
135
|
-
|
|
136
|
-
id: 'i14',
|
|
137
|
-
severity: 'info',
|
|
138
|
-
kind: 'topology_import_unconfirmed',
|
|
139
|
-
message: 'No import edge from checkoutApi to cartStore found in Graphify.',
|
|
140
|
-
target: { kind: 'relation', id: 'r1', label: 'checkoutApi → cartStore', detail: 'references' },
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
id: 'i15',
|
|
144
|
-
severity: 'info',
|
|
145
|
-
kind: 'topology_relation_unconfirmed',
|
|
146
|
-
message: 'Graphify found no inheritance evidence for FileSessionStore → SessionStore.',
|
|
147
|
-
target: { kind: 'relation', id: 'r2', label: 'FileSessionStore → SessionStore', detail: 'extends' },
|
|
148
|
-
},
|
|
149
|
-
];
|
|
128
|
+
];
|
|
150
129
|
|
|
151
130
|
const graphComponents = components([
|
|
152
131
|
['entry', 'checkoutApi', 'function', 'src/checkout/api.ts', 'pkg:github/you/your-app', 'Handles cart requests.', 'checkoutApi'],
|
|
@@ -154,7 +133,7 @@ const graphComponents = components([
|
|
|
154
133
|
['stripe', 'Stripe', 'external', '', 'external', undefined, undefined],
|
|
155
134
|
]);
|
|
156
135
|
|
|
157
|
-
const graphEdges =
|
|
136
|
+
const graphEdges = graphSpecFromHops([
|
|
158
137
|
['entry', 'store', 'writes'],
|
|
159
138
|
['entry', 'stripe', 'calls'],
|
|
160
139
|
]);
|
|
@@ -187,7 +166,6 @@ export const GraphWithIssues: Story = {
|
|
|
187
166
|
<div style={{ width: '100%', height: '100vh' }}>
|
|
188
167
|
<SubsystemComponentGraph
|
|
189
168
|
components={graphComponents}
|
|
190
|
-
relations={graphEdges.relations}
|
|
191
169
|
walkthroughs={graphEdges.walkthroughs}
|
|
192
170
|
title="Checkout"
|
|
193
171
|
description="A small e-commerce checkout subsystem."
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
SubsystemGraphNode,
|
|
10
10
|
SubsystemProcessRegion,
|
|
11
11
|
} from '../../../subsystem/model';
|
|
12
|
-
import {
|
|
12
|
+
import { graphSpecFromHops } from './fixtures';
|
|
13
13
|
|
|
14
14
|
const meta = {
|
|
15
15
|
title: 'Subsystem/ComponentGraph/ModuleBadges',
|
|
@@ -102,12 +102,12 @@ const deepComponents: SubsystemComponent[] = [
|
|
|
102
102
|
},
|
|
103
103
|
];
|
|
104
104
|
|
|
105
|
-
const deepEdges =
|
|
106
|
-
['node-comp', 'group-comp', '
|
|
107
|
-
['edge-comp', 'group-comp', '
|
|
108
|
-
['model-view', 'layers', '
|
|
109
|
-
['use-drawings', 'model-view', '
|
|
110
|
-
['model-view', 'node-comp', '
|
|
105
|
+
const deepEdges = graphSpecFromHops([
|
|
106
|
+
['node-comp', 'group-comp', 'calls'],
|
|
107
|
+
['edge-comp', 'group-comp', 'calls'],
|
|
108
|
+
['model-view', 'layers', 'calls'],
|
|
109
|
+
['use-drawings', 'model-view', 'calls'],
|
|
110
|
+
['model-view', 'node-comp', 'calls'],
|
|
111
111
|
]);
|
|
112
112
|
|
|
113
113
|
/** Collapsed module badges show `first/…/last`. Click one to expand the full
|
|
@@ -122,7 +122,6 @@ export const DeepModulePaths: Story = {
|
|
|
122
122
|
'click the badge to expand the full path (the badge widens past the frame edge — the frame itself stays put), click again to collapse it back.'
|
|
123
123
|
}
|
|
124
124
|
components={deepComponents}
|
|
125
|
-
relations={deepEdges.relations}
|
|
126
125
|
walkthroughs={deepEdges.walkthroughs}
|
|
127
126
|
/>
|
|
128
127
|
</div>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import '@xyflow/react/dist/style.css';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
4
|
+
import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
|
|
5
|
+
import type { SubsystemComponent } from '../../../subsystem/model';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Prototype for path-based module nesting: `module` is the file path, and
|
|
9
|
+
* `moduleNesting="path"` derives directory frames from the path segments and
|
|
10
|
+
* nests the module frames inside them.
|
|
11
|
+
*
|
|
12
|
+
* Compare `FilesFlat` (one module frame per file, the current "column") with
|
|
13
|
+
* `FilesByPath` (directory frames interposed) and `FolderModules` (the same
|
|
14
|
+
* model read with folders as modules instead of files).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const meta = {
|
|
18
|
+
title: 'Subsystem/ComponentGraph/Module path nesting',
|
|
19
|
+
component: SubsystemComponentGraph,
|
|
20
|
+
parameters: { layout: 'fullscreen' },
|
|
21
|
+
tags: ['autodocs'],
|
|
22
|
+
decorators: [
|
|
23
|
+
(Story) => (
|
|
24
|
+
<ThemeProvider theme={defaultEditorTheme}>
|
|
25
|
+
<div style={{ width: '100%', height: '100vh' }}>
|
|
26
|
+
<Story />
|
|
27
|
+
</div>
|
|
28
|
+
</ThemeProvider>
|
|
29
|
+
),
|
|
30
|
+
],
|
|
31
|
+
argTypes: {
|
|
32
|
+
moduleNesting: { control: 'inline-radio', options: ['exact', 'path'] },
|
|
33
|
+
},
|
|
34
|
+
} satisfies Meta<typeof SubsystemComponentGraph>;
|
|
35
|
+
|
|
36
|
+
export default meta;
|
|
37
|
+
type Story = StoryObj<typeof meta>;
|
|
38
|
+
|
|
39
|
+
const PURL = 'pkg:github/you/scheduling-app';
|
|
40
|
+
|
|
41
|
+
function fileModules(): SubsystemComponent[] {
|
|
42
|
+
return [
|
|
43
|
+
{ alias: 'booking-page', name: 'BookingPage', construct: 'function', symbol: 'BookingPage', purl: PURL, file: 'app/book/page.tsx', module: 'app/book/page.tsx' },
|
|
44
|
+
{ alias: 'list-open-slots', name: 'listOpenSlots', construct: 'function', symbol: 'listOpenSlots', purl: PURL, file: 'app/book/actions.ts', module: 'app/book/actions.ts' },
|
|
45
|
+
{ alias: 'book-slot', name: 'bookSlot', construct: 'function', symbol: 'bookSlot', purl: PURL, file: 'app/book/actions.ts', module: 'app/book/actions.ts' },
|
|
46
|
+
{ alias: 'cancel-slot', name: 'cancelSlot', construct: 'function', symbol: 'cancelSlot', purl: PURL, file: 'app/book/actions.ts', module: 'app/book/actions.ts' },
|
|
47
|
+
{ alias: 'list-slots', name: 'listSlots', construct: 'function', symbol: 'listSlots', purl: PURL, file: 'lib/listSlots.ts', module: 'lib/listSlots.ts' },
|
|
48
|
+
{ alias: 'create-booking', name: 'createBooking', construct: 'function', symbol: 'createBooking', purl: PURL, file: 'lib/createBooking.ts', module: 'lib/createBooking.ts' },
|
|
49
|
+
{ alias: 'cancel-booking', name: 'cancelBooking', construct: 'function', symbol: 'cancelBooking', purl: PURL, file: 'lib/cancelBooking.ts', module: 'lib/cancelBooking.ts' },
|
|
50
|
+
{ alias: 'capture-event', name: 'captureEvent', construct: 'function', symbol: 'captureEvent', purl: PURL, file: 'lib/captureEvent.ts', module: 'lib/captureEvent.ts' },
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Current behavior: one frame per file path — the "column". */
|
|
55
|
+
export const FilesFlat: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
title: 'File modules (exact)',
|
|
58
|
+
description: 'module = file path, moduleNesting="exact". One frame per file.',
|
|
59
|
+
components: fileModules(),
|
|
60
|
+
moduleNesting: 'exact',
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Path-nested: directory frames wrap the file frames. */
|
|
65
|
+
export const FilesByPath: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
title: 'File modules (path nesting)',
|
|
68
|
+
description:
|
|
69
|
+
'module = file path, moduleNesting="path". `app/book` and `lib` directory frames wrap their file frames.',
|
|
70
|
+
components: fileModules(),
|
|
71
|
+
moduleNesting: 'path',
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/** Deeper hierarchy: src → host/renderer/bun → file frames. */
|
|
76
|
+
const deepComponents: SubsystemComponent[] = [
|
|
77
|
+
{ alias: 'boot', name: 'boot', construct: 'function', symbol: 'boot', purl: 'pkg:github/p/app', file: 'src/host/main.ts', module: 'src/host/main.ts' },
|
|
78
|
+
{ alias: 'create-host', name: 'createHost', construct: 'function', symbol: 'createHost', purl: 'pkg:github/p/app', file: 'src/host/main.ts', module: 'src/host/main.ts' },
|
|
79
|
+
{ alias: 'session-store', name: 'SessionStore', construct: 'store', symbol: 'SessionStore', purl: 'pkg:github/p/app', file: 'src/host/store.ts', module: 'src/host/store.ts' },
|
|
80
|
+
{ alias: 'bridge', name: 'bridge', construct: 'function', symbol: 'bridge', purl: 'pkg:github/p/app', file: 'src/renderer/bridge.ts', module: 'src/renderer/bridge.ts' },
|
|
81
|
+
{ alias: 'trail-view', name: 'TrailView', construct: 'function', symbol: 'TrailView', framework: 'react', stereotype: 'component', purl: 'pkg:github/p/app', file: 'src/renderer/view.tsx', module: 'src/renderer/view.tsx' },
|
|
82
|
+
{ alias: 'audit-store', name: 'auditStore', construct: 'store', symbol: 'auditStore', purl: 'pkg:github/p/app', file: 'src/bun/audit.ts', module: 'src/bun/audit.ts' },
|
|
83
|
+
{ alias: 'audit-run', name: 'runAudit', construct: 'function', symbol: 'runAudit', purl: 'pkg:github/p/app', file: 'src/bun/audit.ts', module: 'src/bun/audit.ts' },
|
|
84
|
+
{ alias: 'registry', name: 'registry', construct: 'store', symbol: 'registry', purl: 'pkg:github/p/app', file: 'src/bun/registry.ts', module: 'src/bun/registry.ts' },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
export const DeepNesting: Story = {
|
|
88
|
+
args: {
|
|
89
|
+
title: 'Deep path nesting',
|
|
90
|
+
description:
|
|
91
|
+
'src → host / renderer / bun → file frames. Directories nest recursively by path segment.',
|
|
92
|
+
components: deepComponents,
|
|
93
|
+
moduleNesting: 'path',
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** Same shape, but `module` is the folder (no per-file frames). */
|
|
98
|
+
const folderComponents: SubsystemComponent[] = [
|
|
99
|
+
{ alias: 'booking-page', name: 'BookingPage', construct: 'function', symbol: 'BookingPage', purl: PURL, file: 'app/book/page.tsx', module: 'app/book' },
|
|
100
|
+
{ alias: 'list-open-slots', name: 'listOpenSlots', construct: 'function', symbol: 'listOpenSlots', purl: PURL, file: 'app/book/actions.ts', module: 'app/book' },
|
|
101
|
+
{ alias: 'book-slot', name: 'bookSlot', construct: 'function', symbol: 'bookSlot', purl: PURL, file: 'app/book/actions.ts', module: 'app/book' },
|
|
102
|
+
{ alias: 'cancel-slot', name: 'cancelSlot', construct: 'function', symbol: 'cancelSlot', purl: PURL, file: 'app/book/actions.ts', module: 'app/book' },
|
|
103
|
+
{ alias: 'list-slots', name: 'listSlots', construct: 'function', symbol: 'listSlots', purl: PURL, file: 'lib/listSlots.ts', module: 'lib' },
|
|
104
|
+
{ alias: 'create-booking', name: 'createBooking', construct: 'function', symbol: 'createBooking', purl: PURL, file: 'lib/createBooking.ts', module: 'lib' },
|
|
105
|
+
{ alias: 'cancel-booking', name: 'cancelBooking', construct: 'function', symbol: 'cancelBooking', purl: PURL, file: 'lib/cancelBooking.ts', module: 'lib' },
|
|
106
|
+
{ alias: 'capture-event', name: 'captureEvent', construct: 'function', symbol: 'captureEvent', purl: PURL, file: 'lib/captureEvent.ts', module: 'lib' },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
export const FolderModules: Story = {
|
|
110
|
+
args: {
|
|
111
|
+
title: 'Folder modules',
|
|
112
|
+
description:
|
|
113
|
+
'module = folder. Two folder frames hold the exports directly — no per-file frames.',
|
|
114
|
+
components: folderComponents,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
@@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
3
3
|
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
4
4
|
import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
|
|
5
5
|
import type { SubsystemComponent } from '../../../subsystem/model';
|
|
6
|
-
import {
|
|
6
|
+
import { graphSpecFromHops } from './fixtures';
|
|
7
7
|
|
|
8
8
|
const meta = {
|
|
9
9
|
title: 'Subsystem/ComponentGraph/Modules',
|
|
@@ -120,10 +120,10 @@ const moduleComponents: SubsystemComponent[] = [
|
|
|
120
120
|
},
|
|
121
121
|
];
|
|
122
122
|
|
|
123
|
-
const moduleEdges =
|
|
124
|
-
['parse', 'record', '
|
|
125
|
-
['is-rollout', 'record', '
|
|
126
|
-
['reader', 'normalize', '
|
|
123
|
+
const moduleEdges = graphSpecFromHops([
|
|
124
|
+
['parse', 'record', 'uses'],
|
|
125
|
+
['is-rollout', 'record', 'uses'],
|
|
126
|
+
['reader', 'normalize', 'calls'],
|
|
127
127
|
['normalize', 'parse', 'calls'],
|
|
128
128
|
['normalize', 'tool-name', 'calls'],
|
|
129
129
|
['normalize', 'file-path', 'calls'],
|
|
@@ -137,7 +137,6 @@ export const ModuleBoundaries: Story = {
|
|
|
137
137
|
title="Module boundaries"
|
|
138
138
|
description="Concrete exports keep their real construct. Shared `module` (the source path) draws the file as a dashed frame — not `construct: module`. Singleton modules (registerAgent) stay unframed."
|
|
139
139
|
components={moduleComponents}
|
|
140
|
-
relations={moduleEdges.relations}
|
|
141
140
|
walkthroughs={moduleEdges.walkthroughs}
|
|
142
141
|
/>
|
|
143
142
|
</div>
|
|
@@ -260,10 +259,10 @@ const nestedComponents: SubsystemComponent[] = [
|
|
|
260
259
|
},
|
|
261
260
|
];
|
|
262
261
|
|
|
263
|
-
const nestedEdges =
|
|
264
|
-
['boot', 'write-session', '
|
|
265
|
-
['trail-view', 'bridge', '
|
|
266
|
-
['trail-view', 'use-trail', '
|
|
262
|
+
const nestedEdges = graphSpecFromHops([
|
|
263
|
+
['boot', 'write-session', 'calls'],
|
|
264
|
+
['trail-view', 'bridge', 'calls'],
|
|
265
|
+
['trail-view', 'use-trail', 'uses'],
|
|
267
266
|
['boot', 'create-host', 'calls'],
|
|
268
267
|
['create-host', 'write-session', 'calls'],
|
|
269
268
|
['write-session', 'session-store', 'writes'],
|
|
@@ -279,7 +278,6 @@ export const ProcessAndModuleNesting: Story = {
|
|
|
279
278
|
title="Process × module nesting"
|
|
280
279
|
description="process frames wrap module frames wrap exports. Leaves parent to module:; module groups parent to process: when every member shares that process."
|
|
281
280
|
components={nestedComponents}
|
|
282
|
-
relations={nestedEdges.relations}
|
|
283
281
|
walkthroughs={nestedEdges.walkthroughs}
|
|
284
282
|
/>
|
|
285
283
|
</div>
|
|
@@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
3
3
|
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
4
4
|
import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
|
|
5
5
|
import type { SubsystemComponent } from '../../../subsystem/model';
|
|
6
|
-
import {
|
|
6
|
+
import { graphSpecFromHops } from './fixtures';
|
|
7
7
|
|
|
8
8
|
const meta = {
|
|
9
9
|
title: 'Subsystem/ComponentGraph/Packages',
|
|
@@ -80,7 +80,7 @@ const multiRepoComponents: SubsystemComponent[] = [
|
|
|
80
80
|
},
|
|
81
81
|
];
|
|
82
82
|
|
|
83
|
-
const multiRepoEdges =
|
|
83
|
+
const multiRepoEdges = graphSpecFromHops([
|
|
84
84
|
['dispatch', 'session', 'calls'],
|
|
85
85
|
['dispatch', 'parse', 'calls'],
|
|
86
86
|
['parse', 'normalize', 'calls'],
|
|
@@ -90,7 +90,6 @@ export const MultiRepoPackageFrames: Story = {
|
|
|
90
90
|
name: 'Multi-repo package frames',
|
|
91
91
|
args: {
|
|
92
92
|
components: multiRepoComponents,
|
|
93
|
-
relations: multiRepoEdges.relations,
|
|
94
93
|
walkthroughs: multiRepoEdges.walkthroughs,
|
|
95
94
|
},
|
|
96
95
|
render: (args) => (
|
|
@@ -107,7 +106,6 @@ export const SingleRepoNoPackageFrames: Story = {
|
|
|
107
106
|
name: 'Single-repo (no package frames)',
|
|
108
107
|
args: {
|
|
109
108
|
components: singleRepo,
|
|
110
|
-
relations: multiRepoEdges.relations,
|
|
111
109
|
walkthroughs: multiRepoEdges.walkthroughs,
|
|
112
110
|
},
|
|
113
111
|
render: (args) => (
|
|
@@ -220,7 +218,7 @@ const nestedComponents: SubsystemComponent[] = [
|
|
|
220
218
|
},
|
|
221
219
|
];
|
|
222
220
|
|
|
223
|
-
const nestedEdges =
|
|
221
|
+
const nestedEdges = graphSpecFromHops([
|
|
224
222
|
['boot', 'dispatch', 'calls'],
|
|
225
223
|
['dispatch', 'session', 'calls'],
|
|
226
224
|
['dispatch', 'parse', 'calls'],
|
|
@@ -231,7 +229,6 @@ export const PackageProcessModuleNesting: Story = {
|
|
|
231
229
|
name: 'Package → process → module nesting',
|
|
232
230
|
args: {
|
|
233
231
|
components: nestedComponents,
|
|
234
|
-
relations: nestedEdges.relations,
|
|
235
232
|
walkthroughs: nestedEdges.walkthroughs,
|
|
236
233
|
},
|
|
237
234
|
render: (args) => (
|
|
@@ -2,7 +2,7 @@ import '@xyflow/react/dist/style.css';
|
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
4
4
|
import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
|
|
5
|
-
import { components,
|
|
5
|
+
import { components, graphSpecFromHops } from './fixtures';
|
|
6
6
|
|
|
7
7
|
const meta = {
|
|
8
8
|
title: 'Subsystem/ComponentGraph/Processes',
|
|
@@ -54,7 +54,7 @@ const processComponents = [
|
|
|
54
54
|
},
|
|
55
55
|
];
|
|
56
56
|
|
|
57
|
-
const processEdges =
|
|
57
|
+
const processEdges = graphSpecFromHops([
|
|
58
58
|
['main', 'store', 'writes'],
|
|
59
59
|
['main', 'bridge', 'calls'],
|
|
60
60
|
['bridge', 'view', 'feeds'],
|
|
@@ -69,7 +69,7 @@ export const ProcessBoundaries: Story = {
|
|
|
69
69
|
title="Process boundaries"
|
|
70
70
|
description="Host and renderer each render in their own ELK-aware boundary frame. The worker process holds a single node and still gets a frame (singleton frames default on). The telemetry service has no `process` and sits outside every boundary."
|
|
71
71
|
components={processComponents}
|
|
72
|
-
|
|
72
|
+
walkthroughs={processEdges.walkthroughs}
|
|
73
73
|
/>
|
|
74
74
|
</div>
|
|
75
75
|
),
|
|
@@ -7,9 +7,9 @@ import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGr
|
|
|
7
7
|
import { SubsystemComponentNode } from '../../../subsystem/nodes';
|
|
8
8
|
import type {
|
|
9
9
|
SubsystemComponent,
|
|
10
|
-
SubsystemComponentEdge,
|
|
11
10
|
SubsystemGraphNode,
|
|
12
11
|
} from '../../../subsystem/model';
|
|
12
|
+
import { walkthroughFromHops } from './fixtures';
|
|
13
13
|
|
|
14
14
|
const meta = {
|
|
15
15
|
title: 'Subsystem/ComponentGraph/Proposed',
|
|
@@ -225,10 +225,12 @@ const migrationComponents: SubsystemComponent[] = [
|
|
|
225
225
|
},
|
|
226
226
|
];
|
|
227
227
|
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
const migrationWalkthroughs = [
|
|
229
|
+
walkthroughFromHops('migration-hops', 'Migration hops', [
|
|
230
|
+
['audit', 'maintain', 'calls', 'src/bun/verify-subsystem-component.ts', 1],
|
|
231
|
+
['maintain', 'lifecycle', 'uses', 'src/bun/maintain-model.ts', 1],
|
|
232
|
+
['lifecycle', 'cli', 'calls', 'src/bun/opencode-v2.ts', 1],
|
|
233
|
+
]),
|
|
232
234
|
];
|
|
233
235
|
|
|
234
236
|
function MigrationDemo() {
|
|
@@ -237,7 +239,7 @@ function MigrationDemo() {
|
|
|
237
239
|
<div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
238
240
|
<SubsystemComponentGraph
|
|
239
241
|
components={migrationComponents}
|
|
240
|
-
|
|
242
|
+
walkthroughs={migrationWalkthroughs}
|
|
241
243
|
onSelect={(id) => setSelected(id)}
|
|
242
244
|
/>
|
|
243
245
|
<div style={{ marginTop: 8, padding: '0 12px', fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
@@ -151,7 +151,6 @@ function ProposedWalkthroughsDemo() {
|
|
|
151
151
|
<div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
152
152
|
<SubsystemComponentGraph
|
|
153
153
|
components={components}
|
|
154
|
-
relations={[]}
|
|
155
154
|
walkthroughs={walkthroughs}
|
|
156
155
|
title="proposed-work marker"
|
|
157
156
|
description="Walkthroughs that touch a **proposed** component get their title tinted darkgoldenrod in the flows panel; expand a row and each hop onto a proposed component is tinted too (index and title). Nodes for proposed components already draw dashed darkgoldenrod on the canvas."
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
SubsystemModelDocument,
|
|
10
10
|
} from '../../../subsystem/model';
|
|
11
11
|
import type { GraphifyComponentDetail } from '../../../graphify';
|
|
12
|
-
import { components,
|
|
12
|
+
import { components, graphSpecFromHops } from './fixtures';
|
|
13
13
|
|
|
14
14
|
const meta = {
|
|
15
15
|
title: 'Subsystem/ComponentGraph/Scenarios',
|
|
@@ -92,11 +92,11 @@ const mermaidComponents: SubsystemComponent[] = [
|
|
|
92
92
|
},
|
|
93
93
|
];
|
|
94
94
|
|
|
95
|
-
const mermaidEdges =
|
|
95
|
+
const mermaidEdges = graphSpecFromHops([
|
|
96
96
|
['input', 'slide', 'feeds'],
|
|
97
97
|
['slide', 'chunk', 'produces'],
|
|
98
98
|
['chunk', 'lazy', 'feeds'],
|
|
99
|
-
['lazy', 'diagram', '
|
|
99
|
+
['lazy', 'diagram', 'uses'],
|
|
100
100
|
['diagram', 'helpers', 'uses'],
|
|
101
101
|
]);
|
|
102
102
|
|
|
@@ -106,7 +106,7 @@ function MermaidDemo() {
|
|
|
106
106
|
<div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
107
107
|
<SubsystemComponentGraph
|
|
108
108
|
components={mermaidComponents}
|
|
109
|
-
|
|
109
|
+
walkthroughs={mermaidEdges.walkthroughs}
|
|
110
110
|
onSelect={(id) => setSelected(id)}
|
|
111
111
|
/>
|
|
112
112
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
@@ -137,10 +137,10 @@ const multiRepoComponents = components([
|
|
|
137
137
|
['rewire', 'extract.py', 'function', 'graphify/extract.py', graphifyPurl, 'corpus pass folding unique-label stubs onto definitions', '_rewire_unique_stub_nodes'],
|
|
138
138
|
]);
|
|
139
139
|
|
|
140
|
-
const multiRepoEdges =
|
|
141
|
-
['detail', 'reftypes', '
|
|
142
|
-
['resolver', 'reftypes', '
|
|
143
|
-
['resolver', 'engine', '
|
|
140
|
+
const multiRepoEdges = graphSpecFromHops([
|
|
141
|
+
['detail', 'reftypes', 'uses'],
|
|
142
|
+
['resolver', 'reftypes', 'uses'],
|
|
143
|
+
['resolver', 'engine', 'calls'],
|
|
144
144
|
['rewire', 'resolver', 'calls'],
|
|
145
145
|
]);
|
|
146
146
|
|
|
@@ -151,7 +151,7 @@ function MultiRepoDemo() {
|
|
|
151
151
|
title="Type-ref resolution across repos"
|
|
152
152
|
description="Two repos → two file trees. Each tree is scoped to its repo's files and headed by the owner avatar + repo name. Cross-repo edges land on external stubs."
|
|
153
153
|
components={multiRepoComponents}
|
|
154
|
-
|
|
154
|
+
walkthroughs={multiRepoEdges.walkthroughs}
|
|
155
155
|
/>
|
|
156
156
|
</div>
|
|
157
157
|
);
|
|
@@ -354,7 +354,7 @@ const accessSurfaceComponents: SubsystemComponent[] = [
|
|
|
354
354
|
},
|
|
355
355
|
];
|
|
356
356
|
|
|
357
|
-
const accessSurfaceEdges =
|
|
357
|
+
const accessSurfaceEdges = graphSpecFromHops([
|
|
358
358
|
['agents', 'http-entry', 'calls'],
|
|
359
359
|
['http-entry', 'create', 'calls'],
|
|
360
360
|
['http-entry', 'update', 'calls'],
|
|
@@ -384,7 +384,7 @@ function AccessSurfacesDemo() {
|
|
|
384
384
|
title="Access surfaces, roles, and process boundaries"
|
|
385
385
|
description="Two process regions (host, renderer) + boundary entries; agents and the external service float outside every boundary. Hover for the role badge; click the store to drill into its state-only detail."
|
|
386
386
|
components={accessSurfaceComponents}
|
|
387
|
-
|
|
387
|
+
walkthroughs={accessSurfaceEdges.walkthroughs}
|
|
388
388
|
onSelect={(id) => setSelected(id)}
|
|
389
389
|
onEdgeSelect={(e) => setSelectedEdge(e)}
|
|
390
390
|
/>
|
|
@@ -534,7 +534,7 @@ const storeFlavorComponents: SubsystemComponent[] = [
|
|
|
534
534
|
},
|
|
535
535
|
];
|
|
536
536
|
|
|
537
|
-
const storeFlavorEdges =
|
|
537
|
+
const storeFlavorEdges = graphSpecFromHops([
|
|
538
538
|
['f1-create', 'f1-store', 'writes'],
|
|
539
539
|
['f1-get', 'f1-store', 'reads'],
|
|
540
540
|
['f2-cache', 'f2-store', 'writes'],
|
|
@@ -549,7 +549,7 @@ function StoreFlavorsDemo() {
|
|
|
549
549
|
title="Store flavors"
|
|
550
550
|
description="construct:= the node's verifiable anchor. Class-managed stores are TWO nodes: the manager class (declaration, methods) + the state (store block). Click any node to see its anchor-honest drill-down."
|
|
551
551
|
components={storeFlavorComponents}
|
|
552
|
-
|
|
552
|
+
walkthroughs={storeFlavorEdges.walkthroughs}
|
|
553
553
|
onSelect={(id) => setSelected(id)}
|
|
554
554
|
/>
|
|
555
555
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
@@ -637,7 +637,7 @@ const sharedStoreComponents: SubsystemComponent[] = [
|
|
|
637
637
|
},
|
|
638
638
|
];
|
|
639
639
|
|
|
640
|
-
const sharedStoreEdges =
|
|
640
|
+
const sharedStoreEdges = graphSpecFromHops([
|
|
641
641
|
['ss-load', 'ss-store', 'reads'],
|
|
642
642
|
['ss-save', 'ss-store', 'writes'],
|
|
643
643
|
['ss-watch', 'ss-store', 'watches'],
|
|
@@ -652,7 +652,7 @@ function SharedStoreDemo() {
|
|
|
652
652
|
title="Shared store across processes"
|
|
653
653
|
description="A store with no process sits outside every boundary; accessors from both processes reach across to it."
|
|
654
654
|
components={sharedStoreComponents}
|
|
655
|
-
|
|
655
|
+
walkthroughs={sharedStoreEdges.walkthroughs}
|
|
656
656
|
onEdgeSelect={(e) => setSelectedEdge(e)}
|
|
657
657
|
/>
|
|
658
658
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
@@ -919,7 +919,7 @@ const storeSpectrumComponents: SubsystemComponent[] = [
|
|
|
919
919
|
},
|
|
920
920
|
];
|
|
921
921
|
|
|
922
|
-
const storeSpectrumEdges =
|
|
922
|
+
const storeSpectrumEdges = graphSpecFromHops([
|
|
923
923
|
['load', 'db', 'reads'],
|
|
924
924
|
['create', 'graph-store', 'writes'],
|
|
925
925
|
['cache', 'cache-state', 'writes'],
|
|
@@ -938,7 +938,7 @@ function StoreStateSpectrumDemo() {
|
|
|
938
938
|
title="State → Store spectrum, all modeled as store"
|
|
939
939
|
description="Every holder here claims construct: 'store' (state-block anatomy). They differ only in what they hold and how long it lives. Which ones do you call a store? Where is the cut?"
|
|
940
940
|
components={storeSpectrumComponents}
|
|
941
|
-
|
|
941
|
+
walkthroughs={storeSpectrumEdges.walkthroughs}
|
|
942
942
|
onSelect={(id) => setSelected(id)}
|
|
943
943
|
/>
|
|
944
944
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
@@ -1114,12 +1114,12 @@ const typeSpectrumComponents: SubsystemComponent[] = [
|
|
|
1114
1114
|
},
|
|
1115
1115
|
];
|
|
1116
1116
|
|
|
1117
|
-
const typeSpectrumEdges =
|
|
1117
|
+
const typeSpectrumEdges = graphSpecFromHops([
|
|
1118
1118
|
['listener', 'subscriber', 'uses'],
|
|
1119
|
-
['subscriber', 'messages', '
|
|
1119
|
+
['subscriber', 'messages', 'uses'],
|
|
1120
1120
|
['state', 'listener', 'feeds'],
|
|
1121
|
-
['deep', 'record', '
|
|
1122
|
-
['rows', 'record', '
|
|
1121
|
+
['deep', 'record', 'uses'],
|
|
1122
|
+
['rows', 'record', 'uses'],
|
|
1123
1123
|
]);
|
|
1124
1124
|
|
|
1125
1125
|
function TypeFamilySpectrumDemo() {
|
|
@@ -1130,7 +1130,7 @@ function TypeFamilySpectrumDemo() {
|
|
|
1130
1130
|
title="Type-family — what a type can hold"
|
|
1131
1131
|
description="Structured buckets: callable signature (generics + params), interface properties, enum members, union, plain alias reference. `rhs` = verbatim escape hatch for shapes that don't fit (mapped/conditional/template-literal). Click each to see the declaration."
|
|
1132
1132
|
components={typeSpectrumComponents}
|
|
1133
|
-
|
|
1133
|
+
walkthroughs={typeSpectrumEdges.walkthroughs}
|
|
1134
1134
|
onSelect={(id) => setSelected(id)}
|
|
1135
1135
|
/>
|
|
1136
1136
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
@@ -1209,7 +1209,7 @@ const queueComponents: SubsystemComponent[] = [
|
|
|
1209
1209
|
},
|
|
1210
1210
|
];
|
|
1211
1211
|
|
|
1212
|
-
const queueEdges =
|
|
1212
|
+
const queueEdges = graphSpecFromHops([
|
|
1213
1213
|
['q-producer', 'q-queue', 'writes'],
|
|
1214
1214
|
['q-worker', 'q-queue', 'reads'],
|
|
1215
1215
|
['q-worker', 'q-results', 'writes'],
|
|
@@ -1223,7 +1223,7 @@ function QueueAsStoreDemo() {
|
|
|
1223
1223
|
title="Queue as store"
|
|
1224
1224
|
description="Ordered retained state. Stores as pipeline stages: producer writes the queue, the worker reads it and writes results."
|
|
1225
1225
|
components={queueComponents}
|
|
1226
|
-
|
|
1226
|
+
walkthroughs={queueEdges.walkthroughs}
|
|
1227
1227
|
onEdgeSelect={(e) => setSelectedEdge(e)}
|
|
1228
1228
|
/>
|
|
1229
1229
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
@@ -1343,7 +1343,6 @@ const dataVizDoc: SubsystemModelDocument = {
|
|
|
1343
1343
|
},
|
|
1344
1344
|
},
|
|
1345
1345
|
],
|
|
1346
|
-
relations: [],
|
|
1347
1346
|
walkthroughs: [
|
|
1348
1347
|
{
|
|
1349
1348
|
id: 'data-viz-hops',
|
|
@@ -1369,8 +1368,8 @@ function DataVsVisualizationDemo() {
|
|
|
1369
1368
|
setText(next);
|
|
1370
1369
|
try {
|
|
1371
1370
|
const parsed = JSON.parse(next) as SubsystemModelDocument;
|
|
1372
|
-
if (!Array.isArray(parsed.components)
|
|
1373
|
-
throw new Error('document needs `components`
|
|
1371
|
+
if (!Array.isArray(parsed.components)) {
|
|
1372
|
+
throw new Error('document needs a `components` array');
|
|
1374
1373
|
}
|
|
1375
1374
|
setDoc(parsed);
|
|
1376
1375
|
setError(null);
|
|
@@ -1431,7 +1430,6 @@ function DataVsVisualizationDemo() {
|
|
|
1431
1430
|
title="the visualization"
|
|
1432
1431
|
description="Same document, rendered: construct:→ node anatomy, role → topology glyph, process → boundary region, mechanism → edge color/style."
|
|
1433
1432
|
components={doc.components}
|
|
1434
|
-
relations={doc.relations}
|
|
1435
1433
|
walkthroughs={doc.walkthroughs}
|
|
1436
1434
|
/>
|
|
1437
1435
|
</div>
|
|
@@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
3
3
|
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
4
4
|
import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
|
|
5
5
|
import type { SubsystemComponent } from '../../../subsystem/model';
|
|
6
|
-
import {
|
|
6
|
+
import { graphSpecFromHops } from './fixtures';
|
|
7
7
|
|
|
8
8
|
const meta = {
|
|
9
9
|
title: 'Subsystem/ComponentGraph/WorkspacePackages',
|
|
@@ -114,7 +114,7 @@ const components: SubsystemComponent[] = [
|
|
|
114
114
|
},
|
|
115
115
|
];
|
|
116
116
|
|
|
117
|
-
const spec =
|
|
117
|
+
const spec = graphSpecFromHops([
|
|
118
118
|
['read-file', 'get-model', 'calls'],
|
|
119
119
|
['model-view', 'component-graph', 'uses'],
|
|
120
120
|
['component-graph', 'file-drawer', 'calls'],
|
|
@@ -125,7 +125,6 @@ export const PackageOwnedProcess: Story = {
|
|
|
125
125
|
name: 'Package-owned process · library outside',
|
|
126
126
|
args: {
|
|
127
127
|
components,
|
|
128
|
-
relations: spec.relations,
|
|
129
128
|
walkthroughs: spec.walkthroughs,
|
|
130
129
|
graphTitle: 'Opening a file — app package owns the process',
|
|
131
130
|
},
|