nc1709 1.15.4__py3-none-any.whl
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.
- nc1709/__init__.py +13 -0
- nc1709/agent/__init__.py +36 -0
- nc1709/agent/core.py +505 -0
- nc1709/agent/mcp_bridge.py +245 -0
- nc1709/agent/permissions.py +298 -0
- nc1709/agent/tools/__init__.py +21 -0
- nc1709/agent/tools/base.py +440 -0
- nc1709/agent/tools/bash_tool.py +367 -0
- nc1709/agent/tools/file_tools.py +454 -0
- nc1709/agent/tools/notebook_tools.py +516 -0
- nc1709/agent/tools/search_tools.py +322 -0
- nc1709/agent/tools/task_tool.py +284 -0
- nc1709/agent/tools/web_tools.py +555 -0
- nc1709/agents/__init__.py +17 -0
- nc1709/agents/auto_fix.py +506 -0
- nc1709/agents/test_generator.py +507 -0
- nc1709/checkpoints.py +372 -0
- nc1709/cli.py +3380 -0
- nc1709/cli_ui.py +1080 -0
- nc1709/cognitive/__init__.py +149 -0
- nc1709/cognitive/anticipation.py +594 -0
- nc1709/cognitive/context_engine.py +1046 -0
- nc1709/cognitive/council.py +824 -0
- nc1709/cognitive/learning.py +761 -0
- nc1709/cognitive/router.py +583 -0
- nc1709/cognitive/system.py +519 -0
- nc1709/config.py +155 -0
- nc1709/custom_commands.py +300 -0
- nc1709/executor.py +333 -0
- nc1709/file_controller.py +354 -0
- nc1709/git_integration.py +308 -0
- nc1709/github_integration.py +477 -0
- nc1709/image_input.py +446 -0
- nc1709/linting.py +519 -0
- nc1709/llm_adapter.py +667 -0
- nc1709/logger.py +192 -0
- nc1709/mcp/__init__.py +18 -0
- nc1709/mcp/client.py +370 -0
- nc1709/mcp/manager.py +407 -0
- nc1709/mcp/protocol.py +210 -0
- nc1709/mcp/server.py +473 -0
- nc1709/memory/__init__.py +20 -0
- nc1709/memory/embeddings.py +325 -0
- nc1709/memory/indexer.py +474 -0
- nc1709/memory/sessions.py +432 -0
- nc1709/memory/vector_store.py +451 -0
- nc1709/models/__init__.py +86 -0
- nc1709/models/detector.py +377 -0
- nc1709/models/formats.py +315 -0
- nc1709/models/manager.py +438 -0
- nc1709/models/registry.py +497 -0
- nc1709/performance/__init__.py +343 -0
- nc1709/performance/cache.py +705 -0
- nc1709/performance/pipeline.py +611 -0
- nc1709/performance/tiering.py +543 -0
- nc1709/plan_mode.py +362 -0
- nc1709/plugins/__init__.py +17 -0
- nc1709/plugins/agents/__init__.py +18 -0
- nc1709/plugins/agents/django_agent.py +912 -0
- nc1709/plugins/agents/docker_agent.py +623 -0
- nc1709/plugins/agents/fastapi_agent.py +887 -0
- nc1709/plugins/agents/git_agent.py +731 -0
- nc1709/plugins/agents/nextjs_agent.py +867 -0
- nc1709/plugins/base.py +359 -0
- nc1709/plugins/manager.py +411 -0
- nc1709/plugins/registry.py +337 -0
- nc1709/progress.py +443 -0
- nc1709/prompts/__init__.py +22 -0
- nc1709/prompts/agent_system.py +180 -0
- nc1709/prompts/task_prompts.py +340 -0
- nc1709/prompts/unified_prompt.py +133 -0
- nc1709/reasoning_engine.py +541 -0
- nc1709/remote_client.py +266 -0
- nc1709/shell_completions.py +349 -0
- nc1709/slash_commands.py +649 -0
- nc1709/task_classifier.py +408 -0
- nc1709/version_check.py +177 -0
- nc1709/web/__init__.py +8 -0
- nc1709/web/server.py +950 -0
- nc1709/web/templates/index.html +1127 -0
- nc1709-1.15.4.dist-info/METADATA +858 -0
- nc1709-1.15.4.dist-info/RECORD +86 -0
- nc1709-1.15.4.dist-info/WHEEL +5 -0
- nc1709-1.15.4.dist-info/entry_points.txt +2 -0
- nc1709-1.15.4.dist-info/licenses/LICENSE +9 -0
- nc1709-1.15.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1127 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>NC1709 Dashboard</title>
|
|
7
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
|
|
8
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
|
9
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/11.1.1/marked.min.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
:root {
|
|
12
|
+
--bg-primary: #0d1117;
|
|
13
|
+
--bg-secondary: #161b22;
|
|
14
|
+
--bg-tertiary: #21262d;
|
|
15
|
+
--border-color: #30363d;
|
|
16
|
+
--text-primary: #e6edf3;
|
|
17
|
+
--text-secondary: #8b949e;
|
|
18
|
+
--accent: #58a6ff;
|
|
19
|
+
--accent-hover: #79b8ff;
|
|
20
|
+
--success: #3fb950;
|
|
21
|
+
--warning: #d29922;
|
|
22
|
+
--error: #f85149;
|
|
23
|
+
--sidebar-width: 260px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
* {
|
|
27
|
+
margin: 0;
|
|
28
|
+
padding: 0;
|
|
29
|
+
box-sizing: border-box;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
body {
|
|
33
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
|
|
34
|
+
background: var(--bg-primary);
|
|
35
|
+
color: var(--text-primary);
|
|
36
|
+
line-height: 1.5;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Layout */
|
|
40
|
+
.app {
|
|
41
|
+
display: flex;
|
|
42
|
+
height: 100vh;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Sidebar */
|
|
46
|
+
.sidebar {
|
|
47
|
+
width: var(--sidebar-width);
|
|
48
|
+
background: var(--bg-secondary);
|
|
49
|
+
border-right: 1px solid var(--border-color);
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
flex-shrink: 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.sidebar-header {
|
|
56
|
+
padding: 16px;
|
|
57
|
+
border-bottom: 1px solid var(--border-color);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.sidebar-header h1 {
|
|
61
|
+
font-size: 20px;
|
|
62
|
+
font-weight: 600;
|
|
63
|
+
color: var(--accent);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.sidebar-header .version {
|
|
67
|
+
font-size: 12px;
|
|
68
|
+
color: var(--text-secondary);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.nav {
|
|
72
|
+
flex: 1;
|
|
73
|
+
padding: 8px;
|
|
74
|
+
overflow-y: auto;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.nav-item {
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
padding: 10px 12px;
|
|
81
|
+
border-radius: 6px;
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
color: var(--text-secondary);
|
|
84
|
+
transition: all 0.15s ease;
|
|
85
|
+
margin-bottom: 2px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.nav-item:hover {
|
|
89
|
+
background: var(--bg-tertiary);
|
|
90
|
+
color: var(--text-primary);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.nav-item.active {
|
|
94
|
+
background: var(--bg-tertiary);
|
|
95
|
+
color: var(--text-primary);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.nav-item svg {
|
|
99
|
+
width: 16px;
|
|
100
|
+
height: 16px;
|
|
101
|
+
margin-right: 10px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.nav-section {
|
|
105
|
+
padding: 8px 12px 4px;
|
|
106
|
+
font-size: 11px;
|
|
107
|
+
font-weight: 600;
|
|
108
|
+
text-transform: uppercase;
|
|
109
|
+
color: var(--text-secondary);
|
|
110
|
+
margin-top: 16px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Main Content */
|
|
114
|
+
.main {
|
|
115
|
+
flex: 1;
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
overflow: hidden;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.header {
|
|
122
|
+
padding: 16px 24px;
|
|
123
|
+
border-bottom: 1px solid var(--border-color);
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
justify-content: space-between;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.header h2 {
|
|
130
|
+
font-size: 18px;
|
|
131
|
+
font-weight: 600;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.content {
|
|
135
|
+
flex: 1;
|
|
136
|
+
overflow-y: auto;
|
|
137
|
+
padding: 24px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Chat Panel */
|
|
141
|
+
.chat-container {
|
|
142
|
+
display: flex;
|
|
143
|
+
flex-direction: column;
|
|
144
|
+
height: 100%;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.chat-messages {
|
|
148
|
+
flex: 1;
|
|
149
|
+
overflow-y: auto;
|
|
150
|
+
padding: 16px;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.message {
|
|
154
|
+
margin-bottom: 16px;
|
|
155
|
+
max-width: 85%;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.message.user {
|
|
159
|
+
margin-left: auto;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.message-content {
|
|
163
|
+
padding: 12px 16px;
|
|
164
|
+
border-radius: 12px;
|
|
165
|
+
background: var(--bg-tertiary);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.message.user .message-content {
|
|
169
|
+
background: var(--accent);
|
|
170
|
+
color: white;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.message-content pre {
|
|
174
|
+
margin: 8px 0;
|
|
175
|
+
padding: 12px;
|
|
176
|
+
background: var(--bg-primary);
|
|
177
|
+
border-radius: 6px;
|
|
178
|
+
overflow-x: auto;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.message-content code {
|
|
182
|
+
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
183
|
+
font-size: 13px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.message-content p {
|
|
187
|
+
margin-bottom: 8px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.message-content p:last-child {
|
|
191
|
+
margin-bottom: 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.chat-input-container {
|
|
195
|
+
padding: 16px;
|
|
196
|
+
border-top: 1px solid var(--border-color);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.chat-input-wrapper {
|
|
200
|
+
display: flex;
|
|
201
|
+
gap: 12px;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.chat-input {
|
|
205
|
+
flex: 1;
|
|
206
|
+
padding: 12px 16px;
|
|
207
|
+
background: var(--bg-tertiary);
|
|
208
|
+
border: 1px solid var(--border-color);
|
|
209
|
+
border-radius: 8px;
|
|
210
|
+
color: var(--text-primary);
|
|
211
|
+
font-size: 14px;
|
|
212
|
+
resize: none;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.chat-input:focus {
|
|
216
|
+
outline: none;
|
|
217
|
+
border-color: var(--accent);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.send-btn {
|
|
221
|
+
padding: 12px 24px;
|
|
222
|
+
background: var(--accent);
|
|
223
|
+
color: white;
|
|
224
|
+
border: none;
|
|
225
|
+
border-radius: 8px;
|
|
226
|
+
cursor: pointer;
|
|
227
|
+
font-weight: 500;
|
|
228
|
+
transition: background 0.15s ease;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.send-btn:hover {
|
|
232
|
+
background: var(--accent-hover);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.send-btn:disabled {
|
|
236
|
+
opacity: 0.5;
|
|
237
|
+
cursor: not-allowed;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* Cards */
|
|
241
|
+
.card {
|
|
242
|
+
background: var(--bg-secondary);
|
|
243
|
+
border: 1px solid var(--border-color);
|
|
244
|
+
border-radius: 8px;
|
|
245
|
+
margin-bottom: 16px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.card-header {
|
|
249
|
+
padding: 16px;
|
|
250
|
+
border-bottom: 1px solid var(--border-color);
|
|
251
|
+
font-weight: 600;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.card-body {
|
|
255
|
+
padding: 16px;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Stats Grid */
|
|
259
|
+
.stats-grid {
|
|
260
|
+
display: grid;
|
|
261
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
262
|
+
gap: 16px;
|
|
263
|
+
margin-bottom: 24px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.stat-card {
|
|
267
|
+
background: var(--bg-secondary);
|
|
268
|
+
border: 1px solid var(--border-color);
|
|
269
|
+
border-radius: 8px;
|
|
270
|
+
padding: 20px;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.stat-value {
|
|
274
|
+
font-size: 32px;
|
|
275
|
+
font-weight: 700;
|
|
276
|
+
color: var(--accent);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.stat-label {
|
|
280
|
+
font-size: 14px;
|
|
281
|
+
color: var(--text-secondary);
|
|
282
|
+
margin-top: 4px;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* Tables */
|
|
286
|
+
.table {
|
|
287
|
+
width: 100%;
|
|
288
|
+
border-collapse: collapse;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.table th,
|
|
292
|
+
.table td {
|
|
293
|
+
padding: 12px;
|
|
294
|
+
text-align: left;
|
|
295
|
+
border-bottom: 1px solid var(--border-color);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.table th {
|
|
299
|
+
font-weight: 600;
|
|
300
|
+
color: var(--text-secondary);
|
|
301
|
+
font-size: 12px;
|
|
302
|
+
text-transform: uppercase;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/* Buttons */
|
|
306
|
+
.btn {
|
|
307
|
+
padding: 8px 16px;
|
|
308
|
+
border-radius: 6px;
|
|
309
|
+
border: 1px solid var(--border-color);
|
|
310
|
+
background: var(--bg-tertiary);
|
|
311
|
+
color: var(--text-primary);
|
|
312
|
+
cursor: pointer;
|
|
313
|
+
font-size: 14px;
|
|
314
|
+
transition: all 0.15s ease;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.btn:hover {
|
|
318
|
+
background: var(--bg-secondary);
|
|
319
|
+
border-color: var(--accent);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.btn-primary {
|
|
323
|
+
background: var(--accent);
|
|
324
|
+
border-color: var(--accent);
|
|
325
|
+
color: white;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.btn-primary:hover {
|
|
329
|
+
background: var(--accent-hover);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* Status badges */
|
|
333
|
+
.badge {
|
|
334
|
+
display: inline-block;
|
|
335
|
+
padding: 2px 8px;
|
|
336
|
+
border-radius: 12px;
|
|
337
|
+
font-size: 12px;
|
|
338
|
+
font-weight: 500;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.badge-success {
|
|
342
|
+
background: rgba(63, 185, 80, 0.2);
|
|
343
|
+
color: var(--success);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.badge-warning {
|
|
347
|
+
background: rgba(210, 153, 34, 0.2);
|
|
348
|
+
color: var(--warning);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.badge-error {
|
|
352
|
+
background: rgba(248, 81, 73, 0.2);
|
|
353
|
+
color: var(--error);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/* Search */
|
|
357
|
+
.search-container {
|
|
358
|
+
margin-bottom: 24px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.search-input {
|
|
362
|
+
width: 100%;
|
|
363
|
+
padding: 12px 16px;
|
|
364
|
+
background: var(--bg-tertiary);
|
|
365
|
+
border: 1px solid var(--border-color);
|
|
366
|
+
border-radius: 8px;
|
|
367
|
+
color: var(--text-primary);
|
|
368
|
+
font-size: 14px;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.search-input:focus {
|
|
372
|
+
outline: none;
|
|
373
|
+
border-color: var(--accent);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.search-results {
|
|
377
|
+
margin-top: 16px;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.search-result {
|
|
381
|
+
background: var(--bg-secondary);
|
|
382
|
+
border: 1px solid var(--border-color);
|
|
383
|
+
border-radius: 8px;
|
|
384
|
+
margin-bottom: 12px;
|
|
385
|
+
overflow: hidden;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.search-result-header {
|
|
389
|
+
padding: 12px 16px;
|
|
390
|
+
background: var(--bg-tertiary);
|
|
391
|
+
font-size: 14px;
|
|
392
|
+
display: flex;
|
|
393
|
+
justify-content: space-between;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.search-result-code {
|
|
397
|
+
padding: 12px 16px;
|
|
398
|
+
overflow-x: auto;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.search-result-code pre {
|
|
402
|
+
margin: 0;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/* Loading */
|
|
406
|
+
.loading {
|
|
407
|
+
display: flex;
|
|
408
|
+
align-items: center;
|
|
409
|
+
justify-content: center;
|
|
410
|
+
padding: 40px;
|
|
411
|
+
color: var(--text-secondary);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.spinner {
|
|
415
|
+
width: 20px;
|
|
416
|
+
height: 20px;
|
|
417
|
+
border: 2px solid var(--border-color);
|
|
418
|
+
border-top-color: var(--accent);
|
|
419
|
+
border-radius: 50%;
|
|
420
|
+
animation: spin 1s linear infinite;
|
|
421
|
+
margin-right: 12px;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
@keyframes spin {
|
|
425
|
+
to { transform: rotate(360deg); }
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/* Hidden panels */
|
|
429
|
+
.panel {
|
|
430
|
+
display: none;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.panel.active {
|
|
434
|
+
display: block;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/* Sessions list */
|
|
438
|
+
.session-item {
|
|
439
|
+
padding: 12px 16px;
|
|
440
|
+
border-bottom: 1px solid var(--border-color);
|
|
441
|
+
cursor: pointer;
|
|
442
|
+
transition: background 0.15s ease;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.session-item:hover {
|
|
446
|
+
background: var(--bg-tertiary);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.session-item-name {
|
|
450
|
+
font-weight: 500;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.session-item-meta {
|
|
454
|
+
font-size: 12px;
|
|
455
|
+
color: var(--text-secondary);
|
|
456
|
+
margin-top: 4px;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* Plugin/Tool lists */
|
|
460
|
+
.tool-item {
|
|
461
|
+
padding: 16px;
|
|
462
|
+
border-bottom: 1px solid var(--border-color);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.tool-item:last-child {
|
|
466
|
+
border-bottom: none;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.tool-name {
|
|
470
|
+
font-weight: 600;
|
|
471
|
+
margin-bottom: 4px;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.tool-description {
|
|
475
|
+
font-size: 14px;
|
|
476
|
+
color: var(--text-secondary);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.tool-params {
|
|
480
|
+
margin-top: 8px;
|
|
481
|
+
font-size: 12px;
|
|
482
|
+
color: var(--text-secondary);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/* Toast notifications */
|
|
486
|
+
.toast-container {
|
|
487
|
+
position: fixed;
|
|
488
|
+
bottom: 20px;
|
|
489
|
+
right: 20px;
|
|
490
|
+
z-index: 1000;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
.toast {
|
|
494
|
+
background: var(--bg-secondary);
|
|
495
|
+
border: 1px solid var(--border-color);
|
|
496
|
+
border-radius: 8px;
|
|
497
|
+
padding: 12px 20px;
|
|
498
|
+
margin-top: 8px;
|
|
499
|
+
animation: slideIn 0.3s ease;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
@keyframes slideIn {
|
|
503
|
+
from {
|
|
504
|
+
transform: translateX(100%);
|
|
505
|
+
opacity: 0;
|
|
506
|
+
}
|
|
507
|
+
to {
|
|
508
|
+
transform: translateX(0);
|
|
509
|
+
opacity: 1;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
</style>
|
|
513
|
+
</head>
|
|
514
|
+
<body>
|
|
515
|
+
<div class="app">
|
|
516
|
+
<!-- Sidebar -->
|
|
517
|
+
<aside class="sidebar">
|
|
518
|
+
<div class="sidebar-header">
|
|
519
|
+
<h1>NC1709</h1>
|
|
520
|
+
<span class="version">v1.0.0 - Local AI Assistant</span>
|
|
521
|
+
</div>
|
|
522
|
+
<nav class="nav">
|
|
523
|
+
<div class="nav-item active" data-panel="chat">
|
|
524
|
+
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.5 4.5a.5.5 0 00-1 0v4a.5.5 0 00.5.5h2.5a.5.5 0 000-1H8.5v-3.5z"/></svg>
|
|
525
|
+
Chat
|
|
526
|
+
</div>
|
|
527
|
+
|
|
528
|
+
<div class="nav-section">Memory</div>
|
|
529
|
+
<div class="nav-item" data-panel="sessions">
|
|
530
|
+
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M0 1.75A.75.75 0 01.75 1h4.253a.75.75 0 01.592.288l1.67 2.168H14.25a.75.75 0 01.75.75v8.044a.75.75 0 01-.75.75H.75a.75.75 0 01-.75-.75V1.75z"/></svg>
|
|
531
|
+
Sessions
|
|
532
|
+
</div>
|
|
533
|
+
<div class="nav-item" data-panel="search">
|
|
534
|
+
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M11.5 7a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zm-.82 4.74a6 6 0 111.06-1.06l2.28 2.28a.75.75 0 11-1.06 1.06l-2.28-2.28z"/></svg>
|
|
535
|
+
Search Code
|
|
536
|
+
</div>
|
|
537
|
+
|
|
538
|
+
<div class="nav-section">Tools</div>
|
|
539
|
+
<div class="nav-item" data-panel="plugins">
|
|
540
|
+
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M2 3.75A.75.75 0 012.75 3h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 3.75zm0 4A.75.75 0 012.75 7h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 7.75zm0 4a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75z"/></svg>
|
|
541
|
+
Plugins
|
|
542
|
+
</div>
|
|
543
|
+
<div class="nav-item" data-panel="mcp">
|
|
544
|
+
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 0a8 8 0 100 16A8 8 0 008 0zm3.78 5.22a.75.75 0 010 1.06l-4.5 4.5a.75.75 0 01-1.06 0l-2-2a.75.75 0 011.06-1.06L6.75 9.19l3.97-3.97a.75.75 0 011.06 0z"/></svg>
|
|
545
|
+
MCP Tools
|
|
546
|
+
</div>
|
|
547
|
+
|
|
548
|
+
<div class="nav-section">System</div>
|
|
549
|
+
<div class="nav-item" data-panel="config">
|
|
550
|
+
<svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 0a8.2 8.2 0 01.701.031C10.042.11 10.989.39 11.5 1.5c.4.865.464 1.92.32 2.984l.15.022c.732.1 1.332.48 1.78 1.084.447.604.67 1.39.564 2.16-.106.77-.513 1.47-1.128 2-.61.53-1.406.845-2.266.96l-.003.053a3.49 3.49 0 01-.064.498c-.164.775-.576 1.454-1.238 1.914-.66.46-1.52.629-2.315.48-.79-.15-1.513-.61-1.972-1.27a3.24 3.24 0 01-.52-1.667l-.026-.003c-.76-.11-1.456-.5-1.97-1.084a3.26 3.26 0 01-.768-2.16c.045-.77.37-1.472.928-2.005.557-.533 1.296-.852 2.101-.968l.068-.011c-.034-.355-.024-.71.03-1.064.09-.59.303-1.15.633-1.64.33-.49.77-.88 1.28-1.15A3.18 3.18 0 018 0z"/></svg>
|
|
551
|
+
Settings
|
|
552
|
+
</div>
|
|
553
|
+
</nav>
|
|
554
|
+
</aside>
|
|
555
|
+
|
|
556
|
+
<!-- Main Content -->
|
|
557
|
+
<main class="main">
|
|
558
|
+
<!-- Chat Panel -->
|
|
559
|
+
<div id="panel-chat" class="panel active">
|
|
560
|
+
<div class="header">
|
|
561
|
+
<h2>Chat</h2>
|
|
562
|
+
<button class="btn" onclick="clearChat()">Clear Chat</button>
|
|
563
|
+
</div>
|
|
564
|
+
<div class="content chat-container">
|
|
565
|
+
<div class="chat-messages" id="chat-messages">
|
|
566
|
+
<div class="message">
|
|
567
|
+
<div class="message-content">
|
|
568
|
+
<p>Welcome to NC1709! I'm your local AI developer assistant.</p>
|
|
569
|
+
<p>Ask me to help with code, search your project, manage git, docker, and more.</p>
|
|
570
|
+
</div>
|
|
571
|
+
</div>
|
|
572
|
+
</div>
|
|
573
|
+
<div class="chat-input-container">
|
|
574
|
+
<div class="chat-input-wrapper">
|
|
575
|
+
<textarea
|
|
576
|
+
class="chat-input"
|
|
577
|
+
id="chat-input"
|
|
578
|
+
placeholder="Ask me anything..."
|
|
579
|
+
rows="1"
|
|
580
|
+
onkeydown="handleChatKeydown(event)"
|
|
581
|
+
></textarea>
|
|
582
|
+
<button class="send-btn" id="send-btn" onclick="sendMessage()">Send</button>
|
|
583
|
+
</div>
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
</div>
|
|
587
|
+
|
|
588
|
+
<!-- Sessions Panel -->
|
|
589
|
+
<div id="panel-sessions" class="panel">
|
|
590
|
+
<div class="header">
|
|
591
|
+
<h2>Sessions</h2>
|
|
592
|
+
<button class="btn btn-primary" onclick="createSession()">New Session</button>
|
|
593
|
+
</div>
|
|
594
|
+
<div class="content">
|
|
595
|
+
<div id="sessions-list" class="card">
|
|
596
|
+
<div class="loading"><div class="spinner"></div> Loading sessions...</div>
|
|
597
|
+
</div>
|
|
598
|
+
</div>
|
|
599
|
+
</div>
|
|
600
|
+
|
|
601
|
+
<!-- Search Panel -->
|
|
602
|
+
<div id="panel-search" class="panel">
|
|
603
|
+
<div class="header">
|
|
604
|
+
<h2>Semantic Code Search</h2>
|
|
605
|
+
<button class="btn" onclick="indexProject()">Re-index Project</button>
|
|
606
|
+
</div>
|
|
607
|
+
<div class="content">
|
|
608
|
+
<div id="index-status" class="stats-grid">
|
|
609
|
+
<!-- Index stats loaded here -->
|
|
610
|
+
</div>
|
|
611
|
+
<div class="search-container">
|
|
612
|
+
<input
|
|
613
|
+
type="text"
|
|
614
|
+
class="search-input"
|
|
615
|
+
id="search-input"
|
|
616
|
+
placeholder="Search your code semantically... (e.g., 'authentication logic')"
|
|
617
|
+
onkeydown="if(event.key==='Enter')searchCode()"
|
|
618
|
+
>
|
|
619
|
+
</div>
|
|
620
|
+
<div id="search-results" class="search-results">
|
|
621
|
+
<!-- Results loaded here -->
|
|
622
|
+
</div>
|
|
623
|
+
</div>
|
|
624
|
+
</div>
|
|
625
|
+
|
|
626
|
+
<!-- Plugins Panel -->
|
|
627
|
+
<div id="panel-plugins" class="panel">
|
|
628
|
+
<div class="header">
|
|
629
|
+
<h2>Plugins</h2>
|
|
630
|
+
</div>
|
|
631
|
+
<div class="content">
|
|
632
|
+
<div id="plugins-list">
|
|
633
|
+
<div class="loading"><div class="spinner"></div> Loading plugins...</div>
|
|
634
|
+
</div>
|
|
635
|
+
</div>
|
|
636
|
+
</div>
|
|
637
|
+
|
|
638
|
+
<!-- MCP Panel -->
|
|
639
|
+
<div id="panel-mcp" class="panel">
|
|
640
|
+
<div class="header">
|
|
641
|
+
<h2>MCP Tools</h2>
|
|
642
|
+
</div>
|
|
643
|
+
<div class="content">
|
|
644
|
+
<div id="mcp-status" class="stats-grid">
|
|
645
|
+
<!-- MCP stats loaded here -->
|
|
646
|
+
</div>
|
|
647
|
+
<div id="mcp-tools" class="card">
|
|
648
|
+
<div class="card-header">Available Tools</div>
|
|
649
|
+
<div class="card-body" id="mcp-tools-list">
|
|
650
|
+
<div class="loading"><div class="spinner"></div> Loading tools...</div>
|
|
651
|
+
</div>
|
|
652
|
+
</div>
|
|
653
|
+
</div>
|
|
654
|
+
</div>
|
|
655
|
+
|
|
656
|
+
<!-- Config Panel -->
|
|
657
|
+
<div id="panel-config" class="panel">
|
|
658
|
+
<div class="header">
|
|
659
|
+
<h2>Settings</h2>
|
|
660
|
+
</div>
|
|
661
|
+
<div class="content">
|
|
662
|
+
<div class="stats-grid" id="system-status">
|
|
663
|
+
<!-- Status loaded here -->
|
|
664
|
+
</div>
|
|
665
|
+
<div class="card">
|
|
666
|
+
<div class="card-header">Configuration</div>
|
|
667
|
+
<div class="card-body">
|
|
668
|
+
<pre id="config-display" style="background: var(--bg-primary); padding: 16px; border-radius: 6px; overflow-x: auto;"></pre>
|
|
669
|
+
</div>
|
|
670
|
+
</div>
|
|
671
|
+
</div>
|
|
672
|
+
</div>
|
|
673
|
+
</main>
|
|
674
|
+
</div>
|
|
675
|
+
|
|
676
|
+
<div class="toast-container" id="toast-container"></div>
|
|
677
|
+
|
|
678
|
+
<script>
|
|
679
|
+
// Configure marked
|
|
680
|
+
marked.setOptions({
|
|
681
|
+
highlight: function(code, lang) {
|
|
682
|
+
if (lang && hljs.getLanguage(lang)) {
|
|
683
|
+
return hljs.highlight(code, { language: lang }).value;
|
|
684
|
+
}
|
|
685
|
+
return hljs.highlightAuto(code).value;
|
|
686
|
+
},
|
|
687
|
+
breaks: true
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
// Navigation
|
|
691
|
+
document.querySelectorAll('.nav-item').forEach(item => {
|
|
692
|
+
item.addEventListener('click', () => {
|
|
693
|
+
const panel = item.dataset.panel;
|
|
694
|
+
if (panel) {
|
|
695
|
+
// Update nav
|
|
696
|
+
document.querySelectorAll('.nav-item').forEach(i => i.classList.remove('active'));
|
|
697
|
+
item.classList.add('active');
|
|
698
|
+
|
|
699
|
+
// Update panels
|
|
700
|
+
document.querySelectorAll('.panel').forEach(p => p.classList.remove('active'));
|
|
701
|
+
document.getElementById(`panel-${panel}`).classList.add('active');
|
|
702
|
+
|
|
703
|
+
// Load data for panel
|
|
704
|
+
loadPanelData(panel);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
// Load panel data
|
|
710
|
+
function loadPanelData(panel) {
|
|
711
|
+
switch(panel) {
|
|
712
|
+
case 'sessions':
|
|
713
|
+
loadSessions();
|
|
714
|
+
break;
|
|
715
|
+
case 'search':
|
|
716
|
+
loadIndexStatus();
|
|
717
|
+
break;
|
|
718
|
+
case 'plugins':
|
|
719
|
+
loadPlugins();
|
|
720
|
+
break;
|
|
721
|
+
case 'mcp':
|
|
722
|
+
loadMCPStatus();
|
|
723
|
+
loadMCPTools();
|
|
724
|
+
break;
|
|
725
|
+
case 'config':
|
|
726
|
+
loadConfig();
|
|
727
|
+
loadStatus();
|
|
728
|
+
break;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Toast notifications
|
|
733
|
+
function showToast(message, type = 'info') {
|
|
734
|
+
const container = document.getElementById('toast-container');
|
|
735
|
+
const toast = document.createElement('div');
|
|
736
|
+
toast.className = 'toast';
|
|
737
|
+
toast.textContent = message;
|
|
738
|
+
container.appendChild(toast);
|
|
739
|
+
|
|
740
|
+
setTimeout(() => toast.remove(), 3000);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// Chat functions
|
|
744
|
+
function addMessage(role, content) {
|
|
745
|
+
const messages = document.getElementById('chat-messages');
|
|
746
|
+
const div = document.createElement('div');
|
|
747
|
+
div.className = `message ${role}`;
|
|
748
|
+
|
|
749
|
+
const contentDiv = document.createElement('div');
|
|
750
|
+
contentDiv.className = 'message-content';
|
|
751
|
+
|
|
752
|
+
if (role === 'assistant') {
|
|
753
|
+
contentDiv.innerHTML = marked.parse(content);
|
|
754
|
+
contentDiv.querySelectorAll('pre code').forEach(block => {
|
|
755
|
+
hljs.highlightElement(block);
|
|
756
|
+
});
|
|
757
|
+
} else {
|
|
758
|
+
contentDiv.textContent = content;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
div.appendChild(contentDiv);
|
|
762
|
+
messages.appendChild(div);
|
|
763
|
+
messages.scrollTop = messages.scrollHeight;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
async function sendMessage() {
|
|
767
|
+
const input = document.getElementById('chat-input');
|
|
768
|
+
const btn = document.getElementById('send-btn');
|
|
769
|
+
const message = input.value.trim();
|
|
770
|
+
|
|
771
|
+
if (!message) return;
|
|
772
|
+
|
|
773
|
+
// Add user message
|
|
774
|
+
addMessage('user', message);
|
|
775
|
+
input.value = '';
|
|
776
|
+
btn.disabled = true;
|
|
777
|
+
|
|
778
|
+
try {
|
|
779
|
+
const response = await fetch('/api/chat', {
|
|
780
|
+
method: 'POST',
|
|
781
|
+
headers: { 'Content-Type': 'application/json' },
|
|
782
|
+
body: JSON.stringify({ message })
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
const data = await response.json();
|
|
786
|
+
|
|
787
|
+
if (response.ok) {
|
|
788
|
+
addMessage('assistant', data.response);
|
|
789
|
+
} else {
|
|
790
|
+
addMessage('assistant', `Error: ${data.detail}`);
|
|
791
|
+
}
|
|
792
|
+
} catch (e) {
|
|
793
|
+
addMessage('assistant', `Error: ${e.message}`);
|
|
794
|
+
} finally {
|
|
795
|
+
btn.disabled = false;
|
|
796
|
+
input.focus();
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function handleChatKeydown(e) {
|
|
801
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
802
|
+
e.preventDefault();
|
|
803
|
+
sendMessage();
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
function clearChat() {
|
|
808
|
+
const messages = document.getElementById('chat-messages');
|
|
809
|
+
messages.innerHTML = `
|
|
810
|
+
<div class="message">
|
|
811
|
+
<div class="message-content">
|
|
812
|
+
<p>Chat cleared. How can I help you?</p>
|
|
813
|
+
</div>
|
|
814
|
+
</div>
|
|
815
|
+
`;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Sessions
|
|
819
|
+
async function loadSessions() {
|
|
820
|
+
const container = document.getElementById('sessions-list');
|
|
821
|
+
|
|
822
|
+
try {
|
|
823
|
+
const response = await fetch('/api/sessions');
|
|
824
|
+
const data = await response.json();
|
|
825
|
+
|
|
826
|
+
if (data.sessions.length === 0) {
|
|
827
|
+
container.innerHTML = '<div class="card-body">No sessions yet. Start chatting to create one!</div>';
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
container.innerHTML = data.sessions.map(s => `
|
|
832
|
+
<div class="session-item" onclick="loadSession('${s.id}')">
|
|
833
|
+
<div class="session-item-name">${s.name || s.id}</div>
|
|
834
|
+
<div class="session-item-meta">
|
|
835
|
+
${s.message_count || 0} messages • ${s.updated_at ? s.updated_at.slice(0, 16) : 'N/A'}
|
|
836
|
+
</div>
|
|
837
|
+
</div>
|
|
838
|
+
`).join('');
|
|
839
|
+
} catch (e) {
|
|
840
|
+
container.innerHTML = `<div class="card-body">Error loading sessions: ${e.message}</div>`;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
async function loadSession(id) {
|
|
845
|
+
try {
|
|
846
|
+
const response = await fetch(`/api/sessions/${id}`);
|
|
847
|
+
const data = await response.json();
|
|
848
|
+
|
|
849
|
+
// Switch to chat panel and load messages
|
|
850
|
+
document.querySelector('[data-panel="chat"]').click();
|
|
851
|
+
|
|
852
|
+
const messages = document.getElementById('chat-messages');
|
|
853
|
+
messages.innerHTML = '';
|
|
854
|
+
|
|
855
|
+
data.messages.forEach(m => {
|
|
856
|
+
addMessage(m.role, m.content);
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
showToast(`Loaded session: ${data.name || id}`);
|
|
860
|
+
} catch (e) {
|
|
861
|
+
showToast(`Error loading session: ${e.message}`, 'error');
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
async function createSession() {
|
|
866
|
+
try {
|
|
867
|
+
const response = await fetch('/api/sessions', { method: 'POST' });
|
|
868
|
+
const data = await response.json();
|
|
869
|
+
showToast(`Created session: ${data.id}`);
|
|
870
|
+
loadSessions();
|
|
871
|
+
} catch (e) {
|
|
872
|
+
showToast(`Error: ${e.message}`, 'error');
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// Search
|
|
877
|
+
async function loadIndexStatus() {
|
|
878
|
+
const container = document.getElementById('index-status');
|
|
879
|
+
|
|
880
|
+
try {
|
|
881
|
+
const response = await fetch('/api/index/status');
|
|
882
|
+
const data = await response.json();
|
|
883
|
+
|
|
884
|
+
container.innerHTML = `
|
|
885
|
+
<div class="stat-card">
|
|
886
|
+
<div class="stat-value">${data.total_files || 0}</div>
|
|
887
|
+
<div class="stat-label">Files Indexed</div>
|
|
888
|
+
</div>
|
|
889
|
+
<div class="stat-card">
|
|
890
|
+
<div class="stat-value">${data.total_chunks || 0}</div>
|
|
891
|
+
<div class="stat-label">Code Chunks</div>
|
|
892
|
+
</div>
|
|
893
|
+
<div class="stat-card">
|
|
894
|
+
<div class="stat-value">${Object.keys(data.languages || {}).length}</div>
|
|
895
|
+
<div class="stat-label">Languages</div>
|
|
896
|
+
</div>
|
|
897
|
+
`;
|
|
898
|
+
} catch (e) {
|
|
899
|
+
container.innerHTML = `<div class="stat-card">Error loading index status</div>`;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
async function searchCode() {
|
|
904
|
+
const input = document.getElementById('search-input');
|
|
905
|
+
const results = document.getElementById('search-results');
|
|
906
|
+
const query = input.value.trim();
|
|
907
|
+
|
|
908
|
+
if (!query) return;
|
|
909
|
+
|
|
910
|
+
results.innerHTML = '<div class="loading"><div class="spinner"></div> Searching...</div>';
|
|
911
|
+
|
|
912
|
+
try {
|
|
913
|
+
const response = await fetch('/api/search', {
|
|
914
|
+
method: 'POST',
|
|
915
|
+
headers: { 'Content-Type': 'application/json' },
|
|
916
|
+
body: JSON.stringify({ query, n_results: 5 })
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
const data = await response.json();
|
|
920
|
+
|
|
921
|
+
if (data.results.length === 0) {
|
|
922
|
+
results.innerHTML = '<p>No results found.</p>';
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
results.innerHTML = data.results.map(r => `
|
|
927
|
+
<div class="search-result">
|
|
928
|
+
<div class="search-result-header">
|
|
929
|
+
<span>${r.location}</span>
|
|
930
|
+
<span class="badge badge-success">${(r.similarity * 100).toFixed(1)}% match</span>
|
|
931
|
+
</div>
|
|
932
|
+
<div class="search-result-code">
|
|
933
|
+
<pre><code class="language-${r.language || 'plaintext'}">${escapeHtml(r.content)}</code></pre>
|
|
934
|
+
</div>
|
|
935
|
+
</div>
|
|
936
|
+
`).join('');
|
|
937
|
+
|
|
938
|
+
// Highlight code
|
|
939
|
+
results.querySelectorAll('pre code').forEach(block => {
|
|
940
|
+
hljs.highlightElement(block);
|
|
941
|
+
});
|
|
942
|
+
} catch (e) {
|
|
943
|
+
results.innerHTML = `<p>Error: ${e.message}</p>`;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
async function indexProject() {
|
|
948
|
+
showToast('Indexing project...');
|
|
949
|
+
|
|
950
|
+
try {
|
|
951
|
+
const response = await fetch('/api/index', { method: 'POST' });
|
|
952
|
+
const data = await response.json();
|
|
953
|
+
|
|
954
|
+
showToast(`Indexed ${data.files_indexed} files, ${data.chunks_created} chunks`);
|
|
955
|
+
loadIndexStatus();
|
|
956
|
+
} catch (e) {
|
|
957
|
+
showToast(`Error: ${e.message}`, 'error');
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// Plugins
|
|
962
|
+
async function loadPlugins() {
|
|
963
|
+
const container = document.getElementById('plugins-list');
|
|
964
|
+
|
|
965
|
+
try {
|
|
966
|
+
const response = await fetch('/api/plugins');
|
|
967
|
+
const data = await response.json();
|
|
968
|
+
|
|
969
|
+
if (data.plugins.length === 0) {
|
|
970
|
+
container.innerHTML = '<p>No plugins available.</p>';
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
container.innerHTML = data.plugins.map(p => `
|
|
975
|
+
<div class="card" style="margin-bottom: 16px;">
|
|
976
|
+
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
|
|
977
|
+
<span>${p.name} <span style="color: var(--text-secondary);">v${p.version}</span></span>
|
|
978
|
+
<span class="badge ${p.status === 'active' ? 'badge-success' : 'badge-warning'}">${p.status}</span>
|
|
979
|
+
</div>
|
|
980
|
+
<div class="card-body">
|
|
981
|
+
<p style="color: var(--text-secondary); margin-bottom: 12px;">
|
|
982
|
+
${p.builtin ? 'Built-in plugin' : 'Custom plugin'}
|
|
983
|
+
</p>
|
|
984
|
+
<div>
|
|
985
|
+
<strong>Actions:</strong>
|
|
986
|
+
${p.actions.map(a => `<button class="btn" style="margin: 4px;" onclick="executePlugin('${p.name}', '${a}')">${a}</button>`).join('')}
|
|
987
|
+
</div>
|
|
988
|
+
</div>
|
|
989
|
+
</div>
|
|
990
|
+
`).join('');
|
|
991
|
+
} catch (e) {
|
|
992
|
+
container.innerHTML = `<p>Error: ${e.message}</p>`;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
async function executePlugin(plugin, action) {
|
|
997
|
+
try {
|
|
998
|
+
const response = await fetch('/api/plugins/execute', {
|
|
999
|
+
method: 'POST',
|
|
1000
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1001
|
+
body: JSON.stringify({ plugin, action })
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
const data = await response.json();
|
|
1005
|
+
|
|
1006
|
+
if (data.success) {
|
|
1007
|
+
showToast(data.message);
|
|
1008
|
+
// Show result in chat
|
|
1009
|
+
document.querySelector('[data-panel="chat"]').click();
|
|
1010
|
+
addMessage('assistant', `**${plugin}:${action}**\n\n${data.message}\n\n${typeof data.data === 'string' ? data.data : JSON.stringify(data.data, null, 2)}`);
|
|
1011
|
+
} else {
|
|
1012
|
+
showToast(`Error: ${data.error}`, 'error');
|
|
1013
|
+
}
|
|
1014
|
+
} catch (e) {
|
|
1015
|
+
showToast(`Error: ${e.message}`, 'error');
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// MCP
|
|
1020
|
+
async function loadMCPStatus() {
|
|
1021
|
+
const container = document.getElementById('mcp-status');
|
|
1022
|
+
|
|
1023
|
+
try {
|
|
1024
|
+
const response = await fetch('/api/mcp/status');
|
|
1025
|
+
const data = await response.json();
|
|
1026
|
+
|
|
1027
|
+
if (!data.available) {
|
|
1028
|
+
container.innerHTML = '<div class="stat-card">MCP not available</div>';
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
container.innerHTML = `
|
|
1033
|
+
<div class="stat-card">
|
|
1034
|
+
<div class="stat-value">${data.server.tools}</div>
|
|
1035
|
+
<div class="stat-label">Local Tools</div>
|
|
1036
|
+
</div>
|
|
1037
|
+
<div class="stat-card">
|
|
1038
|
+
<div class="stat-value">${data.client.connected_servers}</div>
|
|
1039
|
+
<div class="stat-label">Connected Servers</div>
|
|
1040
|
+
</div>
|
|
1041
|
+
<div class="stat-card">
|
|
1042
|
+
<div class="stat-value">${data.server.running ? 'Yes' : 'No'}</div>
|
|
1043
|
+
<div class="stat-label">Server Running</div>
|
|
1044
|
+
</div>
|
|
1045
|
+
`;
|
|
1046
|
+
} catch (e) {
|
|
1047
|
+
container.innerHTML = `<div class="stat-card">Error loading MCP status</div>`;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
async function loadMCPTools() {
|
|
1052
|
+
const container = document.getElementById('mcp-tools-list');
|
|
1053
|
+
|
|
1054
|
+
try {
|
|
1055
|
+
const response = await fetch('/api/mcp/tools');
|
|
1056
|
+
const data = await response.json();
|
|
1057
|
+
|
|
1058
|
+
const tools = [...data.local, ...data.remote];
|
|
1059
|
+
|
|
1060
|
+
if (tools.length === 0) {
|
|
1061
|
+
container.innerHTML = '<p>No tools available.</p>';
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
container.innerHTML = tools.map(t => `
|
|
1066
|
+
<div class="tool-item">
|
|
1067
|
+
<div class="tool-name">${t.name}</div>
|
|
1068
|
+
<div class="tool-description">${t.description}</div>
|
|
1069
|
+
${t.parameters ? `<div class="tool-params">Parameters: ${t.parameters.map(p => p.name).join(', ')}</div>` : ''}
|
|
1070
|
+
</div>
|
|
1071
|
+
`).join('');
|
|
1072
|
+
} catch (e) {
|
|
1073
|
+
container.innerHTML = `<p>Error: ${e.message}</p>`;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// Config
|
|
1078
|
+
async function loadConfig() {
|
|
1079
|
+
const display = document.getElementById('config-display');
|
|
1080
|
+
|
|
1081
|
+
try {
|
|
1082
|
+
const response = await fetch('/api/config');
|
|
1083
|
+
const data = await response.json();
|
|
1084
|
+
display.textContent = JSON.stringify(data.config, null, 2);
|
|
1085
|
+
} catch (e) {
|
|
1086
|
+
display.textContent = `Error: ${e.message}`;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
async function loadStatus() {
|
|
1091
|
+
const container = document.getElementById('system-status');
|
|
1092
|
+
|
|
1093
|
+
try {
|
|
1094
|
+
const response = await fetch('/api/status');
|
|
1095
|
+
const data = await response.json();
|
|
1096
|
+
|
|
1097
|
+
container.innerHTML = `
|
|
1098
|
+
<div class="stat-card">
|
|
1099
|
+
<div class="stat-value" style="font-size: 20px;">${data.status === 'ok' ? '✅' : '❌'}</div>
|
|
1100
|
+
<div class="stat-label">System Status</div>
|
|
1101
|
+
</div>
|
|
1102
|
+
<div class="stat-card">
|
|
1103
|
+
<div class="stat-value" style="font-size: 16px;">${data.version}</div>
|
|
1104
|
+
<div class="stat-label">Version</div>
|
|
1105
|
+
</div>
|
|
1106
|
+
<div class="stat-card">
|
|
1107
|
+
<div class="stat-value" style="font-size: 14px; word-break: break-all;">${data.project.slice(-30)}</div>
|
|
1108
|
+
<div class="stat-label">Project</div>
|
|
1109
|
+
</div>
|
|
1110
|
+
`;
|
|
1111
|
+
} catch (e) {
|
|
1112
|
+
container.innerHTML = `<div class="stat-card">Error loading status</div>`;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// Utilities
|
|
1117
|
+
function escapeHtml(text) {
|
|
1118
|
+
const div = document.createElement('div');
|
|
1119
|
+
div.textContent = text;
|
|
1120
|
+
return div.innerHTML;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// Initial load
|
|
1124
|
+
loadStatus();
|
|
1125
|
+
</script>
|
|
1126
|
+
</body>
|
|
1127
|
+
</html>
|