@timmeck/brain-core 2.36.18 → 2.36.20
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 +93 -135
- package/command-center.html +600 -115
- package/dist/consciousness/__tests__/thought-stream.test.d.ts +1 -0
- package/dist/consciousness/__tests__/thought-stream.test.js +62 -0
- package/dist/consciousness/__tests__/thought-stream.test.js.map +1 -0
- package/dist/consciousness/thought-stream.d.ts +2 -0
- package/dist/consciousness/thought-stream.js +4 -0
- package/dist/consciousness/thought-stream.js.map +1 -1
- package/dist/dashboard/__tests__/command-center-server.test.js +142 -6
- package/dist/dashboard/__tests__/command-center-server.test.js.map +1 -1
- package/dist/dashboard/command-center-server.d.ts +18 -0
- package/dist/dashboard/command-center-server.js +169 -1
- package/dist/dashboard/command-center-server.js.map +1 -1
- package/dist/debate/debate-engine.js +1 -1
- package/dist/debate/debate-engine.js.map +1 -1
- package/dist/missions/__tests__/mission-engine.test.d.ts +1 -0
- package/dist/missions/__tests__/mission-engine.test.js +66 -0
- package/dist/missions/__tests__/mission-engine.test.js.map +1 -0
- package/dist/missions/mission-engine.js +5 -0
- package/dist/missions/mission-engine.js.map +1 -1
- package/dist/plugin/example-plugin.d.ts +40 -0
- package/dist/plugin/example-plugin.js +91 -0
- package/dist/plugin/example-plugin.js.map +1 -0
- package/dist/prediction/prediction-engine.js +1 -1
- package/dist/research/research-orchestrator.js +9 -0
- package/dist/research/research-orchestrator.js.map +1 -1
- package/dist/utils/__tests__/logger.test.js +27 -0
- package/dist/utils/__tests__/logger.test.js.map +1 -1
- package/dist/utils/logger.js +10 -3
- package/dist/utils/logger.js.map +1 -1
- package/package.json +1 -1
package/command-center.html
CHANGED
|
@@ -143,6 +143,53 @@ canvas{display:block;width:100%;height:100%}
|
|
|
143
143
|
.tbl td{padding:8px 10px;border-bottom:1px solid rgba(100,140,255,0.06)}
|
|
144
144
|
.tbl tr:hover td{background:rgba(0,229,255,0.03)}
|
|
145
145
|
|
|
146
|
+
/* ── Error Feed ───────────────────────────────────────── */
|
|
147
|
+
.error-feed{max-height:260px;overflow-y:auto;font-size:12px}
|
|
148
|
+
.error-item{padding:8px 10px;border-bottom:1px solid rgba(255,68,102,0.08);display:flex;gap:10px;align-items:flex-start}
|
|
149
|
+
.error-level{font-size:10px;font-weight:700;padding:1px 6px;border-radius:6px;white-space:nowrap}
|
|
150
|
+
.error-level.err{color:var(--red);background:rgba(255,68,102,0.12)}
|
|
151
|
+
.error-level.warn{color:var(--orange);background:rgba(255,153,51,0.12)}
|
|
152
|
+
.error-msg{color:var(--text);flex:1;line-height:1.4;word-break:break-word}
|
|
153
|
+
|
|
154
|
+
/* ── Self-Mod ─────────────────────────────────────────── */
|
|
155
|
+
.mod-item{padding:10px;border-bottom:1px solid rgba(100,140,255,0.06);display:flex;gap:12px;align-items:flex-start}
|
|
156
|
+
.mod-status{font-size:9px;font-weight:700;padding:2px 8px;border-radius:8px;white-space:nowrap}
|
|
157
|
+
.mod-applied{color:var(--green);background:rgba(0,255,136,0.12)}
|
|
158
|
+
.mod-testing{color:var(--yellow);background:rgba(255,204,0,0.12)}
|
|
159
|
+
.mod-proposed{color:var(--cyan);background:rgba(0,229,255,0.1)}
|
|
160
|
+
.mod-failed{color:var(--red);background:rgba(255,68,102,0.12)}
|
|
161
|
+
.mod-title{font-weight:600;font-size:12px;margin-bottom:2px}
|
|
162
|
+
.mod-detail{font-size:11px;color:var(--text-dim)}
|
|
163
|
+
|
|
164
|
+
/* ── Mission Card ─────────────────────────────────────── */
|
|
165
|
+
.mission-card{background:var(--bg-card);border:1px solid var(--glass-border);border-radius:var(--radius-sm);padding:12px;margin-bottom:8px}
|
|
166
|
+
.mission-topic{font-weight:600;font-size:13px;margin-bottom:6px}
|
|
167
|
+
.mission-phases{display:flex;gap:4px;margin-top:8px}
|
|
168
|
+
.mission-phase{flex:1;height:4px;border-radius:2px;background:rgba(100,140,255,0.1)}
|
|
169
|
+
.mission-phase.done{background:var(--green)}
|
|
170
|
+
.mission-phase.running{background:var(--cyan);animation:pulse-glow 1.5s infinite}
|
|
171
|
+
.mission-phase.fail{background:var(--red)}
|
|
172
|
+
.mission-meta{font-size:10px;color:var(--text-dim);margin-top:6px;display:flex;gap:12px}
|
|
173
|
+
|
|
174
|
+
/* ── Knowledge Chart ──────────────────────────────────── */
|
|
175
|
+
.chart-wrap{position:relative;height:200px;padding:10px 0}
|
|
176
|
+
.chart-wrap svg{width:100%;height:100%}
|
|
177
|
+
|
|
178
|
+
/* ── Quick Actions ────────────────────────────────────── */
|
|
179
|
+
.quick-actions{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}
|
|
180
|
+
.action-btn{padding:8px 16px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--bg-card);color:var(--text);cursor:pointer;font-size:12px;transition:all .2s;display:flex;align-items:center;gap:6px}
|
|
181
|
+
.action-btn:hover{border-color:var(--cyan);color:var(--cyan);background:var(--bg-card-hover)}
|
|
182
|
+
.action-btn:active{transform:scale(0.97)}
|
|
183
|
+
.action-btn.running{border-color:var(--yellow);color:var(--yellow);pointer-events:none}
|
|
184
|
+
.action-btn .action-icon{font-size:14px}
|
|
185
|
+
|
|
186
|
+
/* ── Dependency Flow ──────────────────────────────────── */
|
|
187
|
+
.dep-flow{display:flex;align-items:stretch;gap:4px;padding:12px 0;overflow-x:auto}
|
|
188
|
+
.dep-group{background:var(--bg-card);border:1px solid var(--glass-border);border-radius:var(--radius-sm);padding:10px;min-width:140px;flex:1}
|
|
189
|
+
.dep-group-title{font-size:10px;text-transform:uppercase;letter-spacing:1px;color:var(--text-dim);margin-bottom:8px;text-align:center}
|
|
190
|
+
.dep-engine{font-size:11px;padding:3px 6px;margin:2px 0;border-radius:4px;background:rgba(0,229,255,0.06);color:var(--text);text-align:center}
|
|
191
|
+
.dep-arrow{display:flex;align-items:center;color:var(--cyan);font-size:18px;opacity:.4;animation:pulse-arrow 2s ease-in-out infinite}
|
|
192
|
+
|
|
146
193
|
/* ── Misc ──────────────────────────────────────────────── */
|
|
147
194
|
.section{margin-bottom:24px}
|
|
148
195
|
.section-title{font-size:14px;font-weight:600;margin-bottom:12px;display:flex;align-items:center;gap:8px}
|
|
@@ -187,6 +234,8 @@ canvas{display:block;width:100%;height:100%}
|
|
|
187
234
|
<div class="nav-item" data-page="marketing"><span class="nav-icon">📣</span><span class="nav-label">Marketing Flow</span></div>
|
|
188
235
|
<div class="nav-section">System</div>
|
|
189
236
|
<div class="nav-item" data-page="crossbrain"><span class="nav-icon">🔗</span><span class="nav-label">Cross-Brain</span></div>
|
|
237
|
+
<div class="nav-item" data-page="debates"><span class="nav-icon">⚖</span><span class="nav-label">Debates</span></div>
|
|
238
|
+
<div class="nav-item" data-page="activity"><span class="nav-icon">⚡</span><span class="nav-label">Aktivität</span></div>
|
|
190
239
|
<div class="nav-item" data-page="infra"><span class="nav-icon">⚙</span><span class="nav-label">Infrastruktur</span></div>
|
|
191
240
|
</div>
|
|
192
241
|
|
|
@@ -207,6 +256,17 @@ canvas{display:block;width:100%;height:100%}
|
|
|
207
256
|
<div class="content">
|
|
208
257
|
<!-- ════ Page 1: Ecosystem Overview ═════════════════ -->
|
|
209
258
|
<div class="page active" id="page-overview">
|
|
259
|
+
<!-- Quick Actions -->
|
|
260
|
+
<div class="section">
|
|
261
|
+
<div class="section-title"><span class="icon">🎮</span> Schnellaktionen</div>
|
|
262
|
+
<div class="quick-actions" id="quickActions">
|
|
263
|
+
<button class="action-btn" data-action="learning-cycle"><span class="action-icon">🔄</span> Lernzyklus starten</button>
|
|
264
|
+
<button class="action-btn" data-action="borg-sync"><span class="action-icon">👾</span> Borg Sync</button>
|
|
265
|
+
<button class="action-btn" data-action="tech-scan"><span class="action-icon">📡</span> Tech-Radar Scan</button>
|
|
266
|
+
<button class="action-btn" data-action="health-check"><span class="action-icon">🏥</span> Health Check</button>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
|
|
210
270
|
<div class="section">
|
|
211
271
|
<div class="section-title"><span class="icon">🤖</span> Brain Status</div>
|
|
212
272
|
<div class="grid grid-3" id="brainCards"></div>
|
|
@@ -228,19 +288,27 @@ canvas{display:block;width:100%;height:100%}
|
|
|
228
288
|
</div>
|
|
229
289
|
</div>
|
|
230
290
|
<div class="section">
|
|
231
|
-
<div class="section-title"><span class="icon">📊</span>
|
|
232
|
-
<div class="card" id="llmCard"><div class="empty">
|
|
291
|
+
<div class="section-title"><span class="icon">📊</span> KI-Nutzung</div>
|
|
292
|
+
<div class="card" id="llmCard"><div class="empty">Warte auf KI-Daten...</div></div>
|
|
233
293
|
</div>
|
|
234
294
|
</div>
|
|
235
295
|
|
|
236
296
|
<div class="section">
|
|
237
297
|
<div class="section-title"><span class="icon">💭</span> Brain denkt gerade... <span id="thoughtCount" style="color:var(--text-dim);font-weight:400;font-size:12px"></span></div>
|
|
238
298
|
<div class="card" style="padding:0">
|
|
239
|
-
<div class="thought-stream" id="thoughtStream"><div class="empty">
|
|
299
|
+
<div class="thought-stream" id="thoughtStream"><div class="empty">Warte auf Gedanken...</div></div>
|
|
240
300
|
</div>
|
|
241
301
|
</div>
|
|
242
302
|
</div>
|
|
243
303
|
|
|
304
|
+
<!-- Error Log -->
|
|
305
|
+
<div class="section">
|
|
306
|
+
<div class="section-title"><span class="icon">⚠</span> Letzte Fehler & Warnungen <span id="errorCount" style="color:var(--text-dim);font-weight:400;font-size:12px"></span></div>
|
|
307
|
+
<div class="card" style="padding:0">
|
|
308
|
+
<div class="error-feed" id="errorFeed"><div class="empty">Keine Fehler — alles läuft!</div></div>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
|
|
244
312
|
<div class="section">
|
|
245
313
|
<div class="section-title"><span class="icon">🌐</span> Peer Verbindungen</div>
|
|
246
314
|
<div class="card canvas-wrap" style="height:180px">
|
|
@@ -252,21 +320,96 @@ canvas{display:block;width:100%;height:100%}
|
|
|
252
320
|
<!-- ════ Page 2: Lern-Kreislauf ═════════════════════ -->
|
|
253
321
|
<div class="page" id="page-learning">
|
|
254
322
|
<div class="section">
|
|
255
|
-
<div class="section-title"><span class="icon">🔄</span> Der
|
|
323
|
+
<div class="section-title"><span class="icon">🔄</span> So lernt Brain — Der Kreislauf</div>
|
|
324
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Daten kommen rein, Brain analysiert sie, bildet Hypothesen, testet sie als Experimente und macht daraus Wissen. Dieser Kreislauf läuft ständig.</p>
|
|
256
325
|
<div class="pipeline" id="learnPipeline">
|
|
257
326
|
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">📥</div><div class="pipe-label">Daten rein</div><div class="pipe-value" id="lp-data">0</div></div></div>
|
|
258
327
|
<div class="pipe-arrow">➡</div>
|
|
259
|
-
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">🔍</div><div class="pipe-label">
|
|
328
|
+
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">🔍</div><div class="pipe-label">Analysieren</div><div class="pipe-value" id="lp-analysis">0</div></div></div>
|
|
260
329
|
<div class="pipe-arrow">➡</div>
|
|
261
|
-
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">💡</div><div class="pipe-label">
|
|
330
|
+
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">💡</div><div class="pipe-label">Ideen bilden</div><div class="pipe-value" id="lp-hypotheses">0</div></div></div>
|
|
262
331
|
<div class="pipe-arrow">➡</div>
|
|
263
|
-
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">🧪</div><div class="pipe-label">
|
|
332
|
+
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">🧪</div><div class="pipe-label">Ausprobieren</div><div class="pipe-value" id="lp-experiments">0</div></div></div>
|
|
264
333
|
<div class="pipe-arrow">➡</div>
|
|
265
|
-
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">📜</div><div class="pipe-label">
|
|
334
|
+
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">📜</div><div class="pipe-label">Wissen merken</div><div class="pipe-value" id="lp-principles">0</div></div></div>
|
|
266
335
|
<div class="pipe-arrow">➡</div>
|
|
267
|
-
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">⚡</div><div class="pipe-label">
|
|
336
|
+
<div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">⚡</div><div class="pipe-label">Umsetzen</div><div class="pipe-value" id="lp-actions">0</div></div></div>
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
|
|
340
|
+
<!-- Engine Dependency Flow -->
|
|
341
|
+
<div class="section">
|
|
342
|
+
<div class="section-title"><span class="icon">🔀</span> Wie die Engines zusammenarbeiten</div>
|
|
343
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Jede Engine hat eine Aufgabe. Zusammen bilden sie eine Kette — von der Beobachtung bis zur Aktion.</p>
|
|
344
|
+
<div class="dep-flow" id="engineDependencyFlow">
|
|
345
|
+
<div class="dep-group">
|
|
346
|
+
<div class="dep-group-title">👁 Beobachten</div>
|
|
347
|
+
<div class="dep-engine">DataScout</div>
|
|
348
|
+
<div class="dep-engine">TechRadar</div>
|
|
349
|
+
<div class="dep-engine">SignalScanner</div>
|
|
350
|
+
<div class="dep-engine">AnomalyDetective</div>
|
|
351
|
+
</div>
|
|
352
|
+
<div class="dep-arrow">➡</div>
|
|
353
|
+
<div class="dep-group">
|
|
354
|
+
<div class="dep-group-title">🧠 Verstehen</div>
|
|
355
|
+
<div class="dep-engine">CausalEngine</div>
|
|
356
|
+
<div class="dep-engine">PatternEngine</div>
|
|
357
|
+
<div class="dep-engine">Curiosity</div>
|
|
358
|
+
<div class="dep-engine">Attention</div>
|
|
359
|
+
</div>
|
|
360
|
+
<div class="dep-arrow">➡</div>
|
|
361
|
+
<div class="dep-group">
|
|
362
|
+
<div class="dep-group-title">💡 Ideen</div>
|
|
363
|
+
<div class="dep-engine">HypothesisEngine</div>
|
|
364
|
+
<div class="dep-engine">DreamEngine</div>
|
|
365
|
+
<div class="dep-engine">DebateEngine</div>
|
|
366
|
+
</div>
|
|
367
|
+
<div class="dep-arrow">➡</div>
|
|
368
|
+
<div class="dep-group">
|
|
369
|
+
<div class="dep-group-title">🧪 Testen</div>
|
|
370
|
+
<div class="dep-engine">ExperimentEngine</div>
|
|
371
|
+
<div class="dep-engine">SimulationEngine</div>
|
|
372
|
+
<div class="dep-engine">Prediction</div>
|
|
373
|
+
</div>
|
|
374
|
+
<div class="dep-arrow">➡</div>
|
|
375
|
+
<div class="dep-group">
|
|
376
|
+
<div class="dep-group-title">📚 Wissen</div>
|
|
377
|
+
<div class="dep-engine">KnowledgeDistiller</div>
|
|
378
|
+
<div class="dep-engine">MemoryPalace</div>
|
|
379
|
+
<div class="dep-engine">ResearchJournal</div>
|
|
380
|
+
</div>
|
|
381
|
+
<div class="dep-arrow">➡</div>
|
|
382
|
+
<div class="dep-group">
|
|
383
|
+
<div class="dep-group-title">⚡ Handeln</div>
|
|
384
|
+
<div class="dep-engine">SelfMod</div>
|
|
385
|
+
<div class="dep-engine">GoalEngine</div>
|
|
386
|
+
<div class="dep-engine">Strategy</div>
|
|
387
|
+
<div class="dep-engine">MetaCognition</div>
|
|
388
|
+
</div>
|
|
268
389
|
</div>
|
|
269
390
|
</div>
|
|
391
|
+
|
|
392
|
+
<!-- Knowledge Growth -->
|
|
393
|
+
<div class="section">
|
|
394
|
+
<div class="section-title"><span class="icon">📈</span> Wissens-Wachstum — Wird Brain schlauer?</div>
|
|
395
|
+
<div class="card">
|
|
396
|
+
<div class="grid grid-4" id="knowledgeTotals">
|
|
397
|
+
<div style="text-align:center"><div class="card-value" id="kn-principles" style="color:var(--cyan)">0</div><div class="card-sub">Regeln gelernt</div></div>
|
|
398
|
+
<div style="text-align:center"><div class="card-value" id="kn-hypotheses" style="color:var(--yellow)">0</div><div class="card-sub">Hypothesen getestet</div></div>
|
|
399
|
+
<div style="text-align:center"><div class="card-value" id="kn-experiments" style="color:var(--green)">0</div><div class="card-sub">Experimente gemacht</div></div>
|
|
400
|
+
<div style="text-align:center"><div class="card-value" id="kn-errors" style="color:var(--red)">0</div><div class="card-sub">Fehler gelöst</div></div>
|
|
401
|
+
</div>
|
|
402
|
+
<div class="chart-wrap" id="knowledgeChart">
|
|
403
|
+
<svg id="knowledgeSvg" viewBox="0 0 600 180" preserveAspectRatio="none"></svg>
|
|
404
|
+
</div>
|
|
405
|
+
<div style="display:flex;gap:16px;justify-content:center;font-size:10px;color:var(--text-dim)">
|
|
406
|
+
<span><span style="color:var(--cyan)">⬤</span> Regeln</span>
|
|
407
|
+
<span><span style="color:var(--green)">⬤</span> Lösungen</span>
|
|
408
|
+
<span><span style="color:var(--red)">⬤</span> Fehler</span>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
</div>
|
|
412
|
+
|
|
270
413
|
<div class="section">
|
|
271
414
|
<div class="section-title"><span class="icon">🏭</span> Engine Stationen</div>
|
|
272
415
|
<div class="engine-grid" id="brainEngineGrid"><div class="empty">Loading...</div></div>
|
|
@@ -276,7 +419,8 @@ canvas{display:block;width:100%;height:100%}
|
|
|
276
419
|
<!-- ════ Page 3: Trading Flow ═══════════════════════ -->
|
|
277
420
|
<div class="page" id="page-trading">
|
|
278
421
|
<div class="section">
|
|
279
|
-
<div class="section-title"><span class="icon">📈</span> Trading
|
|
422
|
+
<div class="section-title"><span class="icon">📈</span> So tradet Trading-Brain</div>
|
|
423
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Signale kommen rein, werden analysiert, als Paper Trade getestet und das Ergebnis fließt zurück ins Lernen.</p>
|
|
280
424
|
<div class="pipeline">
|
|
281
425
|
<div class="pipe-stage"><div class="pipe-box" style="border-color:rgba(0,255,136,0.2)"><div class="pipe-icon">📡</div><div class="pipe-label">Signale</div><div class="pipe-value" id="tp-signals" style="color:var(--green)">0</div></div></div>
|
|
282
426
|
<div class="pipe-arrow" style="color:var(--green)">➡</div>
|
|
@@ -290,9 +434,9 @@ canvas{display:block;width:100%;height:100%}
|
|
|
290
434
|
</div>
|
|
291
435
|
</div>
|
|
292
436
|
<div class="grid grid-3">
|
|
293
|
-
<div class="card"><div class="card-title">Equity</div><div class="card-value" id="tradingEquity" style="color:var(--green)">--</div><div class="card-sub">Paper Trading
|
|
294
|
-
<div class="card"><div class="card-title">Win Rate</div><div class="card-value" id="tradingWinRate" style="color:var(--green)">--</div><div class="card-sub">Gewinnrate</div></div>
|
|
295
|
-
<div class="card"><div class="card-title">Offene Positionen</div><div class="card-value" id="tradingPositions" style="color:var(--green)">--</div><div class="card-sub">Aktive Trades</div></div>
|
|
437
|
+
<div class="card"><div class="card-title">Equity</div><div class="card-value" id="tradingEquity" style="color:var(--green)">--</div><div class="card-sub">Paper Trading Guthaben</div></div>
|
|
438
|
+
<div class="card"><div class="card-title">Win Rate</div><div class="card-value" id="tradingWinRate" style="color:var(--green)">--</div><div class="card-sub">Gewinnrate aller Trades</div></div>
|
|
439
|
+
<div class="card"><div class="card-title">Offene Positionen</div><div class="card-value" id="tradingPositions" style="color:var(--green)">--</div><div class="card-sub">Aktive Trades gerade</div></div>
|
|
296
440
|
</div>
|
|
297
441
|
<div class="section" style="margin-top:16px">
|
|
298
442
|
<div class="section-title"><span class="icon">🏭</span> Trading Engines</div>
|
|
@@ -303,7 +447,8 @@ canvas{display:block;width:100%;height:100%}
|
|
|
303
447
|
<!-- ════ Page 4: Marketing Flow ═════════════════════ -->
|
|
304
448
|
<div class="page" id="page-marketing">
|
|
305
449
|
<div class="section">
|
|
306
|
-
<div class="section-title"><span class="icon">📣</span> Marketing
|
|
450
|
+
<div class="section-title"><span class="icon">📣</span> So lernt Marketing-Brain</div>
|
|
451
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Posts werden veröffentlicht, das Engagement wird gemessen, Muster erkannt und die Strategie angepasst.</p>
|
|
307
452
|
<div class="pipeline">
|
|
308
453
|
<div class="pipe-stage"><div class="pipe-box" style="border-color:rgba(255,68,204,0.2)"><div class="pipe-icon">✍</div><div class="pipe-label">Posts</div><div class="pipe-value" id="mp-posts" style="color:var(--magenta)">0</div></div></div>
|
|
309
454
|
<div class="pipe-arrow" style="color:var(--magenta)">➡</div>
|
|
@@ -328,19 +473,21 @@ canvas{display:block;width:100%;height:100%}
|
|
|
328
473
|
<!-- ════ Page 5: Cross-Brain & Borg ═════════════════ -->
|
|
329
474
|
<div class="page" id="page-crossbrain">
|
|
330
475
|
<div class="section">
|
|
331
|
-
<div class="section-title"><span class="icon">🔗</span>
|
|
476
|
+
<div class="section-title"><span class="icon">🔗</span> So kommunizieren die Brains</div>
|
|
477
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Die drei Brains tauschen ständig Nachrichten aus. Jeder fliegende Punkt ist eine Nachricht. Lila = Borg-Wissens-Sync.</p>
|
|
332
478
|
<div class="card canvas-wrap" style="height:280px">
|
|
333
479
|
<canvas id="crossBrainCanvas"></canvas>
|
|
334
480
|
</div>
|
|
335
481
|
</div>
|
|
336
482
|
<div class="grid grid-2">
|
|
337
483
|
<div class="section">
|
|
338
|
-
<div class="section-title"><span class="icon">👾</span> Borg Sync</div>
|
|
484
|
+
<div class="section-title"><span class="icon">👾</span> Borg Sync — Geteiltes Wissen</div>
|
|
339
485
|
<div class="card" id="borgCard">
|
|
486
|
+
<p style="font-size:11px;color:var(--text-dim);margin-bottom:10px">Borg synchronisiert Wissen zwischen allen Brains. Was einer lernt, wissen alle.</p>
|
|
340
487
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">
|
|
341
488
|
<div>
|
|
342
489
|
<div class="card-title" style="margin-bottom:4px">Collective Sync</div>
|
|
343
|
-
<div id="borgStatus" style="font-size:13px;color:var(--text-dim)">
|
|
490
|
+
<div id="borgStatus" style="font-size:13px;color:var(--text-dim)">Nicht verfügbar</div>
|
|
344
491
|
</div>
|
|
345
492
|
<button class="btn" id="borgToggle" disabled>Toggle</button>
|
|
346
493
|
</div>
|
|
@@ -348,36 +495,107 @@ canvas{display:block;width:100%;height:100%}
|
|
|
348
495
|
</div>
|
|
349
496
|
</div>
|
|
350
497
|
<div class="section">
|
|
351
|
-
<div class="section-title"><span class="icon">📜</span> Korrelationen
|
|
352
|
-
<div class="card"><div id="correlationList"><div class="empty">
|
|
498
|
+
<div class="section-title"><span class="icon">📜</span> Korrelationen — Was hängt zusammen?</div>
|
|
499
|
+
<div class="card"><div id="correlationList"><div class="empty">Noch keine Korrelationen gefunden</div></div></div>
|
|
353
500
|
</div>
|
|
354
501
|
</div>
|
|
355
502
|
<div class="section">
|
|
356
|
-
<div class="section-title"><span class="icon">📃</span> Sync
|
|
357
|
-
<div class="card"><div id="borgHistory"><div class="empty">
|
|
503
|
+
<div class="section-title"><span class="icon">📃</span> Sync Verlauf</div>
|
|
504
|
+
<div class="card"><div id="borgHistory"><div class="empty">Noch kein Sync passiert</div></div></div>
|
|
358
505
|
</div>
|
|
359
506
|
</div>
|
|
360
507
|
|
|
361
|
-
<!-- ════ Page 6:
|
|
362
|
-
<div class="page" id="page-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
508
|
+
<!-- ════ Page 6: Activity (Self-Mod + Missions) ═════ -->
|
|
509
|
+
<div class="page" id="page-activity">
|
|
510
|
+
<!-- Self-Modification -->
|
|
511
|
+
<div class="section">
|
|
512
|
+
<div class="section-title"><span class="icon">🔧</span> Brain verbessert sich selbst</div>
|
|
513
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Brain erkennt Probleme im eigenen Code und schlägt Verbesserungen vor. Jede Änderung wird erst getestet, bevor sie angewendet wird.</p>
|
|
514
|
+
<div class="grid grid-4" id="selfModStats">
|
|
515
|
+
<div class="card" style="text-align:center"><div class="card-value" id="sm-total" style="color:var(--cyan)">0</div><div class="card-sub">Vorschläge insgesamt</div></div>
|
|
516
|
+
<div class="card" style="text-align:center"><div class="card-value" id="sm-applied" style="color:var(--green)">0</div><div class="card-sub">Erfolgreich angewendet</div></div>
|
|
517
|
+
<div class="card" style="text-align:center"><div class="card-value" id="sm-testing" style="color:var(--yellow)">0</div><div class="card-sub">Wird gerade getestet</div></div>
|
|
518
|
+
<div class="card" style="text-align:center"><div class="card-value" id="sm-failed" style="color:var(--red)">0</div><div class="card-sub">Fehlgeschlagen</div></div>
|
|
367
519
|
</div>
|
|
368
|
-
<div class="
|
|
369
|
-
<div
|
|
370
|
-
<div class="card" id="pluginCard"><div class="empty">Loading...</div></div>
|
|
520
|
+
<div class="card" style="padding:0;margin-top:12px">
|
|
521
|
+
<div style="max-height:300px;overflow-y:auto" id="selfModFeed"><div class="empty">Brain hat sich noch nicht selbst verbessert</div></div>
|
|
371
522
|
</div>
|
|
372
523
|
</div>
|
|
524
|
+
|
|
525
|
+
<!-- Mission Tracker -->
|
|
373
526
|
<div class="section">
|
|
374
|
-
<div class="section-title"><span class="icon">&#
|
|
375
|
-
<
|
|
527
|
+
<div class="section-title"><span class="icon">🚀</span> Aktive Recherche-Missionen</div>
|
|
528
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Brain forscht eigenständig zu Themen. Jede Mission durchläuft 5 Phasen: Aufteilen, Sammeln, Hypothesen bilden, Analysieren, Zusammenfassen.</p>
|
|
529
|
+
<div class="grid grid-3" id="missionStats">
|
|
530
|
+
<div class="card" style="text-align:center"><div class="card-value" id="ms-active" style="color:var(--cyan)">0</div><div class="card-sub">Aktive Missionen</div></div>
|
|
531
|
+
<div class="card" style="text-align:center"><div class="card-value" id="ms-completed" style="color:var(--green)">0</div><div class="card-sub">Abgeschlossen</div></div>
|
|
532
|
+
<div class="card" style="text-align:center"><div class="card-value" id="ms-sources" style="color:var(--purple)">0</div><div class="card-sub">Quellen gesammelt</div></div>
|
|
533
|
+
</div>
|
|
534
|
+
<div id="missionList" style="margin-top:12px"><div class="empty">Keine aktiven Missionen</div></div>
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
|
|
538
|
+
<!-- ════ Page 7: Debates & Challenges ═════════════════ -->
|
|
539
|
+
<div class="page" id="page-debates">
|
|
540
|
+
<!-- Debate Engine Status -->
|
|
541
|
+
<div class="section">
|
|
542
|
+
<div class="section-title"><span class="icon">⚖</span> Debate Engine</div>
|
|
543
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Multi-Perspektiven-Debatten zu Schlüsselfragen. Jeder Brain liefert seine Sichtweise basierend auf Prinzipien, Hypothesen und Vorhersagen.</p>
|
|
544
|
+
<div class="grid grid-4" id="debateStats">
|
|
545
|
+
<div class="card" style="text-align:center"><div class="card-value" id="db-total" style="color:var(--cyan)">0</div><div class="card-sub">Debatten gesamt</div></div>
|
|
546
|
+
<div class="card" style="text-align:center"><div class="card-value" id="db-open" style="color:var(--yellow)">0</div><div class="card-sub">Offen</div></div>
|
|
547
|
+
<div class="card" style="text-align:center"><div class="card-value" id="db-synthesized" style="color:var(--green)">0</div><div class="card-sub">Synthesiert</div></div>
|
|
548
|
+
<div class="card" style="text-align:center"><div class="card-value" id="db-challenges" style="color:var(--red)">0</div><div class="card-sub">Challenges</div></div>
|
|
549
|
+
</div>
|
|
550
|
+
</div>
|
|
551
|
+
|
|
552
|
+
<!-- Recent Debates -->
|
|
553
|
+
<div class="section">
|
|
554
|
+
<div class="section-title"><span class="icon">💬</span> Letzte Debatten</div>
|
|
555
|
+
<div id="debateList" style="margin-top:8px"><div class="empty">Noch keine Debatten gestartet</div></div>
|
|
556
|
+
</div>
|
|
557
|
+
|
|
558
|
+
<!-- Advocatus Diaboli: Principle Challenges -->
|
|
559
|
+
<div class="section">
|
|
560
|
+
<div class="section-title"><span class="icon">🔥</span> Advocatus Diaboli — Prinzip-Challenges</div>
|
|
561
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Jedes Prinzip wird aktiv hinterfragt. Überlebt es die Gegenargumente, oder wird es geschwächt/widerlegt?</p>
|
|
562
|
+
<div id="challengeList" style="margin-top:8px"><div class="empty">Noch keine Challenges durchgeführt</div></div>
|
|
563
|
+
</div>
|
|
564
|
+
|
|
565
|
+
<!-- Most Vulnerable Principles -->
|
|
566
|
+
<div class="section">
|
|
567
|
+
<div class="section-title"><span class="icon">⚠</span> Verwundbarste Prinzipien</div>
|
|
568
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Prinzipien mit den niedrigsten Resilienz-Scores — die schwächsten Überzeugungen, die überprüft werden sollten.</p>
|
|
569
|
+
<div id="vulnerableList" style="margin-top:8px"><div class="empty">Keine verwundbaren Prinzipien</div></div>
|
|
570
|
+
</div>
|
|
571
|
+
</div>
|
|
572
|
+
|
|
573
|
+
<!-- ════ Page 8: Infrastruktur ══════════════════════ -->
|
|
574
|
+
<div class="page" id="page-infra">
|
|
575
|
+
<div class="section">
|
|
576
|
+
<div class="section-title"><span class="icon">🛡</span> Watchdog — Daemon-Überwachung</div>
|
|
577
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px">Überwacht alle Brain-Daemons. Grün = gesund, Gelb = läuft aber Healthcheck fehlgeschlagen, Rot = gestoppt. Auto-Update alle 30s.</p>
|
|
578
|
+
<div class="grid grid-3" id="watchdogCards"><div class="empty">Loading...</div></div>
|
|
376
579
|
</div>
|
|
377
580
|
<div class="section">
|
|
378
581
|
<div class="section-title"><span class="icon">✅</span> System Health Check</div>
|
|
379
582
|
<div class="card" id="healthCheckCard"><div class="empty">Loading...</div></div>
|
|
380
583
|
</div>
|
|
584
|
+
<div class="grid grid-2">
|
|
585
|
+
<div class="section">
|
|
586
|
+
<div class="section-title"><span class="icon">🧩</span> Plugins — Erweiterungen</div>
|
|
587
|
+
<div class="card" id="pluginCard"><div class="empty">Loading...</div></div>
|
|
588
|
+
</div>
|
|
589
|
+
<div class="section" style="min-height:100px">
|
|
590
|
+
<div class="section-title"><span class="icon">📊</span> Dienst-Statistik</div>
|
|
591
|
+
<div class="card" id="watchdogStatsCard"><div class="empty">Loading...</div></div>
|
|
592
|
+
</div>
|
|
593
|
+
</div>
|
|
594
|
+
<div class="section">
|
|
595
|
+
<div class="section-title"><span class="icon">🏭</span> Alle Engines auf einen Blick</div>
|
|
596
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:8px">Grün = aktiv, Gelb = bereit, Grau = aus. Die Zahl zeigt wie viele Gedanken die Engine produziert hat.</p>
|
|
597
|
+
<div class="engine-grid" id="allEngineGrid"><div class="empty">Loading...</div></div>
|
|
598
|
+
</div>
|
|
381
599
|
</div>
|
|
382
600
|
</div>
|
|
383
601
|
</div>
|
|
@@ -385,10 +603,23 @@ canvas{display:block;width:100%;height:100%}
|
|
|
385
603
|
|
|
386
604
|
<script>
|
|
387
605
|
// ── State ─────────────────────────────────────────────────
|
|
388
|
-
const state = {
|
|
606
|
+
const state = {
|
|
607
|
+
ecosystem:null, engines:[], watchdog:[], plugins:[], borg:null, analytics:null,
|
|
608
|
+
llm:null, thoughts:[], connected:false, lastThoughtTime:0,
|
|
609
|
+
errors:null, selfmod:null, missions:null, knowledge:null
|
|
610
|
+
};
|
|
389
611
|
|
|
390
612
|
// ── Navigation ────────────────────────────────────────────
|
|
391
|
-
const titles = {
|
|
613
|
+
const titles = {
|
|
614
|
+
overview:'Ecosystem Overview',
|
|
615
|
+
learning:'Der Lern-Kreislauf',
|
|
616
|
+
trading:'Trading Flow',
|
|
617
|
+
marketing:'Marketing Flow',
|
|
618
|
+
crossbrain:'Cross-Brain & Borg',
|
|
619
|
+
activity:'Aktivität & Missionen',
|
|
620
|
+
debates:'Debates & Challenges',
|
|
621
|
+
infra:'Infrastruktur'
|
|
622
|
+
};
|
|
392
623
|
document.querySelectorAll('.nav-item').forEach(item => {
|
|
393
624
|
item.addEventListener('click', () => {
|
|
394
625
|
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
|
|
@@ -410,12 +641,17 @@ function connectSSE() {
|
|
|
410
641
|
es.addEventListener('analytics', e => { state.analytics = JSON.parse(e.data); renderAnalytics(); });
|
|
411
642
|
es.addEventListener('llm', e => { state.llm = JSON.parse(e.data); renderLLM(); });
|
|
412
643
|
es.addEventListener('thought', e => { addThought(JSON.parse(e.data)); });
|
|
644
|
+
es.addEventListener('errors', e => { state.errors = JSON.parse(e.data); renderErrors(); });
|
|
645
|
+
es.addEventListener('selfmod', e => { state.selfmod = JSON.parse(e.data); renderSelfMod(); });
|
|
646
|
+
es.addEventListener('missions', e => { state.missions = JSON.parse(e.data); renderMissions(); });
|
|
647
|
+
es.addEventListener('knowledge', e => { state.knowledge = JSON.parse(e.data); renderKnowledge(); });
|
|
648
|
+
es.addEventListener('debates', e => { state.debates = JSON.parse(e.data); renderDebates(); });
|
|
413
649
|
es.onerror = () => { state.connected = false; updateConnection(); };
|
|
414
650
|
}
|
|
415
651
|
|
|
416
652
|
function updateConnection() {
|
|
417
653
|
const b = document.getElementById('connectionBadge');
|
|
418
|
-
b.textContent = state.connected ? '
|
|
654
|
+
b.textContent = state.connected ? 'Verbunden' : 'Getrennt';
|
|
419
655
|
b.className = 'badge ' + (state.connected ? 'badge-ok' : 'badge-err');
|
|
420
656
|
}
|
|
421
657
|
|
|
@@ -426,8 +662,13 @@ async function loadInitial() {
|
|
|
426
662
|
state.ecosystem = data.ecosystem; state.engines = data.engines || [];
|
|
427
663
|
state.watchdog = data.watchdog || []; state.plugins = data.plugins || [];
|
|
428
664
|
state.borg = data.borg; state.analytics = data.analytics; state.llm = data.llm;
|
|
665
|
+
state.errors = data.errors; state.selfmod = data.selfmod;
|
|
666
|
+
state.missions = data.missions; state.knowledge = data.knowledge;
|
|
667
|
+
state.debates = data.debates;
|
|
429
668
|
if (data.thoughts) { state.thoughts = data.thoughts; renderThoughts(); }
|
|
430
|
-
renderEcosystem(); renderEngines(); renderWatchdog(); renderPlugins();
|
|
669
|
+
renderEcosystem(); renderEngines(); renderWatchdog(); renderPlugins();
|
|
670
|
+
renderBorg(); renderAnalytics(); renderLLM(); renderErrors();
|
|
671
|
+
renderSelfMod(); renderMissions(); renderKnowledge(); renderDebates();
|
|
431
672
|
} catch {}
|
|
432
673
|
}
|
|
433
674
|
|
|
@@ -443,12 +684,12 @@ function addThought(t) {
|
|
|
443
684
|
function renderThoughts() {
|
|
444
685
|
const el = document.getElementById('thoughtStream');
|
|
445
686
|
const cnt = document.getElementById('thoughtCount');
|
|
446
|
-
if (!state.thoughts.length) { el.innerHTML = '<div class="empty">
|
|
687
|
+
if (!state.thoughts.length) { el.innerHTML = '<div class="empty">Warte auf Gedanken...</div>'; cnt.textContent = ''; return; }
|
|
447
688
|
cnt.textContent = `(${state.thoughts.length})`;
|
|
448
689
|
el.innerHTML = state.thoughts.slice(0, 50).map(t => {
|
|
449
690
|
const time = new Date(t.timestamp).toLocaleTimeString('de-DE', { hour:'2-digit', minute:'2-digit', second:'2-digit' });
|
|
450
691
|
const sigClass = t.significance === 'breakthrough' ? 'sig-breakthrough' : t.significance === 'notable' ? 'sig-notable' : 'sig-routine';
|
|
451
|
-
const sigLabel = t.significance === 'breakthrough' ? 'Durchbruch' : t.significance === 'notable' ? 'Bemerkenswert' : '';
|
|
692
|
+
const sigLabel = t.significance === 'breakthrough' ? 'Durchbruch!' : t.significance === 'notable' ? 'Bemerkenswert' : '';
|
|
452
693
|
return `<div class="thought-item">
|
|
453
694
|
<span class="thought-time">${time}</span>
|
|
454
695
|
<span class="thought-engine" style="color:var(--cyan)">${t.engine}</span>
|
|
@@ -463,7 +704,7 @@ function updatePulse() {
|
|
|
463
704
|
const dot = document.getElementById('pulseDot');
|
|
464
705
|
const label = document.getElementById('pulseLabel');
|
|
465
706
|
const age = Date.now() - state.lastThoughtTime;
|
|
466
|
-
if (state.lastThoughtTime === 0) { dot.className = 'pulse-dot off'; label.textContent = '
|
|
707
|
+
if (state.lastThoughtTime === 0) { dot.className = 'pulse-dot off'; label.textContent = 'Warte...'; return; }
|
|
467
708
|
if (age < 30000) { dot.className = 'pulse-dot'; label.textContent = 'Brain arbeitet'; }
|
|
468
709
|
else if (age < 120000) { dot.className = 'pulse-dot idle'; label.textContent = 'Idle'; }
|
|
469
710
|
else { dot.className = 'pulse-dot off'; label.textContent = 'Ruhig'; }
|
|
@@ -474,57 +715,203 @@ setInterval(updatePulse, 5000);
|
|
|
474
715
|
function renderLLM() {
|
|
475
716
|
const el = document.getElementById('llmCard');
|
|
476
717
|
const s = state.llm;
|
|
477
|
-
if (!s) { el.innerHTML = '<div class="empty">Kein
|
|
718
|
+
if (!s) { el.innerHTML = '<div class="empty">Kein KI-Service aktiv</div>'; return; }
|
|
478
719
|
|
|
479
720
|
const hourPct = s.tokensThisHour && s.budgetRemainingHour != null ? Math.min(100, (s.tokensThisHour / (s.tokensThisHour + s.budgetRemainingHour)) * 100) : 0;
|
|
480
721
|
const dayPct = s.tokensToday && s.budgetRemainingDay != null ? Math.min(100, (s.tokensToday / (s.tokensToday + s.budgetRemainingDay)) * 100) : 0;
|
|
481
722
|
|
|
482
723
|
el.innerHTML = `
|
|
483
724
|
<div class="llm-grid">
|
|
484
|
-
<div class="llm-stat"><div class="llm-stat-value">${s.totalCalls ?? 0}</div><div class="llm-stat-label">
|
|
485
|
-
<div class="llm-stat"><div class="llm-stat-value">${formatK(s.totalTokens ?? 0)}</div><div class="llm-stat-label">Tokens
|
|
486
|
-
<div class="llm-stat"><div class="llm-stat-value">${s.cacheHitRate != null ? (s.cacheHitRate * 100).toFixed(0) + '%' : '--'}</div><div class="llm-stat-label">Cache
|
|
487
|
-
<div class="llm-stat"><div class="llm-stat-value">${s.callsThisHour ?? 0}</div><div class="llm-stat-label">
|
|
488
|
-
<div class="llm-stat"><div class="llm-stat-value">${s.averageLatencyMs ? Math.round(s.averageLatencyMs) + 'ms' : '--'}</div><div class="llm-stat-label">
|
|
489
|
-
<div class="llm-stat"><div class="llm-stat-value">${s.errors ?? 0}</div><div class="llm-stat-label">Fehler</div></div>
|
|
725
|
+
<div class="llm-stat"><div class="llm-stat-value">${s.totalCalls ?? 0}</div><div class="llm-stat-label">KI-Anfragen</div></div>
|
|
726
|
+
<div class="llm-stat"><div class="llm-stat-value">${formatK(s.totalTokens ?? 0)}</div><div class="llm-stat-label">Tokens verbraucht</div></div>
|
|
727
|
+
<div class="llm-stat"><div class="llm-stat-value">${s.cacheHitRate != null ? (s.cacheHitRate * 100).toFixed(0) + '%' : '--'}</div><div class="llm-stat-label">Cache Treffer</div></div>
|
|
728
|
+
<div class="llm-stat"><div class="llm-stat-value">${s.callsThisHour ?? 0}</div><div class="llm-stat-label">Anfragen/Stunde</div></div>
|
|
729
|
+
<div class="llm-stat"><div class="llm-stat-value">${s.averageLatencyMs ? Math.round(s.averageLatencyMs) + 'ms' : '--'}</div><div class="llm-stat-label">Antwortzeit</div></div>
|
|
730
|
+
<div class="llm-stat"><div class="llm-stat-value">${s.errors ?? 0}</div><div class="llm-stat-label">KI-Fehler</div></div>
|
|
490
731
|
</div>
|
|
491
732
|
<div style="margin-top:12px">
|
|
492
|
-
<div style="display:flex;justify-content:space-between;font-size:10px;color:var(--text-dim);margin-bottom:2px"><span>Budget Stunde</span><span>${formatK(s.tokensThisHour ?? 0)} / ${formatK((s.tokensThisHour ?? 0) + (s.budgetRemainingHour ?? 0))}</span></div>
|
|
733
|
+
<div style="display:flex;justify-content:space-between;font-size:10px;color:var(--text-dim);margin-bottom:2px"><span>Budget pro Stunde</span><span>${formatK(s.tokensThisHour ?? 0)} / ${formatK((s.tokensThisHour ?? 0) + (s.budgetRemainingHour ?? 0))}</span></div>
|
|
493
734
|
<div class="llm-bar"><div class="llm-bar-fill" style="width:${hourPct}%;background:${hourPct > 80 ? 'var(--red)' : hourPct > 50 ? 'var(--orange)' : 'var(--cyan)'}"></div></div>
|
|
494
|
-
<div style="display:flex;justify-content:space-between;font-size:10px;color:var(--text-dim);margin:8px 0 2px"><span>Budget Tag</span><span>${formatK(s.tokensToday ?? 0)} / ${formatK((s.tokensToday ?? 0) + (s.budgetRemainingDay ?? 0))}</span></div>
|
|
735
|
+
<div style="display:flex;justify-content:space-between;font-size:10px;color:var(--text-dim);margin:8px 0 2px"><span>Budget pro Tag</span><span>${formatK(s.tokensToday ?? 0)} / ${formatK((s.tokensToday ?? 0) + (s.budgetRemainingDay ?? 0))}</span></div>
|
|
495
736
|
<div class="llm-bar"><div class="llm-bar-fill" style="width:${dayPct}%;background:${dayPct > 80 ? 'var(--red)' : dayPct > 50 ? 'var(--orange)' : 'var(--green)'}"></div></div>
|
|
496
737
|
</div>
|
|
497
|
-
${s.model ? `<div style="margin-top:10px;font-size:10px;color:var(--text-dim)">
|
|
498
|
-
${s.providers ? `<div style="margin-top:4px;font-size:10px;color:var(--text-dim)">
|
|
738
|
+
${s.model ? `<div style="margin-top:10px;font-size:10px;color:var(--text-dim)">KI-Modell: ${s.model}</div>` : ''}
|
|
739
|
+
${s.providers ? `<div style="margin-top:4px;font-size:10px;color:var(--text-dim)">Anbieter: ${s.providers.map(p => `<span style="color:${p.available ? 'var(--green)' : 'var(--red)'}">${p.name}</span>`).join(', ')}</div>` : ''}
|
|
499
740
|
`;
|
|
500
741
|
}
|
|
501
742
|
|
|
743
|
+
// ── Error Log ─────────────────────────────────────────────
|
|
744
|
+
function renderErrors() {
|
|
745
|
+
const el = document.getElementById('errorFeed');
|
|
746
|
+
const cnt = document.getElementById('errorCount');
|
|
747
|
+
const d = state.errors;
|
|
748
|
+
if (!d) { el.innerHTML = '<div class="empty">Keine Fehler — alles läuft!</div>'; cnt.textContent = ''; return; }
|
|
749
|
+
const errors = d.errors || d;
|
|
750
|
+
if (!Array.isArray(errors) || !errors.length) { el.innerHTML = '<div class="empty">Keine Fehler — alles läuft!</div>'; cnt.textContent = ''; return; }
|
|
751
|
+
cnt.textContent = `(${errors.length})`;
|
|
752
|
+
el.innerHTML = errors.slice(0, 20).map(e => {
|
|
753
|
+
const time = e.timestamp ? new Date(e.timestamp).toLocaleTimeString('de-DE', { hour:'2-digit', minute:'2-digit' }) : '';
|
|
754
|
+
const level = e.resolved ? 'warn' : 'err';
|
|
755
|
+
const msg = e.message || e.error_message || e.title || 'Unbekannter Fehler';
|
|
756
|
+
const source = e.source || e.project || '';
|
|
757
|
+
return `<div class="error-item">
|
|
758
|
+
<span class="thought-time">${time}</span>
|
|
759
|
+
<span class="error-level ${level}">${e.resolved ? 'Gelöst' : 'Fehler'}</span>
|
|
760
|
+
${source ? `<span style="font-size:11px;color:var(--cyan);min-width:60px">${escHtml(source)}</span>` : ''}
|
|
761
|
+
<span class="error-msg">${escHtml(msg)}</span>
|
|
762
|
+
</div>`;
|
|
763
|
+
}).join('');
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// ── Self-Mod Activity ─────────────────────────────────────
|
|
767
|
+
function renderSelfMod() {
|
|
768
|
+
const d = state.selfmod;
|
|
769
|
+
if (!d || !d.status) {
|
|
770
|
+
setText('sm-total', 0); setText('sm-applied', 0); setText('sm-testing', 0); setText('sm-failed', 0);
|
|
771
|
+
document.getElementById('selfModFeed').innerHTML = '<div class="empty">Brain hat sich noch nicht selbst verbessert</div>';
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
const s = d.status;
|
|
775
|
+
setText('sm-total', s.totalModifications || 0);
|
|
776
|
+
const byStatus = s.byStatus || {};
|
|
777
|
+
setText('sm-applied', byStatus.applied || 0);
|
|
778
|
+
setText('sm-testing', (byStatus.testing || 0) + (byStatus.generating || 0));
|
|
779
|
+
setText('sm-failed', (byStatus.failed || 0) + (byStatus.rejected || 0));
|
|
780
|
+
|
|
781
|
+
const hist = d.history || [];
|
|
782
|
+
const el = document.getElementById('selfModFeed');
|
|
783
|
+
if (!hist.length) { el.innerHTML = '<div class="empty">Noch keine Verbesserungen</div>'; return; }
|
|
784
|
+
el.innerHTML = hist.map(m => {
|
|
785
|
+
const statusMap = { applied:'Angewendet', testing:'Wird getestet', ready:'Bereit', proposed:'Vorgeschlagen', generating:'Generiert', failed:'Fehlgeschlagen', rejected:'Abgelehnt', rolled_back:'Zurückgesetzt' };
|
|
786
|
+
const statusClass = m.status === 'applied' ? 'mod-applied' : m.status === 'testing' || m.status === 'generating' ? 'mod-testing' : m.status === 'failed' || m.status === 'rejected' ? 'mod-failed' : 'mod-proposed';
|
|
787
|
+
const time = m.created_at ? new Date(m.created_at).toLocaleString('de-DE', { day:'2-digit', month:'2-digit', hour:'2-digit', minute:'2-digit' }) : '';
|
|
788
|
+
return `<div class="mod-item">
|
|
789
|
+
<span class="mod-status ${statusClass}">${statusMap[m.status] || m.status}</span>
|
|
790
|
+
<div style="flex:1">
|
|
791
|
+
<div class="mod-title">${escHtml(m.title || 'Verbesserung')}</div>
|
|
792
|
+
<div class="mod-detail">${escHtml(m.problem_description || '')} ${time ? `<span style="float:right">${time}</span>` : ''}</div>
|
|
793
|
+
${m.target_files?.length ? `<div style="font-size:10px;color:var(--text-dim);margin-top:2px">Dateien: ${m.target_files.map(f => f.split('/').pop()).join(', ')}</div>` : ''}
|
|
794
|
+
</div>
|
|
795
|
+
</div>`;
|
|
796
|
+
}).join('');
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// ── Mission Tracker ───────────────────────────────────────
|
|
800
|
+
function renderMissions() {
|
|
801
|
+
const d = state.missions;
|
|
802
|
+
if (!d || !d.status) {
|
|
803
|
+
setText('ms-active', 0); setText('ms-completed', 0); setText('ms-sources', 0);
|
|
804
|
+
document.getElementById('missionList').innerHTML = '<div class="empty">Keine aktiven Missionen</div>';
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
const s = d.status;
|
|
808
|
+
setText('ms-active', s.activeMissions || 0);
|
|
809
|
+
setText('ms-completed', s.completedMissions || 0);
|
|
810
|
+
setText('ms-sources', s.totalSources || 0);
|
|
811
|
+
|
|
812
|
+
const list = d.list || [];
|
|
813
|
+
const el = document.getElementById('missionList');
|
|
814
|
+
if (!list.length) { el.innerHTML = '<div class="empty">Keine aktiven Missionen</div>'; return; }
|
|
815
|
+
const phases = ['decomposing','gathering','hypothesizing','analyzing','synthesizing'];
|
|
816
|
+
const phaseLabels = { decomposing:'Aufteilen', gathering:'Sammeln', hypothesizing:'Ideen bilden', analyzing:'Analysieren', synthesizing:'Zusammenfassen' };
|
|
817
|
+
el.innerHTML = list.slice(0, 10).map(m => {
|
|
818
|
+
const statusIdx = phases.indexOf(m.status);
|
|
819
|
+
const phaseHtml = phases.map((p, i) => {
|
|
820
|
+
const cls = m.status === 'complete' ? 'done' : m.status === 'failed' ? (i <= statusIdx ? 'fail' : '') : (i < statusIdx ? 'done' : i === statusIdx ? 'running' : '');
|
|
821
|
+
return `<div class="mission-phase ${cls}" title="${phaseLabels[p] || p}"></div>`;
|
|
822
|
+
}).join('');
|
|
823
|
+
const statusText = m.status === 'complete' ? 'Fertig' : m.status === 'failed' ? 'Fehlgeschlagen' : phaseLabels[m.status] || m.status;
|
|
824
|
+
const depth = m.depth === 'deep' ? 'Tiefgehend' : m.depth === 'quick' ? 'Schnell' : 'Standard';
|
|
825
|
+
return `<div class="mission-card">
|
|
826
|
+
<div class="mission-topic">${escHtml(m.topic || 'Mission')}</div>
|
|
827
|
+
<div style="font-size:11px;color:var(--text-dim)">${statusText} — ${depth} — ${m.sourceCount || 0} Quellen</div>
|
|
828
|
+
<div class="mission-phases">${phaseHtml}</div>
|
|
829
|
+
<div class="mission-meta">
|
|
830
|
+
<span>Gestartet: ${m.createdAt ? new Date(m.createdAt).toLocaleString('de-DE', { day:'2-digit', month:'2-digit', hour:'2-digit', minute:'2-digit' }) : '?'}</span>
|
|
831
|
+
${m.completedAt ? `<span>Fertig: ${new Date(m.completedAt).toLocaleString('de-DE', { day:'2-digit', month:'2-digit', hour:'2-digit', minute:'2-digit' })}</span>` : ''}
|
|
832
|
+
</div>
|
|
833
|
+
</div>`;
|
|
834
|
+
}).join('');
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// ── Knowledge Growth ──────────────────────────────────────
|
|
838
|
+
function renderKnowledge() {
|
|
839
|
+
const d = state.knowledge;
|
|
840
|
+
if (!d) return;
|
|
841
|
+
// Totals
|
|
842
|
+
if (d.totals) {
|
|
843
|
+
setText('kn-principles', d.totals.principles || d.totals.rules || 0);
|
|
844
|
+
setText('kn-hypotheses', d.totals.hypotheses || 0);
|
|
845
|
+
setText('kn-experiments', d.totals.experiments || 0);
|
|
846
|
+
setText('kn-errors', d.totals.errorsSolved || d.totals.solutions || 0);
|
|
847
|
+
}
|
|
848
|
+
// Time series chart
|
|
849
|
+
const ts = d.timeSeries || [];
|
|
850
|
+
if (!ts.length) return;
|
|
851
|
+
drawKnowledgeChart(ts);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
function drawKnowledgeChart(data) {
|
|
855
|
+
const svg = document.getElementById('knowledgeSvg');
|
|
856
|
+
if (!svg || !data.length) return;
|
|
857
|
+
const w = 600, h = 180, pad = 30;
|
|
858
|
+
const maxVal = Math.max(1, ...data.map(d => Math.max(d.errors || 0, d.solutions || 0)));
|
|
859
|
+
const xStep = (w - pad * 2) / Math.max(1, data.length - 1);
|
|
860
|
+
|
|
861
|
+
function path(key, color) {
|
|
862
|
+
const pts = data.map((d, i) => {
|
|
863
|
+
const x = pad + i * xStep;
|
|
864
|
+
const y = h - pad - ((d[key] || 0) / maxVal) * (h - pad * 2);
|
|
865
|
+
return `${i === 0 ? 'M' : 'L'}${x},${y}`;
|
|
866
|
+
}).join(' ');
|
|
867
|
+
return `<path d="${pts}" fill="none" stroke="${color}" stroke-width="2" stroke-linecap="round"/>`;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// Grid lines
|
|
871
|
+
let grid = '';
|
|
872
|
+
for (let i = 0; i <= 4; i++) {
|
|
873
|
+
const y = pad + (i / 4) * (h - pad * 2);
|
|
874
|
+
grid += `<line x1="${pad}" y1="${y}" x2="${w-pad}" y2="${y}" stroke="rgba(100,140,255,0.08)" stroke-width="1"/>`;
|
|
875
|
+
}
|
|
876
|
+
// X labels (show every few)
|
|
877
|
+
let labels = '';
|
|
878
|
+
const step = Math.max(1, Math.floor(data.length / 7));
|
|
879
|
+
for (let i = 0; i < data.length; i += step) {
|
|
880
|
+
const x = pad + i * xStep;
|
|
881
|
+
const d = data[i].date || '';
|
|
882
|
+
labels += `<text x="${x}" y="${h-5}" text-anchor="middle" fill="var(--text-dim)" font-size="9">${d.slice(5)}</text>`;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
svg.innerHTML = grid + labels + path('errors', '#ff4466') + path('solutions', '#00ff88');
|
|
886
|
+
}
|
|
887
|
+
|
|
502
888
|
// ── Render: Ecosystem ─────────────────────────────────────
|
|
503
889
|
function renderEcosystem() {
|
|
504
890
|
const eco = state.ecosystem; if (!eco) return;
|
|
505
891
|
const hb = document.getElementById('healthBadge');
|
|
506
892
|
const h = eco.health;
|
|
507
893
|
if (h) {
|
|
508
|
-
hb.textContent = h.status === 'healthy' ? '
|
|
894
|
+
hb.textContent = h.status === 'healthy' ? 'Gesund' : h.status === 'degraded' ? 'Eingeschränkt' : 'Kritisch';
|
|
509
895
|
hb.className = 'badge ' + (h.status === 'healthy' ? 'badge-ok' : h.status === 'degraded' ? 'badge-warn' : 'badge-err');
|
|
510
896
|
const score = h.score || 0;
|
|
511
897
|
document.getElementById('gaugeArc').setAttribute('stroke-dasharray', `${(score / 100) * 172} 172`);
|
|
512
898
|
document.getElementById('gaugeArc').setAttribute('stroke', score > 70 ? 'var(--green)' : score > 40 ? 'var(--orange)' : 'var(--red)');
|
|
513
899
|
document.getElementById('gaugeValue').textContent = Math.round(score);
|
|
514
900
|
}
|
|
515
|
-
// Brain cards
|
|
516
901
|
const container = document.getElementById('brainCards');
|
|
517
902
|
const brainNames = ['brain', 'trading-brain', 'marketing-brain'];
|
|
518
903
|
const labels = { brain:'Brain', 'trading-brain':'Trading-Brain', 'marketing-brain':'Marketing-Brain' };
|
|
904
|
+
const descs = { brain:'Lernt aus Fehlern, verbessert Code', 'trading-brain':'Paper Trading, Signal-Analyse', 'marketing-brain':'Content-Strategie, Engagement' };
|
|
519
905
|
const classes = { brain:'brain-brain', 'trading-brain':'brain-trading', 'marketing-brain':'brain-marketing' };
|
|
520
906
|
container.innerHTML = brainNames.map(name => {
|
|
521
907
|
const b = (eco.brains || []).find(x => x.name === name) || { name, available:false };
|
|
522
908
|
return `<div class="card brain-card ${classes[name]}">
|
|
523
909
|
<div class="brain-status"><span class="dot ${b.available ? 'dot-on' : 'dot-off'}"></span><span class="brain-name">${labels[name]}</span></div>
|
|
910
|
+
<div style="font-size:11px;color:var(--text-dim);margin-bottom:6px">${descs[name]}</div>
|
|
524
911
|
<div class="brain-meta">
|
|
525
912
|
<span>${b.available ? 'Online' : 'Offline'}</span>
|
|
526
913
|
${b.version ? `<span>v${b.version}</span>` : ''}${b.pid ? `<span>PID ${b.pid}</span>` : ''}
|
|
527
|
-
${b.uptime ? `<span>${fmtUp(b.uptime)}</span>` : ''}${b.methods ? `<span>${b.methods}
|
|
914
|
+
${b.uptime ? `<span>${fmtUp(b.uptime)}</span>` : ''}${b.methods ? `<span>${b.methods} Tools</span>` : ''}
|
|
528
915
|
</div></div>`;
|
|
529
916
|
}).join('');
|
|
530
917
|
drawPeerGraph(eco.brains || []);
|
|
@@ -533,7 +920,7 @@ function renderEcosystem() {
|
|
|
533
920
|
|
|
534
921
|
function renderCorrelations(c) {
|
|
535
922
|
const el = document.getElementById('correlationList');
|
|
536
|
-
if (!c.length) { el.innerHTML = '<div class="empty">
|
|
923
|
+
if (!c.length) { el.innerHTML = '<div class="empty">Noch keine Zusammenhänge gefunden</div>'; return; }
|
|
537
924
|
el.innerHTML = c.slice(0, 10).map(x => `<div style="padding:6px 0;border-bottom:1px solid var(--border);font-size:12px">
|
|
538
925
|
<span style="color:var(--cyan)">${x.sourceA}/${x.eventA}</span> <span style="color:var(--text-dim)">↔</span>
|
|
539
926
|
<span style="color:var(--magenta)">${x.sourceB}/${x.eventB}</span>
|
|
@@ -555,7 +942,7 @@ function renderEngines() {
|
|
|
555
942
|
|
|
556
943
|
function renderGrid(id, engines, showBrain = false) {
|
|
557
944
|
const el = document.getElementById(id); if (!el) return;
|
|
558
|
-
if (!engines.length) { el.innerHTML = '<div class="empty">
|
|
945
|
+
if (!engines.length) { el.innerHTML = '<div class="empty">Keine Engines</div>'; return; }
|
|
559
946
|
el.innerHTML = engines.map(e => {
|
|
560
947
|
const st = e.lastActivity && (Date.now() - e.lastActivity < 60000) ? 'active' : e.thoughtCount > 0 ? 'idle' : 'off';
|
|
561
948
|
const lbl = showBrain && e.brain ? `${e.brain}/${e.engine}` : (e.engine || e.name || '?');
|
|
@@ -581,48 +968,181 @@ function updateLearningPipeline(engines) {
|
|
|
581
968
|
// ── Render: Analytics ─────────────────────────────────────
|
|
582
969
|
function renderAnalytics() {
|
|
583
970
|
const a = state.analytics; if (!a) return;
|
|
584
|
-
if (a.trading) {
|
|
585
|
-
|
|
971
|
+
if (a.trading) {
|
|
972
|
+
const t = a.trading;
|
|
973
|
+
setText('tp-signals', num(t.signals));
|
|
974
|
+
setText('tp-trades', num(t.trades));
|
|
975
|
+
setText('tradingWinRate', t.winRate ? (Number(t.winRate)*100).toFixed(1)+'%' : '--');
|
|
976
|
+
setText('tradingEquity', t.equity ? '$'+Number(t.equity).toLocaleString() : '--');
|
|
977
|
+
setText('tradingPositions', num(t.positions));
|
|
978
|
+
}
|
|
979
|
+
if (a.marketing) {
|
|
980
|
+
const m = a.marketing;
|
|
981
|
+
setText('mp-posts', num(m.posts));
|
|
982
|
+
setText('mp-engagement', num(m.engagement));
|
|
983
|
+
setText('marketingCampaigns', num(m.campaigns));
|
|
984
|
+
}
|
|
586
985
|
}
|
|
986
|
+
function num(v) { if (v == null) return 0; if (typeof v === 'object') return v.total || v.count || v.length || Object.keys(v).length || 0; return Number(v) || 0; }
|
|
587
987
|
|
|
588
988
|
// ── Render: Watchdog ──────────────────────────────────────
|
|
589
989
|
function renderWatchdog() {
|
|
590
|
-
const el = document.getElementById('
|
|
990
|
+
const el = document.getElementById('watchdogCards');
|
|
591
991
|
const d = state.watchdog || [];
|
|
592
|
-
if (!d.length) { el.innerHTML = '<div class="empty">
|
|
593
|
-
|
|
594
|
-
|
|
992
|
+
if (!d.length) { el.innerHTML = '<div class="empty">Kein Watchdog konfiguriert — starte Brain mit <code>brain start</code></div>'; return; }
|
|
993
|
+
|
|
994
|
+
// Daemon cards — color-coded
|
|
995
|
+
el.innerHTML = d.map(x => {
|
|
996
|
+
const borderColor = !x.running ? 'var(--red)' : x.healthy ? 'var(--green)' : 'var(--orange)';
|
|
997
|
+
const bgColor = !x.running ? 'rgba(239,68,68,0.08)' : x.healthy ? 'rgba(34,197,94,0.08)' : 'rgba(234,179,8,0.08)';
|
|
998
|
+
const statusText = !x.running ? 'Gestoppt' : x.healthy ? 'Gesund' : 'Problem';
|
|
999
|
+
const statusIcon = !x.running ? '🔴' : x.healthy ? '🟢' : '🟡';
|
|
1000
|
+
const uptime = x.uptime ? fmtUp(x.uptime / 1000) : '-';
|
|
1001
|
+
return `<div class="card" style="border-left:3px solid ${borderColor};background:${bgColor};padding:16px">
|
|
1002
|
+
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px">
|
|
1003
|
+
<div style="font-size:15px;font-weight:700">${x.name}</div>
|
|
1004
|
+
<span style="font-size:14px">${statusIcon} ${statusText}</span>
|
|
1005
|
+
</div>
|
|
1006
|
+
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;font-size:12px">
|
|
1007
|
+
<div><span style="color:var(--text-dim)">PID</span><br><span style="font-weight:600;font-size:14px">${x.pid || '-'}</span></div>
|
|
1008
|
+
<div><span style="color:var(--text-dim)">Laufzeit</span><br><span style="font-weight:600;font-size:14px">${uptime}</span></div>
|
|
1009
|
+
<div><span style="color:var(--text-dim)">Neustarts</span><br><span style="font-weight:600;font-size:14px;color:${x.restarts > 0 ? 'var(--orange)' : 'inherit'}">${x.restarts || 0}</span></div>
|
|
1010
|
+
<div><span style="color:var(--text-dim)">Letzter Crash</span><br><span style="font-weight:600;font-size:11px">${x.lastCrash ? new Date(x.lastCrash).toLocaleString('de') : '-'}</span></div>
|
|
1011
|
+
</div>
|
|
1012
|
+
</div>`;
|
|
1013
|
+
}).join('');
|
|
1014
|
+
|
|
1015
|
+
// Health check summary
|
|
595
1016
|
const hc = document.getElementById('healthCheckCard');
|
|
596
1017
|
const ok = d.every(x => x.running && x.healthy), off = d.filter(x => !x.running).length;
|
|
597
|
-
|
|
1018
|
+
const unhealthy = d.filter(x => x.running && !x.healthy).length;
|
|
1019
|
+
hc.innerHTML = `<div style="display:flex;gap:20px;align-items:center"><span style="font-size:32px">${ok?'✅':off?'🚨':'⚠'}</span><div><div style="font-size:15px;font-weight:600;color:${ok?'var(--green)':off?'var(--red)':'var(--orange)'}">${ok?'Alle Systeme laufen':off?`${off} Dienste offline`:`${unhealthy} Dienste mit Problemen`}</div><div style="font-size:12px;color:var(--text-dim);margin-top:4px">${d.length} Dienste überwacht • ${d.filter(x=>x.running).length} laufen • ${d.filter(x=>x.running&&x.healthy).length} gesund</div></div></div>`;
|
|
1020
|
+
|
|
1021
|
+
// Stats card
|
|
1022
|
+
const sc = document.getElementById('watchdogStatsCard');
|
|
1023
|
+
const totalRestarts = d.reduce((s, x) => s + (x.restarts || 0), 0);
|
|
1024
|
+
const avgUptime = d.filter(x => x.uptime).map(x => x.uptime);
|
|
1025
|
+
const maxUp = avgUptime.length ? fmtUp(Math.max(...avgUptime) / 1000) : '-';
|
|
1026
|
+
sc.innerHTML = `<div style="display:flex;gap:24px;font-size:13px">
|
|
1027
|
+
<div><span style="color:var(--text-dim)">Gesamt-Neustarts</span><br><span style="font-size:20px;font-weight:700;color:${totalRestarts>0?'var(--orange)':'var(--green)'}">${totalRestarts}</span></div>
|
|
1028
|
+
<div><span style="color:var(--text-dim)">Längste Laufzeit</span><br><span style="font-size:20px;font-weight:700">${maxUp}</span></div>
|
|
1029
|
+
<div><span style="color:var(--text-dim)">Dienste</span><br><span style="font-size:20px;font-weight:700">${d.length}</span></div>
|
|
1030
|
+
</div>`;
|
|
598
1031
|
}
|
|
599
1032
|
|
|
600
1033
|
function renderPlugins() {
|
|
601
1034
|
const el = document.getElementById('pluginCard');
|
|
602
1035
|
const p = state.plugins || [];
|
|
603
|
-
if (!p.length) { el.innerHTML = '<div class="empty">
|
|
604
|
-
el.innerHTML = p.map(x => `<div style="padding:8px 0;border-bottom:1px solid var(--border);display:flex;justify-content:space-between"><div><div style="font-weight:600;font-size:13px">${x.name}</div><div style="font-size:11px;color:var(--text-dim)">${x.description||''} v${x.version}</div></div><span class="tag tag-green">${x.status||'
|
|
1036
|
+
if (!p.length) { el.innerHTML = '<div class="empty">Keine Plugins installiert</div>'; return; }
|
|
1037
|
+
el.innerHTML = p.map(x => `<div style="padding:8px 0;border-bottom:1px solid var(--border);display:flex;justify-content:space-between"><div><div style="font-weight:600;font-size:13px">${x.name}</div><div style="font-size:11px;color:var(--text-dim)">${x.description||''} v${x.version}</div></div><span class="tag tag-green">${x.status||'Geladen'}</span></div>`).join('');
|
|
605
1038
|
}
|
|
606
1039
|
|
|
607
1040
|
// ── Render: Borg ──────────────────────────────────────────
|
|
608
1041
|
function renderBorg() {
|
|
609
1042
|
const b = state.borg;
|
|
610
1043
|
const sEl = document.getElementById('borgStatus'), btn = document.getElementById('borgToggle'), det = document.getElementById('borgDetails'), hist = document.getElementById('borgHistory');
|
|
611
|
-
if (!b || !b.status) { sEl.textContent = '
|
|
1044
|
+
if (!b || !b.status) { sEl.textContent = 'Nicht verfügbar'; btn.disabled = true; return; }
|
|
612
1045
|
const s = b.status;
|
|
613
|
-
sEl.innerHTML = `<span class="dot ${s.enabled?'dot-on':'dot-off'}" style="margin-right:6px"></span>${s.enabled?'
|
|
614
|
-
btn.disabled = false; btn.className = s.enabled ? 'btn btn-active' : 'btn'; btn.textContent = s.enabled ? '
|
|
615
|
-
det.innerHTML = `<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;font-size:12px;margin-top:8px"><div><span style="color:var(--text-dim)">Syncs</span><br><strong>${s.totalSyncs||0}</strong></div><div><span style="color:var(--text-dim)">
|
|
1046
|
+
sEl.innerHTML = `<span class="dot ${s.enabled?'dot-on':'dot-off'}" style="margin-right:6px"></span>${s.enabled?'Aktiv':'Deaktiviert'} — ${s.mode || 'Standard'}`;
|
|
1047
|
+
btn.disabled = false; btn.className = s.enabled ? 'btn btn-active' : 'btn'; btn.textContent = s.enabled ? 'Deaktivieren' : 'Aktivieren';
|
|
1048
|
+
det.innerHTML = `<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;font-size:12px;margin-top:8px"><div><span style="color:var(--text-dim)">Syncs</span><br><strong>${s.totalSyncs||0}</strong></div><div><span style="color:var(--text-dim)">Gesendet</span><br><strong>${s.totalSent||0}</strong></div><div><span style="color:var(--text-dim)">Empfangen</span><br><strong>${s.totalReceived||0}</strong></div></div>`;
|
|
616
1049
|
const h = b.history || [];
|
|
617
|
-
if (!h.length) { hist.innerHTML = '<div class="empty">
|
|
618
|
-
hist.innerHTML = `<table class="tbl"><thead><tr><th>Zeit</th><th>Richtung</th><th>
|
|
619
|
-
h.slice(-15).reverse().map(x => `<tr><td>${new Date(x.timestamp).toLocaleTimeString('de-DE')}</td><td>${x.direction==='sent'?'⬆':'⬇'} ${x.direction}</td><td>${x.peer}</td><td>${x.itemCount}</td><td>${x.accepted}</td></tr>`).join('') + '</tbody></table>';
|
|
1050
|
+
if (!h.length) { hist.innerHTML = '<div class="empty">Noch kein Sync passiert</div>'; return; }
|
|
1051
|
+
hist.innerHTML = `<table class="tbl"><thead><tr><th>Zeit</th><th>Richtung</th><th>Partner</th><th>Elemente</th><th>Akzeptiert</th></tr></thead><tbody>` +
|
|
1052
|
+
h.slice(-15).reverse().map(x => `<tr><td>${new Date(x.timestamp).toLocaleTimeString('de-DE')}</td><td>${x.direction==='sent'?'⬆':'⬇'} ${x.direction==='sent'?'Gesendet':'Empfangen'}</td><td>${x.peer}</td><td>${x.itemCount}</td><td>${x.accepted}</td></tr>`).join('') + '</tbody></table>';
|
|
620
1053
|
}
|
|
621
1054
|
document.getElementById('borgToggle').addEventListener('click', async () => {
|
|
622
1055
|
if (!state.borg?.status) return;
|
|
623
1056
|
try { await fetch('/api/borg/toggle', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({enabled:!state.borg.status.enabled}) }); } catch {}
|
|
624
1057
|
});
|
|
625
1058
|
|
|
1059
|
+
// ── Render: Debates ──────────────────────────────────────
|
|
1060
|
+
function renderDebates() {
|
|
1061
|
+
const d = state.debates; if (!d) return;
|
|
1062
|
+
const s = d.status;
|
|
1063
|
+
if (s) {
|
|
1064
|
+
const el = (id) => document.getElementById(id);
|
|
1065
|
+
el('db-total').textContent = s.totalDebates ?? 0;
|
|
1066
|
+
el('db-open').textContent = s.openDebates ?? 0;
|
|
1067
|
+
el('db-synthesized').textContent = s.synthesizedDebates ?? 0;
|
|
1068
|
+
el('db-challenges').textContent = s.totalChallenges ?? 0;
|
|
1069
|
+
}
|
|
1070
|
+
// Recent debates
|
|
1071
|
+
const list = d.recent || [];
|
|
1072
|
+
const listEl = document.getElementById('debateList');
|
|
1073
|
+
if (!list.length) { listEl.innerHTML = '<div class="empty">Noch keine Debatten gestartet</div>'; }
|
|
1074
|
+
else {
|
|
1075
|
+
listEl.innerHTML = list.map(db => {
|
|
1076
|
+
const statusCol = db.status === 'synthesized' ? 'var(--green)' : db.status === 'open' ? 'var(--yellow)' : 'var(--cyan)';
|
|
1077
|
+
const persp = (db.perspectives || []).length;
|
|
1078
|
+
return `<div class="card" style="margin-bottom:8px;padding:10px 14px">
|
|
1079
|
+
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
1080
|
+
<strong style="color:var(--cyan)">#${db.id}: ${db.question?.substring(0,80)||'?'}</strong>
|
|
1081
|
+
<span style="color:${statusCol};font-size:11px;text-transform:uppercase">${db.status}</span>
|
|
1082
|
+
</div>
|
|
1083
|
+
<div style="font-size:11px;color:var(--text-dim);margin-top:4px">${persp} Perspektiven | ${db.created_at ? new Date(db.created_at).toLocaleString('de-DE') : ''}</div>
|
|
1084
|
+
${db.synthesis ? `<div style="font-size:11px;margin-top:4px;color:var(--green)">Konsens: ${(db.synthesis.consensus||'').substring(0,120)}...</div>` : ''}
|
|
1085
|
+
</div>`;
|
|
1086
|
+
}).join('');
|
|
1087
|
+
}
|
|
1088
|
+
// Challenges
|
|
1089
|
+
const chList = d.challenges || [];
|
|
1090
|
+
const chEl = document.getElementById('challengeList');
|
|
1091
|
+
if (!chList.length) { chEl.innerHTML = '<div class="empty">Noch keine Challenges durchgeführt</div>'; }
|
|
1092
|
+
else {
|
|
1093
|
+
chEl.innerHTML = chList.map(c => {
|
|
1094
|
+
const icon = c.outcome === 'survived' ? '\u2705' : c.outcome === 'weakened' ? '\u26A0\uFE0F' : '\u274C';
|
|
1095
|
+
const col = c.outcome === 'survived' ? 'var(--green)' : c.outcome === 'weakened' ? 'var(--yellow)' : 'var(--red)';
|
|
1096
|
+
const pct = ((c.resilienceScore || 0) * 100).toFixed(0);
|
|
1097
|
+
return `<div class="card" style="margin-bottom:6px;padding:8px 14px;border-left:3px solid ${col}">
|
|
1098
|
+
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
1099
|
+
<span>${icon} ${(c.principleStatement||'').substring(0,80)}</span>
|
|
1100
|
+
<span style="color:${col};font-size:12px;font-weight:bold">${c.outcome?.toUpperCase()} ${pct}%</span>
|
|
1101
|
+
</div>
|
|
1102
|
+
</div>`;
|
|
1103
|
+
}).join('');
|
|
1104
|
+
}
|
|
1105
|
+
// Vulnerable
|
|
1106
|
+
const vulList = d.vulnerable || [];
|
|
1107
|
+
const vulEl = document.getElementById('vulnerableList');
|
|
1108
|
+
if (!vulList.length) { vulEl.innerHTML = '<div class="empty">Keine verwundbaren Prinzipien</div>'; }
|
|
1109
|
+
else {
|
|
1110
|
+
vulEl.innerHTML = vulList.map(v => {
|
|
1111
|
+
const pct = ((v.resilienceScore || 0) * 100).toFixed(0);
|
|
1112
|
+
const barCol = pct < 30 ? 'var(--red)' : pct < 60 ? 'var(--yellow)' : 'var(--green)';
|
|
1113
|
+
return `<div class="card" style="margin-bottom:6px;padding:8px 14px">
|
|
1114
|
+
<div style="font-size:13px;color:var(--text)">${(v.principleStatement||'').substring(0,100)}</div>
|
|
1115
|
+
<div style="display:flex;align-items:center;gap:8px;margin-top:6px">
|
|
1116
|
+
<div style="flex:1;height:6px;background:rgba(255,255,255,0.05);border-radius:3px;overflow:hidden"><div style="width:${pct}%;height:100%;background:${barCol};border-radius:3px"></div></div>
|
|
1117
|
+
<span style="font-size:11px;color:${barCol};min-width:40px">${pct}%</span>
|
|
1118
|
+
<span style="font-size:11px;color:var(--text-dim)">${v.outcome}</span>
|
|
1119
|
+
</div>
|
|
1120
|
+
</div>`;
|
|
1121
|
+
}).join('');
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// ── Quick Actions ─────────────────────────────────────────
|
|
1126
|
+
document.querySelectorAll('.action-btn').forEach(btn => {
|
|
1127
|
+
btn.addEventListener('click', async () => {
|
|
1128
|
+
const action = btn.dataset.action;
|
|
1129
|
+
btn.classList.add('running');
|
|
1130
|
+
btn.querySelector('.action-icon').textContent = '\u23F3';
|
|
1131
|
+
try {
|
|
1132
|
+
const res = await fetch('/api/action', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ action }) });
|
|
1133
|
+
const data = await res.json();
|
|
1134
|
+
btn.querySelector('.action-icon').textContent = data.ok ? '\u2705' : '\u274C';
|
|
1135
|
+
} catch {
|
|
1136
|
+
btn.querySelector('.action-icon').textContent = '\u274C';
|
|
1137
|
+
}
|
|
1138
|
+
setTimeout(() => {
|
|
1139
|
+
btn.classList.remove('running');
|
|
1140
|
+
const icons = { 'learning-cycle':'\u{1F504}', 'borg-sync':'\u{1F47E}', 'tech-scan':'\u{1F4E1}', 'health-check':'\u{1F3E5}' };
|
|
1141
|
+
btn.querySelector('.action-icon').textContent = icons[action] || '\u26A1';
|
|
1142
|
+
}, 2000);
|
|
1143
|
+
});
|
|
1144
|
+
});
|
|
1145
|
+
|
|
626
1146
|
// ── Canvas: Peer Graph ────────────────────────────────────
|
|
627
1147
|
function drawPeerGraph(brains) {
|
|
628
1148
|
const canvas = document.getElementById('peerCanvas'); if (!canvas) return;
|
|
@@ -650,11 +1170,10 @@ function drawPeerGraph(brains) {
|
|
|
650
1170
|
|
|
651
1171
|
// ── Canvas: Cross-Brain + Borg Animation ──────────────────
|
|
652
1172
|
let particles = [];
|
|
653
|
-
let borgPackets = [];
|
|
1173
|
+
let borgPackets = [];
|
|
654
1174
|
function spawnBorgPacket(src, dst, items) {
|
|
655
1175
|
borgPackets.push({ src, dst, items, progress: 0, speed: 0.004 + Math.random() * 0.003 });
|
|
656
1176
|
}
|
|
657
|
-
// When borg data updates, spawn visual packets from history
|
|
658
1177
|
let lastBorgHistLen = 0;
|
|
659
1178
|
function checkBorgPackets() {
|
|
660
1179
|
const h = state.borg?.history || [];
|
|
@@ -685,35 +1204,24 @@ function initCrossBrainCanvas() {
|
|
|
685
1204
|
let s=n[Math.random()*n.length|0],d=n[Math.random()*n.length|0];
|
|
686
1205
|
while(d===s)d=n[Math.random()*n.length|0];
|
|
687
1206
|
const a=positions[s],b=positions[d];
|
|
688
|
-
particles.push({x:a.x,y:a.y,tx:b.x,ty:b.y,color:a.color,progress:0,speed:.008+Math.random()*.012
|
|
1207
|
+
particles.push({x:a.x,y:a.y,tx:b.x,ty:b.y,color:a.color,progress:0,speed:.008+Math.random()*.012});
|
|
689
1208
|
}
|
|
690
1209
|
|
|
691
1210
|
function draw() {
|
|
692
1211
|
const ctx=canvas.getContext('2d'),w=canvas.width/2,h=canvas.height/2;
|
|
693
1212
|
ctx.save(); ctx.scale(2,2); ctx.clearRect(0,0,w,h); getPos();
|
|
694
1213
|
checkBorgPackets();
|
|
695
|
-
|
|
696
1214
|
const borgEnabled = state.borg?.status?.enabled;
|
|
697
1215
|
const borgSent = state.borg?.status?.totalSent || 0;
|
|
698
1216
|
const borgRecv = state.borg?.status?.totalReceived || 0;
|
|
699
1217
|
const n=Object.keys(positions);
|
|
700
|
-
|
|
701
|
-
// Draw connections
|
|
702
1218
|
for(let i=0;i<n.length;i++) for(let j=i+1;j<n.length;j++) {
|
|
703
1219
|
const a=positions[n[i]],b=positions[n[j]];
|
|
704
|
-
// Borg connections glow brighter when enabled
|
|
705
1220
|
ctx.beginPath(); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y);
|
|
706
1221
|
ctx.strokeStyle = borgEnabled ? 'rgba(170,136,255,0.15)' : 'rgba(100,140,255,0.1)';
|
|
707
|
-
ctx.lineWidth = borgEnabled ? 2 : 1;
|
|
708
|
-
ctx.stroke();
|
|
709
|
-
// Dashed borg overlay
|
|
710
|
-
if (borgEnabled) {
|
|
711
|
-
ctx.beginPath(); ctx.setLineDash([4,8]); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y);
|
|
712
|
-
ctx.strokeStyle='rgba(170,136,255,0.12)'; ctx.lineWidth=1; ctx.stroke(); ctx.setLineDash([]);
|
|
713
|
-
}
|
|
1222
|
+
ctx.lineWidth = borgEnabled ? 2 : 1; ctx.stroke();
|
|
1223
|
+
if (borgEnabled) { ctx.beginPath(); ctx.setLineDash([4,8]); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y); ctx.strokeStyle='rgba(170,136,255,0.12)'; ctx.lineWidth=1; ctx.stroke(); ctx.setLineDash([]); }
|
|
714
1224
|
}
|
|
715
|
-
|
|
716
|
-
// Regular message particles
|
|
717
1225
|
if(Math.random()<.05&&state.connected) spawnMsg();
|
|
718
1226
|
particles=particles.filter(p=>p.progress<1);
|
|
719
1227
|
for(const p of particles) {
|
|
@@ -723,56 +1231,33 @@ function initCrossBrainCanvas() {
|
|
|
723
1231
|
const g=ctx.createRadialGradient(cx,cy,0,cx,cy,6); g.addColorStop(0,p.color+'40'); g.addColorStop(1,p.color+'00');
|
|
724
1232
|
ctx.beginPath(); ctx.arc(cx,cy,6,0,Math.PI*2); ctx.fillStyle=g; ctx.fill();
|
|
725
1233
|
}
|
|
726
|
-
|
|
727
|
-
// Borg sync packets — bigger, purple, with item count label
|
|
728
1234
|
borgPackets=borgPackets.filter(p=>p.progress<1);
|
|
729
1235
|
for(const bp of borgPackets) {
|
|
730
1236
|
bp.progress+=bp.speed;
|
|
731
1237
|
const t=bp.progress;
|
|
732
1238
|
const sp=positions[bp.src]||positions.brain, dp=positions[bp.dst]||positions.brain;
|
|
733
1239
|
const cx=sp.x+(dp.x-sp.x)*t, cy=sp.y+(dp.y-sp.y)*t-Math.sin(t*Math.PI)*35;
|
|
734
|
-
// Outer glow
|
|
735
1240
|
ctx.beginPath(); ctx.arc(cx,cy,14,0,Math.PI*2);
|
|
736
1241
|
const gg=ctx.createRadialGradient(cx,cy,0,cx,cy,14);
|
|
737
1242
|
gg.addColorStop(0,'rgba(170,136,255,0.35)'); gg.addColorStop(1,'rgba(170,136,255,0)');
|
|
738
1243
|
ctx.fillStyle=gg; ctx.fill();
|
|
739
|
-
// Inner packet
|
|
740
1244
|
ctx.beginPath(); ctx.arc(cx,cy,6,0,Math.PI*2); ctx.fillStyle='#aa88ff'; ctx.fill();
|
|
741
1245
|
ctx.beginPath(); ctx.arc(cx,cy,4,0,Math.PI*2); ctx.fillStyle='#ddccff'; ctx.fill();
|
|
742
|
-
|
|
743
|
-
if(bp.items>0) {
|
|
744
|
-
ctx.fillStyle='#fff'; ctx.font='bold 9px Segoe UI,sans-serif'; ctx.textAlign='center';
|
|
745
|
-
ctx.fillText(bp.items+'x',cx,cy-12);
|
|
746
|
-
}
|
|
1246
|
+
if(bp.items>0) { ctx.fillStyle='#fff'; ctx.font='bold 9px Segoe UI,sans-serif'; ctx.textAlign='center'; ctx.fillText(bp.items+'x',cx,cy-12); }
|
|
747
1247
|
}
|
|
748
|
-
|
|
749
|
-
// Draw nodes
|
|
750
1248
|
for(const[name,p]of Object.entries(positions)) {
|
|
751
|
-
|
|
752
|
-
if(borgEnabled) {
|
|
753
|
-
ctx.beginPath(); ctx.arc(p.x,p.y,24,0,Math.PI*2);
|
|
754
|
-
ctx.strokeStyle='rgba(170,136,255,0.25)'; ctx.lineWidth=1; ctx.stroke();
|
|
755
|
-
}
|
|
756
|
-
// Glow
|
|
1249
|
+
if(borgEnabled) { ctx.beginPath(); ctx.arc(p.x,p.y,24,0,Math.PI*2); ctx.strokeStyle='rgba(170,136,255,0.25)'; ctx.lineWidth=1; ctx.stroke(); }
|
|
757
1250
|
ctx.beginPath(); ctx.arc(p.x,p.y,28,0,Math.PI*2);
|
|
758
|
-
const g=ctx.createRadialGradient(p.x,p.y,0,p.x,p.y,28);
|
|
759
|
-
g.addColorStop(0,p.color+'25'); g.addColorStop(1,p.color+'00'); ctx.fillStyle=g; ctx.fill();
|
|
760
|
-
// Circle
|
|
1251
|
+
const g=ctx.createRadialGradient(p.x,p.y,0,p.x,p.y,28); g.addColorStop(0,p.color+'25'); g.addColorStop(1,p.color+'00'); ctx.fillStyle=g; ctx.fill();
|
|
761
1252
|
ctx.beginPath(); ctx.arc(p.x,p.y,18,0,Math.PI*2);
|
|
762
1253
|
ctx.fillStyle=p.color+'15'; ctx.strokeStyle=p.color; ctx.lineWidth=2; ctx.fill(); ctx.stroke();
|
|
763
|
-
// Inner dot
|
|
764
1254
|
ctx.beginPath(); ctx.arc(p.x,p.y,5,0,Math.PI*2); ctx.fillStyle=p.color; ctx.fill();
|
|
765
|
-
|
|
766
|
-
ctx.fillStyle='#fff'; ctx.font='12px Segoe UI,sans-serif'; ctx.textAlign='center';
|
|
767
|
-
ctx.fillText(p.label,p.x,p.y+34);
|
|
1255
|
+
ctx.fillStyle='#fff'; ctx.font='12px Segoe UI,sans-serif'; ctx.textAlign='center'; ctx.fillText(p.label,p.x,p.y+34);
|
|
768
1256
|
}
|
|
769
|
-
|
|
770
|
-
// Borg legend (bottom center)
|
|
771
1257
|
if(borgEnabled) {
|
|
772
1258
|
ctx.fillStyle='rgba(170,136,255,0.7)'; ctx.font='10px Segoe UI,sans-serif'; ctx.textAlign='center';
|
|
773
|
-
ctx.fillText(`BORG
|
|
1259
|
+
ctx.fillText(`BORG AKTIV \u2022 ${borgSent} gesendet \u2022 ${borgRecv} empfangen`, w/2, h-8);
|
|
774
1260
|
}
|
|
775
|
-
|
|
776
1261
|
ctx.restore(); requestAnimationFrame(draw);
|
|
777
1262
|
}
|
|
778
1263
|
draw();
|