@principal-ai/principal-view-react 0.16.35 → 0.16.37
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 +17 -3
- package/dist/graphify/consolidated.d.ts.map +1 -1
- package/dist/graphify/index.d.ts +2 -0
- package/dist/graphify/index.d.ts.map +1 -1
- package/dist/graphify/index.js +1 -1
- package/dist/graphify/index.js.map +1 -1
- package/dist/graphify/resolve.d.ts +48 -0
- package/dist/graphify/resolve.d.ts.map +1 -0
- package/dist/graphify/resolve.js +83 -0
- package/dist/graphify/resolve.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/subsystem/ComponentDetail.d.ts +16 -7
- package/dist/subsystem/ComponentDetail.d.ts.map +1 -1
- package/dist/subsystem/ComponentDetail.js +124 -82
- package/dist/subsystem/ComponentDetail.js.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +47 -10
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/model.d.ts +14 -0
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +26 -1
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/paths.d.ts +38 -0
- package/dist/subsystem/paths.d.ts.map +1 -0
- package/dist/subsystem/paths.js +52 -0
- package/dist/subsystem/paths.js.map +1 -0
- package/package.json +1 -1
- package/src/graphify/consolidated.ts +17 -3
- package/src/graphify/index.ts +9 -0
- package/src/graphify/resolve.test.ts +89 -0
- package/src/graphify/resolve.ts +115 -0
- package/src/index.ts +19 -0
- package/src/stories/SubsystemComponentGraph.stories.tsx +331 -11
- package/src/subsystem/ComponentDetail.tsx +355 -156
- package/src/subsystem/SubsystemComponentGraph.tsx +76 -15
- package/src/subsystem/model.test.ts +11 -0
- package/src/subsystem/model.ts +25 -1
- package/src/subsystem/paths.test.ts +62 -0
- package/src/subsystem/paths.ts +69 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve graphify type-name references to their defining nodes.
|
|
3
|
+
*
|
|
4
|
+
* A `references` edge (`parameter_type`, `return_type`, `field`,
|
|
5
|
+
* `generic_arg`) targets either the type's real definition node or a
|
|
6
|
+
* *sourceless stub* graphify left behind when the name could not be uniquely
|
|
7
|
+
* resolved at extraction time (mirrors `_rewire_unique_stub_nodes` there:
|
|
8
|
+
* ambiguous same-label definitions and never-defined names stay stubs).
|
|
9
|
+
*
|
|
10
|
+
* This module applies the same conservative matching from the consumer side so
|
|
11
|
+
* UI click targets can distinguish "jump to definition" from "N candidates"
|
|
12
|
+
* from "not in this corpus".
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { GraphifyNode } from './types';
|
|
16
|
+
import type { GraphifyReferenceInfo } from './consolidated';
|
|
17
|
+
|
|
18
|
+
/** Outcome of resolving one type reference. */
|
|
19
|
+
export type GraphifyTypeRefStatus =
|
|
20
|
+
/** Target node is a real definition — jump to its `source_file`. */
|
|
21
|
+
| 'resolved'
|
|
22
|
+
/** Target was a stub and multiple same-label definitions exist. */
|
|
23
|
+
| 'ambiguous'
|
|
24
|
+
/** Target was a stub and nothing in the corpus defines the name. */
|
|
25
|
+
| 'unresolved'
|
|
26
|
+
/** No nodeId on the ref, or the id is not in the graph. */
|
|
27
|
+
| 'missing';
|
|
28
|
+
|
|
29
|
+
export interface GraphifyTypeRefResolution {
|
|
30
|
+
status: GraphifyTypeRefStatus;
|
|
31
|
+
/** The definition node when resolved; the stub itself otherwise. */
|
|
32
|
+
node: GraphifyNode | null;
|
|
33
|
+
/** Same-label definitions when the target was an unresolved stub. */
|
|
34
|
+
candidates: GraphifyNode[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Mirror graphify's `normalise_callable_label`: trim, strip surrounding
|
|
39
|
+
* parens/leading dots, lowercase. `SessionReader()` and `sessionreader`
|
|
40
|
+
* collapse to the same key.
|
|
41
|
+
*/
|
|
42
|
+
export function normalizeGraphifyLabel(label: string): string {
|
|
43
|
+
return label
|
|
44
|
+
.trim()
|
|
45
|
+
.replace(/^[()]+|[()]+$/g, '')
|
|
46
|
+
.replace(/^\.+/, '')
|
|
47
|
+
.toLowerCase();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const FILE_SUFFIX_RE =
|
|
51
|
+
/\.(py|js|jsx|ts|tsx|mjs|cjs|java|go|rs|rb|php|cs|cpp|cc|c|h|hpp|pas|pp|dpr|swift|kt|scala|dart|lua|pl|pm|ex|exs|zig|vue|svelte)$/i;
|
|
52
|
+
|
|
53
|
+
function isDefinition(node: GraphifyNode): boolean {
|
|
54
|
+
if (node.file_type !== 'code') return false;
|
|
55
|
+
const file = typeof node.source_file === 'string' ? node.source_file : '';
|
|
56
|
+
if (!file) return false;
|
|
57
|
+
const label = typeof node.label === 'string' ? node.label.trim() : '';
|
|
58
|
+
return !!label && !FILE_SUFFIX_RE.test(label);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Prebuilt lookup state — build once per graph, resolve many refs. */
|
|
62
|
+
export interface GraphifyTypeResolver {
|
|
63
|
+
resolve(nodeId: string | undefined, fallbackLabel?: string): GraphifyTypeRefResolution;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function createGraphifyTypeResolver(nodes: readonly GraphifyNode[]): GraphifyTypeResolver {
|
|
67
|
+
const byId = new Map<string, GraphifyNode>();
|
|
68
|
+
const defsByExactLabel = new Map<string, GraphifyNode[]>();
|
|
69
|
+
const defsByFoldedLabel = new Map<string, GraphifyNode[]>();
|
|
70
|
+
|
|
71
|
+
for (const node of nodes) {
|
|
72
|
+
byId.set(String(node.id), node);
|
|
73
|
+
if (!isDefinition(node)) continue;
|
|
74
|
+
const label = String(node.label).trim();
|
|
75
|
+
(defsByExactLabel.get(label) ?? defsByExactLabel.set(label, []).get(label)!).push(node);
|
|
76
|
+
const folded = normalizeGraphifyLabel(label);
|
|
77
|
+
if (!folded) continue;
|
|
78
|
+
(defsByFoldedLabel.get(folded) ?? defsByFoldedLabel.set(folded, []).get(folded)!).push(node);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function resolve(nodeId: string | undefined, fallbackLabel?: string): GraphifyTypeRefResolution {
|
|
82
|
+
if (!nodeId) return { status: 'missing', node: null, candidates: [] };
|
|
83
|
+
const target = byId.get(nodeId);
|
|
84
|
+
if (!target) return { status: 'missing', node: null, candidates: [] };
|
|
85
|
+
// Real definition (graphify rewired the reference onto it, or it lived in
|
|
86
|
+
// the referencing file all along).
|
|
87
|
+
if (isDefinition(target)) return { status: 'resolved', node: target, candidates: [] };
|
|
88
|
+
|
|
89
|
+
// Sourceless stub — try the rewire tiers: exact label, then folded.
|
|
90
|
+
const label = typeof target.label === 'string' && target.label.trim() ? target.label.trim() : (fallbackLabel ?? '');
|
|
91
|
+
let candidates = defsByExactLabel.get(label) ?? [];
|
|
92
|
+
if (candidates.length !== 1) {
|
|
93
|
+
const folded = normalizeGraphifyLabel(label);
|
|
94
|
+
candidates = folded ? (defsByFoldedLabel.get(folded) ?? []) : [];
|
|
95
|
+
}
|
|
96
|
+
if (candidates.length === 1) {
|
|
97
|
+
// Unique match — same fold `_rewire_unique_stub_nodes` performs at
|
|
98
|
+
// extraction time; graphs built before that pass land here instead.
|
|
99
|
+
return { status: 'resolved', node: candidates[0]!, candidates };
|
|
100
|
+
}
|
|
101
|
+
if (candidates.length > 1) return { status: 'ambiguous', node: target, candidates };
|
|
102
|
+
return { status: 'unresolved', node: target, candidates: [] };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { resolve };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** One-shot convenience over {@link createGraphifyTypeResolver}. */
|
|
109
|
+
export function resolveGraphifyTypeRef(
|
|
110
|
+
nodes: readonly GraphifyNode[],
|
|
111
|
+
ref: Pick<GraphifyReferenceInfo, 'nodeId'> | { nodeId?: string } | undefined,
|
|
112
|
+
fallbackLabel?: string,
|
|
113
|
+
): GraphifyTypeRefResolution {
|
|
114
|
+
return createGraphifyTypeResolver(nodes).resolve(ref?.nodeId, fallbackLabel);
|
|
115
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -242,10 +242,29 @@ export type {
|
|
|
242
242
|
GraphifyComponentDetail,
|
|
243
243
|
GraphifyEdgeRef,
|
|
244
244
|
} from './graphify';
|
|
245
|
+
export type {
|
|
246
|
+
GraphifyTypeRefStatus,
|
|
247
|
+
GraphifyTypeRefResolution,
|
|
248
|
+
} from './graphify';
|
|
249
|
+
export {
|
|
250
|
+
normalizeGraphifyLabel,
|
|
251
|
+
createGraphifyTypeResolver,
|
|
252
|
+
resolveGraphifyTypeRef,
|
|
253
|
+
} from './graphify';
|
|
245
254
|
|
|
246
255
|
// Subsystem component graph
|
|
247
256
|
export { SubsystemComponentGraph } from './subsystem/SubsystemComponentGraph';
|
|
248
257
|
export type { SubsystemComponentGraphProps } from './subsystem/SubsystemComponentGraph';
|
|
258
|
+
export { MECHANISM_COLOR, KIND_COLOR, MECHANISM_STYLE } from './subsystem/model';
|
|
259
|
+
export {
|
|
260
|
+
purlRepoKey,
|
|
261
|
+
purlOwnerName,
|
|
262
|
+
buildTreePathMapping,
|
|
263
|
+
} from './subsystem/paths';
|
|
264
|
+
export type {
|
|
265
|
+
TreeEntry,
|
|
266
|
+
TreePathMapping,
|
|
267
|
+
} from './subsystem/paths';
|
|
249
268
|
export { SubsystemFileTree } from './subsystem/SubsystemFileTree';
|
|
250
269
|
export type { SubsystemFileTreeProps } from './subsystem/SubsystemFileTree';
|
|
251
270
|
export { GraphLayoutCover } from './subsystem/GraphLayoutCover';
|
|
@@ -77,7 +77,6 @@ function TwoNodeDemo({ showEdgeLabels = true }: { showEdgeLabels?: boolean }) {
|
|
|
77
77
|
onSelect={(id) => setSelected(id)}
|
|
78
78
|
onEdgeSelect={(e) => setSelectedEdge(e)}
|
|
79
79
|
showEdgeLabels={showEdgeLabels}
|
|
80
|
-
|
|
81
80
|
/>
|
|
82
81
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
83
82
|
{selectedEdge
|
|
@@ -162,7 +161,7 @@ const readerDetail: GraphifyComponentDetail = {
|
|
|
162
161
|
kind: 'class',
|
|
163
162
|
methods: [
|
|
164
163
|
{ nodeId: 'm1', name: 'normalize', returnType: 'SessionEvent[]' },
|
|
165
|
-
{ nodeId: 'm2', name: 'readSession', parameters: ['string'], returnType: 'SessionRecord' },
|
|
164
|
+
{ nodeId: 'm2', name: 'readSession', parameters: [{ type: 'string' }], returnType: 'SessionRecord' },
|
|
166
165
|
{ nodeId: 'm3', name: 'toUniversalEvents', returnType: 'UniversalEvent[]' },
|
|
167
166
|
],
|
|
168
167
|
properties: [{ name: 'sessionId', type: 'string' }],
|
|
@@ -201,7 +200,6 @@ function V2ReaderDemo() {
|
|
|
201
200
|
edges={v2ReaderEdges}
|
|
202
201
|
onSelect={(id) => setSelected(id)}
|
|
203
202
|
onEdgeSelect={(e) => setSelectedEdge(e)}
|
|
204
|
-
|
|
205
203
|
/>
|
|
206
204
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
207
205
|
{selectedEdge
|
|
@@ -325,7 +323,6 @@ export const NarrowMaxWidth: Story = {
|
|
|
325
323
|
components={investigateOnlyComponents}
|
|
326
324
|
edges={investigateOnlyEdges}
|
|
327
325
|
maxNodeWidth={140}
|
|
328
|
-
|
|
329
326
|
/>
|
|
330
327
|
</div>
|
|
331
328
|
),
|
|
@@ -385,6 +382,8 @@ const namingConventionComponents: SubsystemComponent[] = [
|
|
|
385
382
|
},
|
|
386
383
|
];
|
|
387
384
|
|
|
385
|
+
const namingConventionEdges: SubsystemComponentEdge[] = [];
|
|
386
|
+
|
|
388
387
|
/** Nodes with compact `maxNodeWidth` so the different conventions visibly wrap
|
|
389
388
|
* at their word boundaries (camelCase, snake_case, PascalCase, acronyms). */
|
|
390
389
|
export const NamingConventions: Story = {
|
|
@@ -392,9 +391,8 @@ export const NamingConventions: Story = {
|
|
|
392
391
|
<div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
393
392
|
<SubsystemComponentGraph
|
|
394
393
|
components={namingConventionComponents}
|
|
395
|
-
edges={
|
|
394
|
+
edges={namingConventionEdges}
|
|
396
395
|
maxNodeWidth={180}
|
|
397
|
-
|
|
398
396
|
/>
|
|
399
397
|
</div>
|
|
400
398
|
),
|
|
@@ -449,6 +447,75 @@ const detailKindComponents: SubsystemComponent[] = [
|
|
|
449
447
|
callees: [{ nodeId: 'c2', name: 'toUniversalEvents', source_location: 'L64' }],
|
|
450
448
|
} satisfies GraphifyComponentDetail,
|
|
451
449
|
},
|
|
450
|
+
{
|
|
451
|
+
id: 'detail-fn-rich',
|
|
452
|
+
name: 'mergeSessions',
|
|
453
|
+
kind: 'function',
|
|
454
|
+
file: 'src/session/merge.ts',
|
|
455
|
+
purl: 'pkg:github/principal-ai/agent-monitoring',
|
|
456
|
+
purpose: 'multi-param signature — named, positional (graphify captures types only), union types, generic return',
|
|
457
|
+
symbol: 'mergeSessions',
|
|
458
|
+
detail: {
|
|
459
|
+
kind: 'function',
|
|
460
|
+
parameters: [
|
|
461
|
+
{ name: 'sessions', type: 'SessionRecord[]' },
|
|
462
|
+
{ type: 'MergeOptions' },
|
|
463
|
+
{ name: 'strategy', type: `'append' | 'replace' | 'skip'` },
|
|
464
|
+
{ name: 'onConflict', type: '((a: SessionRecord, b: SessionRecord) => SessionRecord)' },
|
|
465
|
+
],
|
|
466
|
+
returnType: 'Promise<Map<string, SessionEvent[]>>',
|
|
467
|
+
callers: [
|
|
468
|
+
{ nodeId: 'c1', name: 'capture-session', source_location: 'L88' },
|
|
469
|
+
{ nodeId: 'c3', name: 'backfill', source_location: 'L210' },
|
|
470
|
+
],
|
|
471
|
+
callees: [{ nodeId: 'c2', name: 'toUniversalEvents', source_location: 'L64' }],
|
|
472
|
+
} satisfies GraphifyComponentDetail,
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
id: 'detail-fn-void',
|
|
476
|
+
name: 'flush',
|
|
477
|
+
kind: 'function',
|
|
478
|
+
file: 'src/event-processing/sink.ts',
|
|
479
|
+
purl: 'pkg:github/principal-ai/agent-monitoring',
|
|
480
|
+
purpose: 'no parameters, no return type — the barest function signature',
|
|
481
|
+
symbol: 'flush',
|
|
482
|
+
detail: {
|
|
483
|
+
kind: 'function',
|
|
484
|
+
parameters: [],
|
|
485
|
+
callers: [{ nodeId: 'c4', name: 'EventProcessor.dispose', source_location: 'L142' }],
|
|
486
|
+
callees: [],
|
|
487
|
+
} satisfies GraphifyComponentDetail,
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
id: 'detail-class-rich',
|
|
491
|
+
name: 'EventProcessor',
|
|
492
|
+
kind: 'class',
|
|
493
|
+
file: 'src/event-processing/EventProcessor.ts',
|
|
494
|
+
purl: 'pkg:github/principal-ai/agent-monitoring',
|
|
495
|
+
purpose: 'class with fully-typed members — method params + returns, field types, extends + implements',
|
|
496
|
+
symbol: 'EventProcessor',
|
|
497
|
+
detail: {
|
|
498
|
+
kind: 'class',
|
|
499
|
+
methods: [
|
|
500
|
+
{ nodeId: 'rm1', name: 'process', parameters: [{ type: 'RawEvent' }, { type: 'ProcessingOptions' }], returnType: 'ProcessedEvent' },
|
|
501
|
+
{ nodeId: 'rm2', name: 'batch', parameters: [{ type: 'RawEvent[]' }], returnType: 'Promise<ProcessedEvent[]>' },
|
|
502
|
+
{ nodeId: 'rm3', name: 'onError', parameters: [{ type: 'Error' }] },
|
|
503
|
+
{ nodeId: 'rm4', name: 'dispose' },
|
|
504
|
+
],
|
|
505
|
+
properties: [
|
|
506
|
+
{ name: 'queue', type: 'RawEvent[]' },
|
|
507
|
+
{ name: 'options', type: 'Required<ProcessingOptions>' },
|
|
508
|
+
{ name: 'retryLimit', type: 'number' },
|
|
509
|
+
],
|
|
510
|
+
extends: ['BaseProcessor'],
|
|
511
|
+
implements: ['Disposable', 'EventEmitterLike'],
|
|
512
|
+
instantiations: [
|
|
513
|
+
{ nodeId: 'x1', name: 'main' },
|
|
514
|
+
{ nodeId: 'x2', name: 'worker-pool' },
|
|
515
|
+
],
|
|
516
|
+
references: [{ nodeId: 'x3', name: 'pipeline', context: 'type' }],
|
|
517
|
+
} satisfies GraphifyComponentDetail,
|
|
518
|
+
},
|
|
452
519
|
{
|
|
453
520
|
id: 'detail-type',
|
|
454
521
|
name: 'SessionRecord',
|
|
@@ -501,15 +568,16 @@ const detailKindComponents: SubsystemComponent[] = [
|
|
|
501
568
|
},
|
|
502
569
|
];
|
|
503
570
|
|
|
571
|
+
const detailKindEdges: SubsystemComponentEdge[] = [];
|
|
572
|
+
|
|
504
573
|
function DetailKindsDemo() {
|
|
505
574
|
const [selected, setSelected] = useState<string | null>(null);
|
|
506
575
|
return (
|
|
507
576
|
<div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
508
577
|
<SubsystemComponentGraph
|
|
509
578
|
components={detailKindComponents}
|
|
510
|
-
edges={
|
|
579
|
+
edges={detailKindEdges}
|
|
511
580
|
onSelect={(id) => setSelected(id)}
|
|
512
|
-
|
|
513
581
|
/>
|
|
514
582
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
515
583
|
{selected ? `selected: ${selected}` : 'click a component to see its GraphifyComponentDetail'}
|
|
@@ -522,6 +590,261 @@ export const DetailKinds: Story = {
|
|
|
522
590
|
render: () => <DetailKindsDemo />,
|
|
523
591
|
};
|
|
524
592
|
|
|
593
|
+
// ---------------------------------------------------------------------------
|
|
594
|
+
// Kind variations — one column per kind (class / function / type / module /
|
|
595
|
+
// external), rows going bare → detailed. Click a node to see its declaration
|
|
596
|
+
// panel; type names inside it are clickable when they match another node here.
|
|
597
|
+
// ---------------------------------------------------------------------------
|
|
598
|
+
const variationPurl = 'pkg:github/principal-ai/agent-monitoring';
|
|
599
|
+
|
|
600
|
+
const kindVariationComponents: SubsystemComponent[] = [
|
|
601
|
+
// --- class: bare → members only → relationships only
|
|
602
|
+
{
|
|
603
|
+
id: 'cls-bare',
|
|
604
|
+
name: 'SessionStore',
|
|
605
|
+
kind: 'class',
|
|
606
|
+
file: 'src/session/SessionStore.ts',
|
|
607
|
+
purl: variationPurl,
|
|
608
|
+
purpose: 'no drill-down — renders a plain `class SessionStore`',
|
|
609
|
+
symbol: 'SessionStore',
|
|
610
|
+
layer: 1,
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
id: 'cls-members',
|
|
614
|
+
name: 'Transcoder',
|
|
615
|
+
kind: 'class',
|
|
616
|
+
file: 'src/session/Transcoder.ts',
|
|
617
|
+
purl: variationPurl,
|
|
618
|
+
purpose: 'members only — methods with typed params + returns, a typed field',
|
|
619
|
+
symbol: 'Transcoder',
|
|
620
|
+
layer: 1,
|
|
621
|
+
detail: {
|
|
622
|
+
kind: 'class',
|
|
623
|
+
methods: [
|
|
624
|
+
{ nodeId: 'tm1', name: 'encode', parameters: [{ type: 'RawFrame' }], returnType: 'Uint8Array' },
|
|
625
|
+
{ nodeId: 'tm2', name: 'decode', parameters: [{ type: 'Uint8Array' }], returnType: 'RawFrame' },
|
|
626
|
+
{ nodeId: 'tm3', name: 'reset' },
|
|
627
|
+
],
|
|
628
|
+
properties: [{ name: 'bufferSize', type: 'number' }],
|
|
629
|
+
extends: [],
|
|
630
|
+
implements: [],
|
|
631
|
+
instantiations: [],
|
|
632
|
+
references: [],
|
|
633
|
+
} satisfies GraphifyComponentDetail,
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
id: 'cls-relations',
|
|
637
|
+
name: 'HttpTransport',
|
|
638
|
+
kind: 'class',
|
|
639
|
+
file: 'src/transport/HttpTransport.ts',
|
|
640
|
+
purl: variationPurl,
|
|
641
|
+
purpose: 'relationships only — extends + implements, constructed-by comment; empty body elides the braces',
|
|
642
|
+
symbol: 'HttpTransport',
|
|
643
|
+
layer: 1,
|
|
644
|
+
detail: {
|
|
645
|
+
kind: 'class',
|
|
646
|
+
methods: [],
|
|
647
|
+
properties: [],
|
|
648
|
+
extends: ['BaseTransport'],
|
|
649
|
+
implements: ['Transport'],
|
|
650
|
+
instantiations: [{ nodeId: 'x1', name: 'main' }],
|
|
651
|
+
references: [],
|
|
652
|
+
} satisfies GraphifyComponentDetail,
|
|
653
|
+
},
|
|
654
|
+
|
|
655
|
+
// --- function: bare → signature only → signature + call relationships
|
|
656
|
+
{
|
|
657
|
+
id: 'fn-bare',
|
|
658
|
+
name: 'bootstrap',
|
|
659
|
+
kind: 'function',
|
|
660
|
+
file: 'src/bootstrap.ts',
|
|
661
|
+
purl: variationPurl,
|
|
662
|
+
purpose: 'no drill-down — renders a plain `function bootstrap()`',
|
|
663
|
+
symbol: 'bootstrap',
|
|
664
|
+
layer: 2,
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
id: 'fn-signature',
|
|
668
|
+
name: 'normalizeSession',
|
|
669
|
+
kind: 'function',
|
|
670
|
+
file: 'src/event-processing/normalize.ts',
|
|
671
|
+
purl: variationPurl,
|
|
672
|
+
purpose: 'signature only — named + positional (type-only) params, array return; no callers/callees comments',
|
|
673
|
+
symbol: 'normalizeSession',
|
|
674
|
+
layer: 2,
|
|
675
|
+
detail: {
|
|
676
|
+
kind: 'function',
|
|
677
|
+
parameters: [
|
|
678
|
+
{ name: 'session', type: 'SessionRecord' },
|
|
679
|
+
{ type: 'NormalizeOptions' },
|
|
680
|
+
],
|
|
681
|
+
returnType: 'SessionEvent[]',
|
|
682
|
+
callers: [],
|
|
683
|
+
callees: [],
|
|
684
|
+
} satisfies GraphifyComponentDetail,
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
id: 'fn-calls',
|
|
688
|
+
name: 'mergeSessions',
|
|
689
|
+
kind: 'function',
|
|
690
|
+
file: 'src/session/merge.ts',
|
|
691
|
+
purl: variationPurl,
|
|
692
|
+
purpose: 'signature + call relationships — union-typed param, generic return, called-by / calls trailing comments',
|
|
693
|
+
symbol: 'mergeSessions',
|
|
694
|
+
layer: 2,
|
|
695
|
+
detail: {
|
|
696
|
+
kind: 'function',
|
|
697
|
+
parameters: [
|
|
698
|
+
{ name: 'sessions', type: 'SessionRecord[]' },
|
|
699
|
+
{ name: 'strategy', type: `'append' | 'replace'` },
|
|
700
|
+
],
|
|
701
|
+
returnType: 'Promise<SessionEvent[]>',
|
|
702
|
+
callers: [{ nodeId: 'c1', name: 'capture-session', source_location: 'L88' }],
|
|
703
|
+
callees: [{ nodeId: 'c2', name: 'toUniversalEvents', source_location: 'L64' }],
|
|
704
|
+
} satisfies GraphifyComponentDetail,
|
|
705
|
+
},
|
|
706
|
+
|
|
707
|
+
// --- type: bare → fields only → fields + implementors + used-by
|
|
708
|
+
{
|
|
709
|
+
id: 'ty-bare',
|
|
710
|
+
name: 'RawFrame',
|
|
711
|
+
kind: 'type',
|
|
712
|
+
file: 'src/session/RawFrame.ts',
|
|
713
|
+
purl: variationPurl,
|
|
714
|
+
purpose: 'no drill-down — renders a plain `interface RawFrame`',
|
|
715
|
+
symbol: 'RawFrame',
|
|
716
|
+
layer: 3,
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
id: 'ty-fields',
|
|
720
|
+
name: 'SessionRecord',
|
|
721
|
+
kind: 'type',
|
|
722
|
+
file: 'src/session/transcript.ts',
|
|
723
|
+
purl: variationPurl,
|
|
724
|
+
purpose: 'fields only — typed interface body, nothing else',
|
|
725
|
+
symbol: 'SessionRecord',
|
|
726
|
+
layer: 3,
|
|
727
|
+
detail: {
|
|
728
|
+
kind: 'type',
|
|
729
|
+
properties: [
|
|
730
|
+
{ name: 'id', type: 'string' },
|
|
731
|
+
{ name: 'admittedSeq', type: 'number' },
|
|
732
|
+
],
|
|
733
|
+
usedBy: [],
|
|
734
|
+
implementors: [],
|
|
735
|
+
} satisfies GraphifyComponentDetail,
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
id: 'ty-full',
|
|
739
|
+
name: 'Transport',
|
|
740
|
+
kind: 'type',
|
|
741
|
+
file: 'src/transport/Transport.ts',
|
|
742
|
+
purl: variationPurl,
|
|
743
|
+
purpose: 'full — fields + implemented-by (clicks through to HttpTransport) + used-by comments',
|
|
744
|
+
symbol: 'Transport',
|
|
745
|
+
layer: 3,
|
|
746
|
+
detail: {
|
|
747
|
+
kind: 'type',
|
|
748
|
+
properties: [{ name: 'name', type: 'string' }],
|
|
749
|
+
usedBy: [{ nodeId: 'u1', name: 'main', context: 'parameter_type' }],
|
|
750
|
+
implementors: ['HttpTransport'],
|
|
751
|
+
} satisfies GraphifyComponentDetail,
|
|
752
|
+
},
|
|
753
|
+
|
|
754
|
+
// --- module: bare → exports only → exports + imports
|
|
755
|
+
{
|
|
756
|
+
id: 'mod-bare',
|
|
757
|
+
name: 'transcript',
|
|
758
|
+
kind: 'module',
|
|
759
|
+
file: 'src/session/transcript.ts',
|
|
760
|
+
purl: variationPurl,
|
|
761
|
+
purpose: 'no drill-down — symbol-less module named from its file basename',
|
|
762
|
+
symbol: '',
|
|
763
|
+
layer: 4,
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
id: 'mod-exports',
|
|
767
|
+
name: 'paths',
|
|
768
|
+
kind: 'module',
|
|
769
|
+
file: 'src/session/paths.ts',
|
|
770
|
+
purl: variationPurl,
|
|
771
|
+
purpose: 'exports only — export statement + defines comment',
|
|
772
|
+
symbol: '',
|
|
773
|
+
layer: 4,
|
|
774
|
+
detail: {
|
|
775
|
+
kind: 'module',
|
|
776
|
+
exports: ['extractToolName', 'extractFilePath'],
|
|
777
|
+
imports: [],
|
|
778
|
+
symbols: ['extractToolName', 'extractFilePath'],
|
|
779
|
+
} satisfies GraphifyComponentDetail,
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
id: 'mod-full',
|
|
783
|
+
name: 'index',
|
|
784
|
+
kind: 'module',
|
|
785
|
+
file: 'src/index.ts',
|
|
786
|
+
purl: variationPurl,
|
|
787
|
+
purpose: 'full — import statements + re-export statement + defines comment',
|
|
788
|
+
symbol: '',
|
|
789
|
+
layer: 4,
|
|
790
|
+
detail: {
|
|
791
|
+
kind: 'module',
|
|
792
|
+
exports: ['SessionReader', 'SessionStore'],
|
|
793
|
+
imports: [{ nodeId: 'i1', name: 'transcript', relation: 'imports_from' }],
|
|
794
|
+
symbols: ['SessionReader', 'SessionStore'],
|
|
795
|
+
} satisfies GraphifyComponentDetail,
|
|
796
|
+
},
|
|
797
|
+
|
|
798
|
+
// --- external: bare → labeled
|
|
799
|
+
{
|
|
800
|
+
id: 'ext-bare',
|
|
801
|
+
name: 'left-pad',
|
|
802
|
+
kind: 'external',
|
|
803
|
+
file: '',
|
|
804
|
+
purl: 'pkg:npm/left-pad',
|
|
805
|
+
purpose: 'no drill-down — renders a plain `external left-pad`',
|
|
806
|
+
symbol: '',
|
|
807
|
+
layer: 5,
|
|
808
|
+
},
|
|
809
|
+
{
|
|
810
|
+
id: 'ext-label',
|
|
811
|
+
name: 'trail-viewer',
|
|
812
|
+
kind: 'external',
|
|
813
|
+
file: '',
|
|
814
|
+
purl: 'pkg:npm/@principal-ai/trail-viewer',
|
|
815
|
+
purpose: 'labeled — the full purl as a quoted string literal',
|
|
816
|
+
symbol: '',
|
|
817
|
+
layer: 5,
|
|
818
|
+
detail: {
|
|
819
|
+
kind: 'external',
|
|
820
|
+
label: 'pkg:npm/@principal-ai/trail-viewer',
|
|
821
|
+
} satisfies GraphifyComponentDetail,
|
|
822
|
+
},
|
|
823
|
+
];
|
|
824
|
+
|
|
825
|
+
const kindVariationEdges: SubsystemComponentEdge[] = [];
|
|
826
|
+
|
|
827
|
+
function KindVariationsDemo() {
|
|
828
|
+
const [selected, setSelected] = useState<string | null>(null);
|
|
829
|
+
return (
|
|
830
|
+
<div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
831
|
+
<SubsystemComponentGraph
|
|
832
|
+
components={kindVariationComponents}
|
|
833
|
+
edges={kindVariationEdges}
|
|
834
|
+
onSelect={(id) => setSelected(id)}
|
|
835
|
+
/>
|
|
836
|
+
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
837
|
+
columns: class · function · type · module · external — each goes bare → detailed
|
|
838
|
+
{selected ? ` · selected: ${selected}` : ''}
|
|
839
|
+
</div>
|
|
840
|
+
</div>
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
export const KindVariations: Story = {
|
|
845
|
+
render: () => <KindVariationsDemo />,
|
|
846
|
+
};
|
|
847
|
+
|
|
525
848
|
// ---------------------------------------------------------------------------
|
|
526
849
|
// Minimal (pre-graphify) vs Resolved (post-graphify) — the SAME subsystem,
|
|
527
850
|
// showing what the LLM emits (no detail) and what graphify enrichment adds.
|
|
@@ -585,7 +908,6 @@ function MinimalVsResolvedDemo({ resolved }: { resolved: boolean }) {
|
|
|
585
908
|
components={resolved ? resolvedComponents : minimalComponents}
|
|
586
909
|
edges={sharedEdges}
|
|
587
910
|
onSelect={(id) => setSelected(id)}
|
|
588
|
-
|
|
589
911
|
/>
|
|
590
912
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
591
913
|
{resolved
|
|
@@ -662,7 +984,6 @@ function InvestigationDemo() {
|
|
|
662
984
|
components={investigationComponents}
|
|
663
985
|
edges={investigationEdges}
|
|
664
986
|
onSelect={(id) => setSelected(id)}
|
|
665
|
-
|
|
666
987
|
/>
|
|
667
988
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
668
989
|
read-only investigation snapshot (grok 019fd2a9) — components analyzed, not edited
|
|
@@ -754,7 +1075,6 @@ function MermaidDemo() {
|
|
|
754
1075
|
components={mermaidComponents}
|
|
755
1076
|
edges={mermaidEdges}
|
|
756
1077
|
onSelect={(id) => setSelected(id)}
|
|
757
|
-
|
|
758
1078
|
/>
|
|
759
1079
|
<div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
|
|
760
1080
|
mermaid diagram rendering pipeline — lazy → render → zoom → modal
|