apexbot 1.0.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/LICENSE +21 -0
- package/README.md +307 -0
- package/dist/adapters/manifold.js +166 -0
- package/dist/adapters/telegram.js +133 -0
- package/dist/agent/agentManager.js +315 -0
- package/dist/backtest/backtester.js +24 -0
- package/dist/channels/channelManager.js +72 -0
- package/dist/channels/discord.js +136 -0
- package/dist/channels/telegram.js +186 -0
- package/dist/cli/index.js +838 -0
- package/dist/core/eventBus.js +33 -0
- package/dist/decisionEngine.js +69 -0
- package/dist/eventBus.js +21 -0
- package/dist/gateway/dashboard.js +1009 -0
- package/dist/gateway/index.js +303 -0
- package/dist/index.js +195 -0
- package/dist/math/ev.js +25 -0
- package/dist/math/kelly.js +24 -0
- package/dist/rateLimiter.js +42 -0
- package/dist/safety/failsafe.js +32 -0
- package/dist/safety/llmChecker.js +148 -0
- package/dist/sessions/sessionManager.js +120 -0
- package/dist/strategy/arbitrage.js +151 -0
- package/package.json +78 -0
- package/scripts/install.ps1 +114 -0
- package/scripts/install.sh +146 -0
|
@@ -0,0 +1,1009 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ApexBot Dashboard - Professional Web UI like Clawdbot
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getDashboardHtml = getDashboardHtml;
|
|
7
|
+
function getDashboardHtml() {
|
|
8
|
+
return `<!DOCTYPE html>
|
|
9
|
+
<html lang="en">
|
|
10
|
+
<head>
|
|
11
|
+
<meta charset="UTF-8">
|
|
12
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
13
|
+
<title>ApexBot Dashboard</title>
|
|
14
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
15
|
+
<style>
|
|
16
|
+
:root {
|
|
17
|
+
--bg-primary: #0d0d12;
|
|
18
|
+
--bg-secondary: #16161d;
|
|
19
|
+
--bg-tertiary: #1e1e28;
|
|
20
|
+
--bg-hover: #252530;
|
|
21
|
+
--accent: #4ade80;
|
|
22
|
+
--accent-dim: #22c55e33;
|
|
23
|
+
--text-primary: #f0f0f5;
|
|
24
|
+
--text-secondary: #9898a6;
|
|
25
|
+
--text-muted: #5a5a6e;
|
|
26
|
+
--border: #2a2a38;
|
|
27
|
+
--danger: #f87171;
|
|
28
|
+
--warning: #fbbf24;
|
|
29
|
+
--info: #38bdf8;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
33
|
+
|
|
34
|
+
body {
|
|
35
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
36
|
+
background: var(--bg-primary);
|
|
37
|
+
color: var(--text-primary);
|
|
38
|
+
min-height: 100vh;
|
|
39
|
+
display: flex;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Sidebar */
|
|
43
|
+
.sidebar {
|
|
44
|
+
width: 240px;
|
|
45
|
+
background: var(--bg-secondary);
|
|
46
|
+
border-right: 1px solid var(--border);
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
height: 100vh;
|
|
50
|
+
position: fixed;
|
|
51
|
+
left: 0;
|
|
52
|
+
top: 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.sidebar-header {
|
|
56
|
+
padding: 1.25rem;
|
|
57
|
+
border-bottom: 1px solid var(--border);
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: 0.75rem;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.sidebar-logo {
|
|
64
|
+
font-size: 1.25rem;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.sidebar-title {
|
|
68
|
+
font-weight: 600;
|
|
69
|
+
font-size: 1.1rem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.sidebar-version {
|
|
73
|
+
font-size: 0.7rem;
|
|
74
|
+
color: var(--text-muted);
|
|
75
|
+
background: var(--bg-tertiary);
|
|
76
|
+
padding: 0.15rem 0.4rem;
|
|
77
|
+
border-radius: 0.25rem;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.sidebar-nav {
|
|
81
|
+
flex: 1;
|
|
82
|
+
overflow-y: auto;
|
|
83
|
+
padding: 0.5rem 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.nav-section {
|
|
87
|
+
padding: 0.5rem 1rem;
|
|
88
|
+
margin-top: 0.5rem;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.nav-section-title {
|
|
92
|
+
font-size: 0.7rem;
|
|
93
|
+
font-weight: 600;
|
|
94
|
+
text-transform: uppercase;
|
|
95
|
+
letter-spacing: 0.05em;
|
|
96
|
+
color: var(--text-muted);
|
|
97
|
+
margin-bottom: 0.5rem;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.nav-item {
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 0.75rem;
|
|
104
|
+
padding: 0.6rem 1rem;
|
|
105
|
+
color: var(--text-secondary);
|
|
106
|
+
text-decoration: none;
|
|
107
|
+
border-radius: 0.5rem;
|
|
108
|
+
margin: 0.15rem 0.5rem;
|
|
109
|
+
cursor: pointer;
|
|
110
|
+
transition: all 0.15s;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.nav-item:hover {
|
|
114
|
+
background: var(--bg-hover);
|
|
115
|
+
color: var(--text-primary);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.nav-item.active {
|
|
119
|
+
background: var(--accent-dim);
|
|
120
|
+
color: var(--accent);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.nav-icon {
|
|
124
|
+
font-size: 1.1rem;
|
|
125
|
+
width: 1.5rem;
|
|
126
|
+
text-align: center;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.sidebar-footer {
|
|
130
|
+
padding: 1rem;
|
|
131
|
+
border-top: 1px solid var(--border);
|
|
132
|
+
font-size: 0.8rem;
|
|
133
|
+
color: var(--text-muted);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Main Content */
|
|
137
|
+
.main {
|
|
138
|
+
flex: 1;
|
|
139
|
+
margin-left: 240px;
|
|
140
|
+
display: flex;
|
|
141
|
+
flex-direction: column;
|
|
142
|
+
height: 100vh;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.header {
|
|
146
|
+
padding: 1.5rem 2rem;
|
|
147
|
+
border-bottom: 1px solid var(--border);
|
|
148
|
+
background: var(--bg-secondary);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.header-title {
|
|
152
|
+
font-size: 1.5rem;
|
|
153
|
+
font-weight: 600;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.header-subtitle {
|
|
157
|
+
font-size: 0.85rem;
|
|
158
|
+
color: var(--text-secondary);
|
|
159
|
+
margin-top: 0.25rem;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.content {
|
|
163
|
+
flex: 1;
|
|
164
|
+
overflow-y: auto;
|
|
165
|
+
padding: 2rem;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* Pages */
|
|
169
|
+
.page {
|
|
170
|
+
display: none;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.page.active {
|
|
174
|
+
display: block;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Chat Page */
|
|
178
|
+
.chat-container {
|
|
179
|
+
display: flex;
|
|
180
|
+
flex-direction: column;
|
|
181
|
+
height: calc(100vh - 180px);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.messages {
|
|
185
|
+
flex: 1;
|
|
186
|
+
overflow-y: auto;
|
|
187
|
+
padding: 1rem;
|
|
188
|
+
display: flex;
|
|
189
|
+
flex-direction: column;
|
|
190
|
+
gap: 1rem;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.message {
|
|
194
|
+
display: flex;
|
|
195
|
+
gap: 0.75rem;
|
|
196
|
+
max-width: 80%;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.message.user {
|
|
200
|
+
align-self: flex-end;
|
|
201
|
+
flex-direction: row-reverse;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.message-avatar {
|
|
205
|
+
width: 36px;
|
|
206
|
+
height: 36px;
|
|
207
|
+
border-radius: 50%;
|
|
208
|
+
background: var(--bg-tertiary);
|
|
209
|
+
display: flex;
|
|
210
|
+
align-items: center;
|
|
211
|
+
justify-content: center;
|
|
212
|
+
flex-shrink: 0;
|
|
213
|
+
font-size: 1rem;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.message.user .message-avatar {
|
|
217
|
+
background: var(--accent-dim);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.message-content {
|
|
221
|
+
background: var(--bg-tertiary);
|
|
222
|
+
padding: 0.75rem 1rem;
|
|
223
|
+
border-radius: 1rem;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.message.user .message-content {
|
|
227
|
+
background: var(--accent-dim);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.message-text {
|
|
231
|
+
line-height: 1.5;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.message-time {
|
|
235
|
+
font-size: 0.7rem;
|
|
236
|
+
color: var(--text-muted);
|
|
237
|
+
margin-top: 0.25rem;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.tool-call {
|
|
241
|
+
background: var(--bg-hover);
|
|
242
|
+
border: 1px solid var(--border);
|
|
243
|
+
border-radius: 0.5rem;
|
|
244
|
+
padding: 0.75rem;
|
|
245
|
+
margin-top: 0.5rem;
|
|
246
|
+
font-size: 0.85rem;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.tool-call-header {
|
|
250
|
+
display: flex;
|
|
251
|
+
align-items: center;
|
|
252
|
+
gap: 0.5rem;
|
|
253
|
+
color: var(--accent);
|
|
254
|
+
font-weight: 500;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.tool-call-result {
|
|
258
|
+
color: var(--text-secondary);
|
|
259
|
+
margin-top: 0.25rem;
|
|
260
|
+
font-family: monospace;
|
|
261
|
+
font-size: 0.8rem;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.chat-input-area {
|
|
265
|
+
padding: 1rem;
|
|
266
|
+
background: var(--bg-secondary);
|
|
267
|
+
border-top: 1px solid var(--border);
|
|
268
|
+
display: flex;
|
|
269
|
+
gap: 0.75rem;
|
|
270
|
+
align-items: center;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.chat-input {
|
|
274
|
+
flex: 1;
|
|
275
|
+
background: var(--bg-tertiary);
|
|
276
|
+
border: 1px solid var(--border);
|
|
277
|
+
border-radius: 0.75rem;
|
|
278
|
+
padding: 0.75rem 1rem;
|
|
279
|
+
color: var(--text-primary);
|
|
280
|
+
font-size: 0.95rem;
|
|
281
|
+
outline: none;
|
|
282
|
+
transition: border-color 0.15s;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.chat-input:focus {
|
|
286
|
+
border-color: var(--accent);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.chat-input::placeholder {
|
|
290
|
+
color: var(--text-muted);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.btn {
|
|
294
|
+
padding: 0.75rem 1.5rem;
|
|
295
|
+
border: none;
|
|
296
|
+
border-radius: 0.75rem;
|
|
297
|
+
font-weight: 500;
|
|
298
|
+
cursor: pointer;
|
|
299
|
+
transition: all 0.15s;
|
|
300
|
+
font-size: 0.9rem;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.btn-primary {
|
|
304
|
+
background: var(--accent);
|
|
305
|
+
color: #000;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.btn-primary:hover {
|
|
309
|
+
background: #22c55e;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.btn-secondary {
|
|
313
|
+
background: var(--bg-tertiary);
|
|
314
|
+
color: var(--text-primary);
|
|
315
|
+
border: 1px solid var(--border);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.btn-secondary:hover {
|
|
319
|
+
background: var(--bg-hover);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* Overview Page */
|
|
323
|
+
.stats-grid {
|
|
324
|
+
display: grid;
|
|
325
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
326
|
+
gap: 1.5rem;
|
|
327
|
+
margin-bottom: 2rem;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.stat-card {
|
|
331
|
+
background: var(--bg-secondary);
|
|
332
|
+
border: 1px solid var(--border);
|
|
333
|
+
border-radius: 0.75rem;
|
|
334
|
+
padding: 1.5rem;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.stat-label {
|
|
338
|
+
font-size: 0.85rem;
|
|
339
|
+
color: var(--text-secondary);
|
|
340
|
+
margin-bottom: 0.5rem;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.stat-value {
|
|
344
|
+
font-size: 2rem;
|
|
345
|
+
font-weight: 600;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.stat-value.success { color: var(--accent); }
|
|
349
|
+
.stat-value.warning { color: var(--warning); }
|
|
350
|
+
.stat-value.danger { color: var(--danger); }
|
|
351
|
+
.stat-value.info { color: var(--info); }
|
|
352
|
+
|
|
353
|
+
/* Sessions Table */
|
|
354
|
+
.table-container {
|
|
355
|
+
background: var(--bg-secondary);
|
|
356
|
+
border: 1px solid var(--border);
|
|
357
|
+
border-radius: 0.75rem;
|
|
358
|
+
overflow: hidden;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.table-header {
|
|
362
|
+
padding: 1rem 1.5rem;
|
|
363
|
+
border-bottom: 1px solid var(--border);
|
|
364
|
+
font-weight: 600;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
table {
|
|
368
|
+
width: 100%;
|
|
369
|
+
border-collapse: collapse;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
th, td {
|
|
373
|
+
padding: 0.75rem 1.5rem;
|
|
374
|
+
text-align: left;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
th {
|
|
378
|
+
font-size: 0.75rem;
|
|
379
|
+
font-weight: 600;
|
|
380
|
+
text-transform: uppercase;
|
|
381
|
+
letter-spacing: 0.05em;
|
|
382
|
+
color: var(--text-muted);
|
|
383
|
+
background: var(--bg-tertiary);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
tr {
|
|
387
|
+
border-bottom: 1px solid var(--border);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
tr:last-child {
|
|
391
|
+
border-bottom: none;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
tr:hover {
|
|
395
|
+
background: var(--bg-hover);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.badge {
|
|
399
|
+
display: inline-block;
|
|
400
|
+
padding: 0.25rem 0.5rem;
|
|
401
|
+
border-radius: 0.25rem;
|
|
402
|
+
font-size: 0.75rem;
|
|
403
|
+
font-weight: 500;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.badge-success { background: var(--accent-dim); color: var(--accent); }
|
|
407
|
+
.badge-warning { background: #fbbf2433; color: var(--warning); }
|
|
408
|
+
.badge-info { background: #38bdf833; color: var(--info); }
|
|
409
|
+
|
|
410
|
+
/* Config Page */
|
|
411
|
+
.config-section {
|
|
412
|
+
background: var(--bg-secondary);
|
|
413
|
+
border: 1px solid var(--border);
|
|
414
|
+
border-radius: 0.75rem;
|
|
415
|
+
padding: 1.5rem;
|
|
416
|
+
margin-bottom: 1.5rem;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.config-section-title {
|
|
420
|
+
font-weight: 600;
|
|
421
|
+
margin-bottom: 1rem;
|
|
422
|
+
display: flex;
|
|
423
|
+
align-items: center;
|
|
424
|
+
gap: 0.5rem;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.config-item {
|
|
428
|
+
display: flex;
|
|
429
|
+
justify-content: space-between;
|
|
430
|
+
align-items: center;
|
|
431
|
+
padding: 0.75rem 0;
|
|
432
|
+
border-bottom: 1px solid var(--border);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.config-item:last-child {
|
|
436
|
+
border-bottom: none;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.config-key {
|
|
440
|
+
color: var(--text-secondary);
|
|
441
|
+
font-family: monospace;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.config-value {
|
|
445
|
+
color: var(--accent);
|
|
446
|
+
font-family: monospace;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* Logs Page */
|
|
450
|
+
.logs-container {
|
|
451
|
+
background: var(--bg-secondary);
|
|
452
|
+
border: 1px solid var(--border);
|
|
453
|
+
border-radius: 0.75rem;
|
|
454
|
+
padding: 1rem;
|
|
455
|
+
font-family: 'Fira Code', monospace;
|
|
456
|
+
font-size: 0.8rem;
|
|
457
|
+
max-height: 600px;
|
|
458
|
+
overflow-y: auto;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.log-entry {
|
|
462
|
+
padding: 0.25rem 0;
|
|
463
|
+
display: flex;
|
|
464
|
+
gap: 1rem;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.log-time {
|
|
468
|
+
color: var(--text-muted);
|
|
469
|
+
flex-shrink: 0;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.log-level {
|
|
473
|
+
width: 50px;
|
|
474
|
+
flex-shrink: 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.log-level.info { color: var(--info); }
|
|
478
|
+
.log-level.success { color: var(--accent); }
|
|
479
|
+
.log-level.warn { color: var(--warning); }
|
|
480
|
+
.log-level.error { color: var(--danger); }
|
|
481
|
+
|
|
482
|
+
/* New Session Button */
|
|
483
|
+
.chat-actions {
|
|
484
|
+
display: flex;
|
|
485
|
+
gap: 0.5rem;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.emoji-btn {
|
|
489
|
+
background: var(--bg-tertiary);
|
|
490
|
+
border: 1px solid var(--border);
|
|
491
|
+
width: 40px;
|
|
492
|
+
height: 40px;
|
|
493
|
+
border-radius: 50%;
|
|
494
|
+
cursor: pointer;
|
|
495
|
+
font-size: 1.1rem;
|
|
496
|
+
transition: all 0.15s;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.emoji-btn:hover {
|
|
500
|
+
background: var(--bg-hover);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/* Responsive */
|
|
504
|
+
@media (max-width: 768px) {
|
|
505
|
+
.sidebar {
|
|
506
|
+
width: 60px;
|
|
507
|
+
}
|
|
508
|
+
.sidebar-title, .sidebar-version, .nav-section-title, .nav-item span {
|
|
509
|
+
display: none;
|
|
510
|
+
}
|
|
511
|
+
.nav-item {
|
|
512
|
+
justify-content: center;
|
|
513
|
+
padding: 0.75rem;
|
|
514
|
+
}
|
|
515
|
+
.main {
|
|
516
|
+
margin-left: 60px;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
</style>
|
|
520
|
+
</head>
|
|
521
|
+
<body>
|
|
522
|
+
<!-- Sidebar -->
|
|
523
|
+
<aside class="sidebar">
|
|
524
|
+
<div class="sidebar-header">
|
|
525
|
+
<span class="sidebar-logo">🦊</span>
|
|
526
|
+
<span class="sidebar-title">ApexBot</span>
|
|
527
|
+
<span class="sidebar-version">v1.0</span>
|
|
528
|
+
</div>
|
|
529
|
+
|
|
530
|
+
<nav class="sidebar-nav">
|
|
531
|
+
<div class="nav-section">
|
|
532
|
+
<div class="nav-section-title">Chat</div>
|
|
533
|
+
<a class="nav-item active" data-page="chat">
|
|
534
|
+
<span class="nav-icon">💬</span>
|
|
535
|
+
<span>Chat</span>
|
|
536
|
+
</a>
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
<div class="nav-section">
|
|
540
|
+
<div class="nav-section-title">Control</div>
|
|
541
|
+
<a class="nav-item" data-page="overview">
|
|
542
|
+
<span class="nav-icon">📊</span>
|
|
543
|
+
<span>Overview</span>
|
|
544
|
+
</a>
|
|
545
|
+
<a class="nav-item" data-page="channels">
|
|
546
|
+
<span class="nav-icon">🔗</span>
|
|
547
|
+
<span>Channels</span>
|
|
548
|
+
</a>
|
|
549
|
+
<a class="nav-item" data-page="sessions">
|
|
550
|
+
<span class="nav-icon">👥</span>
|
|
551
|
+
<span>Sessions</span>
|
|
552
|
+
</a>
|
|
553
|
+
</div>
|
|
554
|
+
|
|
555
|
+
<div class="nav-section">
|
|
556
|
+
<div class="nav-section-title">Agent</div>
|
|
557
|
+
<a class="nav-item" data-page="skills">
|
|
558
|
+
<span class="nav-icon">⚡</span>
|
|
559
|
+
<span>Skills</span>
|
|
560
|
+
</a>
|
|
561
|
+
<a class="nav-item" data-page="model">
|
|
562
|
+
<span class="nav-icon">🧠</span>
|
|
563
|
+
<span>Model</span>
|
|
564
|
+
</a>
|
|
565
|
+
</div>
|
|
566
|
+
|
|
567
|
+
<div class="nav-section">
|
|
568
|
+
<div class="nav-section-title">Settings</div>
|
|
569
|
+
<a class="nav-item" data-page="config">
|
|
570
|
+
<span class="nav-icon">⚙️</span>
|
|
571
|
+
<span>Config</span>
|
|
572
|
+
</a>
|
|
573
|
+
<a class="nav-item" data-page="logs">
|
|
574
|
+
<span class="nav-icon">📜</span>
|
|
575
|
+
<span>Logs</span>
|
|
576
|
+
</a>
|
|
577
|
+
</div>
|
|
578
|
+
</nav>
|
|
579
|
+
|
|
580
|
+
<div class="sidebar-footer">
|
|
581
|
+
<span id="connection-status">● Connecting...</span>
|
|
582
|
+
</div>
|
|
583
|
+
</aside>
|
|
584
|
+
|
|
585
|
+
<!-- Main Content -->
|
|
586
|
+
<main class="main">
|
|
587
|
+
<!-- Chat Page -->
|
|
588
|
+
<div class="page active" id="page-chat">
|
|
589
|
+
<div class="header">
|
|
590
|
+
<h1 class="header-title">Chat</h1>
|
|
591
|
+
<p class="header-subtitle">Direct gateway chat session for quick interactions.</p>
|
|
592
|
+
</div>
|
|
593
|
+
<div class="chat-container">
|
|
594
|
+
<div class="messages" id="messages"></div>
|
|
595
|
+
<div class="chat-input-area">
|
|
596
|
+
<input type="text" class="chat-input" id="chat-input" placeholder="Message (⏎ to send, Shift+⏎ for line breaks)">
|
|
597
|
+
<div class="chat-actions">
|
|
598
|
+
<button class="emoji-btn" title="Emoji">😀</button>
|
|
599
|
+
<button class="emoji-btn" title="Attach">📎</button>
|
|
600
|
+
</div>
|
|
601
|
+
<button class="btn btn-secondary" onclick="newSession()">New session</button>
|
|
602
|
+
<button class="btn btn-primary" onclick="sendMessage()">Send</button>
|
|
603
|
+
</div>
|
|
604
|
+
</div>
|
|
605
|
+
</div>
|
|
606
|
+
|
|
607
|
+
<!-- Overview Page -->
|
|
608
|
+
<div class="page" id="page-overview">
|
|
609
|
+
<div class="header">
|
|
610
|
+
<h1 class="header-title">Overview</h1>
|
|
611
|
+
<p class="header-subtitle">System status and metrics</p>
|
|
612
|
+
</div>
|
|
613
|
+
<div class="content">
|
|
614
|
+
<div class="stats-grid">
|
|
615
|
+
<div class="stat-card">
|
|
616
|
+
<div class="stat-label">Status</div>
|
|
617
|
+
<div class="stat-value success" id="stat-status">Online</div>
|
|
618
|
+
</div>
|
|
619
|
+
<div class="stat-card">
|
|
620
|
+
<div class="stat-label">Uptime</div>
|
|
621
|
+
<div class="stat-value info" id="stat-uptime">0s</div>
|
|
622
|
+
</div>
|
|
623
|
+
<div class="stat-card">
|
|
624
|
+
<div class="stat-label">Active Sessions</div>
|
|
625
|
+
<div class="stat-value" id="stat-sessions">0</div>
|
|
626
|
+
</div>
|
|
627
|
+
<div class="stat-card">
|
|
628
|
+
<div class="stat-label">Channels</div>
|
|
629
|
+
<div class="stat-value" id="stat-channels">0</div>
|
|
630
|
+
</div>
|
|
631
|
+
</div>
|
|
632
|
+
</div>
|
|
633
|
+
</div>
|
|
634
|
+
|
|
635
|
+
<!-- Channels Page -->
|
|
636
|
+
<div class="page" id="page-channels">
|
|
637
|
+
<div class="header">
|
|
638
|
+
<h1 class="header-title">Channels</h1>
|
|
639
|
+
<p class="header-subtitle">Connected messaging platforms</p>
|
|
640
|
+
</div>
|
|
641
|
+
<div class="content">
|
|
642
|
+
<div class="table-container">
|
|
643
|
+
<div class="table-header">Active Channels</div>
|
|
644
|
+
<table>
|
|
645
|
+
<thead>
|
|
646
|
+
<tr>
|
|
647
|
+
<th>Channel</th>
|
|
648
|
+
<th>Status</th>
|
|
649
|
+
<th>Messages</th>
|
|
650
|
+
<th>Connected</th>
|
|
651
|
+
</tr>
|
|
652
|
+
</thead>
|
|
653
|
+
<tbody id="channels-table">
|
|
654
|
+
<tr>
|
|
655
|
+
<td>🌐 WebChat</td>
|
|
656
|
+
<td><span class="badge badge-success">Connected</span></td>
|
|
657
|
+
<td>0</td>
|
|
658
|
+
<td>Just now</td>
|
|
659
|
+
</tr>
|
|
660
|
+
</tbody>
|
|
661
|
+
</table>
|
|
662
|
+
</div>
|
|
663
|
+
</div>
|
|
664
|
+
</div>
|
|
665
|
+
|
|
666
|
+
<!-- Sessions Page -->
|
|
667
|
+
<div class="page" id="page-sessions">
|
|
668
|
+
<div class="header">
|
|
669
|
+
<h1 class="header-title">Sessions</h1>
|
|
670
|
+
<p class="header-subtitle">Active chat sessions</p>
|
|
671
|
+
</div>
|
|
672
|
+
<div class="content">
|
|
673
|
+
<div class="table-container">
|
|
674
|
+
<div class="table-header">Sessions</div>
|
|
675
|
+
<table>
|
|
676
|
+
<thead>
|
|
677
|
+
<tr>
|
|
678
|
+
<th>ID</th>
|
|
679
|
+
<th>Channel</th>
|
|
680
|
+
<th>Peer</th>
|
|
681
|
+
<th>Messages</th>
|
|
682
|
+
<th>Created</th>
|
|
683
|
+
</tr>
|
|
684
|
+
</thead>
|
|
685
|
+
<tbody id="sessions-table">
|
|
686
|
+
</tbody>
|
|
687
|
+
</table>
|
|
688
|
+
</div>
|
|
689
|
+
</div>
|
|
690
|
+
</div>
|
|
691
|
+
|
|
692
|
+
<!-- Skills Page -->
|
|
693
|
+
<div class="page" id="page-skills">
|
|
694
|
+
<div class="header">
|
|
695
|
+
<h1 class="header-title">Skills</h1>
|
|
696
|
+
<p class="header-subtitle">Agent capabilities and tools</p>
|
|
697
|
+
</div>
|
|
698
|
+
<div class="content">
|
|
699
|
+
<div class="stats-grid">
|
|
700
|
+
<div class="stat-card">
|
|
701
|
+
<div class="stat-label">📝 File Write</div>
|
|
702
|
+
<div class="stat-value info">Enabled</div>
|
|
703
|
+
</div>
|
|
704
|
+
<div class="stat-card">
|
|
705
|
+
<div class="stat-label">🔍 Web Search</div>
|
|
706
|
+
<div class="stat-value success">Enabled</div>
|
|
707
|
+
</div>
|
|
708
|
+
<div class="stat-card">
|
|
709
|
+
<div class="stat-label">📊 Data Analysis</div>
|
|
710
|
+
<div class="stat-value success">Enabled</div>
|
|
711
|
+
</div>
|
|
712
|
+
<div class="stat-card">
|
|
713
|
+
<div class="stat-label">🎯 Task Planning</div>
|
|
714
|
+
<div class="stat-value success">Enabled</div>
|
|
715
|
+
</div>
|
|
716
|
+
</div>
|
|
717
|
+
</div>
|
|
718
|
+
</div>
|
|
719
|
+
|
|
720
|
+
<!-- Model Page -->
|
|
721
|
+
<div class="page" id="page-model">
|
|
722
|
+
<div class="header">
|
|
723
|
+
<h1 class="header-title">Model</h1>
|
|
724
|
+
<p class="header-subtitle">AI model configuration</p>
|
|
725
|
+
</div>
|
|
726
|
+
<div class="content">
|
|
727
|
+
<div class="config-section">
|
|
728
|
+
<div class="config-section-title">🧠 Current Model</div>
|
|
729
|
+
<div class="config-item">
|
|
730
|
+
<span class="config-key">Provider</span>
|
|
731
|
+
<span class="config-value" id="model-provider">ollama</span>
|
|
732
|
+
</div>
|
|
733
|
+
<div class="config-item">
|
|
734
|
+
<span class="config-key">Model</span>
|
|
735
|
+
<span class="config-value" id="model-name">llama3.2:latest</span>
|
|
736
|
+
</div>
|
|
737
|
+
<div class="config-item">
|
|
738
|
+
<span class="config-key">API URL</span>
|
|
739
|
+
<span class="config-value" id="model-url">http://localhost:11434</span>
|
|
740
|
+
</div>
|
|
741
|
+
</div>
|
|
742
|
+
</div>
|
|
743
|
+
</div>
|
|
744
|
+
|
|
745
|
+
<!-- Config Page -->
|
|
746
|
+
<div class="page" id="page-config">
|
|
747
|
+
<div class="header">
|
|
748
|
+
<h1 class="header-title">Config</h1>
|
|
749
|
+
<p class="header-subtitle">System configuration</p>
|
|
750
|
+
</div>
|
|
751
|
+
<div class="content">
|
|
752
|
+
<div class="config-section">
|
|
753
|
+
<div class="config-section-title">🚀 Gateway</div>
|
|
754
|
+
<div class="config-item">
|
|
755
|
+
<span class="config-key">Host</span>
|
|
756
|
+
<span class="config-value">127.0.0.1</span>
|
|
757
|
+
</div>
|
|
758
|
+
<div class="config-item">
|
|
759
|
+
<span class="config-key">Port</span>
|
|
760
|
+
<span class="config-value" id="config-port">18789</span>
|
|
761
|
+
</div>
|
|
762
|
+
</div>
|
|
763
|
+
</div>
|
|
764
|
+
</div>
|
|
765
|
+
|
|
766
|
+
<!-- Logs Page -->
|
|
767
|
+
<div class="page" id="page-logs">
|
|
768
|
+
<div class="header">
|
|
769
|
+
<h1 class="header-title">Logs</h1>
|
|
770
|
+
<p class="header-subtitle">System logs and events</p>
|
|
771
|
+
</div>
|
|
772
|
+
<div class="content">
|
|
773
|
+
<div class="logs-container" id="logs-container">
|
|
774
|
+
<div class="log-entry">
|
|
775
|
+
<span class="log-time">${new Date().toLocaleTimeString()}</span>
|
|
776
|
+
<span class="log-level info">INFO</span>
|
|
777
|
+
<span>Dashboard loaded</span>
|
|
778
|
+
</div>
|
|
779
|
+
</div>
|
|
780
|
+
</div>
|
|
781
|
+
</div>
|
|
782
|
+
</main>
|
|
783
|
+
|
|
784
|
+
<script>
|
|
785
|
+
// State
|
|
786
|
+
let ws = null;
|
|
787
|
+
const logs = [];
|
|
788
|
+
let sessionId = null;
|
|
789
|
+
|
|
790
|
+
// DOM
|
|
791
|
+
const messagesEl = document.getElementById('messages');
|
|
792
|
+
const chatInput = document.getElementById('chat-input');
|
|
793
|
+
const connectionStatus = document.getElementById('connection-status');
|
|
794
|
+
|
|
795
|
+
// Navigation
|
|
796
|
+
document.querySelectorAll('.nav-item').forEach(item => {
|
|
797
|
+
item.addEventListener('click', () => {
|
|
798
|
+
const page = item.dataset.page;
|
|
799
|
+
if (!page) return;
|
|
800
|
+
|
|
801
|
+
document.querySelectorAll('.nav-item').forEach(i => i.classList.remove('active'));
|
|
802
|
+
item.classList.add('active');
|
|
803
|
+
|
|
804
|
+
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
|
805
|
+
document.getElementById('page-' + page).classList.add('active');
|
|
806
|
+
|
|
807
|
+
if (page === 'overview' || page === 'sessions' || page === 'channels') {
|
|
808
|
+
fetchStatus();
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
// WebSocket
|
|
814
|
+
function connect() {
|
|
815
|
+
ws = new WebSocket('ws://' + location.host);
|
|
816
|
+
|
|
817
|
+
ws.onopen = () => {
|
|
818
|
+
connectionStatus.textContent = '● Connected';
|
|
819
|
+
connectionStatus.style.color = '#4ade80';
|
|
820
|
+
addLog('Connected to gateway', 'success');
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
ws.onclose = () => {
|
|
824
|
+
connectionStatus.textContent = '● Disconnected';
|
|
825
|
+
connectionStatus.style.color = '#f87171';
|
|
826
|
+
addLog('Disconnected from gateway', 'error');
|
|
827
|
+
setTimeout(connect, 3000);
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
ws.onerror = () => {
|
|
831
|
+
addLog('WebSocket error', 'error');
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
ws.onmessage = (e) => {
|
|
835
|
+
const msg = JSON.parse(e.data);
|
|
836
|
+
handleMessage(msg);
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function handleMessage(msg) {
|
|
841
|
+
switch (msg.type) {
|
|
842
|
+
case 'connected':
|
|
843
|
+
sessionId = msg.clientId;
|
|
844
|
+
addLog('Session ID: ' + sessionId, 'info');
|
|
845
|
+
break;
|
|
846
|
+
case 'response':
|
|
847
|
+
case 'chat':
|
|
848
|
+
addChatMessage(msg.text || msg.content, 'bot');
|
|
849
|
+
break;
|
|
850
|
+
case 'tool':
|
|
851
|
+
addToolCall(msg);
|
|
852
|
+
break;
|
|
853
|
+
case 'status':
|
|
854
|
+
updateStats(msg);
|
|
855
|
+
break;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// Chat
|
|
860
|
+
function addChatMessage(text, type) {
|
|
861
|
+
const div = document.createElement('div');
|
|
862
|
+
div.className = 'message ' + type;
|
|
863
|
+
div.innerHTML = \`
|
|
864
|
+
<div class="message-avatar">\${type === 'user' ? '👤' : '🦊'}</div>
|
|
865
|
+
<div class="message-content">
|
|
866
|
+
<div class="message-text">\${formatText(text)}</div>
|
|
867
|
+
<div class="message-time">\${new Date().toLocaleTimeString()}</div>
|
|
868
|
+
</div>
|
|
869
|
+
\`;
|
|
870
|
+
messagesEl.appendChild(div);
|
|
871
|
+
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
function addToolCall(msg) {
|
|
875
|
+
const lastMessage = messagesEl.lastElementChild;
|
|
876
|
+
if (lastMessage && !lastMessage.classList.contains('user')) {
|
|
877
|
+
const content = lastMessage.querySelector('.message-content');
|
|
878
|
+
const toolDiv = document.createElement('div');
|
|
879
|
+
toolDiv.className = 'tool-call';
|
|
880
|
+
toolDiv.innerHTML = \`
|
|
881
|
+
<div class="tool-call-header">📝 \${msg.name || 'Tool'}</div>
|
|
882
|
+
<div class="tool-call-result">\${msg.result || ''}</div>
|
|
883
|
+
\`;
|
|
884
|
+
content.appendChild(toolDiv);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
function formatText(text) {
|
|
889
|
+
if (!text) return '';
|
|
890
|
+
return text
|
|
891
|
+
.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>')
|
|
892
|
+
.replace(/\\*(.+?)\\*/g, '<em>$1</em>')
|
|
893
|
+
.replace(/\`(.+?)\`/g, '<code>$1</code>')
|
|
894
|
+
.replace(/\\n/g, '<br>');
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
function sendMessage() {
|
|
898
|
+
const text = chatInput.value.trim();
|
|
899
|
+
if (!text || !ws) return;
|
|
900
|
+
|
|
901
|
+
addChatMessage(text, 'user');
|
|
902
|
+
ws.send(JSON.stringify({ type: 'chat', text, id: Date.now().toString() }));
|
|
903
|
+
chatInput.value = '';
|
|
904
|
+
addLog('Sent message: ' + text.slice(0, 50) + '...', 'info');
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
function newSession() {
|
|
908
|
+
messagesEl.innerHTML = '';
|
|
909
|
+
addLog('New session started', 'success');
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
chatInput.addEventListener('keypress', (e) => {
|
|
913
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
914
|
+
e.preventDefault();
|
|
915
|
+
sendMessage();
|
|
916
|
+
}
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
// Status
|
|
920
|
+
async function fetchStatus() {
|
|
921
|
+
try {
|
|
922
|
+
const res = await fetch('/api/status');
|
|
923
|
+
const data = await res.json();
|
|
924
|
+
updateStats(data);
|
|
925
|
+
updateSessions(data.sessions || []);
|
|
926
|
+
updateChannels(data.channels || []);
|
|
927
|
+
updateModel(data.agents || {});
|
|
928
|
+
} catch (e) {
|
|
929
|
+
addLog('Failed to fetch status', 'error');
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function updateStats(data) {
|
|
934
|
+
document.getElementById('stat-uptime').textContent = formatUptime(data.uptime || 0);
|
|
935
|
+
document.getElementById('stat-sessions').textContent = data.sessions?.length || 0;
|
|
936
|
+
document.getElementById('stat-channels').textContent = data.channels?.length || 0;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
function updateSessions(sessions) {
|
|
940
|
+
const tbody = document.getElementById('sessions-table');
|
|
941
|
+
tbody.innerHTML = sessions.map(s => \`
|
|
942
|
+
<tr>
|
|
943
|
+
<td>\${s.id?.slice(0, 12) || 'N/A'}...</td>
|
|
944
|
+
<td>\${getChannelIcon(s.channel)} \${s.channel || 'Unknown'}</td>
|
|
945
|
+
<td>\${s.peer || 'Anonymous'}</td>
|
|
946
|
+
<td>\${s.messageCount || 0}</td>
|
|
947
|
+
<td>Just now</td>
|
|
948
|
+
</tr>
|
|
949
|
+
\`).join('');
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
function updateChannels(channels) {
|
|
953
|
+
const tbody = document.getElementById('channels-table');
|
|
954
|
+
const rows = channels.map(c => \`
|
|
955
|
+
<tr>
|
|
956
|
+
<td>\${getChannelIcon(c.name)} \${c.name}</td>
|
|
957
|
+
<td><span class="badge \${c.connected ? 'badge-success' : 'badge-warning'}">\${c.connected ? 'Connected' : 'Disconnected'}</span></td>
|
|
958
|
+
<td>0</td>
|
|
959
|
+
<td>Just now</td>
|
|
960
|
+
</tr>
|
|
961
|
+
\`).join('');
|
|
962
|
+
tbody.innerHTML = rows || '<tr><td colspan="4">No channels</td></tr>';
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function updateModel(agents) {
|
|
966
|
+
if (agents.provider) {
|
|
967
|
+
document.getElementById('model-provider').textContent = agents.provider;
|
|
968
|
+
}
|
|
969
|
+
if (agents.model) {
|
|
970
|
+
document.getElementById('model-name').textContent = agents.model;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
function getChannelIcon(name) {
|
|
975
|
+
const icons = { telegram: '📱', discord: '🎮', webchat: '🌐', web: '🌐' };
|
|
976
|
+
return icons[name?.toLowerCase()] || '💬';
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
function formatUptime(seconds) {
|
|
980
|
+
if (seconds < 60) return Math.floor(seconds) + 's';
|
|
981
|
+
if (seconds < 3600) return Math.floor(seconds / 60) + 'm';
|
|
982
|
+
return Math.floor(seconds / 3600) + 'h ' + Math.floor((seconds % 3600) / 60) + 'm';
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// Logs
|
|
986
|
+
function addLog(message, level = 'info') {
|
|
987
|
+
const entry = { time: new Date(), message, level };
|
|
988
|
+
logs.push(entry);
|
|
989
|
+
|
|
990
|
+
const container = document.getElementById('logs-container');
|
|
991
|
+
const div = document.createElement('div');
|
|
992
|
+
div.className = 'log-entry';
|
|
993
|
+
div.innerHTML = \`
|
|
994
|
+
<span class="log-time">\${entry.time.toLocaleTimeString()}</span>
|
|
995
|
+
<span class="log-level \${level}">\${level.toUpperCase()}</span>
|
|
996
|
+
<span>\${message}</span>
|
|
997
|
+
\`;
|
|
998
|
+
container.appendChild(div);
|
|
999
|
+
container.scrollTop = container.scrollHeight;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// Init
|
|
1003
|
+
connect();
|
|
1004
|
+
fetchStatus();
|
|
1005
|
+
setInterval(fetchStatus, 30000);
|
|
1006
|
+
</script>
|
|
1007
|
+
</body>
|
|
1008
|
+
</html>`;
|
|
1009
|
+
}
|