fraude-code 0.1.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 +68 -0
- package/dist/index.js +179297 -0
- package/package.json +88 -0
- package/src/agent/agent.ts +475 -0
- package/src/agent/contextManager.ts +141 -0
- package/src/agent/index.ts +14 -0
- package/src/agent/pendingChanges.ts +270 -0
- package/src/agent/prompts/AskPrompt.txt +10 -0
- package/src/agent/prompts/FastPrompt.txt +40 -0
- package/src/agent/prompts/PlannerPrompt.txt +51 -0
- package/src/agent/prompts/ReviewerPrompt.txt +57 -0
- package/src/agent/prompts/WorkerPrompt.txt +33 -0
- package/src/agent/subagents/askAgent.ts +37 -0
- package/src/agent/subagents/extractionAgent.ts +123 -0
- package/src/agent/subagents/fastAgent.ts +45 -0
- package/src/agent/subagents/managerAgent.ts +36 -0
- package/src/agent/subagents/relationAgent.ts +76 -0
- package/src/agent/subagents/researchSubAgent.ts +79 -0
- package/src/agent/subagents/reviewerSubAgent.ts +42 -0
- package/src/agent/subagents/workerSubAgent.ts +42 -0
- package/src/agent/tools/bashTool.ts +94 -0
- package/src/agent/tools/descriptions/bash.txt +47 -0
- package/src/agent/tools/descriptions/edit.txt +7 -0
- package/src/agent/tools/descriptions/glob.txt +4 -0
- package/src/agent/tools/descriptions/grep.txt +8 -0
- package/src/agent/tools/descriptions/lsp.txt +20 -0
- package/src/agent/tools/descriptions/plan.txt +3 -0
- package/src/agent/tools/descriptions/read.txt +9 -0
- package/src/agent/tools/descriptions/todo.txt +12 -0
- package/src/agent/tools/descriptions/write.txt +8 -0
- package/src/agent/tools/editTool.ts +44 -0
- package/src/agent/tools/globTool.ts +59 -0
- package/src/agent/tools/grepTool.ts +343 -0
- package/src/agent/tools/lspTool.ts +429 -0
- package/src/agent/tools/planTool.ts +118 -0
- package/src/agent/tools/readTool.ts +78 -0
- package/src/agent/tools/rememberTool.ts +91 -0
- package/src/agent/tools/testRunnerTool.ts +77 -0
- package/src/agent/tools/testTool.ts +44 -0
- package/src/agent/tools/todoTool.ts +224 -0
- package/src/agent/tools/writeTool.ts +33 -0
- package/src/commands/COMMANDS.ts +38 -0
- package/src/commands/cerebras/auth.ts +27 -0
- package/src/commands/cerebras/index.ts +31 -0
- package/src/commands/forget.ts +29 -0
- package/src/commands/google/auth.ts +24 -0
- package/src/commands/google/index.ts +31 -0
- package/src/commands/groq/add_model.ts +60 -0
- package/src/commands/groq/auth.ts +24 -0
- package/src/commands/groq/index.ts +33 -0
- package/src/commands/index.ts +65 -0
- package/src/commands/knowledge.ts +92 -0
- package/src/commands/log.ts +32 -0
- package/src/commands/mistral/auth.ts +27 -0
- package/src/commands/mistral/index.ts +31 -0
- package/src/commands/model/index.ts +145 -0
- package/src/commands/models/index.ts +16 -0
- package/src/commands/ollama/index.ts +29 -0
- package/src/commands/openrouter/add_model.ts +64 -0
- package/src/commands/openrouter/auth.ts +24 -0
- package/src/commands/openrouter/index.ts +33 -0
- package/src/commands/remember.ts +48 -0
- package/src/commands/serve.ts +31 -0
- package/src/commands/session/index.ts +21 -0
- package/src/commands/usage.ts +15 -0
- package/src/commands/visualize.ts +773 -0
- package/src/components/App.tsx +55 -0
- package/src/components/IntroComponent.tsx +70 -0
- package/src/components/LoaderComponent.tsx +68 -0
- package/src/components/OutputRenderer.tsx +88 -0
- package/src/components/SettingsRenderer.tsx +23 -0
- package/src/components/input/CommandSuggestions.tsx +41 -0
- package/src/components/input/FileSuggestions.tsx +61 -0
- package/src/components/input/InputBox.tsx +371 -0
- package/src/components/output/CheckpointView.tsx +13 -0
- package/src/components/output/CommandView.tsx +13 -0
- package/src/components/output/CommentView.tsx +12 -0
- package/src/components/output/ConfirmationView.tsx +179 -0
- package/src/components/output/ContextUsage.tsx +62 -0
- package/src/components/output/DiffView.tsx +202 -0
- package/src/components/output/ErrorView.tsx +14 -0
- package/src/components/output/InteractiveServerView.tsx +69 -0
- package/src/components/output/KnowledgeView.tsx +220 -0
- package/src/components/output/MarkdownView.tsx +15 -0
- package/src/components/output/ModelSelectView.tsx +71 -0
- package/src/components/output/ReasoningView.tsx +21 -0
- package/src/components/output/ToolCallView.tsx +45 -0
- package/src/components/settings/ModelList.tsx +250 -0
- package/src/components/settings/TokenUsage.tsx +274 -0
- package/src/config/schema.ts +19 -0
- package/src/config/settings.ts +229 -0
- package/src/index.tsx +100 -0
- package/src/parsers/tree-sitter-python.wasm +0 -0
- package/src/providers/providers.ts +71 -0
- package/src/services/PluginLoader.ts +123 -0
- package/src/services/cerebras.ts +69 -0
- package/src/services/embeddingService.ts +229 -0
- package/src/services/google.ts +65 -0
- package/src/services/graphSerializer.ts +248 -0
- package/src/services/groq.ts +23 -0
- package/src/services/knowledgeOrchestrator.ts +286 -0
- package/src/services/mistral.ts +79 -0
- package/src/services/ollama.ts +109 -0
- package/src/services/openrouter.ts +23 -0
- package/src/services/symbolExtractor.ts +277 -0
- package/src/store/useFraudeStore.ts +123 -0
- package/src/store/useSettingsStore.ts +38 -0
- package/src/theme.ts +26 -0
- package/src/types/Agent.ts +147 -0
- package/src/types/CommandDefinition.ts +8 -0
- package/src/types/Model.ts +94 -0
- package/src/types/OutputItem.ts +24 -0
- package/src/types/PluginContext.ts +55 -0
- package/src/types/TokenUsage.ts +5 -0
- package/src/types/assets.d.ts +4 -0
- package/src/utils/agentCognition.ts +1152 -0
- package/src/utils/fileSuggestions.ts +111 -0
- package/src/utils/index.ts +17 -0
- package/src/utils/initFraude.ts +8 -0
- package/src/utils/logger.ts +24 -0
- package/src/utils/lspClient.ts +1415 -0
- package/src/utils/paths.ts +24 -0
- package/src/utils/queryHandler.ts +227 -0
- package/src/utils/router.ts +278 -0
- package/src/utils/streamHandler.ts +132 -0
- package/src/utils/treeSitterQueries.ts +125 -0
- package/tsconfig.json +33 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
import { BunApiRouter } from "@/utils/router";
|
|
2
|
+
import type { Command } from "@/types/CommandDefinition";
|
|
3
|
+
import log from "@/utils/logger";
|
|
4
|
+
import AgentCognition from "@/utils/agentCognition";
|
|
5
|
+
import { exec } from "child_process";
|
|
6
|
+
|
|
7
|
+
const VISUALIZATION_HTML = `
|
|
8
|
+
<!DOCTYPE html>
|
|
9
|
+
<html lang="en">
|
|
10
|
+
<head>
|
|
11
|
+
<meta charset="UTF-8">
|
|
12
|
+
<title>Fraude | Neural Matrix</title>
|
|
13
|
+
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
|
|
14
|
+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Inter:wght@300;400;600&display=swap" rel="stylesheet">
|
|
15
|
+
<style>
|
|
16
|
+
:root {
|
|
17
|
+
--bg-dark: #050510;
|
|
18
|
+
--bg-panel: rgba(20, 20, 35, 0.7);
|
|
19
|
+
--border-color: rgba(255, 255, 255, 0.1);
|
|
20
|
+
--accent-primary: #00f2ea;
|
|
21
|
+
--accent-secondary: #7c3aed;
|
|
22
|
+
--text-main: #e0e0e0;
|
|
23
|
+
--text-dim: #94a3b8;
|
|
24
|
+
--glass-blur: blur(12px);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
* { box-sizing: border-box; outline: none; }
|
|
28
|
+
|
|
29
|
+
body, html {
|
|
30
|
+
height: 100%;
|
|
31
|
+
margin: 0;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
font-family: 'Inter', sans-serif;
|
|
34
|
+
background-color: var(--bg-dark);
|
|
35
|
+
background-image:
|
|
36
|
+
radial-gradient(circle at 15% 50%, rgba(124, 58, 237, 0.08), transparent 25%),
|
|
37
|
+
radial-gradient(circle at 85% 30%, rgba(0, 242, 234, 0.08), transparent 25%);
|
|
38
|
+
color: var(--text-main);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* --- Canvas --- */
|
|
42
|
+
#mynetwork {
|
|
43
|
+
width: 100%;
|
|
44
|
+
height: 100%;
|
|
45
|
+
position: absolute;
|
|
46
|
+
top: 0;
|
|
47
|
+
left: 0;
|
|
48
|
+
z-index: 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* --- UI Layer --- */
|
|
52
|
+
.ui-layer {
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 0;
|
|
55
|
+
left: 0;
|
|
56
|
+
width: 100%;
|
|
57
|
+
height: 100%;
|
|
58
|
+
pointer-events: none; /* Let clicks pass through to network */
|
|
59
|
+
z-index: 10;
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
justify-content: space-between;
|
|
63
|
+
padding: 20px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.interactive { pointer-events: auto; }
|
|
67
|
+
|
|
68
|
+
/* --- Header --- */
|
|
69
|
+
.header {
|
|
70
|
+
display: flex;
|
|
71
|
+
justify-content: space-between;
|
|
72
|
+
align-items: center;
|
|
73
|
+
padding: 12px 24px;
|
|
74
|
+
background: var(--bg-panel);
|
|
75
|
+
border: 1px solid var(--border-color);
|
|
76
|
+
border-radius: 16px;
|
|
77
|
+
backdrop-filter: var(--glass-blur);
|
|
78
|
+
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
|
|
79
|
+
max-width: 1200px;
|
|
80
|
+
margin: 0 auto;
|
|
81
|
+
width: 90%;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.brand {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
gap: 12px;
|
|
88
|
+
font-family: 'JetBrains Mono', monospace;
|
|
89
|
+
font-weight: 700;
|
|
90
|
+
font-size: 1.1rem;
|
|
91
|
+
color: #fff;
|
|
92
|
+
text-shadow: 0 0 10px rgba(255,255,255,0.3);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.brand-dot {
|
|
96
|
+
width: 10px;
|
|
97
|
+
height: 10px;
|
|
98
|
+
background: var(--accent-primary);
|
|
99
|
+
border-radius: 50%;
|
|
100
|
+
box-shadow: 0 0 10px var(--accent-primary);
|
|
101
|
+
animation: pulse 2s infinite;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@keyframes pulse {
|
|
105
|
+
0% { box-shadow: 0 0 0 0 rgba(0, 242, 234, 0.4); }
|
|
106
|
+
70% { box-shadow: 0 0 0 10px rgba(0, 242, 234, 0); }
|
|
107
|
+
100% { box-shadow: 0 0 0 0 rgba(0, 242, 234, 0); }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* --- Search Bar --- */
|
|
111
|
+
.search-container {
|
|
112
|
+
position: relative;
|
|
113
|
+
width: 300px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.search-input {
|
|
117
|
+
width: 100%;
|
|
118
|
+
background: rgba(0, 0, 0, 0.3);
|
|
119
|
+
border: 1px solid var(--border-color);
|
|
120
|
+
border-radius: 8px;
|
|
121
|
+
padding: 8px 16px 8px 36px;
|
|
122
|
+
color: #fff;
|
|
123
|
+
font-family: 'Inter', sans-serif;
|
|
124
|
+
font-size: 0.9rem;
|
|
125
|
+
transition: all 0.3s ease;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.search-input:focus {
|
|
129
|
+
border-color: var(--accent-primary);
|
|
130
|
+
background: rgba(0, 0, 0, 0.5);
|
|
131
|
+
box-shadow: 0 0 15px rgba(0, 242, 234, 0.1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.search-icon {
|
|
135
|
+
position: absolute;
|
|
136
|
+
left: 10px;
|
|
137
|
+
top: 50%;
|
|
138
|
+
transform: translateY(-50%);
|
|
139
|
+
opacity: 0.5;
|
|
140
|
+
width: 16px;
|
|
141
|
+
height: 16px;
|
|
142
|
+
fill: currentColor;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* --- Stats --- */
|
|
146
|
+
.stats {
|
|
147
|
+
font-family: 'JetBrains Mono', monospace;
|
|
148
|
+
font-size: 0.8rem;
|
|
149
|
+
color: var(--text-dim);
|
|
150
|
+
display: flex;
|
|
151
|
+
gap: 16px;
|
|
152
|
+
}
|
|
153
|
+
.stat-item b { color: #fff; margin-left: 4px; }
|
|
154
|
+
|
|
155
|
+
/* --- Side Panel --- */
|
|
156
|
+
.side-panel {
|
|
157
|
+
position: absolute;
|
|
158
|
+
right: 20px;
|
|
159
|
+
top: 90px;
|
|
160
|
+
bottom: 20px;
|
|
161
|
+
width: 350px;
|
|
162
|
+
background: rgba(13, 17, 26, 0.85); /* Darker, more opaque */
|
|
163
|
+
border-left: 1px solid var(--border-color);
|
|
164
|
+
backdrop-filter: blur(20px);
|
|
165
|
+
transform: translateX(120%);
|
|
166
|
+
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
|
|
167
|
+
z-index: 20;
|
|
168
|
+
border-radius: 16px;
|
|
169
|
+
display: flex;
|
|
170
|
+
flex-direction: column;
|
|
171
|
+
overflow: hidden;
|
|
172
|
+
box-shadow: -10px 0 30px rgba(0,0,0,0.5);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.side-panel.open { transform: translateX(0); }
|
|
176
|
+
|
|
177
|
+
.panel-header {
|
|
178
|
+
padding: 20px;
|
|
179
|
+
border-bottom: 1px solid var(--border-color);
|
|
180
|
+
background: rgba(255,255,255,0.02);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.panel-title {
|
|
184
|
+
font-size: 1.2rem;
|
|
185
|
+
font-weight: 600;
|
|
186
|
+
margin: 0 0 4px 0;
|
|
187
|
+
color: #fff;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.panel-subtitle {
|
|
191
|
+
font-size: 0.8rem;
|
|
192
|
+
color: var(--text-dim);
|
|
193
|
+
text-transform: uppercase;
|
|
194
|
+
letter-spacing: 1px;
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: center;
|
|
197
|
+
gap: 6px;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.type-badge {
|
|
201
|
+
display: inline-block;
|
|
202
|
+
width: 8px;
|
|
203
|
+
height: 8px;
|
|
204
|
+
border-radius: 50%;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.panel-content {
|
|
208
|
+
padding: 20px;
|
|
209
|
+
flex: 1;
|
|
210
|
+
overflow-y: auto;
|
|
211
|
+
font-family: 'JetBrains Mono', monospace;
|
|
212
|
+
font-size: 0.9rem;
|
|
213
|
+
line-height: 1.5;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.prop-row {
|
|
217
|
+
margin-bottom: 16px;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.prop-label {
|
|
221
|
+
display: block;
|
|
222
|
+
font-size: 0.75rem;
|
|
223
|
+
color: var(--text-dim);
|
|
224
|
+
margin-bottom: 4px;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.prop-value {
|
|
228
|
+
color: var(--text-main);
|
|
229
|
+
word-break: break-word;
|
|
230
|
+
background: rgba(0,0,0,0.2);
|
|
231
|
+
padding: 8px;
|
|
232
|
+
border-radius: 6px;
|
|
233
|
+
border: 1px solid var(--border-color);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.close-btn {
|
|
237
|
+
position: absolute;
|
|
238
|
+
top: 15px;
|
|
239
|
+
right: 15px;
|
|
240
|
+
background: none;
|
|
241
|
+
border: none;
|
|
242
|
+
color: var(--text-dim);
|
|
243
|
+
cursor: pointer;
|
|
244
|
+
font-size: 1.2rem;
|
|
245
|
+
transition: color 0.2s;
|
|
246
|
+
}
|
|
247
|
+
.close-btn:hover { color: #fff; }
|
|
248
|
+
|
|
249
|
+
/* --- Dock (Legend/Filter) --- */
|
|
250
|
+
.dock-container {
|
|
251
|
+
position: absolute;
|
|
252
|
+
bottom: 30px;
|
|
253
|
+
left: 50%;
|
|
254
|
+
transform: translateX(-50%);
|
|
255
|
+
background: var(--bg-panel);
|
|
256
|
+
padding: 10px 20px;
|
|
257
|
+
border-radius: 20px;
|
|
258
|
+
border: 1px solid var(--border-color);
|
|
259
|
+
backdrop-filter: var(--glass-blur);
|
|
260
|
+
display: flex;
|
|
261
|
+
gap: 8px;
|
|
262
|
+
box-shadow: 0 10px 40px rgba(0,0,0,0.4);
|
|
263
|
+
overflow-x: auto;
|
|
264
|
+
max-width: 90%;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.dock-item {
|
|
268
|
+
display: flex;
|
|
269
|
+
align-items: center;
|
|
270
|
+
gap: 6px;
|
|
271
|
+
padding: 6px 12px;
|
|
272
|
+
border-radius: 12px;
|
|
273
|
+
cursor: pointer;
|
|
274
|
+
transition: all 0.2s;
|
|
275
|
+
border: 1px solid transparent;
|
|
276
|
+
white-space: nowrap;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.dock-item:hover {
|
|
280
|
+
background: rgba(255,255,255,0.05);
|
|
281
|
+
border-color: rgba(255,255,255,0.1);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.dock-item.active {
|
|
285
|
+
background: rgba(255,255,255,0.1);
|
|
286
|
+
border-color: rgba(255,255,255,0.15);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.dock-item.faded { opacity: 0.4; }
|
|
290
|
+
|
|
291
|
+
.dock-dot { width: 8px; height: 8px; border-radius: 50%; box-shadow: 0 0 5px currentColor; }
|
|
292
|
+
|
|
293
|
+
/* --- Loading Screen --- */
|
|
294
|
+
#loading {
|
|
295
|
+
position: absolute;
|
|
296
|
+
top: 0; left: 0; width: 100%; height: 100%;
|
|
297
|
+
background: #050510;
|
|
298
|
+
z-index: 100;
|
|
299
|
+
display: flex;
|
|
300
|
+
flex-direction: column;
|
|
301
|
+
align-items: center;
|
|
302
|
+
justify-content: center;
|
|
303
|
+
transition: opacity 0.8s ease;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.loader-ring {
|
|
307
|
+
width: 60px; height: 60px;
|
|
308
|
+
border: 2px solid transparent;
|
|
309
|
+
border-top-color: var(--accent-primary);
|
|
310
|
+
border-right-color: var(--accent-secondary);
|
|
311
|
+
border-radius: 50%;
|
|
312
|
+
animation: spin 1s linear infinite;
|
|
313
|
+
margin-bottom: 20px;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.loading-text {
|
|
317
|
+
font-family: 'JetBrains Mono', monospace;
|
|
318
|
+
color: var(--accent-primary);
|
|
319
|
+
font-size: 0.9rem;
|
|
320
|
+
letter-spacing: 2px;
|
|
321
|
+
animation: blink 1.5s infinite;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
@keyframes spin { 100% { transform: rotate(360deg); } }
|
|
325
|
+
@keyframes blink { 50% { opacity: 0.5; } }
|
|
326
|
+
|
|
327
|
+
</style>
|
|
328
|
+
</head>
|
|
329
|
+
<body>
|
|
330
|
+
|
|
331
|
+
<!-- Loading Screen -->
|
|
332
|
+
<div id="loading">
|
|
333
|
+
<div class="loader-ring"></div>
|
|
334
|
+
<div class="loading-text" id="loading-text">INITIALIZING NEURAL MATRIX...</div>
|
|
335
|
+
</div>
|
|
336
|
+
|
|
337
|
+
<!-- Network Container -->
|
|
338
|
+
<div id="mynetwork"></div>
|
|
339
|
+
|
|
340
|
+
<!-- UI Overlay -->
|
|
341
|
+
<div class="ui-layer">
|
|
342
|
+
|
|
343
|
+
<!-- Top Header -->
|
|
344
|
+
<div class="header interactive">
|
|
345
|
+
<div class="brand">
|
|
346
|
+
<div class="brand-dot"></div>
|
|
347
|
+
FRAUDE CODE
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
<div class="search-container">
|
|
351
|
+
<svg class="search-icon" viewBox="0 0 24 24"><path d="M21.71 20.29L18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42zM11 18a7 7 0 1 1 7-7 7 7 0 0 1-7 7z"/></svg>
|
|
352
|
+
<input type="text" class="search-input" placeholder="Search function, file..." id="search-input" oninput="handleSearch(this.value)">
|
|
353
|
+
</div>
|
|
354
|
+
|
|
355
|
+
<div class="stats">
|
|
356
|
+
<span class="stat-item">NODES<b id="node-count">0</b></span>
|
|
357
|
+
<span class="stat-item">RELATIONS<b id="edge-count">0</b></span>
|
|
358
|
+
</div>
|
|
359
|
+
</div>
|
|
360
|
+
|
|
361
|
+
<!-- Side Panel -->
|
|
362
|
+
<div class="side-panel interactive" id="side-panel">
|
|
363
|
+
<button class="close-btn" onclick="closePanel()">×</button>
|
|
364
|
+
<div class="panel-header">
|
|
365
|
+
<h2 class="panel-title" id="panel-title">Node Name</h2>
|
|
366
|
+
<div class="panel-subtitle">
|
|
367
|
+
<span class="type-badge" id="panel-color"></span>
|
|
368
|
+
<span id="panel-type">Type</span>
|
|
369
|
+
</div>
|
|
370
|
+
</div>
|
|
371
|
+
<div class="panel-content">
|
|
372
|
+
<div class="prop-row">
|
|
373
|
+
<span class="prop-label">Full Identifier</span>
|
|
374
|
+
<div class="prop-value" id="panel-id">...</div>
|
|
375
|
+
</div>
|
|
376
|
+
<div class="prop-row">
|
|
377
|
+
<span class="prop-label">Context / Content</span>
|
|
378
|
+
<div class="prop-value" id="panel-desc">...</div>
|
|
379
|
+
</div>
|
|
380
|
+
<div class="prop-row">
|
|
381
|
+
<span class="prop-label">Relationships</span>
|
|
382
|
+
<div id="panel-rels"></div>
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
385
|
+
</div>
|
|
386
|
+
|
|
387
|
+
<!-- Bottom Dock -->
|
|
388
|
+
<div class="dock-container interactive" id="filter-dock">
|
|
389
|
+
<!-- Generated via JS -->
|
|
390
|
+
</div>
|
|
391
|
+
|
|
392
|
+
</div>
|
|
393
|
+
|
|
394
|
+
<script type="text/javascript">
|
|
395
|
+
let network;
|
|
396
|
+
let allNodes;
|
|
397
|
+
let allEdges;
|
|
398
|
+
let nodesDataSet;
|
|
399
|
+
let edgesDataSet;
|
|
400
|
+
const typeColors = {
|
|
401
|
+
// Semantic
|
|
402
|
+
fact: "#00f2ea", // Cyan
|
|
403
|
+
decision: "#39ff14", // Neon Green
|
|
404
|
+
concept: "#ff00ff", // Magenta
|
|
405
|
+
reference: "#ffaa00", // Orange
|
|
406
|
+
// Code
|
|
407
|
+
file: "#58a6ff", // Blue
|
|
408
|
+
module: "#7c3aed", // Violet
|
|
409
|
+
function: "#f97316", // Orange
|
|
410
|
+
class: "#ec4899", // Pink
|
|
411
|
+
interface: "#14b8a6", // Teal
|
|
412
|
+
variable: "#a855f7", // Purple
|
|
413
|
+
symbol: "#94a3b8" // Slate
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
async function fetchGraph() {
|
|
417
|
+
try {
|
|
418
|
+
const response = await fetch('/api/graph');
|
|
419
|
+
const data = await response.json();
|
|
420
|
+
|
|
421
|
+
// Update Stats
|
|
422
|
+
document.getElementById('node-count').innerText = data.nodes.length;
|
|
423
|
+
document.getElementById('edge-count').innerText = data.edges.length;
|
|
424
|
+
|
|
425
|
+
initGraph(data.nodes, data.edges);
|
|
426
|
+
generateDock(data.nodes);
|
|
427
|
+
} catch (error) {
|
|
428
|
+
document.getElementById('loading-text').textContent = 'SYSTEM FAILURE: ' + error.message;
|
|
429
|
+
document.getElementById('loading-text').style.color = '#ff5555';
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function initGraph(nodes, edges) {
|
|
434
|
+
var container = document.getElementById('mynetwork');
|
|
435
|
+
|
|
436
|
+
nodesDataSet = new vis.DataSet(nodes);
|
|
437
|
+
edgesDataSet = new vis.DataSet(edges);
|
|
438
|
+
|
|
439
|
+
var data = { nodes: nodesDataSet, edges: edgesDataSet };
|
|
440
|
+
|
|
441
|
+
var options = {
|
|
442
|
+
nodes: {
|
|
443
|
+
shape: 'dot',
|
|
444
|
+
size: 20,
|
|
445
|
+
font: {
|
|
446
|
+
color: '#e0e0e0',
|
|
447
|
+
size: 14,
|
|
448
|
+
face: 'Inter',
|
|
449
|
+
strokeWidth: 4,
|
|
450
|
+
strokeColor: '#050510',
|
|
451
|
+
vadjust: -35 // Push label above node
|
|
452
|
+
},
|
|
453
|
+
borderWidth: 0,
|
|
454
|
+
shadow: {
|
|
455
|
+
enabled: true,
|
|
456
|
+
color: 'rgba(0,0,0,0.5)',
|
|
457
|
+
size: 10,
|
|
458
|
+
x: 0, y: 5
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
edges: {
|
|
462
|
+
width: 1,
|
|
463
|
+
color: {
|
|
464
|
+
color: 'rgba(255,255,255,0.15)',
|
|
465
|
+
highlight: '#fff',
|
|
466
|
+
hover: '#fff'
|
|
467
|
+
},
|
|
468
|
+
smooth: { type: 'continuous', roundness: 0.5 },
|
|
469
|
+
selectionWidth: 2
|
|
470
|
+
},
|
|
471
|
+
physics: {
|
|
472
|
+
stabilization: {
|
|
473
|
+
enabled: true,
|
|
474
|
+
iterations: 1000,
|
|
475
|
+
updateInterval: 50
|
|
476
|
+
},
|
|
477
|
+
barnesHut: {
|
|
478
|
+
gravitationalConstant: -10000, // Strong repulsion
|
|
479
|
+
centralGravity: 0.3,
|
|
480
|
+
springLength: 150,
|
|
481
|
+
springConstant: 0.05,
|
|
482
|
+
damping: 0.4
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
interaction: {
|
|
486
|
+
hover: true,
|
|
487
|
+
tooltipDelay: 200,
|
|
488
|
+
hideEdgesOnDrag: true
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
network = new vis.Network(container, data, options);
|
|
493
|
+
|
|
494
|
+
// Fade out loading screen when stabilized or after a timeout
|
|
495
|
+
network.once("stabilizationIterationsDone", finishLoading);
|
|
496
|
+
setTimeout(finishLoading, 4000); // Fallback
|
|
497
|
+
|
|
498
|
+
// Click Event
|
|
499
|
+
network.on("click", function (params) {
|
|
500
|
+
if (params.nodes.length > 0) {
|
|
501
|
+
const nodeId = params.nodes[0];
|
|
502
|
+
const node = nodesDataSet.get(nodeId);
|
|
503
|
+
openPanel(node);
|
|
504
|
+
} else {
|
|
505
|
+
closePanel();
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// Hover Event (Glow effect)
|
|
510
|
+
network.on("hoverNode", function (params) {
|
|
511
|
+
container.style.cursor = 'pointer';
|
|
512
|
+
});
|
|
513
|
+
network.on("blurNode", function () {
|
|
514
|
+
container.style.cursor = 'default';
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// Custom Rendering for "Neon Glow"
|
|
518
|
+
network.on("beforeDrawing", function(ctx) {
|
|
519
|
+
// Optional: Add global glow or background effects here
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function finishLoading() {
|
|
524
|
+
const el = document.getElementById('loading');
|
|
525
|
+
if (el.style.opacity !== '0') {
|
|
526
|
+
el.style.opacity = '0';
|
|
527
|
+
setTimeout(() => el.style.display = 'none', 800);
|
|
528
|
+
network.fit();
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// --- Search Logic ---
|
|
533
|
+
function handleSearch(query) {
|
|
534
|
+
if (!query) {
|
|
535
|
+
// Reset view
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
const lower = query.toLowerCase();
|
|
539
|
+
const matches = nodesDataSet.get({
|
|
540
|
+
filter: function (item) {
|
|
541
|
+
return (item.label && item.label.toLowerCase().includes(lower));
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
if (matches.length > 0) {
|
|
546
|
+
network.selectNodes(matches.map(n => n.id));
|
|
547
|
+
if (matches.length === 1) {
|
|
548
|
+
network.focus(matches[0].id, { scale: 1.5, animation: true });
|
|
549
|
+
openPanel(matches[0]);
|
|
550
|
+
}
|
|
551
|
+
} else {
|
|
552
|
+
network.unselectAll();
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// --- Side Panel Logic ---
|
|
557
|
+
function openPanel(node) {
|
|
558
|
+
const panel = document.getElementById('side-panel');
|
|
559
|
+
document.getElementById('panel-title').textContent = node.label || 'Unknown Node';
|
|
560
|
+
document.getElementById('panel-type').textContent = node.group;
|
|
561
|
+
document.getElementById('panel-color').style.backgroundColor = node.color.background;
|
|
562
|
+
document.getElementById('panel-id').textContent = node.id;
|
|
563
|
+
document.getElementById('panel-desc').textContent = node.title || 'No details available.';
|
|
564
|
+
|
|
565
|
+
// Find relationships
|
|
566
|
+
const connectedEdges = edgesDataSet.get({
|
|
567
|
+
filter: function (item) {
|
|
568
|
+
return item.from === node.id || item.to === node.id;
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const relsHtml = connectedEdges.map(edge => {
|
|
573
|
+
const isSource = edge.from === node.id;
|
|
574
|
+
const otherId = isSource ? edge.to : edge.from;
|
|
575
|
+
const otherNode = nodesDataSet.get(otherId);
|
|
576
|
+
const direction = isSource ? "→" : "←";
|
|
577
|
+
return \`<div style="margin-top:4px; font-size:0.8rem; border-left: 2px solid rgba(255,255,255,0.1); padding-left:8px;">
|
|
578
|
+
<span style="color:var(--text-dim)">\${direction} [\${edge.label}]</span>
|
|
579
|
+
<span style="color:var(--accent-primary)">\${otherNode ? otherNode.label : otherId}</span>
|
|
580
|
+
</div>\`;
|
|
581
|
+
}).join('');
|
|
582
|
+
|
|
583
|
+
document.getElementById('panel-rels').innerHTML = relsHtml || '<span style="color:var(--text-dim); font-size: 0.8rem">No connections</span>';
|
|
584
|
+
|
|
585
|
+
panel.classList.add('open');
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function closePanel() {
|
|
589
|
+
document.getElementById('side-panel').classList.remove('open');
|
|
590
|
+
network.unselectAll();
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// --- Dock / Filter Logic ---
|
|
594
|
+
function generateDock(nodes) {
|
|
595
|
+
const types = [...new Set(nodes.map(n => n.group))];
|
|
596
|
+
const dock = document.getElementById('filter-dock');
|
|
597
|
+
dock.innerHTML = '';
|
|
598
|
+
|
|
599
|
+
types.forEach(type => {
|
|
600
|
+
const color = typeColors[type] || '#999';
|
|
601
|
+
|
|
602
|
+
const item = document.createElement('div');
|
|
603
|
+
item.className = 'dock-item active';
|
|
604
|
+
item.innerHTML = \`<div class="dock-dot" style="background:\${color}; box-shadow: 0 0 8px \${color}"></div> \${type}\`;
|
|
605
|
+
item.onclick = () => toggleFilter(type, item);
|
|
606
|
+
dock.appendChild(item);
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const activeFilters = new Set();
|
|
611
|
+
|
|
612
|
+
// Initialize with all active
|
|
613
|
+
setTimeout(() => {
|
|
614
|
+
const types = document.querySelectorAll('.dock-item');
|
|
615
|
+
types.forEach(t => activeFilters.add(t.textContent.trim()));
|
|
616
|
+
}, 1000);
|
|
617
|
+
|
|
618
|
+
function toggleFilter(type, element) {
|
|
619
|
+
// NOTE: For a real filter, we'd use a DataView or hide nodes.
|
|
620
|
+
// For this simplified version, we'll just dim them or hide them.
|
|
621
|
+
// Re-implementing visually:
|
|
622
|
+
|
|
623
|
+
if (element.classList.contains('active')) {
|
|
624
|
+
element.classList.remove('active');
|
|
625
|
+
element.classList.add('faded');
|
|
626
|
+
// Hide nodes
|
|
627
|
+
const toHide = nodesDataSet.get({ filter: n => n.group === type });
|
|
628
|
+
toHide.forEach(n => {
|
|
629
|
+
nodesDataSet.update({id: n.id, hidden: true});
|
|
630
|
+
});
|
|
631
|
+
} else {
|
|
632
|
+
element.classList.add('active');
|
|
633
|
+
element.classList.remove('faded');
|
|
634
|
+
// Show nodes
|
|
635
|
+
const toShow = nodesDataSet.get({ filter: n => n.group === type });
|
|
636
|
+
toShow.forEach(n => {
|
|
637
|
+
nodesDataSet.update({id: n.id, hidden: false});
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
fetchGraph();
|
|
643
|
+
</script>
|
|
644
|
+
</body>
|
|
645
|
+
</html>
|
|
646
|
+
`;
|
|
647
|
+
|
|
648
|
+
const command: Command = {
|
|
649
|
+
name: "visualize",
|
|
650
|
+
description: "Opens a browser visualization of the knowledge graph",
|
|
651
|
+
usage: "/visualize",
|
|
652
|
+
action: async (args: string[]) => {
|
|
653
|
+
const port = args[0] ? parseInt(args[0], 10) : 3001;
|
|
654
|
+
const cognition = AgentCognition.getInstance();
|
|
655
|
+
const router = new BunApiRouter();
|
|
656
|
+
|
|
657
|
+
// Register API endpoint for graph data
|
|
658
|
+
router.register("GET", "/api/graph", async () => {
|
|
659
|
+
try {
|
|
660
|
+
// Fetch all nodes
|
|
661
|
+
const nodesResult = await cognition.query(`
|
|
662
|
+
MATCH (n:Fact)
|
|
663
|
+
RETURN n.id as id, n.type as type, n.content as content
|
|
664
|
+
`);
|
|
665
|
+
|
|
666
|
+
// Fetch all relationships
|
|
667
|
+
const edgesResult = await cognition.query(`
|
|
668
|
+
MATCH (a:Fact)-[r:RELATED_TO]->(b:Fact)
|
|
669
|
+
RETURN a.id as from, b.id as to, r.relation as label
|
|
670
|
+
`);
|
|
671
|
+
|
|
672
|
+
// Format for vis-network
|
|
673
|
+
const typeColors: Record<
|
|
674
|
+
string,
|
|
675
|
+
{ background: string; border?: string; highlight?: object }
|
|
676
|
+
> = {
|
|
677
|
+
// Semantic types
|
|
678
|
+
fact: { background: "#00f2ea" },
|
|
679
|
+
decision: { background: "#39ff14" },
|
|
680
|
+
concept: { background: "#ff00ff" },
|
|
681
|
+
reference: { background: "#ffaa00" },
|
|
682
|
+
// Code entity types
|
|
683
|
+
file: { background: "#58a6ff" },
|
|
684
|
+
module: { background: "#7c3aed" },
|
|
685
|
+
function: { background: "#f97316" },
|
|
686
|
+
class: { background: "#ec4899" },
|
|
687
|
+
interface: { background: "#14b8a6" },
|
|
688
|
+
variable: { background: "#a855f7" },
|
|
689
|
+
symbol: { background: "#94a3b8" },
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
const nodes = nodesResult.map((row: any) => {
|
|
693
|
+
const baseColor = typeColors[row.type]?.background || "#97c2fc";
|
|
694
|
+
|
|
695
|
+
return {
|
|
696
|
+
id: row.id,
|
|
697
|
+
label:
|
|
698
|
+
row.content.length > 25
|
|
699
|
+
? row.content.substring(0, 25) + "..."
|
|
700
|
+
: row.content,
|
|
701
|
+
title: row.content, // Tooltip content
|
|
702
|
+
group: row.type,
|
|
703
|
+
color: {
|
|
704
|
+
background: baseColor,
|
|
705
|
+
border: baseColor,
|
|
706
|
+
highlight: {
|
|
707
|
+
background: "#fff",
|
|
708
|
+
border: "#fff",
|
|
709
|
+
},
|
|
710
|
+
},
|
|
711
|
+
// Custom shadows for glow effect
|
|
712
|
+
shadow: {
|
|
713
|
+
enabled: true,
|
|
714
|
+
color: baseColor,
|
|
715
|
+
size: 10,
|
|
716
|
+
x: 0,
|
|
717
|
+
y: 0,
|
|
718
|
+
},
|
|
719
|
+
};
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
const edges = edgesResult.map((row: any) => ({
|
|
723
|
+
from: row.from,
|
|
724
|
+
to: row.to,
|
|
725
|
+
label: row.label,
|
|
726
|
+
color: { color: "rgba(255,255,255,0.1)" },
|
|
727
|
+
font: {
|
|
728
|
+
align: "middle",
|
|
729
|
+
size: 10,
|
|
730
|
+
strokeWidth: 0,
|
|
731
|
+
color: "#8b949e",
|
|
732
|
+
background: "transparent",
|
|
733
|
+
},
|
|
734
|
+
}));
|
|
735
|
+
|
|
736
|
+
return new Response(JSON.stringify({ nodes, edges }), {
|
|
737
|
+
headers: { "Content-Type": "application/json" },
|
|
738
|
+
});
|
|
739
|
+
} catch (error) {
|
|
740
|
+
log("Error fetching graph data:", error);
|
|
741
|
+
return new Response(JSON.stringify({ error: String(error) }), {
|
|
742
|
+
status: 500,
|
|
743
|
+
headers: { "Content-Type": "application/json" },
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
// Register Visualization IO
|
|
749
|
+
router.register("GET", "/visualize", () => {
|
|
750
|
+
return new Response(VISUALIZATION_HTML, {
|
|
751
|
+
headers: { "Content-Type": "text/html" },
|
|
752
|
+
});
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
log(`Starting visualization server on port ${port}...`);
|
|
756
|
+
|
|
757
|
+
const url = `http://localhost:${port}/visualize`;
|
|
758
|
+
log(`Opening ${url} ...`);
|
|
759
|
+
|
|
760
|
+
exec(`open ${url}`, (err) => {
|
|
761
|
+
if (err) log("Failed to open browser:", err);
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
try {
|
|
765
|
+
await router.serve(port);
|
|
766
|
+
log(`Visualization server on port ${port} stopped.`);
|
|
767
|
+
} catch (error) {
|
|
768
|
+
log("Server error:", error);
|
|
769
|
+
}
|
|
770
|
+
},
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
export default command;
|