spec-gen-cli 1.1.0 → 1.2.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/README.md +163 -77
- package/dist/api/analyze.d.ts.map +1 -1
- package/dist/api/analyze.js +56 -27
- package/dist/api/analyze.js.map +1 -1
- package/dist/api/drift.d.ts.map +1 -1
- package/dist/api/drift.js +26 -20
- package/dist/api/drift.js.map +1 -1
- package/dist/api/generate.d.ts.map +1 -1
- package/dist/api/generate.js +19 -43
- package/dist/api/generate.js.map +1 -1
- package/dist/api/init.d.ts.map +1 -1
- package/dist/api/init.js +6 -5
- package/dist/api/init.js.map +1 -1
- package/dist/api/run.d.ts.map +1 -1
- package/dist/api/run.js +67 -51
- package/dist/api/run.js.map +1 -1
- package/dist/api/specs.d.ts.map +1 -1
- package/dist/api/specs.js +5 -4
- package/dist/api/specs.js.map +1 -1
- package/dist/api/types.d.ts +7 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/verify.d.ts.map +1 -1
- package/dist/api/verify.js +31 -32
- package/dist/api/verify.js.map +1 -1
- package/dist/cli/commands/analyze.d.ts.map +1 -1
- package/dist/cli/commands/analyze.js +41 -62
- package/dist/cli/commands/analyze.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +9 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +273 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/drift.d.ts.map +1 -1
- package/dist/cli/commands/drift.js +18 -32
- package/dist/cli/commands/drift.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +40 -101
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +17 -15
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +3 -2
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/run.d.ts +0 -15
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +61 -111
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/verify.d.ts.map +1 -1
- package/dist/cli/commands/verify.js +18 -52
- package/dist/cli/commands/verify.js.map +1 -1
- package/dist/cli/commands/view.d.ts +4 -0
- package/dist/cli/commands/view.d.ts.map +1 -1
- package/dist/cli/commands/view.js +33 -26
- package/dist/cli/commands/view.js.map +1 -1
- package/dist/cli/index.js +22 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/constants.d.ts +254 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +320 -0
- package/dist/constants.js.map +1 -0
- package/dist/core/analyzer/artifact-generator.d.ts +8 -0
- package/dist/core/analyzer/artifact-generator.d.ts.map +1 -1
- package/dist/core/analyzer/artifact-generator.js +59 -11
- package/dist/core/analyzer/artifact-generator.js.map +1 -1
- package/dist/core/analyzer/call-graph.d.ts.map +1 -1
- package/dist/core/analyzer/call-graph.js +135 -1
- package/dist/core/analyzer/call-graph.js.map +1 -1
- package/dist/core/analyzer/dependency-graph.d.ts +32 -0
- package/dist/core/analyzer/dependency-graph.d.ts.map +1 -1
- package/dist/core/analyzer/dependency-graph.js +104 -10
- package/dist/core/analyzer/dependency-graph.js.map +1 -1
- package/dist/core/analyzer/duplicate-detector.d.ts.map +1 -1
- package/dist/core/analyzer/duplicate-detector.js +4 -0
- package/dist/core/analyzer/duplicate-detector.js.map +1 -1
- package/dist/core/analyzer/embedding-service.d.ts +6 -0
- package/dist/core/analyzer/embedding-service.d.ts.map +1 -1
- package/dist/core/analyzer/embedding-service.js +15 -1
- package/dist/core/analyzer/embedding-service.js.map +1 -1
- package/dist/core/analyzer/file-walker.d.ts.map +1 -1
- package/dist/core/analyzer/file-walker.js +4 -3
- package/dist/core/analyzer/file-walker.js.map +1 -1
- package/dist/core/analyzer/http-route-parser.d.ts +111 -0
- package/dist/core/analyzer/http-route-parser.d.ts.map +1 -0
- package/dist/core/analyzer/http-route-parser.js +466 -0
- package/dist/core/analyzer/http-route-parser.js.map +1 -0
- package/dist/core/analyzer/import-parser.d.ts.map +1 -1
- package/dist/core/analyzer/import-parser.js +19 -5
- package/dist/core/analyzer/import-parser.js.map +1 -1
- package/dist/core/analyzer/refactor-analyzer.d.ts.map +1 -1
- package/dist/core/analyzer/refactor-analyzer.js +8 -7
- package/dist/core/analyzer/refactor-analyzer.js.map +1 -1
- package/dist/core/analyzer/repository-mapper.d.ts.map +1 -1
- package/dist/core/analyzer/repository-mapper.js +12 -13
- package/dist/core/analyzer/repository-mapper.js.map +1 -1
- package/dist/core/analyzer/signature-extractor.d.ts +1 -1
- package/dist/core/analyzer/signature-extractor.d.ts.map +1 -1
- package/dist/core/analyzer/signature-extractor.js +69 -1
- package/dist/core/analyzer/signature-extractor.js.map +1 -1
- package/dist/core/analyzer/spec-vector-index.d.ts.map +1 -1
- package/dist/core/analyzer/spec-vector-index.js +4 -3
- package/dist/core/analyzer/spec-vector-index.js.map +1 -1
- package/dist/core/analyzer/vector-index.d.ts.map +1 -1
- package/dist/core/analyzer/vector-index.js +29 -1
- package/dist/core/analyzer/vector-index.js.map +1 -1
- package/dist/core/drift/drift-detector.d.ts.map +1 -1
- package/dist/core/drift/drift-detector.js +7 -6
- package/dist/core/drift/drift-detector.js.map +1 -1
- package/dist/core/drift/git-diff.d.ts.map +1 -1
- package/dist/core/drift/git-diff.js +28 -16
- package/dist/core/drift/git-diff.js.map +1 -1
- package/dist/core/generator/mapping-generator.d.ts.map +1 -1
- package/dist/core/generator/mapping-generator.js +11 -10
- package/dist/core/generator/mapping-generator.js.map +1 -1
- package/dist/core/generator/openspec-compat.d.ts.map +1 -1
- package/dist/core/generator/openspec-compat.js +3 -2
- package/dist/core/generator/openspec-compat.js.map +1 -1
- package/dist/core/generator/openspec-format-generator.js.map +1 -1
- package/dist/core/generator/openspec-writer.d.ts +0 -4
- package/dist/core/generator/openspec-writer.d.ts.map +1 -1
- package/dist/core/generator/openspec-writer.js +30 -41
- package/dist/core/generator/openspec-writer.js.map +1 -1
- package/dist/core/generator/spec-pipeline.d.ts.map +1 -1
- package/dist/core/generator/spec-pipeline.js +4 -4
- package/dist/core/generator/spec-pipeline.js.map +1 -1
- package/dist/core/generator/stages/stage1-survey.d.ts.map +1 -1
- package/dist/core/generator/stages/stage1-survey.js +5 -3
- package/dist/core/generator/stages/stage1-survey.js.map +1 -1
- package/dist/core/generator/stages/stage2-entities.d.ts.map +1 -1
- package/dist/core/generator/stages/stage2-entities.js +10 -9
- package/dist/core/generator/stages/stage2-entities.js.map +1 -1
- package/dist/core/generator/stages/stage3-services.d.ts.map +1 -1
- package/dist/core/generator/stages/stage3-services.js +9 -8
- package/dist/core/generator/stages/stage3-services.js.map +1 -1
- package/dist/core/generator/stages/stage4-api.d.ts.map +1 -1
- package/dist/core/generator/stages/stage4-api.js +10 -9
- package/dist/core/generator/stages/stage4-api.js.map +1 -1
- package/dist/core/generator/stages/stage5-architecture.d.ts.map +1 -1
- package/dist/core/generator/stages/stage5-architecture.js +5 -4
- package/dist/core/generator/stages/stage5-architecture.js.map +1 -1
- package/dist/core/generator/stages/stage6-adr.d.ts.map +1 -1
- package/dist/core/generator/stages/stage6-adr.js +7 -2
- package/dist/core/generator/stages/stage6-adr.js.map +1 -1
- package/dist/core/services/chat-agent.d.ts.map +1 -1
- package/dist/core/services/chat-agent.js +46 -15
- package/dist/core/services/chat-agent.js.map +1 -1
- package/dist/core/services/config-manager.d.ts.map +1 -1
- package/dist/core/services/config-manager.js +32 -26
- package/dist/core/services/config-manager.js.map +1 -1
- package/dist/core/services/gitignore-manager.d.ts.map +1 -1
- package/dist/core/services/gitignore-manager.js +2 -13
- package/dist/core/services/gitignore-manager.js.map +1 -1
- package/dist/core/services/llm-service.d.ts.map +1 -1
- package/dist/core/services/llm-service.js +33 -35
- package/dist/core/services/llm-service.js.map +1 -1
- package/dist/core/services/mcp-handlers/analysis.d.ts.map +1 -1
- package/dist/core/services/mcp-handlers/analysis.js +23 -14
- package/dist/core/services/mcp-handlers/analysis.js.map +1 -1
- package/dist/core/services/mcp-handlers/graph.d.ts.map +1 -1
- package/dist/core/services/mcp-handlers/graph.js +24 -23
- package/dist/core/services/mcp-handlers/graph.js.map +1 -1
- package/dist/core/services/mcp-handlers/semantic.d.ts +1 -1
- package/dist/core/services/mcp-handlers/semantic.d.ts.map +1 -1
- package/dist/core/services/mcp-handlers/semantic.js +17 -16
- package/dist/core/services/mcp-handlers/semantic.js.map +1 -1
- package/dist/core/services/mcp-handlers/utils.d.ts.map +1 -1
- package/dist/core/services/mcp-handlers/utils.js +4 -3
- package/dist/core/services/mcp-handlers/utils.js.map +1 -1
- package/dist/core/services/project-detector.d.ts.map +1 -1
- package/dist/core/services/project-detector.js +2 -13
- package/dist/core/services/project-detector.js.map +1 -1
- package/dist/core/verifier/verification-engine.d.ts +9 -3
- package/dist/core/verifier/verification-engine.d.ts.map +1 -1
- package/dist/core/verifier/verification-engine.js +25 -13
- package/dist/core/verifier/verification-engine.js.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/command-helpers.d.ts +38 -0
- package/dist/utils/command-helpers.d.ts.map +1 -0
- package/dist/utils/command-helpers.js +82 -0
- package/dist/utils/command-helpers.js.map +1 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +4 -3
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +14 -3
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/progress.d.ts +1 -1
- package/dist/utils/progress.d.ts.map +1 -1
- package/dist/utils/progress.js +15 -12
- package/dist/utils/progress.js.map +1 -1
- package/dist/utils/shutdown.d.ts.map +1 -1
- package/dist/utils/shutdown.js +4 -3
- package/dist/utils/shutdown.js.map +1 -1
- package/package.json +9 -5
- package/src/viewer/InteractiveGraphViewer.jsx +182 -139
- package/src/viewer/components/ArchitectureView.jsx +19 -19
- package/src/viewer/components/ChatPanel.jsx +40 -40
- package/src/viewer/components/ClusterGraph.jsx +34 -22
- package/src/viewer/components/FilterBar.jsx +26 -26
- package/src/viewer/components/FlatGraph.jsx +22 -15
- package/src/viewer/components/MicroComponents.jsx +14 -12
- package/src/viewer/utils/constants.js +17 -0
- package/src/viewer/utils/graph-helpers.js +7 -3
- package/src/viewer/utils/graph-helpers.test.ts +39 -0
- package/src/viewer/utils/themes.js +170 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
|
|
2
|
-
import { extColor } from './utils/constants.js';
|
|
2
|
+
import { extColor, CLUSTER_PALETTE, CLUSTER_PALETTE_LIGHT } from './utils/constants.js';
|
|
3
3
|
import {
|
|
4
4
|
parseSpecRequirements,
|
|
5
5
|
buildMappingIndex,
|
|
@@ -14,9 +14,10 @@ import { FilterBar } from './components/FilterBar.jsx';
|
|
|
14
14
|
import { ArchitectureView } from './components/ArchitectureView.jsx';
|
|
15
15
|
import { Hint, SL, Row, Chip, KindBadge } from './components/MicroComponents.jsx';
|
|
16
16
|
import { ChatPanel } from './components/ChatPanel.jsx';
|
|
17
|
+
import { THEMES, THEME_KEYS, DEFAULT_THEME } from './utils/themes.js';
|
|
17
18
|
|
|
18
19
|
export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '/api/spec' }) {
|
|
19
|
-
const [
|
|
20
|
+
const [rawGraph, setRawGraph] = useState(null);
|
|
20
21
|
const [llmCtx, setLlmCtx] = useState(null);
|
|
21
22
|
const [refReport, setRefReport] = useState(null);
|
|
22
23
|
const [mapping, setMapping] = useState(null);
|
|
@@ -42,6 +43,24 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
42
43
|
});
|
|
43
44
|
const [loaded, setLoaded] = useState(false);
|
|
44
45
|
const [chatOpen, setChatOpen] = useState(false);
|
|
46
|
+
const [themeName, setThemeName] = useState(
|
|
47
|
+
() => localStorage.getItem('spec-gen-theme') || DEFAULT_THEME
|
|
48
|
+
);
|
|
49
|
+
const theme = THEMES[themeName] ?? THEMES[DEFAULT_THEME];
|
|
50
|
+
const clusterPalette = themeName === 'light' ? CLUSTER_PALETTE_LIGHT : CLUSTER_PALETTE;
|
|
51
|
+
|
|
52
|
+
// Derive graph from raw data — recomputes automatically when theme, refReport or raw data changes.
|
|
53
|
+
const graph = useMemo(() => {
|
|
54
|
+
if (!rawGraph) return null;
|
|
55
|
+
const g = parseGraph(rawGraph, clusterPalette);
|
|
56
|
+
return refReport ? enrichGraphWithRefactors(g, refReport) : g;
|
|
57
|
+
}, [rawGraph, clusterPalette, refReport]);
|
|
58
|
+
const cycleTheme = () => setThemeName((prev) => {
|
|
59
|
+
const idx = THEME_KEYS.indexOf(prev);
|
|
60
|
+
const next = THEME_KEYS[(idx + 1) % THEME_KEYS.length];
|
|
61
|
+
localStorage.setItem('spec-gen-theme', next);
|
|
62
|
+
return next;
|
|
63
|
+
});
|
|
45
64
|
const fileRef = useRef();
|
|
46
65
|
const hasAutoLoadedRef = useRef(false);
|
|
47
66
|
|
|
@@ -52,8 +71,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
52
71
|
const loadGraph = useCallback(
|
|
53
72
|
(jsonStr) => {
|
|
54
73
|
try {
|
|
55
|
-
|
|
56
|
-
setGraph(refReport ? enrichGraphWithRefactors(g, refReport) : g);
|
|
74
|
+
setRawGraph(JSON.parse(jsonStr));
|
|
57
75
|
setSelectedId(null);
|
|
58
76
|
setAffectedIds([]);
|
|
59
77
|
setFocusedIds([]);
|
|
@@ -70,7 +88,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
70
88
|
alert('Invalid JSON: ' + e.message);
|
|
71
89
|
}
|
|
72
90
|
},
|
|
73
|
-
[
|
|
91
|
+
[]
|
|
74
92
|
);
|
|
75
93
|
|
|
76
94
|
const loadMapping = useCallback((jsonStr) => {
|
|
@@ -109,7 +127,6 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
109
127
|
if (refRes.ok) {
|
|
110
128
|
const report = await refRes.json();
|
|
111
129
|
setRefReport(report);
|
|
112
|
-
setGraph((g) => (g ? enrichGraphWithRefactors(g, report) : g));
|
|
113
130
|
}
|
|
114
131
|
} catch { /* ignore */ }
|
|
115
132
|
|
|
@@ -283,14 +300,14 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
283
300
|
});
|
|
284
301
|
}
|
|
285
302
|
|
|
286
|
-
//
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
setSelectedId(
|
|
290
|
-
setAffectedIds(
|
|
303
|
+
// If exactly one node matched, auto-select it for details — but skip blast radius
|
|
304
|
+
// to avoid lighting up unrelated edges through the full reachability set.
|
|
305
|
+
if (validNodeIds.length === 1) {
|
|
306
|
+
setSelectedId(validNodeIds[0]);
|
|
307
|
+
setAffectedIds([]);
|
|
291
308
|
setTab(mapping ? 'spec' : 'node');
|
|
292
309
|
}
|
|
293
|
-
}, [focusedIds, graph,
|
|
310
|
+
}, [focusedIds, graph, mapping]);
|
|
294
311
|
|
|
295
312
|
const selectedNode = graph?.nodes.find((n) => n.id === selectedId);
|
|
296
313
|
|
|
@@ -320,32 +337,38 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
320
337
|
}, [selectedId, affectedIds, visibleEdges]);
|
|
321
338
|
|
|
322
339
|
const stats = graph?.statistics || {};
|
|
323
|
-
|
|
340
|
+
// Use structuralClusters (clusters with real internal edges) for all UI.
|
|
341
|
+
// Compute from clusters if not present in the JSON (for backward compatibility).
|
|
342
|
+
const structuralClusters = graph?.structuralClusters ??
|
|
343
|
+
(graph?.clusters?.filter(c => c.internalEdges > 0) ?? []);
|
|
344
|
+
const displayClusters = structuralClusters;
|
|
345
|
+
const clusterNames = displayClusters.map((c) => c.name);
|
|
324
346
|
|
|
325
347
|
// ── Upload screen ─────────────────────────────────────────────────────────
|
|
326
348
|
if (!graph)
|
|
327
349
|
return (
|
|
328
350
|
<div
|
|
329
351
|
style={{
|
|
352
|
+
...theme.vars,
|
|
330
353
|
width: '100%',
|
|
331
354
|
height: '100vh',
|
|
332
|
-
background: '
|
|
355
|
+
background: 'var(--bg-base)',
|
|
333
356
|
display: 'flex',
|
|
334
357
|
flexDirection: 'column',
|
|
335
358
|
alignItems: 'center',
|
|
336
359
|
justifyContent: 'center',
|
|
337
360
|
fontFamily: "'JetBrains Mono',monospace",
|
|
338
|
-
color: '
|
|
361
|
+
color: 'var(--tx-primary)',
|
|
339
362
|
opacity: loaded ? 1 : 0,
|
|
340
363
|
transition: 'opacity 0.3s',
|
|
341
364
|
}}
|
|
342
365
|
>
|
|
343
|
-
<div style={{ fontSize: 10, letterSpacing: '0.18em', color: '
|
|
366
|
+
<div style={{ fontSize: 10, letterSpacing: '0.18em', color: 'var(--tx-faint)', marginBottom: 28 }}>
|
|
344
367
|
INTERACTIVE GRAPH VIEWER
|
|
345
368
|
</div>
|
|
346
369
|
<div
|
|
347
370
|
style={{
|
|
348
|
-
border: '1px dashed
|
|
371
|
+
border: '1px dashed var(--ac-edge-type)',
|
|
349
372
|
borderRadius: 12,
|
|
350
373
|
padding: '44px 64px',
|
|
351
374
|
textAlign: 'center',
|
|
@@ -363,11 +386,11 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
363
386
|
}
|
|
364
387
|
}}
|
|
365
388
|
>
|
|
366
|
-
<div style={{ fontSize: 32, marginBottom: 14, color: '
|
|
367
|
-
<div style={{ fontSize: 12, color: '
|
|
368
|
-
Drop a <code style={{ color: '
|
|
389
|
+
<div style={{ fontSize: 32, marginBottom: 14, color: 'var(--ac-primary)' }}>⬡</div>
|
|
390
|
+
<div style={{ fontSize: 12, color: 'var(--tx-secondary)', marginBottom: 6 }}>
|
|
391
|
+
Drop a <code style={{ color: 'var(--ac-primary)' }}>dependency-graph.json</code>
|
|
369
392
|
</div>
|
|
370
|
-
<div style={{ fontSize: 10, color: '
|
|
393
|
+
<div style={{ fontSize: 10, color: 'var(--tx-ghost)' }}>or click to browse</div>
|
|
371
394
|
</div>
|
|
372
395
|
<input
|
|
373
396
|
ref={fileRef}
|
|
@@ -411,11 +434,12 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
411
434
|
return (
|
|
412
435
|
<div
|
|
413
436
|
style={{
|
|
437
|
+
...theme.vars,
|
|
414
438
|
width: '100%',
|
|
415
439
|
height: '100vh',
|
|
416
|
-
background: '
|
|
440
|
+
background: 'var(--bg-base)',
|
|
417
441
|
fontFamily: "'JetBrains Mono',monospace",
|
|
418
|
-
color: '
|
|
442
|
+
color: 'var(--tx-primary)',
|
|
419
443
|
display: 'flex',
|
|
420
444
|
flexDirection: 'column',
|
|
421
445
|
opacity: loaded ? 1 : 0,
|
|
@@ -429,8 +453,8 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
429
453
|
alignItems: 'center',
|
|
430
454
|
gap: 10,
|
|
431
455
|
padding: '8px 18px',
|
|
432
|
-
borderBottom: '1px solid
|
|
433
|
-
background: '
|
|
456
|
+
borderBottom: '1px solid var(--bd-faint)',
|
|
457
|
+
background: 'var(--bg-panel)',
|
|
434
458
|
flexShrink: 0,
|
|
435
459
|
}}
|
|
436
460
|
>
|
|
@@ -440,12 +464,12 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
440
464
|
width: 6,
|
|
441
465
|
height: 6,
|
|
442
466
|
borderRadius: '50%',
|
|
443
|
-
background: '
|
|
444
|
-
boxShadow: '0 0 8px
|
|
467
|
+
background: 'var(--ac-primary)',
|
|
468
|
+
boxShadow: '0 0 8px var(--ac-primary)',
|
|
445
469
|
}}
|
|
446
470
|
/>
|
|
447
471
|
<span
|
|
448
|
-
style={{ fontSize: 10, fontWeight: 700, color: '
|
|
472
|
+
style={{ fontSize: 10, fontWeight: 700, color: 'var(--tx-bright)', letterSpacing: '0.09em' }}
|
|
449
473
|
>
|
|
450
474
|
GRAPH VIEWER
|
|
451
475
|
</span>
|
|
@@ -453,20 +477,20 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
453
477
|
{[
|
|
454
478
|
['nodes', stats.nodeCount],
|
|
455
479
|
['edges', stats.edgeCount],
|
|
456
|
-
['clusters', stats.
|
|
480
|
+
['clusters', stats.structuralClusterCount ?? displayClusters.length],
|
|
457
481
|
].map(([l, v]) => (
|
|
458
482
|
<div
|
|
459
483
|
key={l}
|
|
460
484
|
style={{
|
|
461
485
|
fontSize: 9,
|
|
462
|
-
color: '
|
|
463
|
-
background: '
|
|
486
|
+
color: 'var(--tx-dim)',
|
|
487
|
+
background: 'var(--bg-raised)',
|
|
464
488
|
borderRadius: 4,
|
|
465
489
|
padding: '2px 7px',
|
|
466
|
-
border: '1px solid
|
|
490
|
+
border: '1px solid var(--bd-muted)',
|
|
467
491
|
}}
|
|
468
492
|
>
|
|
469
|
-
<span style={{ color: '
|
|
493
|
+
<span style={{ color: 'var(--tx-muted)' }}>{v}</span> {l}
|
|
470
494
|
</div>
|
|
471
495
|
))}
|
|
472
496
|
<div style={{ display: 'flex', gap: 2, marginLeft: 8 }}>
|
|
@@ -485,10 +509,10 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
485
509
|
style={{
|
|
486
510
|
padding: '3px 10px',
|
|
487
511
|
fontSize: 9,
|
|
488
|
-
background: viewMode === v ? '
|
|
489
|
-
border: `1px solid ${viewMode === v ? '
|
|
512
|
+
background: viewMode === v ? 'var(--bg-select)' : 'transparent',
|
|
513
|
+
border: `1px solid ${viewMode === v ? 'var(--ac-primary)' : 'var(--bd-muted)'}`,
|
|
490
514
|
borderRadius: 4,
|
|
491
|
-
color: viewMode === v ? '
|
|
515
|
+
color: viewMode === v ? 'var(--tx-primary)' : 'var(--tx-ghost)',
|
|
492
516
|
cursor: 'pointer',
|
|
493
517
|
fontFamily: 'inherit',
|
|
494
518
|
}}
|
|
@@ -503,9 +527,9 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
503
527
|
onChange={(e) => handleSearch(e.target.value)}
|
|
504
528
|
placeholder="search name, path, export, tag..."
|
|
505
529
|
style={{
|
|
506
|
-
background: '
|
|
507
|
-
border: '1px solid
|
|
508
|
-
color: '
|
|
530
|
+
background: 'var(--bg-input)',
|
|
531
|
+
border: '1px solid var(--bd-muted)',
|
|
532
|
+
color: 'var(--tx-primary)',
|
|
509
533
|
padding: '5px 12px 5px 26px',
|
|
510
534
|
borderRadius: 5,
|
|
511
535
|
fontSize: 9,
|
|
@@ -521,7 +545,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
521
545
|
top: '50%',
|
|
522
546
|
transform: 'translateY(-50%)',
|
|
523
547
|
fontSize: 11,
|
|
524
|
-
color: '
|
|
548
|
+
color: 'var(--tx-ghost)',
|
|
525
549
|
}}
|
|
526
550
|
>
|
|
527
551
|
⌕
|
|
@@ -535,7 +559,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
535
559
|
top: '50%',
|
|
536
560
|
transform: 'translateY(-50%)',
|
|
537
561
|
fontSize: 10,
|
|
538
|
-
color: '
|
|
562
|
+
color: 'var(--tx-ghost)',
|
|
539
563
|
cursor: 'pointer',
|
|
540
564
|
lineHeight: 1,
|
|
541
565
|
}}
|
|
@@ -551,7 +575,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
551
575
|
top: '50%',
|
|
552
576
|
transform: 'translateY(-50%)',
|
|
553
577
|
fontSize: 9,
|
|
554
|
-
color: '
|
|
578
|
+
color: 'var(--ac-primary)',
|
|
555
579
|
}}
|
|
556
580
|
>
|
|
557
581
|
{focusedIds.length}
|
|
@@ -565,16 +589,16 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
565
589
|
right: 0,
|
|
566
590
|
marginTop: 4,
|
|
567
591
|
width: 280,
|
|
568
|
-
background: '
|
|
569
|
-
border: '1px solid
|
|
592
|
+
background: 'var(--bg-input)',
|
|
593
|
+
border: '1px solid var(--bd-muted)',
|
|
570
594
|
borderRadius: 5,
|
|
571
595
|
zIndex: 100,
|
|
572
596
|
boxShadow: '0 4px 16px rgba(0,0,0,0.5)',
|
|
573
597
|
overflow: 'hidden',
|
|
574
598
|
}}
|
|
575
599
|
>
|
|
576
|
-
<div style={{ padding: '4px 8px', borderBottom: '1px solid
|
|
577
|
-
semantic matches
|
|
600
|
+
<div style={{ padding: '4px 8px', borderBottom: '1px solid var(--bd-muted)', fontSize: 8, color: 'var(--tx-ghost)', fontFamily: 'inherit' }}>
|
|
601
|
+
✦ semantic matches
|
|
578
602
|
</div>
|
|
579
603
|
{semanticResults.map((r) => {
|
|
580
604
|
const node = graph?.nodes.find((n) => n.path === r.filePath || n.path.endsWith(r.filePath) || r.filePath.endsWith(n.path));
|
|
@@ -585,20 +609,20 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
585
609
|
style={{
|
|
586
610
|
padding: '5px 8px',
|
|
587
611
|
cursor: node ? 'pointer' : 'default',
|
|
588
|
-
borderBottom: '1px solid
|
|
612
|
+
borderBottom: '1px solid var(--bd-faint)',
|
|
589
613
|
display: 'flex',
|
|
590
614
|
flexDirection: 'column',
|
|
591
615
|
gap: 2,
|
|
592
616
|
opacity: node ? 1 : 0.4,
|
|
593
617
|
}}
|
|
594
|
-
onMouseEnter={(e) => { if (node) e.currentTarget.style.background = '
|
|
618
|
+
onMouseEnter={(e) => { if (node) e.currentTarget.style.background = 'var(--bg-hover)'; }}
|
|
595
619
|
onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}
|
|
596
620
|
>
|
|
597
621
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
598
|
-
<span style={{ fontSize: 9, color: '
|
|
599
|
-
<span style={{ fontSize: 8, color: '
|
|
622
|
+
<span style={{ fontSize: 9, color: 'var(--tx-primary)', fontFamily: "'JetBrains Mono',monospace" }}>{r.name}</span>
|
|
623
|
+
<span style={{ fontSize: 8, color: 'var(--tx-dim)', fontFamily: 'inherit' }}>{(1 - r.score).toFixed(2)}</span>
|
|
600
624
|
</div>
|
|
601
|
-
<span style={{ fontSize: 8, color: '
|
|
625
|
+
<span style={{ fontSize: 8, color: 'var(--tx-ghost)', fontFamily: 'inherit', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
602
626
|
{r.filePath.split('/').slice(-2).join('/')}
|
|
603
627
|
</span>
|
|
604
628
|
</div>
|
|
@@ -609,14 +633,14 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
609
633
|
</div>
|
|
610
634
|
<button
|
|
611
635
|
onClick={() => {
|
|
612
|
-
|
|
636
|
+
setRawGraph(null);
|
|
613
637
|
setSelectedId(null);
|
|
614
638
|
}}
|
|
615
639
|
style={{
|
|
616
640
|
background: 'none',
|
|
617
|
-
border: '1px solid
|
|
641
|
+
border: '1px solid var(--bd-muted)',
|
|
618
642
|
borderRadius: 4,
|
|
619
|
-
color: '
|
|
643
|
+
color: 'var(--tx-ghost)',
|
|
620
644
|
fontSize: 8,
|
|
621
645
|
padding: '3px 8px',
|
|
622
646
|
cursor: 'pointer',
|
|
@@ -629,10 +653,10 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
629
653
|
<button
|
|
630
654
|
onClick={() => mappingRef.current.click()}
|
|
631
655
|
style={{
|
|
632
|
-
background: mapping ? '
|
|
633
|
-
border: `1px solid ${mapping ? '
|
|
656
|
+
background: mapping ? 'var(--bg-select)' : 'none',
|
|
657
|
+
border: `1px solid ${mapping ? 'var(--ac-teal)' : 'var(--bd-muted)'}`,
|
|
634
658
|
borderRadius: 4,
|
|
635
|
-
color: mapping ? '
|
|
659
|
+
color: mapping ? 'var(--ac-teal)' : 'var(--tx-ghost)',
|
|
636
660
|
fontSize: 8,
|
|
637
661
|
padding: '3px 8px',
|
|
638
662
|
cursor: 'pointer',
|
|
@@ -646,10 +670,10 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
646
670
|
<button
|
|
647
671
|
onClick={() => specRef.current.click()}
|
|
648
672
|
style={{
|
|
649
|
-
background: Object.keys(specReqs).length ? '
|
|
650
|
-
border: `1px solid ${Object.keys(specReqs).length ? '
|
|
673
|
+
background: Object.keys(specReqs).length ? 'var(--bg-select)' : 'none',
|
|
674
|
+
border: `1px solid ${Object.keys(specReqs).length ? 'var(--ac-primary)' : 'var(--bd-muted)'}`,
|
|
651
675
|
borderRadius: 4,
|
|
652
|
-
color: Object.keys(specReqs).length ? '
|
|
676
|
+
color: Object.keys(specReqs).length ? 'var(--ac-primary)' : 'var(--tx-ghost)',
|
|
653
677
|
fontSize: 8,
|
|
654
678
|
padding: '3px 8px',
|
|
655
679
|
cursor: 'pointer',
|
|
@@ -663,10 +687,10 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
663
687
|
<button
|
|
664
688
|
onClick={() => setChatOpen((v) => !v)}
|
|
665
689
|
style={{
|
|
666
|
-
background: chatOpen ? '
|
|
667
|
-
border: `1px solid ${chatOpen ? '
|
|
690
|
+
background: chatOpen ? 'var(--bg-select)' : 'none',
|
|
691
|
+
border: `1px solid ${chatOpen ? 'var(--ac-primary)' : 'var(--bd-muted)'}`,
|
|
668
692
|
borderRadius: 4,
|
|
669
|
-
color: chatOpen ? '
|
|
693
|
+
color: chatOpen ? 'var(--ac-primary)' : 'var(--tx-ghost)',
|
|
670
694
|
fontSize: 8,
|
|
671
695
|
padding: '3px 8px',
|
|
672
696
|
cursor: 'pointer',
|
|
@@ -677,6 +701,23 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
677
701
|
>
|
|
678
702
|
CHAT
|
|
679
703
|
</button>
|
|
704
|
+
<button
|
|
705
|
+
onClick={cycleTheme}
|
|
706
|
+
title="Cycle theme"
|
|
707
|
+
style={{
|
|
708
|
+
background: 'none',
|
|
709
|
+
border: '1px solid var(--bd-muted)',
|
|
710
|
+
borderRadius: 4,
|
|
711
|
+
color: 'var(--ac-primary)',
|
|
712
|
+
fontSize: 8,
|
|
713
|
+
padding: '3px 8px',
|
|
714
|
+
cursor: 'pointer',
|
|
715
|
+
fontFamily: 'inherit',
|
|
716
|
+
letterSpacing: '0.06em',
|
|
717
|
+
}}
|
|
718
|
+
>
|
|
719
|
+
{theme.label}
|
|
720
|
+
</button>
|
|
680
721
|
<input
|
|
681
722
|
ref={mappingRef}
|
|
682
723
|
type="file"
|
|
@@ -723,7 +764,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
723
764
|
<ArchitectureView graph={graph} llmCtx={llmCtx} focusedIds={focusedIds} />
|
|
724
765
|
) : viewMode === 'clusters' ? (
|
|
725
766
|
<ClusterGraph
|
|
726
|
-
clusters={
|
|
767
|
+
clusters={displayClusters.filter(
|
|
727
768
|
(cl) => !filters.cluster || cl.name === filters.cluster
|
|
728
769
|
)}
|
|
729
770
|
edges={visibleEdges}
|
|
@@ -740,6 +781,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
740
781
|
affectedIds={affectedIds}
|
|
741
782
|
linkedIds={linkedIds}
|
|
742
783
|
focusedIds={focusedIds}
|
|
784
|
+
noGlow={themeName === 'light' || themeName === 'warm'}
|
|
743
785
|
/>
|
|
744
786
|
) : (
|
|
745
787
|
<FlatGraph
|
|
@@ -751,6 +793,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
751
793
|
onSelect={handleSelect}
|
|
752
794
|
refactorOnly={filters.refactorOnly}
|
|
753
795
|
linkedIds={linkedIds}
|
|
796
|
+
noGlow={themeName === 'light' || themeName === 'warm'}
|
|
754
797
|
/>
|
|
755
798
|
)}
|
|
756
799
|
{!selectedId && (
|
|
@@ -761,7 +804,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
761
804
|
left: '50%',
|
|
762
805
|
transform: 'translateX(-50%)',
|
|
763
806
|
fontSize: 9,
|
|
764
|
-
color: '
|
|
807
|
+
color: 'var(--bd-edge)',
|
|
765
808
|
letterSpacing: '0.1em',
|
|
766
809
|
pointerEvents: 'none',
|
|
767
810
|
whiteSpace: 'nowrap',
|
|
@@ -786,15 +829,15 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
786
829
|
<div
|
|
787
830
|
style={{
|
|
788
831
|
width: 282,
|
|
789
|
-
borderLeft: '1px solid
|
|
790
|
-
background: '
|
|
832
|
+
borderLeft: '1px solid var(--bd-faint)',
|
|
833
|
+
background: 'var(--bg-deep)',
|
|
791
834
|
display: viewMode === 'architecture' ? 'none' : 'flex',
|
|
792
835
|
flexDirection: 'column',
|
|
793
836
|
overflow: 'hidden',
|
|
794
837
|
flexShrink: 0,
|
|
795
838
|
}}
|
|
796
839
|
>
|
|
797
|
-
<div style={{ display: 'flex', borderBottom: '1px solid
|
|
840
|
+
<div style={{ display: 'flex', borderBottom: '1px solid var(--bd-faint)', flexShrink: 0 }}>
|
|
798
841
|
{['node', 'links', 'blast', 'spec', 'skeleton', 'info'].map((t) => (
|
|
799
842
|
<button
|
|
800
843
|
key={t}
|
|
@@ -804,8 +847,8 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
804
847
|
padding: '7px 0',
|
|
805
848
|
background: 'none',
|
|
806
849
|
border: 'none',
|
|
807
|
-
borderBottom: tab === t ? '2px solid
|
|
808
|
-
color: tab === t ? '
|
|
850
|
+
borderBottom: tab === t ? '2px solid var(--ac-primary)' : '2px solid transparent',
|
|
851
|
+
color: tab === t ? 'var(--tx-primary)' : 'var(--tx-ghost)',
|
|
809
852
|
fontSize: 8,
|
|
810
853
|
letterSpacing: '0.06em',
|
|
811
854
|
fontWeight: 700,
|
|
@@ -824,13 +867,13 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
824
867
|
{tab === 'node' && !selectedNode && <Hint>Select a node to inspect it.</Hint>}
|
|
825
868
|
{tab === 'node' && selectedNode && (
|
|
826
869
|
<div>
|
|
827
|
-
<div style={{ fontSize: 12, fontWeight: 700, color: '
|
|
870
|
+
<div style={{ fontSize: 12, fontWeight: 700, color: 'var(--tx-bright)', marginBottom: 2 }}>
|
|
828
871
|
{selectedNode.label}
|
|
829
872
|
</div>
|
|
830
873
|
<div
|
|
831
874
|
style={{
|
|
832
875
|
fontSize: 8,
|
|
833
|
-
color: '
|
|
876
|
+
color: 'var(--tx-ghost)',
|
|
834
877
|
marginBottom: 9,
|
|
835
878
|
wordBreak: 'break-all',
|
|
836
879
|
lineHeight: 1.7,
|
|
@@ -847,7 +890,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
847
890
|
<Row
|
|
848
891
|
label="score"
|
|
849
892
|
value={
|
|
850
|
-
<span style={{ color: '
|
|
893
|
+
<span style={{ color: 'var(--ac-primary)', fontWeight: 700 }}>{selectedNode.score}</span>
|
|
851
894
|
}
|
|
852
895
|
/>
|
|
853
896
|
<Row
|
|
@@ -877,12 +920,12 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
877
920
|
gap: 5,
|
|
878
921
|
alignItems: 'center',
|
|
879
922
|
padding: '3px 0',
|
|
880
|
-
borderBottom: '1px solid
|
|
923
|
+
borderBottom: '1px solid var(--bd-faint)',
|
|
881
924
|
}}
|
|
882
925
|
>
|
|
883
926
|
<KindBadge kind={ex.kind} />
|
|
884
|
-
<span style={{ fontSize: 9, color: '
|
|
885
|
-
<span style={{ marginLeft: 'auto', fontSize: 8, color: '
|
|
927
|
+
<span style={{ fontSize: 9, color: 'var(--tx-secondary)' }}>{ex.name}</span>
|
|
928
|
+
<span style={{ marginLeft: 'auto', fontSize: 8, color: 'var(--tx-faint)' }}>
|
|
886
929
|
L{ex.line}
|
|
887
930
|
</span>
|
|
888
931
|
</div>
|
|
@@ -948,7 +991,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
948
991
|
<>
|
|
949
992
|
<SL>Imports ({outEdges.length})</SL>
|
|
950
993
|
{outEdges.length === 0 && (
|
|
951
|
-
<div style={{ color: '
|
|
994
|
+
<div style={{ color: 'var(--tx-faint)', fontSize: 9 }}>No imports.</div>
|
|
952
995
|
)}
|
|
953
996
|
{outEdges.map((e, i) => {
|
|
954
997
|
const tn = graph.nodes.find((n) => n.id === e.target);
|
|
@@ -959,9 +1002,9 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
959
1002
|
style={{
|
|
960
1003
|
padding: '5px 7px',
|
|
961
1004
|
marginBottom: 3,
|
|
962
|
-
background: '
|
|
1005
|
+
background: 'var(--bg-input)',
|
|
963
1006
|
borderRadius: 4,
|
|
964
|
-
border: `1px solid ${tn?.cluster.color || '
|
|
1007
|
+
border: `1px solid ${tn?.cluster.color || 'var(--bd-muted)'}22`,
|
|
965
1008
|
cursor: 'pointer',
|
|
966
1009
|
}}
|
|
967
1010
|
>
|
|
@@ -974,17 +1017,17 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
974
1017
|
}}
|
|
975
1018
|
>
|
|
976
1019
|
<span style={{ fontSize: 8, color: extColor(tn?.ext || '') }}>↗</span>
|
|
977
|
-
<span style={{ fontSize: 9, color: '
|
|
1020
|
+
<span style={{ fontSize: 9, color: 'var(--tx-primary)' }}>
|
|
978
1021
|
{tn?.label || e.target}
|
|
979
1022
|
</span>
|
|
980
1023
|
{e.isType && (
|
|
981
|
-
<span style={{ fontSize: 7, color: '
|
|
1024
|
+
<span style={{ fontSize: 7, color: 'var(--tx-ghost)', marginLeft: 'auto' }}>
|
|
982
1025
|
type
|
|
983
1026
|
</span>
|
|
984
1027
|
)}
|
|
985
1028
|
</div>
|
|
986
1029
|
{e.importedNames.length > 0 && (
|
|
987
|
-
<div style={{ fontSize: 7.5, color: '
|
|
1030
|
+
<div style={{ fontSize: 7.5, color: 'var(--tx-dim)', paddingLeft: 12 }}>
|
|
988
1031
|
{e.importedNames.join(', ')}
|
|
989
1032
|
</div>
|
|
990
1033
|
)}
|
|
@@ -993,7 +1036,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
993
1036
|
})}
|
|
994
1037
|
<SL>Imported by ({inEdges.length})</SL>
|
|
995
1038
|
{inEdges.length === 0 && (
|
|
996
|
-
<div style={{ color: '
|
|
1039
|
+
<div style={{ color: 'var(--tx-faint)', fontSize: 9 }}>
|
|
997
1040
|
Not imported by any visible files.
|
|
998
1041
|
</div>
|
|
999
1042
|
)}
|
|
@@ -1006,9 +1049,9 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1006
1049
|
style={{
|
|
1007
1050
|
padding: '5px 7px',
|
|
1008
1051
|
marginBottom: 3,
|
|
1009
|
-
background: '
|
|
1052
|
+
background: 'var(--bg-input)',
|
|
1010
1053
|
borderRadius: 4,
|
|
1011
|
-
border: `1px solid ${sn?.cluster.color || '
|
|
1054
|
+
border: `1px solid ${sn?.cluster.color || 'var(--bd-muted)'}22`,
|
|
1012
1055
|
cursor: 'pointer',
|
|
1013
1056
|
}}
|
|
1014
1057
|
>
|
|
@@ -1020,18 +1063,18 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1020
1063
|
marginBottom: e.importedNames.length ? 3 : 0,
|
|
1021
1064
|
}}
|
|
1022
1065
|
>
|
|
1023
|
-
<span style={{ fontSize: 8, color: '
|
|
1024
|
-
<span style={{ fontSize: 9, color: '
|
|
1066
|
+
<span style={{ fontSize: 8, color: 'var(--ac-primary)' }}>↙</span>
|
|
1067
|
+
<span style={{ fontSize: 9, color: 'var(--tx-primary)' }}>
|
|
1025
1068
|
{sn?.label || e.source}
|
|
1026
1069
|
</span>
|
|
1027
1070
|
{e.isType && (
|
|
1028
|
-
<span style={{ fontSize: 7, color: '
|
|
1071
|
+
<span style={{ fontSize: 7, color: 'var(--tx-ghost)', marginLeft: 'auto' }}>
|
|
1029
1072
|
type
|
|
1030
1073
|
</span>
|
|
1031
1074
|
)}
|
|
1032
1075
|
</div>
|
|
1033
1076
|
{e.importedNames.length > 0 && (
|
|
1034
|
-
<div style={{ fontSize: 7.5, color: '
|
|
1077
|
+
<div style={{ fontSize: 7.5, color: 'var(--tx-dim)', paddingLeft: 12 }}>
|
|
1035
1078
|
{e.importedNames.join(', ')}
|
|
1036
1079
|
</div>
|
|
1037
1080
|
)}
|
|
@@ -1050,11 +1093,11 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1050
1093
|
)}
|
|
1051
1094
|
{tab === 'blast' && selectedId && (
|
|
1052
1095
|
<div>
|
|
1053
|
-
<div style={{ fontSize: 9, color: '
|
|
1054
|
-
Modifying <span style={{ color: '
|
|
1096
|
+
<div style={{ fontSize: 9, color: 'var(--tx-secondary)', marginBottom: 10 }}>
|
|
1097
|
+
Modifying <span style={{ color: 'var(--ac-primary)' }}>{selectedNode?.label}</span> impacts:
|
|
1055
1098
|
</div>
|
|
1056
1099
|
{affectedIds.length === 0 ? (
|
|
1057
|
-
<div style={{ color: '
|
|
1100
|
+
<div style={{ color: 'var(--tx-faint)', fontSize: 9 }}>No visible downstream nodes.</div>
|
|
1058
1101
|
) : (
|
|
1059
1102
|
affectedIds.map((id) => {
|
|
1060
1103
|
const n = graph.nodes.find((x) => x.id === id);
|
|
@@ -1068,9 +1111,9 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1068
1111
|
gap: 6,
|
|
1069
1112
|
padding: '4px 7px',
|
|
1070
1113
|
marginBottom: 3,
|
|
1071
|
-
background: '
|
|
1114
|
+
background: 'var(--bg-input)',
|
|
1072
1115
|
borderRadius: 4,
|
|
1073
|
-
border: '1px solid
|
|
1116
|
+
border: '1px solid var(--bd-muted)',
|
|
1074
1117
|
cursor: 'pointer',
|
|
1075
1118
|
}}
|
|
1076
1119
|
>
|
|
@@ -1080,7 +1123,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1080
1123
|
<span
|
|
1081
1124
|
style={{
|
|
1082
1125
|
fontSize: 9,
|
|
1083
|
-
color: '
|
|
1126
|
+
color: 'var(--tx-primary)',
|
|
1084
1127
|
flex: 1,
|
|
1085
1128
|
overflow: 'hidden',
|
|
1086
1129
|
textOverflow: 'ellipsis',
|
|
@@ -1100,12 +1143,12 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1100
1143
|
style={{
|
|
1101
1144
|
marginTop: 10,
|
|
1102
1145
|
padding: '8px 10px',
|
|
1103
|
-
background: '
|
|
1146
|
+
background: 'var(--bg-input)',
|
|
1104
1147
|
borderRadius: 5,
|
|
1105
|
-
border: '1px solid
|
|
1148
|
+
border: '1px solid var(--bd-muted)',
|
|
1106
1149
|
}}
|
|
1107
1150
|
>
|
|
1108
|
-
<div style={{ fontSize: 8, color: '
|
|
1151
|
+
<div style={{ fontSize: 8, color: 'var(--tx-ghost)', marginBottom: 2 }}>BLAST RADIUS</div>
|
|
1109
1152
|
<div
|
|
1110
1153
|
style={{
|
|
1111
1154
|
fontSize: 22,
|
|
@@ -1115,11 +1158,11 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1115
1158
|
? '#f77c6a'
|
|
1116
1159
|
: affectedIds.length > 3
|
|
1117
1160
|
? '#f7c76a'
|
|
1118
|
-
: '
|
|
1161
|
+
: 'var(--ac-primary)',
|
|
1119
1162
|
}}
|
|
1120
1163
|
>
|
|
1121
1164
|
{affectedIds.length}{' '}
|
|
1122
|
-
<span style={{ fontSize: 10, fontWeight: 400, color: '
|
|
1165
|
+
<span style={{ fontSize: 10, fontWeight: 400, color: 'var(--tx-ghost)' }}>nodes</span>
|
|
1123
1166
|
</div>
|
|
1124
1167
|
</div>
|
|
1125
1168
|
</div>
|
|
@@ -1128,8 +1171,8 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1128
1171
|
{/* SPEC */}
|
|
1129
1172
|
{tab === 'spec' && !mapping && (
|
|
1130
1173
|
<Hint>
|
|
1131
|
-
Load a <code style={{ color: '
|
|
1132
|
-
<code style={{ color: '
|
|
1174
|
+
Load a <code style={{ color: 'var(--ac-primary)' }}>mapping.json</code> and{' '}
|
|
1175
|
+
<code style={{ color: 'var(--ac-primary)' }}>spec.md</code> using the MAP / SPEC buttons in
|
|
1133
1176
|
the top bar.
|
|
1134
1177
|
</Hint>
|
|
1135
1178
|
)}
|
|
@@ -1158,11 +1201,11 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1158
1201
|
if (unique.length === 0)
|
|
1159
1202
|
return <Hint>No spec requirements mapped to this file.</Hint>;
|
|
1160
1203
|
|
|
1161
|
-
const confidenceColor = (c) => (c === 'llm' ? '#4ade80' : '
|
|
1204
|
+
const confidenceColor = (c) => (c === 'llm' ? '#4ade80' : 'var(--tx-ghost)');
|
|
1162
1205
|
|
|
1163
1206
|
return (
|
|
1164
1207
|
<div>
|
|
1165
|
-
<div style={{ fontSize: 8, color: '
|
|
1208
|
+
<div style={{ fontSize: 8, color: 'var(--tx-ghost)', marginBottom: 8 }}>
|
|
1166
1209
|
{unique.length} requirement{unique.length > 1 ? 's' : ''} linked
|
|
1167
1210
|
</div>
|
|
1168
1211
|
{unique.map((entry, i) => {
|
|
@@ -1179,16 +1222,16 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1179
1222
|
key={i}
|
|
1180
1223
|
style={{
|
|
1181
1224
|
marginBottom: 10,
|
|
1182
|
-
background: '
|
|
1225
|
+
background: 'var(--bg-node)',
|
|
1183
1226
|
borderRadius: 5,
|
|
1184
|
-
border: '1px solid
|
|
1227
|
+
border: '1px solid var(--bd-muted)',
|
|
1185
1228
|
overflow: 'hidden',
|
|
1186
1229
|
}}
|
|
1187
1230
|
>
|
|
1188
1231
|
<div
|
|
1189
1232
|
style={{
|
|
1190
1233
|
padding: '6px 9px',
|
|
1191
|
-
borderBottom: '1px solid
|
|
1234
|
+
borderBottom: '1px solid var(--bd-faint)',
|
|
1192
1235
|
display: 'flex',
|
|
1193
1236
|
alignItems: 'center',
|
|
1194
1237
|
gap: 5,
|
|
@@ -1196,7 +1239,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1196
1239
|
}}
|
|
1197
1240
|
>
|
|
1198
1241
|
<span
|
|
1199
|
-
style={{ fontSize: 9, fontWeight: 700, color: '
|
|
1242
|
+
style={{ fontSize: 9, fontWeight: 700, color: 'var(--tx-primary)', flex: 1 }}
|
|
1200
1243
|
>
|
|
1201
1244
|
{entry.requirement}
|
|
1202
1245
|
</span>
|
|
@@ -1224,7 +1267,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1224
1267
|
style={{
|
|
1225
1268
|
padding: '7px 9px',
|
|
1226
1269
|
fontSize: 8.5,
|
|
1227
|
-
color: '
|
|
1270
|
+
color: 'var(--tx-secondary)',
|
|
1228
1271
|
lineHeight: 1.7,
|
|
1229
1272
|
maxHeight: 200,
|
|
1230
1273
|
overflow: 'auto',
|
|
@@ -1236,7 +1279,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1236
1279
|
<div
|
|
1237
1280
|
key={li}
|
|
1238
1281
|
style={{
|
|
1239
|
-
color: '
|
|
1282
|
+
color: 'var(--tx-node)',
|
|
1240
1283
|
fontWeight: 700,
|
|
1241
1284
|
marginTop: 6,
|
|
1242
1285
|
fontSize: 8,
|
|
@@ -1247,7 +1290,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1247
1290
|
);
|
|
1248
1291
|
if (line.startsWith('- **'))
|
|
1249
1292
|
return (
|
|
1250
|
-
<div key={li} style={{ paddingLeft: 6, color: '
|
|
1293
|
+
<div key={li} style={{ paddingLeft: 6, color: 'var(--tx-secondary)' }}>
|
|
1251
1294
|
{line.replace(/\*\*/g, '')}
|
|
1252
1295
|
</div>
|
|
1253
1296
|
);
|
|
@@ -1257,21 +1300,21 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1257
1300
|
})}
|
|
1258
1301
|
</div>
|
|
1259
1302
|
) : (
|
|
1260
|
-
<div style={{ padding: '7px 9px', fontSize: 8, color: '
|
|
1303
|
+
<div style={{ padding: '7px 9px', fontSize: 8, color: 'var(--tx-faint)' }}>
|
|
1261
1304
|
{req
|
|
1262
|
-
? 'Requirement title mismatch
|
|
1263
|
-
: <>Spec not loaded
|
|
1305
|
+
? 'Requirement title mismatch — spec section not found in the spec file.'
|
|
1306
|
+
: <>Spec not loaded — run <code style={{ color: 'var(--ac-primary)' }}>spec-gen view</code> or load <code style={{ color: 'var(--ac-primary)' }}>spec.md</code> manually.</>}
|
|
1264
1307
|
</div>
|
|
1265
1308
|
)}
|
|
1266
1309
|
<div
|
|
1267
1310
|
style={{
|
|
1268
1311
|
padding: '4px 9px',
|
|
1269
|
-
borderTop: '1px solid
|
|
1312
|
+
borderTop: '1px solid var(--bd-faint)',
|
|
1270
1313
|
fontSize: 7.5,
|
|
1271
|
-
color: '
|
|
1314
|
+
color: 'var(--ac-cluster-arr)',
|
|
1272
1315
|
}}
|
|
1273
1316
|
>
|
|
1274
|
-
service: <span style={{ color: '
|
|
1317
|
+
service: <span style={{ color: 'var(--tx-dim)' }}>{entry.service}</span>
|
|
1275
1318
|
</div>
|
|
1276
1319
|
</div>
|
|
1277
1320
|
);
|
|
@@ -1291,10 +1334,10 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1291
1334
|
{!skeletonLoading && skeletonData && (
|
|
1292
1335
|
<div>
|
|
1293
1336
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
|
|
1294
|
-
<span style={{ fontSize: 9, color: '
|
|
1337
|
+
<span style={{ fontSize: 9, color: 'var(--tx-muted)', fontFamily: 'inherit' }}>
|
|
1295
1338
|
{skeletonData.language} · {skeletonData.skeletonLines}/{skeletonData.originalLines} lines
|
|
1296
1339
|
</span>
|
|
1297
|
-
<span style={{ fontSize: 9, color: skeletonData.reductionPct >= 20 ? '
|
|
1340
|
+
<span style={{ fontSize: 9, color: skeletonData.reductionPct >= 20 ? 'var(--ac-primary)' : 'var(--tx-ghost)', fontFamily: 'inherit' }}>
|
|
1298
1341
|
-{skeletonData.reductionPct}%
|
|
1299
1342
|
</span>
|
|
1300
1343
|
</div>
|
|
@@ -1302,12 +1345,12 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1302
1345
|
margin: 0,
|
|
1303
1346
|
fontSize: 8,
|
|
1304
1347
|
lineHeight: 1.6,
|
|
1305
|
-
color: '
|
|
1348
|
+
color: 'var(--tx-secondary)',
|
|
1306
1349
|
fontFamily: "'JetBrains Mono', monospace",
|
|
1307
1350
|
whiteSpace: 'pre-wrap',
|
|
1308
1351
|
wordBreak: 'break-word',
|
|
1309
|
-
background: '
|
|
1310
|
-
border: '1px solid
|
|
1352
|
+
background: 'var(--bg-deep)',
|
|
1353
|
+
border: '1px solid var(--bd-faint)',
|
|
1311
1354
|
borderRadius: 4,
|
|
1312
1355
|
padding: '8px 10px',
|
|
1313
1356
|
}}>
|
|
@@ -1325,7 +1368,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1325
1368
|
{[
|
|
1326
1369
|
['Nodes', stats.nodeCount],
|
|
1327
1370
|
['Edges', stats.edgeCount],
|
|
1328
|
-
['Clusters', stats.
|
|
1371
|
+
['Clusters', stats.structuralClusterCount ?? displayClusters.length],
|
|
1329
1372
|
['Cycles', stats.cycleCount],
|
|
1330
1373
|
['Avg degree', stats.avgDegree?.toFixed(2)],
|
|
1331
1374
|
['Density', stats.density?.toFixed(4)],
|
|
@@ -1335,11 +1378,11 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1335
1378
|
<SL>Active filters</SL>
|
|
1336
1379
|
<Row
|
|
1337
1380
|
label="Visible nodes"
|
|
1338
|
-
value={<span style={{ color: '
|
|
1381
|
+
value={<span style={{ color: 'var(--ac-primary)' }}>{filterStats.visible}</span>}
|
|
1339
1382
|
/>
|
|
1340
1383
|
<Row
|
|
1341
1384
|
label="Visible edges"
|
|
1342
|
-
value={<span style={{ color: '
|
|
1385
|
+
value={<span style={{ color: 'var(--ac-teal)' }}>{filterStats.visibleEdges}</span>}
|
|
1343
1386
|
/>
|
|
1344
1387
|
<Row label="Orphans" value={filterStats.orphanCount} />
|
|
1345
1388
|
<SL>Top 10 by score</SL>
|
|
@@ -1358,12 +1401,12 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1358
1401
|
cursor: 'pointer',
|
|
1359
1402
|
}}
|
|
1360
1403
|
>
|
|
1361
|
-
<span style={{ fontSize: 8, color: '
|
|
1362
|
-
<span style={{ fontSize: 8, color: extColor(n.ext) }}>{n.ext || '
|
|
1404
|
+
<span style={{ fontSize: 8, color: 'var(--tx-faint)', minWidth: 12 }}>{i + 1}</span>
|
|
1405
|
+
<span style={{ fontSize: 8, color: extColor(n.ext) }}>{n.ext || '—'}</span>
|
|
1363
1406
|
<span
|
|
1364
1407
|
style={{
|
|
1365
1408
|
fontSize: 9,
|
|
1366
|
-
color: '
|
|
1409
|
+
color: 'var(--tx-secondary)',
|
|
1367
1410
|
flex: 1,
|
|
1368
1411
|
overflow: 'hidden',
|
|
1369
1412
|
textOverflow: 'ellipsis',
|
|
@@ -1372,7 +1415,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1372
1415
|
>
|
|
1373
1416
|
{n.label}
|
|
1374
1417
|
</span>
|
|
1375
|
-
<span style={{ fontSize: 9, color: '
|
|
1418
|
+
<span style={{ fontSize: 9, color: 'var(--ac-primary)' }}>{n.score}</span>
|
|
1376
1419
|
</div>
|
|
1377
1420
|
);
|
|
1378
1421
|
})}
|
|
@@ -1381,7 +1424,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1381
1424
|
</div>
|
|
1382
1425
|
|
|
1383
1426
|
{/* Cluster legend */}
|
|
1384
|
-
<div style={{ padding: '9px 13px', borderTop: '1px solid
|
|
1427
|
+
<div style={{ padding: '9px 13px', borderTop: '1px solid var(--bd-faint)', flexShrink: 0 }}>
|
|
1385
1428
|
<div style={{ display: 'flex', gap: 12, marginBottom: 8 }}>
|
|
1386
1429
|
<div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
|
|
1387
1430
|
<svg width="24" height="8" style={{ overflow: 'visible' }}>
|
|
@@ -1390,7 +1433,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1390
1433
|
y1="4"
|
|
1391
1434
|
x2="18"
|
|
1392
1435
|
y2="4"
|
|
1393
|
-
stroke="
|
|
1436
|
+
stroke="var(--tx-node)"
|
|
1394
1437
|
strokeWidth="1.5"
|
|
1395
1438
|
markerEnd="url(#arr-legend)"
|
|
1396
1439
|
/>
|
|
@@ -1403,11 +1446,11 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1403
1446
|
refY="2.5"
|
|
1404
1447
|
orient="auto"
|
|
1405
1448
|
>
|
|
1406
|
-
<path d="M0,0 L0,5 L5,2.5z"
|
|
1449
|
+
<path d="M0,0 L0,5 L5,2.5z" style={{ fill: 'var(--tx-node)' }} />
|
|
1407
1450
|
</marker>
|
|
1408
1451
|
</defs>
|
|
1409
1452
|
</svg>
|
|
1410
|
-
<span style={{ fontSize: 7.5, color: '
|
|
1453
|
+
<span style={{ fontSize: 7.5, color: 'var(--tx-ghost)' }}>runtime import</span>
|
|
1411
1454
|
</div>
|
|
1412
1455
|
<div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
|
|
1413
1456
|
<svg width="24" height="8" style={{ overflow: 'visible' }}>
|
|
@@ -1416,7 +1459,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1416
1459
|
y1="4"
|
|
1417
1460
|
x2="18"
|
|
1418
1461
|
y2="4"
|
|
1419
|
-
stroke="
|
|
1462
|
+
stroke="var(--tx-ghost)"
|
|
1420
1463
|
strokeWidth="1.2"
|
|
1421
1464
|
strokeDasharray="3 2"
|
|
1422
1465
|
markerEnd="url(#arr-legend-type)"
|
|
@@ -1430,20 +1473,20 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1430
1473
|
refY="2.5"
|
|
1431
1474
|
orient="auto"
|
|
1432
1475
|
>
|
|
1433
|
-
<path d="M0,0 L0,5 L5,2.5z"
|
|
1476
|
+
<path d="M0,0 L0,5 L5,2.5z" style={{ fill: 'var(--tx-ghost)' }} />
|
|
1434
1477
|
</marker>
|
|
1435
1478
|
</defs>
|
|
1436
1479
|
</svg>
|
|
1437
|
-
<span style={{ fontSize: 7.5, color: '
|
|
1480
|
+
<span style={{ fontSize: 7.5, color: 'var(--tx-ghost)' }}>type-only</span>
|
|
1438
1481
|
</div>
|
|
1439
1482
|
</div>
|
|
1440
1483
|
<div
|
|
1441
|
-
style={{ fontSize: 8, color: '
|
|
1484
|
+
style={{ fontSize: 8, color: 'var(--ac-arrow)', letterSpacing: '0.08em', marginBottom: 5 }}
|
|
1442
1485
|
>
|
|
1443
1486
|
CLUSTERS · click to filter
|
|
1444
1487
|
</div>
|
|
1445
1488
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
|
|
1446
|
-
{
|
|
1489
|
+
{displayClusters.map((cl) => (
|
|
1447
1490
|
<div
|
|
1448
1491
|
key={cl.id}
|
|
1449
1492
|
onClick={() =>
|
|
@@ -1470,7 +1513,7 @@ export default function App({ graphUrl, mappingUrl = '/api/mapping', specUrl = '
|
|
|
1470
1513
|
<span
|
|
1471
1514
|
style={{
|
|
1472
1515
|
fontSize: 7.5,
|
|
1473
|
-
color: filters.cluster === cl.name ? cl.color : '
|
|
1516
|
+
color: filters.cluster === cl.name ? cl.color : 'var(--tx-ghost)',
|
|
1474
1517
|
}}
|
|
1475
1518
|
>
|
|
1476
1519
|
{cl.name}
|