spec-gen-cli 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +2 -1
- 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 +29 -24
- 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
|
@@ -10,7 +10,7 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
10
10
|
return new Set(graph.nodes.filter(n => focusedIds.includes(n.id)).map(n => n.cluster.id));
|
|
11
11
|
}, [focusedIds, graph]);
|
|
12
12
|
|
|
13
|
-
if (!overview) return <div style={{ color: '
|
|
13
|
+
if (!overview) return <div style={{ color: 'var(--tx-ghost)', padding: 24, fontSize: 11 }}>No graph loaded.</div>;
|
|
14
14
|
|
|
15
15
|
const { summary, clusters, globalEntryPoints, criticalHubs } = overview;
|
|
16
16
|
|
|
@@ -49,7 +49,7 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
49
49
|
<line
|
|
50
50
|
key={`${cl.id}->${toId}`}
|
|
51
51
|
x1={sx} y1={sy} x2={ex} y2={ey}
|
|
52
|
-
stroke={isHov ? '
|
|
52
|
+
stroke={isHov ? 'var(--ac-primary)' : 'var(--ac-arrow)'}
|
|
53
53
|
strokeWidth={isHov ? 1.5 : 1}
|
|
54
54
|
markerEnd="url(#arrowhead)"
|
|
55
55
|
opacity={isHov ? 1 : 0.6}
|
|
@@ -71,8 +71,8 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
71
71
|
summary.cycles > 0 ? ['⚠ cycles', summary.cycles] : null,
|
|
72
72
|
summary.layerViolations > 0 ? ['⚠ violations', summary.layerViolations] : null,
|
|
73
73
|
].filter(Boolean).map(([l, v]) => (
|
|
74
|
-
<div key={l} style={{ fontSize: 9, color: '
|
|
75
|
-
<span style={{ color: l.startsWith('⚠') ? '#f97316' : '
|
|
74
|
+
<div key={l} style={{ fontSize: 9, color: 'var(--tx-muted)', background: 'var(--bg-raised)', borderRadius: 4, padding: '2px 8px', border: '1px solid var(--bd-muted)' }}>
|
|
75
|
+
<span style={{ color: l.startsWith('⚠') ? '#f97316' : 'var(--tx-primary)' }}>{v}</span> {l}
|
|
76
76
|
</div>
|
|
77
77
|
))}
|
|
78
78
|
</div>
|
|
@@ -80,7 +80,7 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
80
80
|
<svg width={SVG_W} height={SVG_H} style={{ display: 'block', minWidth: SVG_W }}>
|
|
81
81
|
<defs>
|
|
82
82
|
<marker id="arrowhead" markerWidth="6" markerHeight="6" refX="3" refY="3" orient="auto">
|
|
83
|
-
<path d="M0,0 L0,6 L6,3 z"
|
|
83
|
+
<path d="M0,0 L0,6 L6,3 z" style={{ fill: 'var(--ac-cluster-arr)' }} />
|
|
84
84
|
</marker>
|
|
85
85
|
</defs>
|
|
86
86
|
|
|
@@ -102,25 +102,25 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
102
102
|
<rect
|
|
103
103
|
x={x} y={y} width={BOX_W} height={BOX_H}
|
|
104
104
|
rx={6} ry={6}
|
|
105
|
-
|
|
106
|
-
stroke={isHov ? color : isDimmed ? '
|
|
105
|
+
style={{ fill: isHov ? 'var(--bg-hover)' : 'var(--bg-node)' }}
|
|
106
|
+
stroke={isHov ? color : isDimmed ? 'var(--bg-raised)' : 'var(--ac-arrow)'}
|
|
107
107
|
strokeWidth={isHov ? 1.5 : 1}
|
|
108
108
|
/>
|
|
109
109
|
<rect x={x} y={y} width={4} height={BOX_H} rx={3} ry={3} fill={color} opacity={0.8} />
|
|
110
|
-
<text x={x + 12} y={y + 18}
|
|
111
|
-
{cl.name.length > 18 ? cl.name.slice(0, 17) + '
|
|
110
|
+
<text x={x + 12} y={y + 18} style={{ fill: 'var(--tx-primary)' }} fontSize={10} fontWeight="600" fontFamily="inherit">
|
|
111
|
+
{cl.name.length > 18 ? cl.name.slice(0, 17) + '…' : cl.name}
|
|
112
112
|
</text>
|
|
113
113
|
<text x={x + 12} y={y + 31} fill={color} fontSize={8} fontFamily="inherit" opacity={0.9}>
|
|
114
114
|
{ROLE_LABEL[cl.role] ?? cl.role}
|
|
115
115
|
</text>
|
|
116
|
-
<text x={x + 12} y={y + 44}
|
|
116
|
+
<text x={x + 12} y={y + 44} style={{ fill: 'var(--tx-dim)' }} fontSize={8} fontFamily="inherit">
|
|
117
117
|
{cl.fileCount} files
|
|
118
118
|
{cl.hubCount > 0 ? ` · ${cl.hubCount} hub${cl.hubCount > 1 ? 's' : ''}` : ''}
|
|
119
119
|
{cl.entryPointCount > 0 ? ` · ${cl.entryPointCount} entry` : ''}
|
|
120
120
|
</text>
|
|
121
121
|
{cl.dependsOn.length > 0 && (
|
|
122
|
-
<text x={x + BOX_W - 6} y={y + 18}
|
|
123
|
-
{
|
|
122
|
+
<text x={x + BOX_W - 6} y={y + 18} style={{ fill: 'var(--tx-dim)' }} fontSize={7} fontFamily="inherit" textAnchor="end">
|
|
123
|
+
→{cl.dependsOn.length}
|
|
124
124
|
</text>
|
|
125
125
|
)}
|
|
126
126
|
</g>
|
|
@@ -130,7 +130,7 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
130
130
|
|
|
131
131
|
<div style={{ display: 'flex', gap: 12, marginTop: 12, flexWrap: 'wrap' }}>
|
|
132
132
|
{Object.entries(ROLE_LABEL).map(([role, label]) => (
|
|
133
|
-
<div key={role} style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 8, color: '
|
|
133
|
+
<div key={role} style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 8, color: 'var(--tx-dim)' }}>
|
|
134
134
|
<div style={{ width: 8, height: 8, borderRadius: 2, background: ROLE_COLOR[role] }} />
|
|
135
135
|
{label}
|
|
136
136
|
</div>
|
|
@@ -138,7 +138,7 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
138
138
|
</div>
|
|
139
139
|
</div>
|
|
140
140
|
|
|
141
|
-
<div style={{ width: 220, borderLeft: '1px solid
|
|
141
|
+
<div style={{ width: 220, borderLeft: '1px solid var(--bd-faint)', overflow: 'auto', padding: '12px 10px', flexShrink: 0 }}>
|
|
142
142
|
{globalEntryPoints.length > 0 && (
|
|
143
143
|
<>
|
|
144
144
|
<div style={{ ...S, color: '#4ade80', fontWeight: 600, marginBottom: 6, letterSpacing: '0.08em', textTransform: 'uppercase' }}>
|
|
@@ -146,8 +146,8 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
146
146
|
</div>
|
|
147
147
|
{globalEntryPoints.map((ep, i) => (
|
|
148
148
|
<div key={i} style={{ marginBottom: 6 }}>
|
|
149
|
-
<div style={{ ...S, color: '
|
|
150
|
-
<div style={{ ...S, color: '
|
|
149
|
+
<div style={{ ...S, color: 'var(--tx-primary)', fontWeight: 600 }}>{ep.name}</div>
|
|
150
|
+
<div style={{ ...S, color: 'var(--tx-dim)', wordBreak: 'break-all' }}>{ep.file}</div>
|
|
151
151
|
</div>
|
|
152
152
|
))}
|
|
153
153
|
</>
|
|
@@ -160,8 +160,8 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
160
160
|
</div>
|
|
161
161
|
{criticalHubs.map((hub, i) => (
|
|
162
162
|
<div key={i} style={{ marginBottom: 6 }}>
|
|
163
|
-
<div style={{ ...S, color: '
|
|
164
|
-
<div style={{ ...S, color: '
|
|
163
|
+
<div style={{ ...S, color: 'var(--tx-primary)', fontWeight: 600 }}>{hub.name}</div>
|
|
164
|
+
<div style={{ ...S, color: 'var(--tx-dim)', wordBreak: 'break-all' }}>{hub.file}</div>
|
|
165
165
|
<div style={{ ...S, color: '#f97316', opacity: 0.7 }}>fanIn {hub.fanIn} · fanOut {hub.fanOut}</div>
|
|
166
166
|
</div>
|
|
167
167
|
))}
|
|
@@ -169,7 +169,7 @@ export function ArchitectureView({ graph, llmCtx, focusedIds }) {
|
|
|
169
169
|
)}
|
|
170
170
|
|
|
171
171
|
{globalEntryPoints.length === 0 && criticalHubs.length === 0 && (
|
|
172
|
-
<div style={{ ...S, color: '
|
|
172
|
+
<div style={{ ...S, color: 'var(--tx-ghost)' }}>Run <code style={{ color: 'var(--ac-primary)' }}>spec-gen analyze</code> to populate call graph data.</div>
|
|
173
173
|
)}
|
|
174
174
|
</div>
|
|
175
175
|
</div>
|
|
@@ -11,9 +11,9 @@ function escapeHtml(str) {
|
|
|
11
11
|
function renderInline(text) {
|
|
12
12
|
// Escape HTML first to prevent XSS, then apply markdown formatting
|
|
13
13
|
return escapeHtml(text)
|
|
14
|
-
.replace(/`([^`]+)`/g, '<code style="background
|
|
15
|
-
.replace(/\*\*([^*]+)\*\*/g, '<strong style="color
|
|
16
|
-
.replace(/\*([^*]+)\*/g, '<em style="color
|
|
14
|
+
.replace(/`([^`]+)`/g, '<code style="background:var(--bd-muted);padding:1px 4px;border-radius:3px;font-family:JetBrains Mono,monospace;font-size:8px;color:var(--tx-primary)">$1</code>')
|
|
15
|
+
.replace(/\*\*([^*]+)\*\*/g, '<strong style="color:var(--tx-primary)">$1</strong>')
|
|
16
|
+
.replace(/\*([^*]+)\*/g, '<em style="color:var(--tx-secondary)">$1</em>');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function MarkdownBlock({ text }) {
|
|
@@ -34,9 +34,9 @@ function MarkdownBlock({ text }) {
|
|
|
34
34
|
}
|
|
35
35
|
elements.push(
|
|
36
36
|
<pre key={i} style={{
|
|
37
|
-
background: '
|
|
37
|
+
background: 'var(--bg-input)', border: '1px solid var(--bd-muted)', borderRadius: 4,
|
|
38
38
|
padding: '6px 8px', margin: '4px 0', overflowX: 'auto',
|
|
39
|
-
fontSize: 8, color: '
|
|
39
|
+
fontSize: 8, color: 'var(--tx-secondary)', fontFamily: 'JetBrains Mono,monospace', lineHeight: 1.5,
|
|
40
40
|
}}>
|
|
41
41
|
{codeLines.join('\n')}
|
|
42
42
|
</pre>
|
|
@@ -49,7 +49,7 @@ function MarkdownBlock({ text }) {
|
|
|
49
49
|
if (/^#{3,4}\s+/.test(line)) {
|
|
50
50
|
const content = line.replace(/^#{3,4}\s+/, '');
|
|
51
51
|
elements.push(
|
|
52
|
-
<div key={i} style={{ fontSize: 9, color: '
|
|
52
|
+
<div key={i} style={{ fontSize: 9, color: 'var(--ac-primary)', fontWeight: 600, margin: '8px 0 3px', letterSpacing: '0.04em' }}
|
|
53
53
|
dangerouslySetInnerHTML={{ __html: renderInline(content) }} />
|
|
54
54
|
);
|
|
55
55
|
i++;
|
|
@@ -60,7 +60,7 @@ function MarkdownBlock({ text }) {
|
|
|
60
60
|
if (/^#{1,2}\s+/.test(line)) {
|
|
61
61
|
const content = line.replace(/^#{1,2}\s+/, '');
|
|
62
62
|
elements.push(
|
|
63
|
-
<div key={i} style={{ fontSize: 10, color: '
|
|
63
|
+
<div key={i} style={{ fontSize: 10, color: 'var(--tx-primary)', fontWeight: 700, margin: '10px 0 4px' }}
|
|
64
64
|
dangerouslySetInnerHTML={{ __html: renderInline(content) }} />
|
|
65
65
|
);
|
|
66
66
|
i++;
|
|
@@ -77,8 +77,8 @@ function MarkdownBlock({ text }) {
|
|
|
77
77
|
elements.push(
|
|
78
78
|
<ul key={i} style={{ margin: '3px 0', paddingLeft: 14, listStyle: 'none' }}>
|
|
79
79
|
{items.map((item, j) => (
|
|
80
|
-
<li key={j} style={{ fontSize: 9, color: '
|
|
81
|
-
<span style={{ position: 'absolute', left: 0, color: '
|
|
80
|
+
<li key={j} style={{ fontSize: 9, color: 'var(--tx-secondary)', lineHeight: 1.6, position: 'relative', paddingLeft: 8 }}>
|
|
81
|
+
<span style={{ position: 'absolute', left: 0, color: 'var(--ac-primary)' }}>·</span>
|
|
82
82
|
<span dangerouslySetInnerHTML={{ __html: renderInline(item) }} />
|
|
83
83
|
</li>
|
|
84
84
|
))}
|
|
@@ -98,8 +98,8 @@ function MarkdownBlock({ text }) {
|
|
|
98
98
|
elements.push(
|
|
99
99
|
<ol key={i} style={{ margin: '3px 0', paddingLeft: 0, listStyle: 'none' }}>
|
|
100
100
|
{items.map((item, j) => (
|
|
101
|
-
<li key={j} style={{ fontSize: 9, color: '
|
|
102
|
-
<span style={{ color: '
|
|
101
|
+
<li key={j} style={{ fontSize: 9, color: 'var(--tx-secondary)', lineHeight: 1.6, display: 'flex', gap: 5, margin: '1px 0' }}>
|
|
102
|
+
<span style={{ color: 'var(--ac-primary)', flexShrink: 0, fontVariantNumeric: 'tabular-nums' }}>{item.num}.</span>
|
|
103
103
|
<span dangerouslySetInnerHTML={{ __html: renderInline(item.text) }} />
|
|
104
104
|
</li>
|
|
105
105
|
))}
|
|
@@ -110,7 +110,7 @@ function MarkdownBlock({ text }) {
|
|
|
110
110
|
|
|
111
111
|
// Horizontal rule
|
|
112
112
|
if (/^---+$/.test(line.trim())) {
|
|
113
|
-
elements.push(<hr key={i} style={{ border: 'none', borderTop: '1px solid
|
|
113
|
+
elements.push(<hr key={i} style={{ border: 'none', borderTop: '1px solid var(--bd-muted)', margin: '6px 0' }} />);
|
|
114
114
|
i++;
|
|
115
115
|
continue;
|
|
116
116
|
}
|
|
@@ -124,7 +124,7 @@ function MarkdownBlock({ text }) {
|
|
|
124
124
|
|
|
125
125
|
// Plain paragraph
|
|
126
126
|
elements.push(
|
|
127
|
-
<div key={i} style={{ fontSize: 9, color: '
|
|
127
|
+
<div key={i} style={{ fontSize: 9, color: 'var(--tx-secondary)', lineHeight: 1.6 }}
|
|
128
128
|
dangerouslySetInnerHTML={{ __html: renderInline(line) }} />
|
|
129
129
|
);
|
|
130
130
|
i++;
|
|
@@ -144,7 +144,7 @@ function ToolSpinner() {
|
|
|
144
144
|
const id = setInterval(() => setFrame((f) => (f + 1) % frames.length), 80);
|
|
145
145
|
return () => clearInterval(id);
|
|
146
146
|
}, []);
|
|
147
|
-
return <span style={{ color: '
|
|
147
|
+
return <span style={{ color: 'var(--ac-primary)', fontFamily: 'monospace', fontSize: 10, lineHeight: 1 }}>{frames[frame]}</span>;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// ============================================================================
|
|
@@ -270,8 +270,8 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
270
270
|
<div
|
|
271
271
|
style={{
|
|
272
272
|
width: 340,
|
|
273
|
-
borderLeft: '1px solid
|
|
274
|
-
background: '
|
|
273
|
+
borderLeft: '1px solid var(--bd-faint)',
|
|
274
|
+
background: 'var(--bg-deep)',
|
|
275
275
|
display: 'flex',
|
|
276
276
|
flexDirection: 'column',
|
|
277
277
|
overflow: 'hidden',
|
|
@@ -284,22 +284,22 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
284
284
|
display: 'flex',
|
|
285
285
|
flexDirection: 'column',
|
|
286
286
|
padding: '6px 10px',
|
|
287
|
-
borderBottom: '1px solid
|
|
287
|
+
borderBottom: '1px solid var(--bd-faint)',
|
|
288
288
|
flexShrink: 0,
|
|
289
289
|
gap: 5,
|
|
290
290
|
}}
|
|
291
291
|
>
|
|
292
292
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
293
|
-
<span style={{ fontSize: 9, color: '
|
|
294
|
-
DIAGRAM CHAT
|
|
293
|
+
<span style={{ fontSize: 9, color: 'var(--ac-primary)', letterSpacing: '0.1em', fontFamily: 'inherit' }}>
|
|
294
|
+
✦ DIAGRAM CHAT
|
|
295
295
|
</span>
|
|
296
296
|
<div style={{ display: 'flex', gap: 6 }}>
|
|
297
297
|
<button
|
|
298
298
|
onClick={clear}
|
|
299
299
|
title="Clear conversation"
|
|
300
300
|
style={{
|
|
301
|
-
background: 'none', border: '1px solid
|
|
302
|
-
color: '
|
|
301
|
+
background: 'none', border: '1px solid var(--bd-muted)', borderRadius: 3,
|
|
302
|
+
color: 'var(--tx-ghost)', fontSize: 8, padding: '2px 6px', cursor: 'pointer', fontFamily: 'inherit',
|
|
303
303
|
}}
|
|
304
304
|
>
|
|
305
305
|
CLEAR
|
|
@@ -308,8 +308,8 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
308
308
|
onClick={onClose}
|
|
309
309
|
title="Close chat"
|
|
310
310
|
style={{
|
|
311
|
-
background: 'none', border: '1px solid
|
|
312
|
-
color: '
|
|
311
|
+
background: 'none', border: '1px solid var(--bd-muted)', borderRadius: 3,
|
|
312
|
+
color: 'var(--tx-ghost)', fontSize: 10, padding: '2px 6px', cursor: 'pointer', fontFamily: 'inherit', lineHeight: 1,
|
|
313
313
|
}}
|
|
314
314
|
>
|
|
315
315
|
x
|
|
@@ -319,15 +319,15 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
319
319
|
{/* Model selector */}
|
|
320
320
|
{modelInfo && (
|
|
321
321
|
<div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
|
|
322
|
-
<span style={{ fontSize: 8, color: '
|
|
322
|
+
<span style={{ fontSize: 8, color: 'var(--tx-ghost)', letterSpacing: '0.06em', flexShrink: 0 }}>
|
|
323
323
|
{modelInfo.provider.toUpperCase()}
|
|
324
324
|
</span>
|
|
325
325
|
<select
|
|
326
326
|
value={modelInfo.currentModel}
|
|
327
327
|
onChange={(e) => setModelInfo((prev) => ({ ...prev, currentModel: e.target.value }))}
|
|
328
328
|
style={{
|
|
329
|
-
flex: 1, background: '
|
|
330
|
-
color: '
|
|
329
|
+
flex: 1, background: 'var(--bg-input)', border: '1px solid var(--bd-muted)', borderRadius: 3,
|
|
330
|
+
color: 'var(--tx-secondary)', fontSize: 8, padding: '2px 4px', fontFamily: 'inherit',
|
|
331
331
|
cursor: 'pointer', outline: 'none',
|
|
332
332
|
}}
|
|
333
333
|
>
|
|
@@ -353,15 +353,15 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
353
353
|
<div key={i} style={{ alignSelf: m.role === 'user' ? 'flex-end' : 'flex-start', maxWidth: '96%' }}>
|
|
354
354
|
<div
|
|
355
355
|
style={{
|
|
356
|
-
background: m.role === 'user' ? '
|
|
357
|
-
border: `1px solid ${m.role === 'user' ? '
|
|
356
|
+
background: m.role === 'user' ? 'var(--bg-hover)' : 'var(--bg-input)',
|
|
357
|
+
border: `1px solid ${m.role === 'user' ? 'var(--bd-muted)' : 'var(--bd-faint)'}`,
|
|
358
358
|
borderRadius: m.role === 'user' ? '8px 8px 2px 8px' : '8px 8px 8px 2px',
|
|
359
359
|
padding: '6px 10px',
|
|
360
360
|
fontFamily: 'inherit',
|
|
361
361
|
}}
|
|
362
362
|
>
|
|
363
363
|
{m.role === 'user' ? (
|
|
364
|
-
<div style={{ fontSize: 9, color: '
|
|
364
|
+
<div style={{ fontSize: 9, color: 'var(--tx-primary)', lineHeight: 1.5, whiteSpace: 'pre-wrap' }}>
|
|
365
365
|
{m.content}
|
|
366
366
|
</div>
|
|
367
367
|
) : (
|
|
@@ -374,8 +374,8 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
374
374
|
{loading && (
|
|
375
375
|
<div style={{ alignSelf: 'flex-start' }}>
|
|
376
376
|
<div style={{
|
|
377
|
-
fontSize: 9, color: '
|
|
378
|
-
border: '1px solid
|
|
377
|
+
fontSize: 9, color: 'var(--ac-primary)', background: 'var(--bg-input)',
|
|
378
|
+
border: '1px solid var(--bd-faint)', borderRadius: '8px 8px 8px 2px',
|
|
379
379
|
padding: '6px 10px', fontFamily: 'inherit',
|
|
380
380
|
display: 'flex', flexDirection: 'column', gap: 4,
|
|
381
381
|
}}>
|
|
@@ -385,7 +385,7 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
385
385
|
activeTools.map((name, i) => (
|
|
386
386
|
<div key={i} style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
|
|
387
387
|
<ToolSpinner />
|
|
388
|
-
<span style={{ color: '
|
|
388
|
+
<span style={{ color: 'var(--tx-secondary)' }}>{name.replace(/_/g, ' ')}</span>
|
|
389
389
|
</div>
|
|
390
390
|
))
|
|
391
391
|
)}
|
|
@@ -395,8 +395,8 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
395
395
|
|
|
396
396
|
{error && (
|
|
397
397
|
<div style={{
|
|
398
|
-
fontSize: 9, color: '
|
|
399
|
-
border: '1px solid
|
|
398
|
+
fontSize: 9, color: 'var(--tx-primary)', background: 'rgba(192,57,43,0.10)',
|
|
399
|
+
border: '1px solid rgba(192,57,43,0.35)', borderRadius: 4,
|
|
400
400
|
padding: '5px 8px', fontFamily: 'inherit',
|
|
401
401
|
}}>
|
|
402
402
|
Error: {error}
|
|
@@ -409,7 +409,7 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
409
409
|
{/* Input area */}
|
|
410
410
|
<div
|
|
411
411
|
style={{
|
|
412
|
-
borderTop: '1px solid
|
|
412
|
+
borderTop: '1px solid var(--bd-faint)', padding: '8px 10px',
|
|
413
413
|
display: 'flex', flexDirection: 'column', gap: 6, flexShrink: 0,
|
|
414
414
|
}}
|
|
415
415
|
>
|
|
@@ -420,8 +420,8 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
420
420
|
placeholder="Ask about the codebase... (Enter to send, Shift+Enter for newline)"
|
|
421
421
|
rows={3}
|
|
422
422
|
style={{
|
|
423
|
-
background: '
|
|
424
|
-
color: '
|
|
423
|
+
background: 'var(--bg-input)', border: '1px solid var(--bd-muted)', borderRadius: 4,
|
|
424
|
+
color: 'var(--tx-primary)', fontSize: 9, padding: '6px 8px',
|
|
425
425
|
resize: 'none', outline: 'none', fontFamily: 'inherit', lineHeight: 1.4,
|
|
426
426
|
}}
|
|
427
427
|
/>
|
|
@@ -430,10 +430,10 @@ export function ChatPanel({ onHighlight, onClose }) {
|
|
|
430
430
|
onClick={send}
|
|
431
431
|
disabled={!input.trim() || loading}
|
|
432
432
|
style={{
|
|
433
|
-
background: input.trim() && !loading ? '
|
|
434
|
-
border: `1px solid ${input.trim() && !loading ? '
|
|
433
|
+
background: input.trim() && !loading ? 'var(--bg-select)' : 'transparent',
|
|
434
|
+
border: `1px solid ${input.trim() && !loading ? 'var(--ac-primary)' : 'var(--bd-muted)'}`,
|
|
435
435
|
borderRadius: 4,
|
|
436
|
-
color: input.trim() && !loading ? '
|
|
436
|
+
color: input.trim() && !loading ? 'var(--tx-primary)' : 'var(--tx-ghost)',
|
|
437
437
|
fontSize: 8, padding: '4px 12px',
|
|
438
438
|
cursor: input.trim() && !loading ? 'pointer' : 'default',
|
|
439
439
|
fontFamily: 'inherit', letterSpacing: '0.06em',
|
|
@@ -17,6 +17,7 @@ export function ClusterGraph({
|
|
|
17
17
|
affectedIds,
|
|
18
18
|
linkedIds,
|
|
19
19
|
focusedIds,
|
|
20
|
+
noGlow,
|
|
20
21
|
}) {
|
|
21
22
|
const clusterPos = useMemo(
|
|
22
23
|
() => computeClusterLayout(clusters),
|
|
@@ -112,13 +113,13 @@ export function ClusterGraph({
|
|
|
112
113
|
>
|
|
113
114
|
<defs>
|
|
114
115
|
<marker id="carr" markerWidth="6" markerHeight="6" refX="5" refY="2.5" orient="auto">
|
|
115
|
-
<path d="M0,0 L0,5 L6,2.5z"
|
|
116
|
+
<path d="M0,0 L0,5 L6,2.5z" style={{ fill: 'var(--ac-cluster-arr)' }} />
|
|
116
117
|
</marker>
|
|
117
118
|
<marker id="carr-sel" markerWidth="6" markerHeight="6" refX="5" refY="2.5" orient="auto">
|
|
118
|
-
<path d="M0,0 L0,5 L6,2.5z"
|
|
119
|
+
<path d="M0,0 L0,5 L6,2.5z" style={{ fill: 'var(--ac-primary)' }} />
|
|
119
120
|
</marker>
|
|
120
121
|
<marker id="carr-in" markerWidth="6" markerHeight="6" refX="5" refY="2.5" orient="auto">
|
|
121
|
-
<path d="M0,0 L0,5 L6,2.5z"
|
|
122
|
+
<path d="M0,0 L0,5 L6,2.5z" style={{ fill: 'var(--ac-teal)' }} />
|
|
122
123
|
</marker>
|
|
123
124
|
<filter id="cglow">
|
|
124
125
|
<feGaussianBlur stdDeviation="6" result="b" />
|
|
@@ -139,7 +140,11 @@ export function ClusterGraph({
|
|
|
139
140
|
<g transform={`translate(${transform.x},${transform.y}) scale(${transform.k})`}>
|
|
140
141
|
{/* Inter-cluster edges */}
|
|
141
142
|
{!selectedId &&
|
|
142
|
-
|
|
143
|
+
(() => {
|
|
144
|
+
const focusedClusterIds = focusedIds?.length > 0
|
|
145
|
+
? new Set(nodes.filter((n) => focusedIds.includes(n.id)).map((n) => n.cluster.id))
|
|
146
|
+
: null;
|
|
147
|
+
return clusterEdges.map((e) => {
|
|
143
148
|
const s = clusterPos[e.source],
|
|
144
149
|
t = clusterPos[e.target];
|
|
145
150
|
if (!s || !t) return null;
|
|
@@ -151,6 +156,8 @@ export function ClusterGraph({
|
|
|
151
156
|
const rs = 38,
|
|
152
157
|
rt = 38;
|
|
153
158
|
const w = Math.min(1 + e.count * 0.15, 4);
|
|
159
|
+
const isDimEdge = focusedClusterIds &&
|
|
160
|
+
!focusedClusterIds.has(e.source) && !focusedClusterIds.has(e.target);
|
|
154
161
|
return (
|
|
155
162
|
<g key={e.id}>
|
|
156
163
|
<line
|
|
@@ -158,9 +165,9 @@ export function ClusterGraph({
|
|
|
158
165
|
y1={s.y + ny * rs}
|
|
159
166
|
x2={t.x - nx * (rt + 5)}
|
|
160
167
|
y2={t.y - ny * (rt + 5)}
|
|
161
|
-
stroke="
|
|
168
|
+
stroke="var(--ac-arrow)"
|
|
162
169
|
strokeWidth={w}
|
|
163
|
-
strokeOpacity={0.5}
|
|
170
|
+
strokeOpacity={isDimEdge ? 0.06 : 0.5}
|
|
164
171
|
markerEnd="url(#carr)"
|
|
165
172
|
/>
|
|
166
173
|
<text
|
|
@@ -168,15 +175,15 @@ export function ClusterGraph({
|
|
|
168
175
|
y={(s.y + ny * rs + t.y - ny * (rt + 5)) / 2 - 4}
|
|
169
176
|
textAnchor="middle"
|
|
170
177
|
fontSize={7}
|
|
171
|
-
fill="#2a3060"
|
|
172
178
|
fontFamily="'JetBrains Mono',monospace"
|
|
173
|
-
style={{ pointerEvents: 'none' }}
|
|
179
|
+
style={{ pointerEvents: 'none', fill: 'var(--ac-cluster-arr)' }}
|
|
174
180
|
>
|
|
175
181
|
{e.count}
|
|
176
182
|
</text>
|
|
177
183
|
</g>
|
|
178
184
|
);
|
|
179
|
-
})
|
|
185
|
+
});
|
|
186
|
+
})()}
|
|
180
187
|
|
|
181
188
|
{/* Node-level edges when a node is selected */}
|
|
182
189
|
{selectedId &&
|
|
@@ -208,7 +215,7 @@ export function ClusterGraph({
|
|
|
208
215
|
y1={sp.y + ny * 14}
|
|
209
216
|
x2={tp.x - nx * 19}
|
|
210
217
|
y2={tp.y - ny * 19}
|
|
211
|
-
stroke={isOut ? '
|
|
218
|
+
stroke={isOut ? 'var(--ac-primary)' : 'var(--ac-teal)'}
|
|
212
219
|
strokeWidth={1.5}
|
|
213
220
|
strokeOpacity={0.9}
|
|
214
221
|
strokeDasharray={e.isType ? '4 2' : undefined}
|
|
@@ -239,6 +246,9 @@ export function ClusterGraph({
|
|
|
239
246
|
const nx = dx / len,
|
|
240
247
|
ny = dy / len,
|
|
241
248
|
r = 13;
|
|
249
|
+
const isSel = e.source === selectedId || e.target === selectedId;
|
|
250
|
+
const isDimEdge = focusedIds?.length > 0 && !isSel &&
|
|
251
|
+
!focusedIds.includes(e.source) && !focusedIds.includes(e.target);
|
|
242
252
|
return (
|
|
243
253
|
<line
|
|
244
254
|
key={e.id}
|
|
@@ -248,7 +258,7 @@ export function ClusterGraph({
|
|
|
248
258
|
y2={t.y - ny * (r + 4)}
|
|
249
259
|
stroke={cl.color}
|
|
250
260
|
strokeWidth={0.8}
|
|
251
|
-
strokeOpacity={0.45}
|
|
261
|
+
strokeOpacity={isDimEdge ? 0.06 : 0.45}
|
|
252
262
|
strokeDasharray={e.isType ? '3 2' : undefined}
|
|
253
263
|
markerEnd="url(#carr)"
|
|
254
264
|
/>
|
|
@@ -278,7 +288,7 @@ export function ClusterGraph({
|
|
|
278
288
|
linkedIds.size > 0 && allMembers.some((n) => linkedIds.has(n.id));
|
|
279
289
|
const hasFocused = focusedIds?.length > 0;
|
|
280
290
|
const clusterFocused = hasFocused && allMembers.some((n) => focusedIds.includes(n.id));
|
|
281
|
-
const isClusterGreyed =
|
|
291
|
+
const isClusterGreyed =
|
|
282
292
|
(hasFocused && !clusterFocused && !clusterLinked) ||
|
|
283
293
|
(!hasFocused && visibleMembers.length === 0 && !clusterLinked);
|
|
284
294
|
const isLinkedCollapsed = clusterLinked && !isExpanded;
|
|
@@ -290,10 +300,11 @@ export function ClusterGraph({
|
|
|
290
300
|
}}
|
|
291
301
|
style={{ cursor: 'pointer' }}
|
|
292
302
|
filter={
|
|
293
|
-
isExpanded ? 'url(#cglow)' : isLinkedCollapsed ? 'url(#cglow)' : undefined
|
|
303
|
+
noGlow ? undefined : isExpanded ? 'url(#cglow)' : isLinkedCollapsed ? 'url(#cglow)' : undefined
|
|
294
304
|
}
|
|
295
305
|
opacity={isClusterGreyed ? 0.18 : 1}
|
|
296
306
|
>
|
|
307
|
+
<title>{cl.name} — {allMembers.length} file{allMembers.length !== 1 ? 's' : ''}</title>
|
|
297
308
|
<circle
|
|
298
309
|
r={r}
|
|
299
310
|
fill={isLinkedCollapsed ? `${cl.color}18` : `${cl.color}10`}
|
|
@@ -371,12 +382,13 @@ export function ClusterGraph({
|
|
|
371
382
|
if (!isDrag()) onSelectNode(n.id);
|
|
372
383
|
}}
|
|
373
384
|
style={{ cursor: 'pointer' }}
|
|
374
|
-
filter={isSel ? 'url(#nglow)' : undefined}
|
|
385
|
+
filter={noGlow ? undefined : isSel ? 'url(#nglow)' : undefined}
|
|
375
386
|
opacity={isGreyed ? 0.18 : 1}
|
|
376
387
|
>
|
|
388
|
+
<title>{n.label}{n.path ? `\n${n.path}` : ''}</title>
|
|
377
389
|
<circle
|
|
378
390
|
r={13}
|
|
379
|
-
fill={isSel ? `${col}1a` : '
|
|
391
|
+
fill={isSel ? `${col}1a` : 'var(--bg-node)'}
|
|
380
392
|
stroke={isSel ? col : isAff ? col : cl.color}
|
|
381
393
|
strokeWidth={isSel ? 2 : 0.8}
|
|
382
394
|
strokeOpacity={isSel ? 1 : isAff ? 0.9 : 0.45}
|
|
@@ -385,7 +397,7 @@ export function ClusterGraph({
|
|
|
385
397
|
textAnchor="middle"
|
|
386
398
|
dominantBaseline="middle"
|
|
387
399
|
fontSize={6}
|
|
388
|
-
fill={isSel ? '
|
|
400
|
+
fill={isSel ? 'var(--tx-node-sel)' : 'var(--tx-node)'}
|
|
389
401
|
fontFamily="'JetBrains Mono',monospace"
|
|
390
402
|
style={{ pointerEvents: 'none' }}
|
|
391
403
|
>
|
|
@@ -406,10 +418,10 @@ export function ClusterGraph({
|
|
|
406
418
|
style={{
|
|
407
419
|
fontSize: 8,
|
|
408
420
|
padding: '2px 6px',
|
|
409
|
-
background: '
|
|
410
|
-
border: `1px solid ${transform.x !== 0 || transform.y !== 0 || transform.k !== 1 ? '
|
|
421
|
+
background: 'var(--bg-input)',
|
|
422
|
+
border: `1px solid ${transform.x !== 0 || transform.y !== 0 || transform.k !== 1 ? 'var(--ac-primary)' : 'var(--bd-muted)'}`,
|
|
411
423
|
borderRadius: 4,
|
|
412
|
-
color: transform.x !== 0 || transform.y !== 0 || transform.k !== 1 ? '
|
|
424
|
+
color: transform.x !== 0 || transform.y !== 0 || transform.k !== 1 ? 'var(--ac-primary)' : 'var(--tx-faint)',
|
|
413
425
|
cursor: 'pointer',
|
|
414
426
|
fontFamily: "'JetBrains Mono',monospace",
|
|
415
427
|
letterSpacing: '0.05em',
|
|
@@ -423,10 +435,10 @@ export function ClusterGraph({
|
|
|
423
435
|
style={{
|
|
424
436
|
fontSize: 8,
|
|
425
437
|
padding: '2px 6px',
|
|
426
|
-
background: '
|
|
427
|
-
border: `1px solid ${hasSelection ? '
|
|
438
|
+
background: 'var(--bg-input)',
|
|
439
|
+
border: `1px solid ${hasSelection ? 'var(--ac-primary)' : 'var(--bd-muted)'}`,
|
|
428
440
|
borderRadius: 4,
|
|
429
|
-
color: hasSelection ? '
|
|
441
|
+
color: hasSelection ? 'var(--ac-primary)' : 'var(--tx-faint)',
|
|
430
442
|
cursor: hasSelection ? 'pointer' : 'default',
|
|
431
443
|
fontFamily: "'JetBrains Mono',monospace",
|
|
432
444
|
letterSpacing: '0.05em',
|