@principal-ai/subsystems-react 0.24.1 → 0.24.3
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/components/session-events/SessionEventFeed.d.ts +2 -1
- package/dist/components/session-events/SessionEventFeed.d.ts.map +1 -1
- package/dist/components/session-events/SessionEventFeed.js +43 -35
- package/dist/components/session-events/SessionEventFeed.js.map +1 -1
- package/dist/pierre/PierreFileView.d.ts.map +1 -1
- package/dist/pierre/PierreFileView.js +23 -1
- package/dist/pierre/PierreFileView.js.map +1 -1
- package/dist/subsystem/ConstructsCatalog.d.ts.map +1 -1
- package/dist/subsystem/ConstructsCatalog.js +18 -38
- package/dist/subsystem/ConstructsCatalog.js.map +1 -1
- package/dist/subsystem/IssueList.d.ts +1 -0
- package/dist/subsystem/IssueList.d.ts.map +1 -1
- package/dist/subsystem/IssueList.js +38 -10
- package/dist/subsystem/IssueList.js.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +2 -2
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/SubsystemFileTree.js +2 -2
- package/dist/subsystem/SubsystemFileTree.js.map +1 -1
- package/dist/subsystem/nodes.js +5 -5
- package/dist/subsystem/nodes.js.map +1 -1
- package/package.json +1 -1
- package/src/components/session-events/SessionEventFeed.tsx +54 -45
- package/src/pierre/PierreFileView.tsx +27 -1
- package/src/subsystem/ConstructsCatalog.tsx +32 -72
- package/src/subsystem/IssueList.tsx +41 -10
- package/src/subsystem/SubsystemComponentGraph.tsx +1 -2
- package/src/subsystem/SubsystemFileTree.tsx +2 -2
- package/src/subsystem/nodes.tsx +5 -5
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* repo-normalized form, and `accumulated` the AgentSessionEvent the File City
|
|
11
11
|
* UI actually renders (null when the accumulator drops the event).
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* The categorical event-hue palette (kind/operation/todo colors) is intentionally
|
|
14
|
+
* self-contained rather than themed; typography comes from the theme scale.
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
@@ -422,7 +423,7 @@ function RawEventCard({
|
|
|
422
423
|
border: '1px dashed #1f2937',
|
|
423
424
|
backgroundColor: '#0d1117',
|
|
424
425
|
fontFamily: theme.fonts.body,
|
|
425
|
-
fontSize:
|
|
426
|
+
fontSize: theme.fontSizes[0],
|
|
426
427
|
}}
|
|
427
428
|
>
|
|
428
429
|
<span style={{ color: '#4b5563', fontStyle: 'italic' }}>no raw payload</span>
|
|
@@ -483,7 +484,7 @@ function RawEventCard({
|
|
|
483
484
|
const todos = (state?.input as AnyRecord | undefined)?.['todos'];
|
|
484
485
|
return (
|
|
485
486
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
|
486
|
-
<div style={{ fontSize:
|
|
487
|
+
<div style={{ fontSize: theme.fontSizes[0], color: '#9ca3af' }}>
|
|
487
488
|
callID {String(part?.callID ?? '')} · {String(state?.status ?? '')}
|
|
488
489
|
</div>
|
|
489
490
|
{Array.isArray(todos) ? <TodosView todos={todos} /> : null}
|
|
@@ -547,7 +548,7 @@ function RawEventCard({
|
|
|
547
548
|
overflow: 'hidden',
|
|
548
549
|
backgroundColor: expanded ? '#111827' : '#161b26',
|
|
549
550
|
fontFamily: theme.fonts.body,
|
|
550
|
-
fontSize:
|
|
551
|
+
fontSize: theme.fontSizes[0],
|
|
551
552
|
}}
|
|
552
553
|
>
|
|
553
554
|
<button
|
|
@@ -566,10 +567,10 @@ function RawEventCard({
|
|
|
566
567
|
textAlign: 'left',
|
|
567
568
|
}}
|
|
568
569
|
>
|
|
569
|
-
<span style={{ color: '#6b7280', fontSize:
|
|
570
|
+
<span style={{ color: '#6b7280', fontSize: theme.fontSizes[0], whiteSpace: 'nowrap' }}>#{event.seq}</span>
|
|
570
571
|
<span
|
|
571
572
|
style={{
|
|
572
|
-
fontSize:
|
|
573
|
+
fontSize: theme.fontSizes[0],
|
|
573
574
|
fontWeight: 600,
|
|
574
575
|
textTransform: 'uppercase',
|
|
575
576
|
letterSpacing: 0.5,
|
|
@@ -583,7 +584,7 @@ function RawEventCard({
|
|
|
583
584
|
<span
|
|
584
585
|
title={`${runCount} separate runs of this command`}
|
|
585
586
|
style={{
|
|
586
|
-
fontSize:
|
|
587
|
+
fontSize: theme.fontSizes[0],
|
|
587
588
|
fontWeight: 700,
|
|
588
589
|
color: '#f59e0b',
|
|
589
590
|
whiteSpace: 'nowrap',
|
|
@@ -596,7 +597,7 @@ function RawEventCard({
|
|
|
596
597
|
<span
|
|
597
598
|
title={`${snapshotCount} raw event snapshots collapsed into this row`}
|
|
598
599
|
style={{
|
|
599
|
-
fontSize:
|
|
600
|
+
fontSize: theme.fontSizes[0],
|
|
600
601
|
fontWeight: 600,
|
|
601
602
|
color: '#60a5fa',
|
|
602
603
|
whiteSpace: 'nowrap',
|
|
@@ -616,7 +617,7 @@ function RawEventCard({
|
|
|
616
617
|
>
|
|
617
618
|
{describe(event)}
|
|
618
619
|
</span>
|
|
619
|
-
<span style={{ color: '#6b7280', fontSize:
|
|
620
|
+
<span style={{ color: '#6b7280', fontSize: theme.fontSizes[0], whiteSpace: 'nowrap' }}>
|
|
620
621
|
{formatTime(eventTimestamp(event))}
|
|
621
622
|
</span>
|
|
622
623
|
</button>
|
|
@@ -673,7 +674,7 @@ function NormalizedEventCard({
|
|
|
673
674
|
overflow: 'hidden',
|
|
674
675
|
backgroundColor: expanded ? '#0d1520' : '#101722',
|
|
675
676
|
fontFamily: theme.fonts.body,
|
|
676
|
-
fontSize:
|
|
677
|
+
fontSize: theme.fontSizes[0],
|
|
677
678
|
}}
|
|
678
679
|
>
|
|
679
680
|
<button
|
|
@@ -692,10 +693,10 @@ function NormalizedEventCard({
|
|
|
692
693
|
textAlign: 'left',
|
|
693
694
|
}}
|
|
694
695
|
>
|
|
695
|
-
<span style={{ color: '#6b7280', fontSize:
|
|
696
|
+
<span style={{ color: '#6b7280', fontSize: theme.fontSizes[0], whiteSpace: 'nowrap' }}>#{seq}</span>
|
|
696
697
|
<span
|
|
697
698
|
style={{
|
|
698
|
-
fontSize:
|
|
699
|
+
fontSize: theme.fontSizes[0],
|
|
699
700
|
fontWeight: 600,
|
|
700
701
|
textTransform: 'uppercase',
|
|
701
702
|
letterSpacing: 0.5,
|
|
@@ -716,7 +717,7 @@ function NormalizedEventCard({
|
|
|
716
717
|
>
|
|
717
718
|
{normalizedDescribe(event)}
|
|
718
719
|
</span>
|
|
719
|
-
<span style={{ color: '#6b7280', fontSize:
|
|
720
|
+
<span style={{ color: '#6b7280', fontSize: theme.fontSizes[0], whiteSpace: 'nowrap' }}>
|
|
720
721
|
{formatTime(event.timestamp)}
|
|
721
722
|
</span>
|
|
722
723
|
</button>
|
|
@@ -734,7 +735,7 @@ function NormalizedEventCard({
|
|
|
734
735
|
/>
|
|
735
736
|
{event.files && event.files.length > 0 ? (
|
|
736
737
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
|
737
|
-
<div style={{ fontSize:
|
|
738
|
+
<div style={{ fontSize: theme.fontSizes[0], color: '#6b7280' }}>files ({event.files.length})</div>
|
|
738
739
|
{event.files.map((file, i) => (
|
|
739
740
|
<FileRow key={i} file={file} />
|
|
740
741
|
))}
|
|
@@ -756,14 +757,14 @@ function FileRow({ file }: { file: NormalizedPathInfo }) {
|
|
|
756
757
|
<div
|
|
757
758
|
style={{
|
|
758
759
|
color: '#93c5fd',
|
|
759
|
-
fontSize:
|
|
760
|
+
fontSize: theme.fontSizes[0],
|
|
760
761
|
wordBreak: 'break-word',
|
|
761
762
|
fontFamily: theme.fonts.monospace,
|
|
762
763
|
}}
|
|
763
764
|
>
|
|
764
765
|
{file.displayPath}
|
|
765
766
|
</div>
|
|
766
|
-
<div style={{ color: '#6b7280', fontSize:
|
|
767
|
+
<div style={{ color: '#6b7280', fontSize: theme.fontSizes[0], wordBreak: 'break-word' }}>
|
|
767
768
|
{file.context}
|
|
768
769
|
{file.repository
|
|
769
770
|
? ` · ${file.repository.gitRoot} → ${file.repository.relativePath}`
|
|
@@ -817,7 +818,7 @@ function AccumulatedEventCard({
|
|
|
817
818
|
border: '1px dashed #1f2937',
|
|
818
819
|
backgroundColor: '#0d1117',
|
|
819
820
|
fontFamily: theme.fonts.body,
|
|
820
|
-
fontSize:
|
|
821
|
+
fontSize: theme.fontSizes[0],
|
|
821
822
|
}}
|
|
822
823
|
>
|
|
823
824
|
<span style={{ color: '#374151', whiteSpace: 'nowrap' }}>#{seq}</span>
|
|
@@ -842,7 +843,7 @@ function AccumulatedEventCard({
|
|
|
842
843
|
overflow: 'hidden',
|
|
843
844
|
backgroundColor: expanded ? '#121a13' : '#141b16',
|
|
844
845
|
fontFamily: theme.fonts.body,
|
|
845
|
-
fontSize:
|
|
846
|
+
fontSize: theme.fontSizes[0],
|
|
846
847
|
}}
|
|
847
848
|
>
|
|
848
849
|
<button
|
|
@@ -870,10 +871,10 @@ function AccumulatedEventCard({
|
|
|
870
871
|
backgroundColor: event.sessionColor,
|
|
871
872
|
}}
|
|
872
873
|
/>
|
|
873
|
-
<span style={{ color: '#6b7280', fontSize:
|
|
874
|
+
<span style={{ color: '#6b7280', fontSize: theme.fontSizes[0], whiteSpace: 'nowrap' }}>#{seq}</span>
|
|
874
875
|
<span
|
|
875
876
|
style={{
|
|
876
|
-
fontSize:
|
|
877
|
+
fontSize: theme.fontSizes[0],
|
|
877
878
|
fontWeight: 600,
|
|
878
879
|
textTransform: 'uppercase',
|
|
879
880
|
letterSpacing: 0.5,
|
|
@@ -894,7 +895,7 @@ function AccumulatedEventCard({
|
|
|
894
895
|
>
|
|
895
896
|
{event.description}
|
|
896
897
|
</span>
|
|
897
|
-
<span style={{ color: '#6b7280', fontSize:
|
|
898
|
+
<span style={{ color: '#6b7280', fontSize: theme.fontSizes[0], whiteSpace: 'nowrap' }}>
|
|
898
899
|
{formatTime(event.timestamp)}
|
|
899
900
|
</span>
|
|
900
901
|
</button>
|
|
@@ -910,18 +911,18 @@ function AccumulatedEventCard({
|
|
|
910
911
|
['childSessionId', event.childSessionId],
|
|
911
912
|
]}
|
|
912
913
|
/>
|
|
913
|
-
<div style={{ fontSize:
|
|
914
|
+
<div style={{ fontSize: theme.fontSizes[0], color: '#6b7280' }}>{event.description}</div>
|
|
914
915
|
{event.files.length > 0 ? <PathList label="files" paths={event.files} /> : null}
|
|
915
916
|
{event.dependencies.length > 0 ? (
|
|
916
917
|
<PathList label="dependencies" paths={event.dependencies} />
|
|
917
918
|
) : null}
|
|
918
919
|
{event.layers.length > 0 ? (
|
|
919
920
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
920
|
-
<div style={{ fontSize:
|
|
921
|
+
<div style={{ fontSize: theme.fontSizes[0], color: '#6b7280' }}>layers</div>
|
|
921
922
|
{event.layers.map((layer) => (
|
|
922
923
|
<div
|
|
923
924
|
key={layer.id}
|
|
924
|
-
style={{ display: 'flex', gap: 6, alignItems: 'center', fontSize:
|
|
925
|
+
style={{ display: 'flex', gap: 6, alignItems: 'center', fontSize: theme.fontSizes[0] }}
|
|
925
926
|
>
|
|
926
927
|
<span
|
|
927
928
|
style={{
|
|
@@ -949,11 +950,11 @@ function PathList({ label, paths }: { label: string; paths: NormalizedPathInfo[]
|
|
|
949
950
|
const { theme } = useTheme();
|
|
950
951
|
return (
|
|
951
952
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
952
|
-
<div style={{ fontSize:
|
|
953
|
+
<div style={{ fontSize: theme.fontSizes[0], color: '#6b7280' }}>{label}</div>
|
|
953
954
|
{paths.map((p, i) => (
|
|
954
955
|
<div
|
|
955
956
|
key={i}
|
|
956
|
-
style={{ color: '#93c5fd', fontSize:
|
|
957
|
+
style={{ color: '#93c5fd', fontSize: theme.fontSizes[0], fontFamily: theme.fonts.monospace, wordBreak: 'break-word' }}
|
|
957
958
|
>
|
|
958
959
|
{p.displayPath}
|
|
959
960
|
</div>
|
|
@@ -963,12 +964,13 @@ function PathList({ label, paths }: { label: string; paths: NormalizedPathInfo[]
|
|
|
963
964
|
}
|
|
964
965
|
|
|
965
966
|
function TextView({ text }: { text?: string }) {
|
|
966
|
-
|
|
967
|
+
const { theme } = useTheme();
|
|
968
|
+
if (!text) return <div style={{ color: '#6b7280', fontSize: theme.fontSizes[0] }}>(empty)</div>;
|
|
967
969
|
return (
|
|
968
970
|
<div
|
|
969
971
|
style={{
|
|
970
972
|
color: '#d1d5db',
|
|
971
|
-
fontSize:
|
|
973
|
+
fontSize: theme.fontSizes[0],
|
|
972
974
|
lineHeight: 1.5,
|
|
973
975
|
maxHeight: 120,
|
|
974
976
|
overflowY: 'auto',
|
|
@@ -988,11 +990,12 @@ const TODO_STATUS_COLORS: Record<string, string> = {
|
|
|
988
990
|
};
|
|
989
991
|
|
|
990
992
|
function TodosView({ todos }: { todos: Array<Record<string, unknown>> }) {
|
|
993
|
+
const { theme } = useTheme();
|
|
991
994
|
return (
|
|
992
995
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
|
993
|
-
<div style={{ fontSize:
|
|
996
|
+
<div style={{ fontSize: theme.fontSizes[0], color: '#6b7280' }}>todos ({todos.length})</div>
|
|
994
997
|
{todos.map((t, i) => (
|
|
995
|
-
<div key={i} style={{ display: 'flex', gap: 8, fontSize:
|
|
998
|
+
<div key={i} style={{ display: 'flex', gap: 8, fontSize: theme.fontSizes[0], alignItems: 'baseline' }}>
|
|
996
999
|
<span
|
|
997
1000
|
style={{
|
|
998
1001
|
color: TODO_STATUS_COLORS[String(t.status ?? '')] ?? '#6b7280',
|
|
@@ -1013,13 +1016,15 @@ function TodosView({ todos }: { todos: Array<Record<string, unknown>> }) {
|
|
|
1013
1016
|
);
|
|
1014
1017
|
}
|
|
1015
1018
|
|
|
1016
|
-
function ToolIO({ input, output }: { input?: unknown; output?: unknown }) {
|
|
1019
|
+
function ToolIO({ input, output }: { input?: unknown; output?: unknown }) {
|
|
1020
|
+
const { theme } = useTheme();
|
|
1021
|
+
const summary = toolSummary(input);
|
|
1017
1022
|
return (
|
|
1018
1023
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
|
1019
1024
|
{summary ? (
|
|
1020
1025
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
1021
|
-
<span style={{ fontSize:
|
|
1022
|
-
<code style={{ color: '#93c5fd', fontSize:
|
|
1026
|
+
<span style={{ fontSize: theme.fontSizes[0], color: '#60a5fa', fontWeight: 600 }}>IN</span>
|
|
1027
|
+
<code style={{ color: '#93c5fd', fontSize: theme.fontSizes[0], wordBreak: 'break-word' }}>{summary}</code>
|
|
1023
1028
|
</div>
|
|
1024
1029
|
) : null}
|
|
1025
1030
|
{input !== undefined && input !== null && typeof input === 'object' ? (
|
|
@@ -1028,8 +1033,8 @@ function ToolIO({ input, output }: { input?: unknown; output?: unknown }) { con
|
|
|
1028
1033
|
{output !== undefined && output !== null ? (
|
|
1029
1034
|
<>
|
|
1030
1035
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
1031
|
-
<span style={{ fontSize:
|
|
1032
|
-
<span style={{ fontSize:
|
|
1036
|
+
<span style={{ fontSize: theme.fontSizes[0], color: '#34d399', fontWeight: 600 }}>OUT</span>
|
|
1037
|
+
<span style={{ fontSize: theme.fontSizes[0], color: '#6b7280' }}>
|
|
1033
1038
|
{typeof output === 'string' ? `${output.length.toLocaleString()} chars` : 'object'}
|
|
1034
1039
|
</span>
|
|
1035
1040
|
</div>
|
|
@@ -1041,6 +1046,7 @@ function ToolIO({ input, output }: { input?: unknown; output?: unknown }) { con
|
|
|
1041
1046
|
}
|
|
1042
1047
|
|
|
1043
1048
|
function CodeBlock({ value }: { value: string }) {
|
|
1049
|
+
const { theme } = useTheme();
|
|
1044
1050
|
return (
|
|
1045
1051
|
<pre
|
|
1046
1052
|
style={{
|
|
@@ -1049,7 +1055,7 @@ function CodeBlock({ value }: { value: string }) {
|
|
|
1049
1055
|
borderRadius: 6,
|
|
1050
1056
|
backgroundColor: '#0b1220',
|
|
1051
1057
|
color: '#9ca3af',
|
|
1052
|
-
fontSize:
|
|
1058
|
+
fontSize: theme.fontSizes[0],
|
|
1053
1059
|
lineHeight: 1.45,
|
|
1054
1060
|
maxHeight: 180,
|
|
1055
1061
|
overflow: 'auto',
|
|
@@ -1063,12 +1069,13 @@ function CodeBlock({ value }: { value: string }) {
|
|
|
1063
1069
|
}
|
|
1064
1070
|
|
|
1065
1071
|
function MetaRows({ rows }: { rows: Array<[string, unknown]> }) {
|
|
1072
|
+
const { theme } = useTheme();
|
|
1066
1073
|
const present = rows.filter(([, v]) => v !== undefined && v !== null && v !== '');
|
|
1067
1074
|
if (present.length === 0) return null;
|
|
1068
1075
|
return (
|
|
1069
1076
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
|
1070
1077
|
{present.map(([label, value]) => (
|
|
1071
|
-
<div key={label} style={{ display: 'flex', gap: 8, fontSize:
|
|
1078
|
+
<div key={label} style={{ display: 'flex', gap: 8, fontSize: theme.fontSizes[0] }}>
|
|
1072
1079
|
<span style={{ color: '#6b7280', minWidth: 76, whiteSpace: 'nowrap' }}>{label}</span>
|
|
1073
1080
|
<span
|
|
1074
1081
|
style={{
|
|
@@ -1382,8 +1389,8 @@ export function SessionEventFeed({ title, rows }: SessionEventFeedProps) {
|
|
|
1382
1389
|
fontFamily: theme.fonts.body,
|
|
1383
1390
|
}}
|
|
1384
1391
|
>
|
|
1385
|
-
<h1 style={{ margin: 0, color: '#f3f4f6', fontSize:
|
|
1386
|
-
<span style={{ color: '#6b7280', fontSize:
|
|
1392
|
+
<h1 style={{ margin: 0, color: '#f3f4f6', fontSize: theme.fontSizes[3], fontWeight: 600 }}>{title}</h1>
|
|
1393
|
+
<span style={{ color: '#6b7280', fontSize: theme.fontSizes[0] }}>
|
|
1387
1394
|
{items.length} raw events · {visibleEvents.length} visible · {expandedCount} expanded
|
|
1388
1395
|
</span>
|
|
1389
1396
|
</div>
|
|
@@ -1456,7 +1463,7 @@ export function SessionEventFeedGrouped({ title, rows }: SessionEventFeedGrouped
|
|
|
1456
1463
|
return (
|
|
1457
1464
|
<div style={{ padding: 24, backgroundColor: '#0d1117', minHeight: '100vh' }}>
|
|
1458
1465
|
{title ? (
|
|
1459
|
-
<h1 style={{ margin: '0 0 12px', color: '#f3f4f6', fontSize:
|
|
1466
|
+
<h1 style={{ margin: '0 0 12px', color: '#f3f4f6', fontSize: theme.fontSizes[3], fontWeight: 600, fontFamily: theme.fonts.body }}>
|
|
1460
1467
|
{title}
|
|
1461
1468
|
</h1>
|
|
1462
1469
|
) : null}
|
|
@@ -1494,10 +1501,10 @@ function GroupSection({
|
|
|
1494
1501
|
fontFamily: theme.fonts.body,
|
|
1495
1502
|
}}
|
|
1496
1503
|
>
|
|
1497
|
-
<span style={{ color: kindColor(kind), fontWeight: 600, fontSize:
|
|
1504
|
+
<span style={{ color: kindColor(kind), fontWeight: 600, fontSize: theme.fontSizes[0] }}>
|
|
1498
1505
|
{kindLabel(kind)}
|
|
1499
1506
|
</span>
|
|
1500
|
-
<span style={{ color: '#6b7280', fontSize:
|
|
1507
|
+
<span style={{ color: '#6b7280', fontSize: theme.fontSizes[0] }}>{group.length}</span>
|
|
1501
1508
|
<span style={{ flex: 1 }} />
|
|
1502
1509
|
<FilterChip label="Expand all" active={false} onClick={() => setAll(false)} />
|
|
1503
1510
|
<FilterChip label="Collapse all" active={false} onClick={() => setAll(true)} />
|
|
@@ -1546,10 +1553,11 @@ function ColumnHeaders() {
|
|
|
1546
1553
|
}
|
|
1547
1554
|
|
|
1548
1555
|
function HeaderLabel({ children }: { children: React.ReactNode }) {
|
|
1556
|
+
const { theme } = useTheme();
|
|
1549
1557
|
return (
|
|
1550
1558
|
<span
|
|
1551
1559
|
style={{
|
|
1552
|
-
fontSize:
|
|
1560
|
+
fontSize: theme.fontSizes[0],
|
|
1553
1561
|
fontWeight: 600,
|
|
1554
1562
|
textTransform: 'uppercase',
|
|
1555
1563
|
letterSpacing: 0.5,
|
|
@@ -1742,7 +1750,7 @@ function EventRow({
|
|
|
1742
1750
|
cursor: 'pointer',
|
|
1743
1751
|
background: copied ? 'rgba(16,185,129,0.12)' : 'transparent',
|
|
1744
1752
|
color: copied ? '#10b981' : theme.colors.textTertiary,
|
|
1745
|
-
fontSize:
|
|
1753
|
+
fontSize: theme.fontSizes[0],
|
|
1746
1754
|
}}
|
|
1747
1755
|
>
|
|
1748
1756
|
{copied ? <Check size={13} /> : <Copy size={13} />}
|
|
@@ -1777,6 +1785,7 @@ function FilterChip({
|
|
|
1777
1785
|
color?: string;
|
|
1778
1786
|
onClick: () => void;
|
|
1779
1787
|
}) {
|
|
1788
|
+
const { theme } = useTheme();
|
|
1780
1789
|
return (
|
|
1781
1790
|
<button
|
|
1782
1791
|
onClick={onClick}
|
|
@@ -1786,7 +1795,7 @@ function FilterChip({
|
|
|
1786
1795
|
border: `1px solid ${active ? color ?? '#3b82f6' : '#1f2937'}`,
|
|
1787
1796
|
backgroundColor: active ? (color ?? '#3b82f6') + '22' : 'transparent',
|
|
1788
1797
|
color: active ? '#f3f4f6' : '#9ca3af',
|
|
1789
|
-
fontSize:
|
|
1798
|
+
fontSize: theme.fontSizes[0],
|
|
1790
1799
|
cursor: 'pointer',
|
|
1791
1800
|
fontFamily: 'inherit',
|
|
1792
1801
|
}}
|
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
|
|
8
8
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
9
9
|
import { File } from '@pierre/diffs/react';
|
|
10
|
+
import {
|
|
11
|
+
getFiletypeFromFileName,
|
|
12
|
+
getHighlighterOptions,
|
|
13
|
+
preloadHighlighter,
|
|
14
|
+
} from '@pierre/diffs';
|
|
10
15
|
import { useTheme } from '@principal-ade/industry-theme';
|
|
11
16
|
import { buildPierreOptions, PIERRE_FILE_STYLE } from './pierreBackground';
|
|
12
17
|
import { pierreLangForPath } from './pierreFileLang';
|
|
@@ -33,6 +38,12 @@ export function PierreFileView({
|
|
|
33
38
|
const { theme } = useTheme();
|
|
34
39
|
const [contents, setContents] = useState<string | null>(null);
|
|
35
40
|
const [error, setError] = useState<string | null>(null);
|
|
41
|
+
// Pierre highlights on the main thread with no worker pool: a cold first
|
|
42
|
+
// render paints an empty <pre> and never re-renders once Shiki resolves.
|
|
43
|
+
// Warm the shared highlighter for this file before mounting <File> so the
|
|
44
|
+
// very first render produces content.
|
|
45
|
+
const [highlighterReady, setHighlighterReady] = useState(false);
|
|
46
|
+
const lang = pierreLangForPath(filePath) ?? getFiletypeFromFileName(fileName);
|
|
36
47
|
|
|
37
48
|
const fileObject = useMemo(
|
|
38
49
|
() =>
|
|
@@ -60,6 +71,21 @@ export function PierreFileView({
|
|
|
60
71
|
};
|
|
61
72
|
}, [filePath, readFile]);
|
|
62
73
|
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
let cancelled = false;
|
|
76
|
+
setHighlighterReady(false);
|
|
77
|
+
void preloadHighlighter(getHighlighterOptions(lang, {}))
|
|
78
|
+
.catch(() => {
|
|
79
|
+
// Fall through: let <File> attempt its own (plain-text) render.
|
|
80
|
+
})
|
|
81
|
+
.then(() => {
|
|
82
|
+
if (!cancelled) setHighlighterReady(true);
|
|
83
|
+
});
|
|
84
|
+
return () => {
|
|
85
|
+
cancelled = true;
|
|
86
|
+
};
|
|
87
|
+
}, [lang]);
|
|
88
|
+
|
|
63
89
|
const onPostRender = useCallback(
|
|
64
90
|
(fileContainer: HTMLElement) => {
|
|
65
91
|
if (focusLine == null) return;
|
|
@@ -83,7 +109,7 @@ export function PierreFileView({
|
|
|
83
109
|
</div>
|
|
84
110
|
);
|
|
85
111
|
}
|
|
86
|
-
if (fileObject === null) {
|
|
112
|
+
if (fileObject === null || !highlighterReady) {
|
|
87
113
|
return (
|
|
88
114
|
<div style={{ padding: 16, color: theme.colors.textSecondary }}>
|
|
89
115
|
Loading…
|
|
@@ -174,18 +174,6 @@ export function ConstructsCatalog({
|
|
|
174
174
|
[onFileSelect],
|
|
175
175
|
);
|
|
176
176
|
|
|
177
|
-
const openComponentSource = useCallback(
|
|
178
|
-
(c: SubsystemComponent) => {
|
|
179
|
-
if (!c.file) return;
|
|
180
|
-
const startLine = c.declarationRef?.startLine;
|
|
181
|
-
onOpenFile(
|
|
182
|
-
c.file,
|
|
183
|
-
startLine != null ? { startLine } : undefined,
|
|
184
|
-
);
|
|
185
|
-
},
|
|
186
|
-
[onOpenFile],
|
|
187
|
-
);
|
|
188
|
-
|
|
189
177
|
const onRelatedSelect = useCallback(
|
|
190
178
|
(ref: string) => {
|
|
191
179
|
const comp = resolveRelated(components, ref);
|
|
@@ -385,7 +373,6 @@ export function ConstructsCatalog({
|
|
|
385
373
|
theme={theme}
|
|
386
374
|
disableScroll={true}
|
|
387
375
|
disableBasePadding
|
|
388
|
-
fontSizeScale={0.9}
|
|
389
376
|
enableKeyboardScrolling={false}
|
|
390
377
|
autoFocusOnVisible={false}
|
|
391
378
|
/>
|
|
@@ -426,6 +413,7 @@ export function ConstructsCatalog({
|
|
|
426
413
|
const focused = c.id === focusedId;
|
|
427
414
|
const color = componentColor(c, pierreTheme);
|
|
428
415
|
const badgeColor = constructBadgeColor(c) ?? color;
|
|
416
|
+
const badgeLabel = constructBadgeLabel(c);
|
|
429
417
|
const displayName = deriveNameFromSymbol(
|
|
430
418
|
c.symbol,
|
|
431
419
|
c.construct,
|
|
@@ -490,73 +478,45 @@ export function ConstructsCatalog({
|
|
|
490
478
|
>
|
|
491
479
|
{displayName}
|
|
492
480
|
</span>
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
481
|
+
{role && roleColor && (
|
|
482
|
+
<span
|
|
483
|
+
style={{
|
|
484
|
+
flexShrink: 0,
|
|
485
|
+
fontFamily: theme.fonts.monospace,
|
|
486
|
+
fontSize: theme.fontSizes[0],
|
|
487
|
+
letterSpacing: 0.4,
|
|
488
|
+
textTransform: 'uppercase',
|
|
489
|
+
color: roleColor,
|
|
490
|
+
}}
|
|
491
|
+
>
|
|
492
|
+
{role}
|
|
493
|
+
</span>
|
|
494
|
+
)}
|
|
505
495
|
</span>
|
|
506
|
-
{
|
|
496
|
+
{badgeLabel && (
|
|
507
497
|
<span
|
|
508
498
|
style={{
|
|
509
499
|
display: 'flex',
|
|
510
500
|
alignItems: 'center',
|
|
511
|
-
gap: 8,
|
|
512
501
|
minWidth: 0,
|
|
513
502
|
}}
|
|
514
503
|
>
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
whiteSpace: 'nowrap',
|
|
532
|
-
fontFamily: theme.fonts.body,
|
|
533
|
-
fontSize: theme.fontSizes[0],
|
|
534
|
-
color: muted,
|
|
535
|
-
cursor: fileViewer ? 'pointer' : undefined,
|
|
536
|
-
textDecoration: fileViewer ? 'underline' : undefined,
|
|
537
|
-
textDecorationStyle: fileViewer ? 'dotted' : undefined,
|
|
538
|
-
textUnderlineOffset: 2,
|
|
539
|
-
}}
|
|
540
|
-
>
|
|
541
|
-
{c.file}
|
|
542
|
-
</span>
|
|
543
|
-
) : (
|
|
544
|
-
<span style={{ flex: 1 }} />
|
|
545
|
-
)}
|
|
546
|
-
{role && roleColor && (
|
|
547
|
-
<span
|
|
548
|
-
style={{
|
|
549
|
-
flexShrink: 0,
|
|
550
|
-
fontFamily: theme.fonts.monospace,
|
|
551
|
-
fontSize: theme.fontSizes[0] * 0.9,
|
|
552
|
-
letterSpacing: 0.4,
|
|
553
|
-
textTransform: 'uppercase',
|
|
554
|
-
color: roleColor,
|
|
555
|
-
}}
|
|
556
|
-
>
|
|
557
|
-
{role}
|
|
558
|
-
</span>
|
|
559
|
-
)}
|
|
504
|
+
<span
|
|
505
|
+
style={{
|
|
506
|
+
flex: 1,
|
|
507
|
+
minWidth: 0,
|
|
508
|
+
overflow: 'hidden',
|
|
509
|
+
textOverflow: 'ellipsis',
|
|
510
|
+
whiteSpace: 'nowrap',
|
|
511
|
+
fontFamily: theme.fonts.monospace,
|
|
512
|
+
fontSize: theme.fontSizes[0],
|
|
513
|
+
letterSpacing: 0.4,
|
|
514
|
+
textTransform: 'uppercase',
|
|
515
|
+
color: badgeColor,
|
|
516
|
+
}}
|
|
517
|
+
>
|
|
518
|
+
{badgeLabel}
|
|
519
|
+
</span>
|
|
560
520
|
</span>
|
|
561
521
|
)}
|
|
562
522
|
</button>
|
|
@@ -123,8 +123,34 @@ export function humanizeIssueKind(kind: string): string {
|
|
|
123
123
|
return spaced.charAt(0).toUpperCase() + spaced.slice(1);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Curated short labels, trimmed of prefixes the grouping already implies
|
|
128
|
+
* (`topology_`, `boundary_`) but kept unambiguous within a layer — so
|
|
129
|
+
* `construct_mismatch` reads "Wrong construct", not a bare "Mismatch" that
|
|
130
|
+
* would collide with `signature_mismatch`. Explicit `issue.kindLabel` wins.
|
|
131
|
+
*/
|
|
132
|
+
const KIND_LABEL: Record<string, string> = {
|
|
133
|
+
missing_file: 'Missing file',
|
|
134
|
+
missing_symbol: 'Missing symbol',
|
|
135
|
+
stale_declaration: 'Stale declaration',
|
|
136
|
+
construct_mismatch: 'Wrong construct',
|
|
137
|
+
construct_unconfirmed: 'Unconfirmed construct',
|
|
138
|
+
signature_mismatch: 'Signature mismatch',
|
|
139
|
+
signature_unconfirmed: 'Signature unconfirmed',
|
|
140
|
+
anchor: 'Anchor',
|
|
141
|
+
unresolved: 'Unresolved',
|
|
142
|
+
topology_broken_endpoint: 'Broken endpoint',
|
|
143
|
+
topology_import_unconfirmed: 'Import unconfirmed',
|
|
144
|
+
topology_relation_unconfirmed: 'Relation unconfirmed',
|
|
145
|
+
boundary_module_without_file: 'Module without file',
|
|
146
|
+
boundary_module_file_mismatch: 'Module file mismatch',
|
|
147
|
+
boundary_process_nest_disagree: 'Process nest disagree',
|
|
148
|
+
walkthrough: 'Step issue',
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/** Label for an issue's kind. Explicit `kindLabel` wins; unknown kinds humanize. */
|
|
126
152
|
export function issueKindLabel(issue: SubsystemIssue): string {
|
|
127
|
-
return issue.kindLabel ?? humanizeIssueKind(issue.kind);
|
|
153
|
+
return issue.kindLabel ?? KIND_LABEL[issue.kind] ?? humanizeIssueKind(issue.kind);
|
|
128
154
|
}
|
|
129
155
|
|
|
130
156
|
export function severityRank(severity: SubsystemIssueSeverity): number {
|
|
@@ -300,7 +326,6 @@ export function SubsystemIssueCard({
|
|
|
300
326
|
flexDirection: 'column',
|
|
301
327
|
gap: 5,
|
|
302
328
|
padding: '9px 12px 10px',
|
|
303
|
-
borderLeft: `3px solid ${color}`,
|
|
304
329
|
borderBottom: `1px solid ${theme.colors.border}`,
|
|
305
330
|
background: hover ? theme.colors.background : 'transparent',
|
|
306
331
|
cursor: 'pointer',
|
|
@@ -308,25 +333,24 @@ export function SubsystemIssueCard({
|
|
|
308
333
|
fontFamily: theme.fonts.body,
|
|
309
334
|
}}
|
|
310
335
|
>
|
|
311
|
-
<div style={{ display: 'flex', alignItems: '
|
|
336
|
+
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 6, minWidth: 0 }}>
|
|
312
337
|
<div
|
|
313
338
|
style={{
|
|
314
339
|
flex: 1,
|
|
315
340
|
minWidth: 0,
|
|
316
341
|
display: 'flex',
|
|
317
|
-
|
|
318
|
-
gap:
|
|
342
|
+
flexDirection: 'column',
|
|
343
|
+
gap: 1,
|
|
319
344
|
}}
|
|
320
345
|
>
|
|
321
346
|
<span
|
|
322
347
|
style={{
|
|
323
|
-
flexShrink: 0,
|
|
324
348
|
fontFamily: theme.fonts.monospace,
|
|
325
|
-
fontSize: theme.fontSizes[0]
|
|
349
|
+
fontSize: theme.fontSizes[0],
|
|
326
350
|
fontWeight: 600,
|
|
327
351
|
letterSpacing: 0.3,
|
|
328
352
|
textTransform: 'uppercase',
|
|
329
|
-
color
|
|
353
|
+
color,
|
|
330
354
|
whiteSpace: 'nowrap',
|
|
331
355
|
}}
|
|
332
356
|
>
|
|
@@ -337,7 +361,7 @@ export function SubsystemIssueCard({
|
|
|
337
361
|
style={{
|
|
338
362
|
minWidth: 0,
|
|
339
363
|
fontFamily: theme.fonts.monospace,
|
|
340
|
-
fontSize: theme.fontSizes[0]
|
|
364
|
+
fontSize: theme.fontSizes[0],
|
|
341
365
|
color: theme.colors.text,
|
|
342
366
|
whiteSpace: 'nowrap',
|
|
343
367
|
overflow: 'hidden',
|
|
@@ -349,7 +373,14 @@ export function SubsystemIssueCard({
|
|
|
349
373
|
</span>
|
|
350
374
|
)}
|
|
351
375
|
</div>
|
|
352
|
-
<span
|
|
376
|
+
<span
|
|
377
|
+
style={{
|
|
378
|
+
display: 'inline-flex',
|
|
379
|
+
color: muted,
|
|
380
|
+
flexShrink: 0,
|
|
381
|
+
marginTop: 1,
|
|
382
|
+
}}
|
|
383
|
+
>
|
|
353
384
|
{expanded ? <ChevronDown size={13} /> : <ChevronRight size={13} />}
|
|
354
385
|
</span>
|
|
355
386
|
</div>
|