@principal-ai/subsystems-react 0.21.1 → 0.23.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.
- package/dist/graphify/consolidated.d.ts +5 -24
- package/dist/graphify/consolidated.d.ts.map +1 -1
- package/dist/graphify/index.d.ts +1 -1
- package/dist/graphify/index.d.ts.map +1 -1
- package/dist/graphify/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pierre/PierreFileView.d.ts +3 -1
- package/dist/pierre/PierreFileView.d.ts.map +1 -1
- package/dist/pierre/PierreFileView.js +13 -3
- package/dist/pierre/PierreFileView.js.map +1 -1
- package/dist/pierre/PierreSnippetView.d.ts.map +1 -1
- package/dist/pierre/PierreSnippetView.js +5 -26
- package/dist/pierre/PierreSnippetView.js.map +1 -1
- package/dist/pierre/PierreWalkthroughCodeView.d.ts +3 -1
- package/dist/pierre/PierreWalkthroughCodeView.d.ts.map +1 -1
- package/dist/pierre/PierreWalkthroughCodeView.js +65 -8
- package/dist/pierre/PierreWalkthroughCodeView.js.map +1 -1
- package/dist/pierre/constructColors.d.ts.map +1 -1
- package/dist/pierre/constructColors.js +0 -5
- package/dist/pierre/constructColors.js.map +1 -1
- package/dist/pierre/index.d.ts +1 -1
- package/dist/pierre/index.d.ts.map +1 -1
- package/dist/pierre/index.js +1 -1
- package/dist/pierre/index.js.map +1 -1
- package/dist/pierre/scrollAnchor.d.ts +2 -0
- package/dist/pierre/scrollAnchor.d.ts.map +1 -1
- package/dist/pierre/scrollAnchor.js +7 -0
- package/dist/pierre/scrollAnchor.js.map +1 -1
- package/dist/pierre/sliceSnippet.d.ts +6 -0
- package/dist/pierre/sliceSnippet.d.ts.map +1 -1
- package/dist/pierre/sliceSnippet.js +25 -0
- package/dist/pierre/sliceSnippet.js.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js +0 -4
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
- package/dist/subsystem/FileDrawer.d.ts +7 -2
- package/dist/subsystem/FileDrawer.d.ts.map +1 -1
- package/dist/subsystem/FileDrawer.js +13 -9
- package/dist/subsystem/FileDrawer.js.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.d.ts +2 -0
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +97 -8
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/declarationRef.d.ts +6 -1
- package/dist/subsystem/declarationRef.d.ts.map +1 -1
- package/dist/subsystem/formatDeclaration.d.ts.map +1 -1
- package/dist/subsystem/formatDeclaration.js +0 -15
- package/dist/subsystem/formatDeclaration.js.map +1 -1
- package/dist/subsystem/model.d.ts +61 -22
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +185 -65
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/nodes.d.ts +3 -4
- package/dist/subsystem/nodes.d.ts.map +1 -1
- package/dist/subsystem/nodes.js +5 -6
- package/dist/subsystem/nodes.js.map +1 -1
- package/dist/utils/elkLayout.d.ts +6 -4
- package/dist/utils/elkLayout.d.ts.map +1 -1
- package/dist/utils/elkLayout.js +144 -54
- package/dist/utils/elkLayout.js.map +1 -1
- package/package.json +3 -3
- package/src/graphify/consolidated.ts +4 -26
- package/src/graphify/index.ts +0 -2
- package/src/index.ts +0 -2
- package/src/pierre/PierreFileView.tsx +25 -2
- package/src/pierre/PierreSnippetView.tsx +5 -31
- package/src/pierre/PierreWalkthroughCodeView.tsx +110 -5
- package/src/pierre/constructColors.test.ts +1 -2
- package/src/pierre/constructColors.ts +0 -5
- package/src/pierre/index.ts +1 -1
- package/src/pierre/scrollAnchor.ts +13 -0
- package/src/pierre/sliceSnippet.test.ts +44 -1
- package/src/pierre/sliceSnippet.ts +28 -0
- package/src/stories/Subsystem/ComponentDeclarationAudit.stories.tsx +0 -31
- package/src/stories/Subsystem/ComponentGraph/Appearance.stories.tsx +2 -46
- package/src/stories/Subsystem/ComponentGraph/Captures.stories.tsx +9 -24
- package/src/stories/Subsystem/ComponentGraph/DetailPanel.stories.tsx +2 -2
- package/src/stories/Subsystem/ComponentGraph/Flows.stories.tsx +2 -1
- package/src/stories/Subsystem/ComponentGraph/Modules.stories.tsx +287 -0
- package/src/stories/Subsystem/ComponentGraph/Processes.stories.tsx +1 -1
- package/src/stories/Subsystem/ComponentGraph/Scenarios.stories.tsx +6 -6
- package/src/stories/Subsystem/ComponentGraph/fixtures.ts +0 -4
- package/src/subsystem/FileDrawer.tsx +19 -7
- package/src/subsystem/SubsystemComponentGraph.tsx +153 -7
- package/src/subsystem/declarationRef.ts +6 -1
- package/src/subsystem/formatDeclaration.ts +0 -19
- package/src/subsystem/model.test.ts +190 -9
- package/src/subsystem/model.ts +219 -77
- package/src/subsystem/nodes.tsx +6 -6
- package/src/utils/elkLayout.ts +148 -58
|
@@ -7,7 +7,14 @@
|
|
|
7
7
|
* `PierreSnippetView`).
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
useCallback,
|
|
12
|
+
useEffect,
|
|
13
|
+
useMemo,
|
|
14
|
+
useRef,
|
|
15
|
+
useState,
|
|
16
|
+
type ReactElement,
|
|
17
|
+
} from 'react';
|
|
11
18
|
import {
|
|
12
19
|
CodeView,
|
|
13
20
|
type CodeViewHandle,
|
|
@@ -16,6 +23,7 @@ import {
|
|
|
16
23
|
type DiffLineAnnotation,
|
|
17
24
|
type LineAnnotation,
|
|
18
25
|
} from '@pierre/diffs/react';
|
|
26
|
+
import { Maximize2 } from 'lucide-react';
|
|
19
27
|
|
|
20
28
|
/** Mirrors Pierre's CodeViewLineSelection (not re-exported from the React entry). */
|
|
21
29
|
type CodeViewLineSelection = {
|
|
@@ -32,7 +40,11 @@ import {
|
|
|
32
40
|
pierreLangForPath,
|
|
33
41
|
} from './pierreFileLang';
|
|
34
42
|
import { resolvePierreSyntaxThemeName } from './pierreSyntaxTheme';
|
|
35
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
remapSnippetLineNumbers,
|
|
45
|
+
sliceSnippetWindow,
|
|
46
|
+
type SnippetSlice,
|
|
47
|
+
} from './sliceSnippet';
|
|
36
48
|
|
|
37
49
|
export interface PierreWalkthroughCodeViewProps {
|
|
38
50
|
walkthrough: SubsystemWalkthrough;
|
|
@@ -43,6 +55,8 @@ export interface PierreWalkthroughCodeViewProps {
|
|
|
43
55
|
contextLines?: number;
|
|
44
56
|
/** Override Pierre's container background. */
|
|
45
57
|
background?: string;
|
|
58
|
+
/** Open the step's full source file (header button or double-click snippet body). */
|
|
59
|
+
onOpenFile?: (path: string) => void;
|
|
46
60
|
}
|
|
47
61
|
|
|
48
62
|
type FileLoadState =
|
|
@@ -54,12 +68,54 @@ function stepItemId(walkthroughId: string, index: number): string {
|
|
|
54
68
|
return `${walkthroughId}:${index}`;
|
|
55
69
|
}
|
|
56
70
|
|
|
71
|
+
function OpenFileHeaderButton({
|
|
72
|
+
file,
|
|
73
|
+
onOpenFile,
|
|
74
|
+
}: {
|
|
75
|
+
file: string;
|
|
76
|
+
onOpenFile: (path: string) => void;
|
|
77
|
+
}) {
|
|
78
|
+
const { theme } = useTheme();
|
|
79
|
+
const [hover, setHover] = useState(false);
|
|
80
|
+
return (
|
|
81
|
+
<button
|
|
82
|
+
type="button"
|
|
83
|
+
onClick={(e) => {
|
|
84
|
+
e.stopPropagation();
|
|
85
|
+
onOpenFile(file);
|
|
86
|
+
}}
|
|
87
|
+
onMouseEnter={() => setHover(true)}
|
|
88
|
+
onMouseLeave={() => setHover(false)}
|
|
89
|
+
title={`Open ${file}`}
|
|
90
|
+
aria-label={`Open full file ${file}`}
|
|
91
|
+
style={{
|
|
92
|
+
display: 'inline-flex',
|
|
93
|
+
alignItems: 'center',
|
|
94
|
+
gap: 4,
|
|
95
|
+
padding: '1px 6px',
|
|
96
|
+
border: `1px solid ${theme.colors.border}`,
|
|
97
|
+
borderRadius: 4,
|
|
98
|
+
background: hover ? theme.colors.border : 'transparent',
|
|
99
|
+
color: hover ? theme.colors.text : theme.colors.textSecondary,
|
|
100
|
+
cursor: 'pointer',
|
|
101
|
+
fontFamily: theme.fonts.monospace,
|
|
102
|
+
fontSize: theme.fontSizes[0],
|
|
103
|
+
transition: 'background 120ms ease, color 120ms ease',
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
<Maximize2 size={11} />
|
|
107
|
+
Open file
|
|
108
|
+
</button>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
57
112
|
export function PierreWalkthroughCodeView({
|
|
58
113
|
walkthrough,
|
|
59
114
|
stepIndex,
|
|
60
115
|
readFile,
|
|
61
116
|
contextLines = 8,
|
|
62
117
|
background,
|
|
118
|
+
onOpenFile,
|
|
63
119
|
}: PierreWalkthroughCodeViewProps) {
|
|
64
120
|
const { theme, mode } = useTheme();
|
|
65
121
|
const viewRef = useRef<CodeViewHandle<undefined>>(null);
|
|
@@ -154,6 +210,30 @@ const items = useMemo((): CodeViewItem<WalkthroughStepAnnotation>[] => {
|
|
|
154
210
|
};
|
|
155
211
|
}, [stepIndex, slices, walkthrough.id]);
|
|
156
212
|
|
|
213
|
+
const sliceStartByItemId = useMemo(() => {
|
|
214
|
+
const map = new Map<string, number>();
|
|
215
|
+
for (let i = 0; i < slices.length; i++) {
|
|
216
|
+
map.set(stepItemId(walkthrough.id, i), slices[i]!.sliceStart);
|
|
217
|
+
}
|
|
218
|
+
return map;
|
|
219
|
+
}, [slices, walkthrough.id]);
|
|
220
|
+
|
|
221
|
+
const onPostRender = useCallback(
|
|
222
|
+
(
|
|
223
|
+
node: HTMLElement,
|
|
224
|
+
_instance: unknown,
|
|
225
|
+
_phase: unknown,
|
|
226
|
+
context?: { item?: { id?: string } },
|
|
227
|
+
) => {
|
|
228
|
+
const id = context?.item?.id;
|
|
229
|
+
if (id == null) return;
|
|
230
|
+
const sliceStart = sliceStartByItemId.get(id);
|
|
231
|
+
if (sliceStart == null) return;
|
|
232
|
+
remapSnippetLineNumbers(node, sliceStart);
|
|
233
|
+
},
|
|
234
|
+
[sliceStartByItemId],
|
|
235
|
+
);
|
|
236
|
+
|
|
157
237
|
const renderHeaderPrefix = useMemo(() => {
|
|
158
238
|
return (item: CodeViewItem) => {
|
|
159
239
|
const index = Number.parseInt(item.id.split(':').pop() ?? '', 10);
|
|
@@ -186,17 +266,23 @@ const items = useMemo((): CodeViewItem<WalkthroughStepAnnotation>[] => {
|
|
|
186
266
|
return (
|
|
187
267
|
<span
|
|
188
268
|
style={{
|
|
269
|
+
display: 'inline-flex',
|
|
270
|
+
alignItems: 'center',
|
|
271
|
+
gap: 6,
|
|
272
|
+
marginLeft: 8,
|
|
189
273
|
fontFamily: theme.fonts.monospace,
|
|
190
274
|
fontSize: theme.fontSizes[0],
|
|
191
275
|
color: theme.colors.textSecondary,
|
|
192
|
-
marginLeft: 8,
|
|
193
276
|
}}
|
|
194
277
|
>
|
|
195
278
|
L{step.line}
|
|
279
|
+
{onOpenFile && (
|
|
280
|
+
<OpenFileHeaderButton file={step.file} onOpenFile={onOpenFile} />
|
|
281
|
+
)}
|
|
196
282
|
</span>
|
|
197
283
|
);
|
|
198
284
|
};
|
|
199
|
-
}, [walkthrough.steps, theme]);
|
|
285
|
+
}, [walkthrough.steps, theme, onOpenFile]);
|
|
200
286
|
|
|
201
287
|
const renderAnnotation = useMemo(() => {
|
|
202
288
|
return (
|
|
@@ -226,6 +312,23 @@ const items = useMemo((): CodeViewItem<WalkthroughStepAnnotation>[] => {
|
|
|
226
312
|
};
|
|
227
313
|
}, [walkthrough.steps, theme]);
|
|
228
314
|
|
|
315
|
+
const onLineClick = useCallback(
|
|
316
|
+
(
|
|
317
|
+
props: { event?: { detail?: number } },
|
|
318
|
+
context?: { item?: { id?: string } },
|
|
319
|
+
) => {
|
|
320
|
+
if (!onOpenFile) return;
|
|
321
|
+
if (props.event?.detail !== 2) return;
|
|
322
|
+
const id = context?.item?.id;
|
|
323
|
+
if (id == null) return;
|
|
324
|
+
const index = Number.parseInt(id.split(':').pop() ?? '', 10);
|
|
325
|
+
const step = walkthrough.steps[index];
|
|
326
|
+
if (!step) return;
|
|
327
|
+
onOpenFile(step.file);
|
|
328
|
+
},
|
|
329
|
+
[onOpenFile, walkthrough.steps],
|
|
330
|
+
);
|
|
331
|
+
|
|
229
332
|
const options = useMemo((): CodeViewReactOptions => {
|
|
230
333
|
return {
|
|
231
334
|
theme: {
|
|
@@ -235,10 +338,12 @@ const items = useMemo((): CodeViewItem<WalkthroughStepAnnotation>[] => {
|
|
|
235
338
|
stickyHeaders: true,
|
|
236
339
|
disableFileHeader: false,
|
|
237
340
|
layout: { paddingTop: 8, paddingBottom: 16, gap: 12 },
|
|
341
|
+
onPostRender,
|
|
342
|
+
...(onOpenFile ? { onLineClick } : {}),
|
|
238
343
|
...(background ? buildPierreOptions(background) : {}),
|
|
239
344
|
...(mode === 'light' || mode === 'dark' ? { themeType: mode } : {}),
|
|
240
345
|
};
|
|
241
|
-
}, [background, mode]);
|
|
346
|
+
}, [background, mode, onPostRender, onOpenFile, onLineClick]);
|
|
242
347
|
|
|
243
348
|
useEffect(() => {
|
|
244
349
|
if (load.status !== 'ready' || stepIndex == null) return;
|
|
@@ -13,7 +13,6 @@ const CONSTRUCTS: SubsystemComponentConstruct[] = [
|
|
|
13
13
|
'interface',
|
|
14
14
|
'type_alias',
|
|
15
15
|
'enum',
|
|
16
|
-
'module',
|
|
17
16
|
'store',
|
|
18
17
|
'external',
|
|
19
18
|
'custom_entity',
|
|
@@ -31,7 +30,7 @@ describe('constructColorsFromPierreTheme', () => {
|
|
|
31
30
|
}
|
|
32
31
|
});
|
|
33
32
|
|
|
34
|
-
test('all
|
|
33
|
+
test('all nine constructs are distinguishable within a theme', () => {
|
|
35
34
|
for (const themeName of ['pierre-dark', 'pierre-light'] as const) {
|
|
36
35
|
const colors = constructColorsFromPierreTheme(themeName);
|
|
37
36
|
const values = CONSTRUCTS.map((c) => colors[c]);
|
|
@@ -89,7 +89,6 @@ export function constructColorsFromPierreTheme(
|
|
|
89
89
|
const classColor = pick('entity.name.class');
|
|
90
90
|
const functionColor = pick('entity.name.function');
|
|
91
91
|
const typeColor = pick('support.type');
|
|
92
|
-
const moduleColor = pick('entity.name.namespace');
|
|
93
92
|
|
|
94
93
|
return {
|
|
95
94
|
class: classColor,
|
|
@@ -101,10 +100,6 @@ export function constructColorsFromPierreTheme(
|
|
|
101
100
|
method: towardBackground(functionColor, 0.14),
|
|
102
101
|
// enum members are constants — the generic constant hue
|
|
103
102
|
enum: pick('constant'),
|
|
104
|
-
// module and store share the constant hue — the module holds the store,
|
|
105
|
-
// and the store IS the retained value, so the store keeps the pure
|
|
106
|
-
// `variable.other.constant` color and the module takes the shade
|
|
107
|
-
module: towardBackground(moduleColor, 0.18),
|
|
108
103
|
store: pick('variable.other.constant'),
|
|
109
104
|
external: pick('comment'),
|
|
110
105
|
// custom entities are actors, not code — the heading/emphasis coral reads
|
package/src/pierre/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { PierreSnippetView } from './PierreSnippetView';
|
|
|
4
4
|
export type { PierreSnippetViewProps } from './PierreSnippetView';
|
|
5
5
|
export { PierreWalkthroughCodeView } from './PierreWalkthroughCodeView';
|
|
6
6
|
export type { PierreWalkthroughCodeViewProps } from './PierreWalkthroughCodeView';
|
|
7
|
-
export { sliceSnippetWindow } from './sliceSnippet';
|
|
7
|
+
export { remapSnippetLineNumbers, sliceSnippetWindow } from './sliceSnippet';
|
|
8
8
|
export type { SnippetSlice } from './sliceSnippet';
|
|
9
9
|
export {
|
|
10
10
|
isPierreCFamilyPath,
|
|
@@ -9,3 +9,16 @@ export function scrollAnchorLine(
|
|
|
9
9
|
if (focusOffset <= 1) return 1;
|
|
10
10
|
return Math.max(1, focusOffset - leadingLines);
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
/** Scroll a Pierre file container so `focusLine` (1-based) sits near the top. */
|
|
14
|
+
export function scrollFocusLineIntoView(
|
|
15
|
+
fileContainer: HTMLElement,
|
|
16
|
+
focusLine: number,
|
|
17
|
+
): void {
|
|
18
|
+
const root = fileContainer.shadowRoot ?? fileContainer;
|
|
19
|
+
const anchorLine = scrollAnchorLine(focusLine);
|
|
20
|
+
const lineEl = root.querySelector(
|
|
21
|
+
`[data-line="${anchorLine}"]`,
|
|
22
|
+
) as HTMLElement | null;
|
|
23
|
+
lineEl?.scrollIntoView({ block: 'start', behavior: 'auto' });
|
|
24
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
import {
|
|
2
|
+
import { Window } from 'happy-dom';
|
|
3
|
+
import { remapSnippetLineNumbers, sliceSnippetWindow } from './sliceSnippet';
|
|
3
4
|
|
|
4
5
|
describe('sliceSnippetWindow', () => {
|
|
5
6
|
const content = ['line1', 'line2', 'line3', 'line4', 'line5'].join('\n');
|
|
@@ -19,3 +20,45 @@ describe('sliceSnippetWindow', () => {
|
|
|
19
20
|
expect(s.focusOffset).toBe(95);
|
|
20
21
|
});
|
|
21
22
|
});
|
|
23
|
+
|
|
24
|
+
describe('remapSnippetLineNumbers', () => {
|
|
25
|
+
function gutter(doc: Document, lineIndex: number, label: string): HTMLElement {
|
|
26
|
+
const el = doc.createElement('div');
|
|
27
|
+
el.setAttribute('data-column-number', '');
|
|
28
|
+
el.dataset.lineIndex = String(lineIndex);
|
|
29
|
+
const span = doc.createElement('span');
|
|
30
|
+
span.setAttribute('data-line-number-content', '');
|
|
31
|
+
span.textContent = label;
|
|
32
|
+
el.appendChild(span);
|
|
33
|
+
return el;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
test('rewrites gutters to absolute file lines', () => {
|
|
37
|
+
const win = new Window();
|
|
38
|
+
const doc = win.document;
|
|
39
|
+
const root = doc.createElement('div');
|
|
40
|
+
root.appendChild(gutter(doc, 0, '1'));
|
|
41
|
+
root.appendChild(gutter(doc, 1, '2'));
|
|
42
|
+
root.appendChild(gutter(doc, 2, '3'));
|
|
43
|
+
|
|
44
|
+
remapSnippetLineNumbers(root as unknown as HTMLElement, 250);
|
|
45
|
+
|
|
46
|
+
const labels = [...root.querySelectorAll('[data-line-number-content]')].map(
|
|
47
|
+
(n) => n.textContent,
|
|
48
|
+
);
|
|
49
|
+
expect(labels).toEqual(['250', '251', '252']);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('no-ops when slice already starts at line 1', () => {
|
|
53
|
+
const win = new Window();
|
|
54
|
+
const doc = win.document;
|
|
55
|
+
const root = doc.createElement('div');
|
|
56
|
+
root.appendChild(gutter(doc, 0, '1'));
|
|
57
|
+
|
|
58
|
+
remapSnippetLineNumbers(root as unknown as HTMLElement, 1);
|
|
59
|
+
|
|
60
|
+
expect(
|
|
61
|
+
root.querySelector('[data-line-number-content]')?.textContent,
|
|
62
|
+
).toBe('1');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -29,3 +29,31 @@ export function sliceSnippetWindow(
|
|
|
29
29
|
focusLine == null ? null : Math.max(1, focusLine - sliceStart + 1),
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Remap Pierre gutter numbers from slice-local (1-based) to absolute file lines.
|
|
35
|
+
* Pierre numbers whatever `contents` it receives starting at 1; sliced snippets
|
|
36
|
+
* need `sliceStart` applied so the gutter matches the source file.
|
|
37
|
+
*/
|
|
38
|
+
export function remapSnippetLineNumbers(
|
|
39
|
+
fileContainer: HTMLElement,
|
|
40
|
+
sliceStart: number,
|
|
41
|
+
): void {
|
|
42
|
+
const lineNumberOffset = sliceStart - 1;
|
|
43
|
+
if (lineNumberOffset === 0) return;
|
|
44
|
+
const root = fileContainer.shadowRoot ?? fileContainer;
|
|
45
|
+
const items = root.querySelectorAll(
|
|
46
|
+
'[data-column-number][data-line-index]',
|
|
47
|
+
);
|
|
48
|
+
items.forEach((el) => {
|
|
49
|
+
const idxStr = (el as HTMLElement).dataset.lineIndex;
|
|
50
|
+
if (idxStr == null) return;
|
|
51
|
+
const idx = Number.parseInt(idxStr, 10);
|
|
52
|
+
if (Number.isNaN(idx)) return;
|
|
53
|
+
const display = String(idx + 1 + lineNumberOffset);
|
|
54
|
+
const span = el.querySelector('[data-line-number-content]');
|
|
55
|
+
if (span && span.textContent !== display) {
|
|
56
|
+
span.textContent = display;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -197,37 +197,6 @@ const cases: { label: string; component: SubsystemComponent }[] = [
|
|
|
197
197
|
} satisfies GraphifyComponentDetail,
|
|
198
198
|
},
|
|
199
199
|
},
|
|
200
|
-
{
|
|
201
|
-
label: 'module — imports + exports',
|
|
202
|
-
component: {
|
|
203
|
-
id: 'mod-full',
|
|
204
|
-
name: 'index',
|
|
205
|
-
construct: 'module',
|
|
206
|
-
file: 'src/index.ts',
|
|
207
|
-
purl: 'pkg:github/principal-ai/agent-monitoring',
|
|
208
|
-
symbol: 'index',
|
|
209
|
-
declaration: {
|
|
210
|
-
kind: 'module',
|
|
211
|
-
imports: [
|
|
212
|
-
{ name: './session/SessionReader' },
|
|
213
|
-
{ name: './event-processing/EventProcessor' },
|
|
214
|
-
],
|
|
215
|
-
exports: ['SessionReader', 'EventProcessor'],
|
|
216
|
-
symbols: ['SessionReader', 'EventProcessor', 'normalizeSession'],
|
|
217
|
-
} satisfies GraphifyComponentDetail,
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
label: 'module — no detail (fallback)',
|
|
222
|
-
component: {
|
|
223
|
-
id: 'mod-plain',
|
|
224
|
-
name: 'utils',
|
|
225
|
-
construct: 'module',
|
|
226
|
-
file: 'src/utils.ts',
|
|
227
|
-
purl: 'pkg:github/principal-ai/agent-monitoring',
|
|
228
|
-
symbol: 'utils',
|
|
229
|
-
},
|
|
230
|
-
},
|
|
231
200
|
{
|
|
232
201
|
label: 'external',
|
|
233
202
|
component: {
|
|
@@ -109,7 +109,7 @@ export const NamingConventions: Story = {
|
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
// ---------------------------------------------------------------------------
|
|
112
|
-
// Kind variations — one column per kind (class / function / type /
|
|
112
|
+
// Kind variations — one column per kind (class / function / type / external —
|
|
113
113
|
// external), rows going bare → detailed. Click a node to see its declaration
|
|
114
114
|
// panel; type names inside it are clickable when they match another node here.
|
|
115
115
|
// ---------------------------------------------------------------------------
|
|
@@ -269,50 +269,6 @@ const kindVariationComponents: SubsystemComponent[] = [
|
|
|
269
269
|
} satisfies GraphifyComponentDetail,
|
|
270
270
|
},
|
|
271
271
|
|
|
272
|
-
// --- module: bare → exports only → exports + imports
|
|
273
|
-
{
|
|
274
|
-
id: 'mod-bare',
|
|
275
|
-
name: 'transcript',
|
|
276
|
-
construct: 'module',
|
|
277
|
-
file: 'src/session/transcript.ts',
|
|
278
|
-
purl: variationPurl,
|
|
279
|
-
purpose: 'no drill-down — symbol-less module named from its file basename',
|
|
280
|
-
symbol: '',
|
|
281
|
-
layer: 4,
|
|
282
|
-
},
|
|
283
|
-
{
|
|
284
|
-
id: 'mod-exports',
|
|
285
|
-
name: 'paths',
|
|
286
|
-
construct: 'module',
|
|
287
|
-
file: 'src/session/paths.ts',
|
|
288
|
-
purl: variationPurl,
|
|
289
|
-
purpose: 'exports only — export statement + defines comment',
|
|
290
|
-
symbol: '',
|
|
291
|
-
layer: 4,
|
|
292
|
-
declaration: {
|
|
293
|
-
kind: 'module',
|
|
294
|
-
exports: ['extractToolName', 'extractFilePath'],
|
|
295
|
-
imports: [],
|
|
296
|
-
symbols: ['extractToolName', 'extractFilePath'],
|
|
297
|
-
} satisfies GraphifyComponentDetail,
|
|
298
|
-
},
|
|
299
|
-
{
|
|
300
|
-
id: 'mod-full',
|
|
301
|
-
name: 'index',
|
|
302
|
-
construct: 'module',
|
|
303
|
-
file: 'src/index.ts',
|
|
304
|
-
purl: variationPurl,
|
|
305
|
-
purpose: 'full — import statements + re-export statement + defines comment',
|
|
306
|
-
symbol: '',
|
|
307
|
-
layer: 4,
|
|
308
|
-
declaration: {
|
|
309
|
-
kind: 'module',
|
|
310
|
-
exports: ['SessionReader', 'SessionStore'],
|
|
311
|
-
imports: [{ nodeId: 'i1', name: 'transcript', relation: 'imports_from' }],
|
|
312
|
-
symbols: ['SessionReader', 'SessionStore'],
|
|
313
|
-
} satisfies GraphifyComponentDetail,
|
|
314
|
-
},
|
|
315
|
-
|
|
316
272
|
// --- external: bare → labeled
|
|
317
273
|
{
|
|
318
274
|
id: 'ext-bare',
|
|
@@ -351,7 +307,7 @@ function KindVariationsDemo() {
|
|
|
351
307
|
onSelect={(id) => setSelected(id)}
|
|
352
308
|
/>
|
|
353
309
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
354
|
-
columns: class · function · type ·
|
|
310
|
+
columns: class · function · type · external — each goes bare → detailed
|
|
355
311
|
{selected ? ` · selected: ${selected}` : ''}
|
|
356
312
|
</div>
|
|
357
313
|
</div>
|
|
@@ -31,10 +31,10 @@ type Story = StoryObj<typeof meta>;
|
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
32
32
|
const v2ReaderComponents = components([
|
|
33
33
|
['capture', 'capture script', 'function', 'scripts/capture-session.ts', 'pkg:github/principal-ai/agent-monitoring', 'captures a real session for fixtures'],
|
|
34
|
-
['transcript', 'transcript', '
|
|
35
|
-
['paths', 'paths', '
|
|
34
|
+
['transcript', 'transcript', 'function', 'transcript.ts', 'pkg:github/principal-ai/agent-monitoring', 'parses session records + type guards'],
|
|
35
|
+
['paths', 'paths', 'function', 'paths.ts', 'pkg:github/principal-ai/agent-monitoring', 'extracts tool names + file paths'],
|
|
36
36
|
['reader', 'SessionReader', 'class', 'SessionReader.ts', 'pkg:github/principal-ai/agent-monitoring', 'normalizes a session into universal events', 'SessionReader.normalize', readerDetail],
|
|
37
|
-
['registry', 'supported-agents', '
|
|
37
|
+
['registry', 'supported-agents', 'function', 'supported-agents.ts', 'pkg:github/principal-ai/agent-monitoring', 'registry of supported agents (the shared seam)', 'registerAgent'],
|
|
38
38
|
]);
|
|
39
39
|
|
|
40
40
|
const v2ReaderEdges = graphSpecFromEdges([
|
|
@@ -95,11 +95,11 @@ const minimalComponents = components([
|
|
|
95
95
|
['reader', 'SessionReader', 'class', 'SessionReader.ts', 'pkg:github/principal-ai/agent-monitoring', 'normalizes a session into universal events', 'SessionReader'],
|
|
96
96
|
['normalize', 'normalize', 'function', 'SessionReader.ts', 'pkg:github/principal-ai/agent-monitoring', 'maps a session into universal events', 'SessionReader.normalize'],
|
|
97
97
|
['record', 'SessionRecord', 'type', 'transcript.ts', 'pkg:github/principal-ai/agent-monitoring', 'the parsed codex session record', 'SessionRecord'],
|
|
98
|
-
['transcript', 'transcript', '
|
|
98
|
+
['transcript', 'transcript', 'function', 'transcript.ts', 'pkg:github/principal-ai/agent-monitoring', 'parses session records + type guards', 'transcript'],
|
|
99
99
|
]);
|
|
100
100
|
|
|
101
101
|
const sharedEdges = graphSpecFromEdges([
|
|
102
|
-
['transcript', 'record', '
|
|
102
|
+
['transcript', 'record', 'references'],
|
|
103
103
|
['reader', 'normalize', 'method'],
|
|
104
104
|
['normalize', 'record', 'references'],
|
|
105
105
|
]);
|
|
@@ -129,15 +129,6 @@ const resolvedComponents: SubsystemComponent[] = [
|
|
|
129
129
|
implementors: ['SessionReaderLike'],
|
|
130
130
|
} satisfies GraphifyComponentDetail,
|
|
131
131
|
},
|
|
132
|
-
{
|
|
133
|
-
...minimalComponents[3],
|
|
134
|
-
declaration: {
|
|
135
|
-
kind: 'module',
|
|
136
|
-
exports: ['CodexRolloutRecord', 'CodexSessionMeta'],
|
|
137
|
-
imports: [{ nodeId: 'i1', name: 'paths', relation: 'imports_from' }],
|
|
138
|
-
symbols: ['CodexRolloutRecord', 'CodexSessionMeta'],
|
|
139
|
-
} satisfies GraphifyComponentDetail,
|
|
140
|
-
},
|
|
141
132
|
];
|
|
142
133
|
|
|
143
134
|
function MinimalVsResolvedDemo({ resolved }: { resolved: boolean }) {
|
|
@@ -174,22 +165,16 @@ const investigationComponents: SubsystemComponent[] = [
|
|
|
174
165
|
{
|
|
175
166
|
id: 'adapter',
|
|
176
167
|
name: 'OpenCodeAdapter',
|
|
177
|
-
construct: '
|
|
168
|
+
construct: 'function',
|
|
178
169
|
file: 'apps/server/src/provider/Layers/OpenCodeAdapter.ts',
|
|
179
170
|
purl: 'pkg:github/t3code/t3code',
|
|
180
171
|
purpose: 'adapts opencode session/threads + events to the t3 runtime',
|
|
181
172
|
symbol: 'makeOpenCodeAdapter',
|
|
182
|
-
declaration: {
|
|
183
|
-
kind: 'module',
|
|
184
|
-
exports: ['makeOpenCodeAdapter', 'OpenCodeAdapterLiveOptions'],
|
|
185
|
-
imports: [{ nodeId: 'i1', name: 'orchestration', relation: 'imports_from' }],
|
|
186
|
-
symbols: ['makeOpenCodeAdapter', 'isOpenCodeNotFound', 'OpenCodeSessionContext'],
|
|
187
|
-
} satisfies GraphifyComponentDetail,
|
|
188
173
|
},
|
|
189
174
|
{
|
|
190
175
|
id: 'ingestion',
|
|
191
176
|
name: 'ProviderRuntimeIngestion',
|
|
192
|
-
construct: '
|
|
177
|
+
construct: 'function',
|
|
193
178
|
file: 'apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts',
|
|
194
179
|
purl: 'pkg:github/t3code/t3code',
|
|
195
180
|
purpose: 'ingests provider events into the runtime',
|
|
@@ -198,7 +183,7 @@ const investigationComponents: SubsystemComponent[] = [
|
|
|
198
183
|
{
|
|
199
184
|
id: 'contracts',
|
|
200
185
|
name: 'orchestration',
|
|
201
|
-
construct: '
|
|
186
|
+
construct: 'function',
|
|
202
187
|
file: 'packages/contracts/src/orchestration.ts',
|
|
203
188
|
purl: 'pkg:github/t3code/t3code',
|
|
204
189
|
purpose: 'contracts for orchestration/providers',
|
|
@@ -207,7 +192,7 @@ const investigationComponents: SubsystemComponent[] = [
|
|
|
207
192
|
];
|
|
208
193
|
|
|
209
194
|
const investigationEdges = graphSpecFromEdges([
|
|
210
|
-
['adapter', 'contracts', '
|
|
195
|
+
['adapter', 'contracts', 'imports'],
|
|
211
196
|
['ingestion', 'adapter', 'uses'],
|
|
212
197
|
['ingestion', 'contracts', 'references'],
|
|
213
198
|
]);
|
|
@@ -234,7 +234,7 @@ const declarationOpenComponents: SubsystemComponent[] = [
|
|
|
234
234
|
{
|
|
235
235
|
id: 'detail',
|
|
236
236
|
name: 'ComponentDeclaration',
|
|
237
|
-
construct: '
|
|
237
|
+
construct: 'function',
|
|
238
238
|
file: 'packages/subsystems-react/src/subsystem/ComponentDeclaration.tsx',
|
|
239
239
|
purl: 'pkg:github/principal-ai/principal-view-core-library',
|
|
240
240
|
purpose: 'declaration panel — click file or L251 to open the drawer at the export line',
|
|
@@ -249,7 +249,7 @@ const declarationOpenComponents: SubsystemComponent[] = [
|
|
|
249
249
|
{
|
|
250
250
|
id: 'resolver',
|
|
251
251
|
name: 'resolve.ts',
|
|
252
|
-
construct: '
|
|
252
|
+
construct: 'function',
|
|
253
253
|
file: 'packages/subsystems-react/src/graphify/resolve.ts',
|
|
254
254
|
purl: 'pkg:github/principal-ai/principal-view-core-library',
|
|
255
255
|
purpose: 'graphify type-ref resolver (second file for tree navigation)',
|
|
@@ -159,12 +159,13 @@ const drawingWalkthroughs: SubsystemWalkthrough[] = [
|
|
|
159
159
|
|
|
160
160
|
function FlowsDemo() {
|
|
161
161
|
const renderWalkthroughViewer = useCallback(
|
|
162
|
-
({ walkthrough, stepIndex }: WalkthroughViewerContext) => (
|
|
162
|
+
({ walkthrough, stepIndex, onOpenFile }: WalkthroughViewerContext) => (
|
|
163
163
|
<PierreWalkthroughCodeView
|
|
164
164
|
walkthrough={walkthrough}
|
|
165
165
|
stepIndex={stepIndex}
|
|
166
166
|
readFile={readStoryFile}
|
|
167
167
|
contextLines={4}
|
|
168
|
+
onOpenFile={onOpenFile}
|
|
168
169
|
/>
|
|
169
170
|
),
|
|
170
171
|
[],
|