@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.
Files changed (31) hide show
  1. package/README.md +93 -135
  2. package/command-center.html +600 -115
  3. package/dist/consciousness/__tests__/thought-stream.test.d.ts +1 -0
  4. package/dist/consciousness/__tests__/thought-stream.test.js +62 -0
  5. package/dist/consciousness/__tests__/thought-stream.test.js.map +1 -0
  6. package/dist/consciousness/thought-stream.d.ts +2 -0
  7. package/dist/consciousness/thought-stream.js +4 -0
  8. package/dist/consciousness/thought-stream.js.map +1 -1
  9. package/dist/dashboard/__tests__/command-center-server.test.js +142 -6
  10. package/dist/dashboard/__tests__/command-center-server.test.js.map +1 -1
  11. package/dist/dashboard/command-center-server.d.ts +18 -0
  12. package/dist/dashboard/command-center-server.js +169 -1
  13. package/dist/dashboard/command-center-server.js.map +1 -1
  14. package/dist/debate/debate-engine.js +1 -1
  15. package/dist/debate/debate-engine.js.map +1 -1
  16. package/dist/missions/__tests__/mission-engine.test.d.ts +1 -0
  17. package/dist/missions/__tests__/mission-engine.test.js +66 -0
  18. package/dist/missions/__tests__/mission-engine.test.js.map +1 -0
  19. package/dist/missions/mission-engine.js +5 -0
  20. package/dist/missions/mission-engine.js.map +1 -1
  21. package/dist/plugin/example-plugin.d.ts +40 -0
  22. package/dist/plugin/example-plugin.js +91 -0
  23. package/dist/plugin/example-plugin.js.map +1 -0
  24. package/dist/prediction/prediction-engine.js +1 -1
  25. package/dist/research/research-orchestrator.js +9 -0
  26. package/dist/research/research-orchestrator.js.map +1 -1
  27. package/dist/utils/__tests__/logger.test.js +27 -0
  28. package/dist/utils/__tests__/logger.test.js.map +1 -1
  29. package/dist/utils/logger.js +10 -3
  30. package/dist/utils/logger.js.map +1 -1
  31. package/package.json +1 -1
@@ -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">&#x1F4E3;</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">&#x1F517;</span><span class="nav-label">Cross-Brain</span></div>
237
+ <div class="nav-item" data-page="debates"><span class="nav-icon">&#x2696;</span><span class="nav-label">Debates</span></div>
238
+ <div class="nav-item" data-page="activity"><span class="nav-icon">&#x26A1;</span><span class="nav-label">Aktivität</span></div>
190
239
  <div class="nav-item" data-page="infra"><span class="nav-icon">&#x2699;</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">&#x1F3AE;</span> Schnellaktionen</div>
262
+ <div class="quick-actions" id="quickActions">
263
+ <button class="action-btn" data-action="learning-cycle"><span class="action-icon">&#x1F504;</span> Lernzyklus starten</button>
264
+ <button class="action-btn" data-action="borg-sync"><span class="action-icon">&#x1F47E;</span> Borg Sync</button>
265
+ <button class="action-btn" data-action="tech-scan"><span class="action-icon">&#x1F4E1;</span> Tech-Radar Scan</button>
266
+ <button class="action-btn" data-action="health-check"><span class="action-icon">&#x1F3E5;</span> Health Check</button>
267
+ </div>
268
+ </div>
269
+
210
270
  <div class="section">
211
271
  <div class="section-title"><span class="icon">&#x1F916;</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">&#x1F4CA;</span> LLM Nutzung</div>
232
- <div class="card" id="llmCard"><div class="empty">Waiting for LLM data...</div></div>
291
+ <div class="section-title"><span class="icon">&#x1F4CA;</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">&#x1F4AD;</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">Waiting for thoughts...</div></div>
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">&#x26A0;</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">&#x1F310;</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">&#x1F504;</span> Der Lern-Kreislauf</div>
323
+ <div class="section-title"><span class="icon">&#x1F504;</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">&#x1F4E5;</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">&#x27A1;</div>
259
- <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x1F50D;</div><div class="pipe-label">Analyse</div><div class="pipe-value" id="lp-analysis">0</div></div></div>
328
+ <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x1F50D;</div><div class="pipe-label">Analysieren</div><div class="pipe-value" id="lp-analysis">0</div></div></div>
260
329
  <div class="pipe-arrow">&#x27A1;</div>
261
- <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x1F4A1;</div><div class="pipe-label">Hypothesen</div><div class="pipe-value" id="lp-hypotheses">0</div></div></div>
330
+ <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x1F4A1;</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">&#x27A1;</div>
263
- <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x1F9EA;</div><div class="pipe-label">Experimente</div><div class="pipe-value" id="lp-experiments">0</div></div></div>
332
+ <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x1F9EA;</div><div class="pipe-label">Ausprobieren</div><div class="pipe-value" id="lp-experiments">0</div></div></div>
264
333
  <div class="pipe-arrow">&#x27A1;</div>
265
- <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x1F4DC;</div><div class="pipe-label">Prinzipien</div><div class="pipe-value" id="lp-principles">0</div></div></div>
334
+ <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x1F4DC;</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">&#x27A1;</div>
267
- <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x26A1;</div><div class="pipe-label">Aktionen</div><div class="pipe-value" id="lp-actions">0</div></div></div>
336
+ <div class="pipe-stage"><div class="pipe-box"><div class="pipe-icon">&#x26A1;</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">&#x1F500;</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">&#x1F441; 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">&#x27A1;</div>
353
+ <div class="dep-group">
354
+ <div class="dep-group-title">&#x1F9E0; 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">&#x27A1;</div>
361
+ <div class="dep-group">
362
+ <div class="dep-group-title">&#x1F4A1; 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">&#x27A1;</div>
368
+ <div class="dep-group">
369
+ <div class="dep-group-title">&#x1F9EA; 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">&#x27A1;</div>
375
+ <div class="dep-group">
376
+ <div class="dep-group-title">&#x1F4DA; 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">&#x27A1;</div>
382
+ <div class="dep-group">
383
+ <div class="dep-group-title">&#x26A1; 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">&#x1F4C8;</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)">&#x2B24;</span> Regeln</span>
407
+ <span><span style="color:var(--green)">&#x2B24;</span> Lösungen</span>
408
+ <span><span style="color:var(--red)">&#x2B24;</span> Fehler</span>
409
+ </div>
410
+ </div>
411
+ </div>
412
+
270
413
  <div class="section">
271
414
  <div class="section-title"><span class="icon">&#x1F3ED;</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">&#x1F4C8;</span> Trading Pipeline</div>
422
+ <div class="section-title"><span class="icon">&#x1F4C8;</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">&#x1F4E1;</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)">&#x27A1;</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 Balance</div></div>
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">&#x1F3ED;</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">&#x1F4E3;</span> Marketing Pipeline</div>
450
+ <div class="section-title"><span class="icon">&#x1F4E3;</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">&#x270D;</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)">&#x27A1;</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">&#x1F517;</span> Cross-Brain Kommunikation</div>
476
+ <div class="section-title"><span class="icon">&#x1F517;</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">&#x1F47E;</span> Borg Sync</div>
484
+ <div class="section-title"><span class="icon">&#x1F47E;</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)">Not available</div>
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">&#x1F4DC;</span> Korrelationen</div>
352
- <div class="card"><div id="correlationList"><div class="empty">No correlations yet</div></div></div>
498
+ <div class="section-title"><span class="icon">&#x1F4DC;</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">&#x1F4C3;</span> Sync Historie</div>
357
- <div class="card"><div id="borgHistory"><div class="empty">No sync history</div></div></div>
503
+ <div class="section-title"><span class="icon">&#x1F4C3;</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: Infrastruktur ══════════════════════ -->
362
- <div class="page" id="page-infra">
363
- <div class="grid grid-2">
364
- <div class="section">
365
- <div class="section-title"><span class="icon">&#x1F6E1;</span> Watchdog</div>
366
- <div class="card" id="watchdogCard"><div class="empty">Loading...</div></div>
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">&#x1F527;</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="section">
369
- <div class="section-title"><span class="icon">&#x1F9E9;</span> Plugins</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">&#x1F3ED;</span> Alle Engines</div>
375
- <div class="engine-grid" id="allEngineGrid"><div class="empty">Loading...</div></div>
527
+ <div class="section-title"><span class="icon">&#x1F680;</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">&#x2696;</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">&#x1F4AC;</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">&#x1F525;</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">&#x26A0;</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">&#x1F6E1;</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">&#x2705;</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">&#x1F9E9;</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">&#x1F4CA;</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">&#x1F3ED;</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 = { ecosystem:null, engines:[], watchdog:[], plugins:[], borg:null, analytics:null, llm:null, thoughts:[], connected:false, lastThoughtTime:0 };
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 = { overview:'Ecosystem Overview', learning:'Der Lern-Kreislauf', trading:'Trading Flow', marketing:'Marketing Flow', crossbrain:'Cross-Brain & Borg', infra:'Infrastruktur' };
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 ? 'Connected' : 'Disconnected';
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(); renderBorg(); renderAnalytics(); renderLLM();
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">Waiting for thoughts...</div>'; cnt.textContent = ''; return; }
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 = 'Waiting...'; return; }
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 LLM Service</div>'; return; }
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">API Calls</div></div>
485
- <div class="llm-stat"><div class="llm-stat-value">${formatK(s.totalTokens ?? 0)}</div><div class="llm-stat-label">Tokens Total</div></div>
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 Hit Rate</div></div>
487
- <div class="llm-stat"><div class="llm-stat-value">${s.callsThisHour ?? 0}</div><div class="llm-stat-label">Calls/Stunde</div></div>
488
- <div class="llm-stat"><div class="llm-stat-value">${s.averageLatencyMs ? Math.round(s.averageLatencyMs) + 'ms' : '--'}</div><div class="llm-stat-label">Latenz</div></div>
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)">Model: ${s.model}</div>` : ''}
498
- ${s.providers ? `<div style="margin-top:4px;font-size:10px;color:var(--text-dim)">Provider: ${s.providers.map(p => `<span style="color:${p.available ? 'var(--green)' : 'var(--red)'}">${p.name}</span>`).join(', ')}</div>` : ''}
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' ? 'Healthy' : h.status === 'degraded' ? 'Degraded' : 'Critical';
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} methods</span>` : ''}
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">No correlations yet</div>'; return; }
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)">&#x2194;</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">No engines</div>'; return; }
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) { setText('tp-signals', a.trading.signals||0); setText('tp-trades', a.trading.trades||0); setText('tradingWinRate', a.trading.winRate ? (a.trading.winRate*100).toFixed(1)+'%' : '--'); }
585
- if (a.marketing) { setText('mp-posts', a.marketing.posts||0); setText('mp-engagement', a.marketing.engagement||0); setText('marketingCampaigns', a.marketing.campaigns||0); }
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('watchdogCard');
990
+ const el = document.getElementById('watchdogCards');
591
991
  const d = state.watchdog || [];
592
- if (!d.length) { el.innerHTML = '<div class="empty">No watchdog configured</div>'; return; }
593
- el.innerHTML = `<table class="tbl"><thead><tr><th>Daemon</th><th>Status</th><th>PID</th><th>Uptime</th><th>Restarts</th></tr></thead><tbody>` +
594
- d.map(x => `<tr><td>${x.name}</td><td><span class="dot ${x.running?'dot-on':'dot-off'}" style="margin-right:6px"></span>${x.running?(x.healthy?'Healthy':'Unhealthy'):'Stopped'}</td><td>${x.pid||'-'}</td><td>${x.uptime?fmtUp(x.uptime/1000):'-'}</td><td>${x.restarts||0}</td></tr>`).join('') + '</tbody></table>';
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 ? '&#x1F534;' : x.healthy ? '&#x1F7E2;' : '&#x1F7E1;';
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
- hc.innerHTML = `<div style="display:flex;gap:20px;align-items:center"><span style="font-size:32px">${ok?'&#x2705;':'&#x26A0;'}</span><div><div style="font-size:15px;font-weight:600;color:${ok?'var(--green)':'var(--orange)'}">${ok?'All Systems Operational':`${off} offline`}</div><div style="font-size:12px;color:var(--text-dim);margin-top:4px">${d.length} daemons</div></div></div>`;
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?'&#x2705;':off?'&#x1F6A8;':'&#x26A0;'}</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 &bull; ${d.filter(x=>x.running).length} laufen &bull; ${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">No plugins</div>'; return; }
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||'loaded'}</span></div>`).join('');
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 = 'Not available'; btn.disabled = true; return; }
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?'Active':'Disabled'} &mdash; ${s.mode}`;
614
- btn.disabled = false; btn.className = s.enabled ? 'btn btn-active' : 'btn'; btn.textContent = s.enabled ? 'Disable' : 'Enable';
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)">Sent</span><br><strong>${s.totalSent||0}</strong></div><div><span style="color:var(--text-dim)">Received</span><br><strong>${s.totalReceived||0}</strong></div></div>`;
1046
+ sEl.innerHTML = `<span class="dot ${s.enabled?'dot-on':'dot-off'}" style="margin-right:6px"></span>${s.enabled?'Aktiv':'Deaktiviert'} &mdash; ${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">No sync history</div>'; return; }
618
- hist.innerHTML = `<table class="tbl"><thead><tr><th>Zeit</th><th>Richtung</th><th>Peer</th><th>Items</th><th>Akzeptiert</th></tr></thead><tbody>` +
619
- h.slice(-15).reverse().map(x => `<tr><td>${new Date(x.timestamp).toLocaleTimeString('de-DE')}</td><td>${x.direction==='sent'?'&#x2B06;':'&#x2B07;'} ${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'?'&#x2B06;':'&#x2B07;'} ${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 = []; // big borg sync packets
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,isBorg:false});
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
- // Item count label
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
- // Borg ring (purple outer ring when borg enabled)
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
- // Label
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 ACTIVE \u2022 ${borgSent} sent \u2022 ${borgRecv} received`, w/2, h-8);
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();