@timmeck/brain-core 2.36.18 → 2.36.19

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.
@@ -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,7 @@ 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="activity"><span class="nav-icon">&#x26A1;</span><span class="nav-label">Aktivität</span></div>
190
238
  <div class="nav-item" data-page="infra"><span class="nav-icon">&#x2699;</span><span class="nav-label">Infrastruktur</span></div>
191
239
  </div>
192
240
 
@@ -207,6 +255,17 @@ canvas{display:block;width:100%;height:100%}
207
255
  <div class="content">
208
256
  <!-- ════ Page 1: Ecosystem Overview ═════════════════ -->
209
257
  <div class="page active" id="page-overview">
258
+ <!-- Quick Actions -->
259
+ <div class="section">
260
+ <div class="section-title"><span class="icon">&#x1F3AE;</span> Schnellaktionen</div>
261
+ <div class="quick-actions" id="quickActions">
262
+ <button class="action-btn" data-action="learning-cycle"><span class="action-icon">&#x1F504;</span> Lernzyklus starten</button>
263
+ <button class="action-btn" data-action="borg-sync"><span class="action-icon">&#x1F47E;</span> Borg Sync</button>
264
+ <button class="action-btn" data-action="tech-scan"><span class="action-icon">&#x1F4E1;</span> Tech-Radar Scan</button>
265
+ <button class="action-btn" data-action="health-check"><span class="action-icon">&#x1F3E5;</span> Health Check</button>
266
+ </div>
267
+ </div>
268
+
210
269
  <div class="section">
211
270
  <div class="section-title"><span class="icon">&#x1F916;</span> Brain Status</div>
212
271
  <div class="grid grid-3" id="brainCards"></div>
@@ -228,19 +287,27 @@ canvas{display:block;width:100%;height:100%}
228
287
  </div>
229
288
  </div>
230
289
  <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>
290
+ <div class="section-title"><span class="icon">&#x1F4CA;</span> KI-Nutzung</div>
291
+ <div class="card" id="llmCard"><div class="empty">Warte auf KI-Daten...</div></div>
233
292
  </div>
234
293
  </div>
235
294
 
236
295
  <div class="section">
237
296
  <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
297
  <div class="card" style="padding:0">
239
- <div class="thought-stream" id="thoughtStream"><div class="empty">Waiting for thoughts...</div></div>
298
+ <div class="thought-stream" id="thoughtStream"><div class="empty">Warte auf Gedanken...</div></div>
240
299
  </div>
241
300
  </div>
242
301
  </div>
243
302
 
303
+ <!-- Error Log -->
304
+ <div class="section">
305
+ <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>
306
+ <div class="card" style="padding:0">
307
+ <div class="error-feed" id="errorFeed"><div class="empty">Keine Fehler — alles läuft!</div></div>
308
+ </div>
309
+ </div>
310
+
244
311
  <div class="section">
245
312
  <div class="section-title"><span class="icon">&#x1F310;</span> Peer Verbindungen</div>
246
313
  <div class="card canvas-wrap" style="height:180px">
@@ -252,21 +319,96 @@ canvas{display:block;width:100%;height:100%}
252
319
  <!-- ════ Page 2: Lern-Kreislauf ═════════════════════ -->
253
320
  <div class="page" id="page-learning">
254
321
  <div class="section">
255
- <div class="section-title"><span class="icon">&#x1F504;</span> Der Lern-Kreislauf</div>
322
+ <div class="section-title"><span class="icon">&#x1F504;</span> So lernt Brain — Der Kreislauf</div>
323
+ <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
324
  <div class="pipeline" id="learnPipeline">
257
325
  <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
326
  <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>
327
+ <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
328
  <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>
329
+ <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
330
  <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>
331
+ <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
332
  <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>
333
+ <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
334
  <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>
335
+ <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>
268
336
  </div>
269
337
  </div>
338
+
339
+ <!-- Engine Dependency Flow -->
340
+ <div class="section">
341
+ <div class="section-title"><span class="icon">&#x1F500;</span> Wie die Engines zusammenarbeiten</div>
342
+ <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>
343
+ <div class="dep-flow" id="engineDependencyFlow">
344
+ <div class="dep-group">
345
+ <div class="dep-group-title">&#x1F441; Beobachten</div>
346
+ <div class="dep-engine">DataScout</div>
347
+ <div class="dep-engine">TechRadar</div>
348
+ <div class="dep-engine">SignalScanner</div>
349
+ <div class="dep-engine">AnomalyDetective</div>
350
+ </div>
351
+ <div class="dep-arrow">&#x27A1;</div>
352
+ <div class="dep-group">
353
+ <div class="dep-group-title">&#x1F9E0; Verstehen</div>
354
+ <div class="dep-engine">CausalEngine</div>
355
+ <div class="dep-engine">PatternEngine</div>
356
+ <div class="dep-engine">Curiosity</div>
357
+ <div class="dep-engine">Attention</div>
358
+ </div>
359
+ <div class="dep-arrow">&#x27A1;</div>
360
+ <div class="dep-group">
361
+ <div class="dep-group-title">&#x1F4A1; Ideen</div>
362
+ <div class="dep-engine">HypothesisEngine</div>
363
+ <div class="dep-engine">DreamEngine</div>
364
+ <div class="dep-engine">DebateEngine</div>
365
+ </div>
366
+ <div class="dep-arrow">&#x27A1;</div>
367
+ <div class="dep-group">
368
+ <div class="dep-group-title">&#x1F9EA; Testen</div>
369
+ <div class="dep-engine">ExperimentEngine</div>
370
+ <div class="dep-engine">SimulationEngine</div>
371
+ <div class="dep-engine">Prediction</div>
372
+ </div>
373
+ <div class="dep-arrow">&#x27A1;</div>
374
+ <div class="dep-group">
375
+ <div class="dep-group-title">&#x1F4DA; Wissen</div>
376
+ <div class="dep-engine">KnowledgeDistiller</div>
377
+ <div class="dep-engine">MemoryPalace</div>
378
+ <div class="dep-engine">ResearchJournal</div>
379
+ </div>
380
+ <div class="dep-arrow">&#x27A1;</div>
381
+ <div class="dep-group">
382
+ <div class="dep-group-title">&#x26A1; Handeln</div>
383
+ <div class="dep-engine">SelfMod</div>
384
+ <div class="dep-engine">GoalEngine</div>
385
+ <div class="dep-engine">Strategy</div>
386
+ <div class="dep-engine">MetaCognition</div>
387
+ </div>
388
+ </div>
389
+ </div>
390
+
391
+ <!-- Knowledge Growth -->
392
+ <div class="section">
393
+ <div class="section-title"><span class="icon">&#x1F4C8;</span> Wissens-Wachstum — Wird Brain schlauer?</div>
394
+ <div class="card">
395
+ <div class="grid grid-4" id="knowledgeTotals">
396
+ <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>
397
+ <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>
398
+ <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>
399
+ <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>
400
+ </div>
401
+ <div class="chart-wrap" id="knowledgeChart">
402
+ <svg id="knowledgeSvg" viewBox="0 0 600 180" preserveAspectRatio="none"></svg>
403
+ </div>
404
+ <div style="display:flex;gap:16px;justify-content:center;font-size:10px;color:var(--text-dim)">
405
+ <span><span style="color:var(--cyan)">&#x2B24;</span> Regeln</span>
406
+ <span><span style="color:var(--green)">&#x2B24;</span> Lösungen</span>
407
+ <span><span style="color:var(--red)">&#x2B24;</span> Fehler</span>
408
+ </div>
409
+ </div>
410
+ </div>
411
+
270
412
  <div class="section">
271
413
  <div class="section-title"><span class="icon">&#x1F3ED;</span> Engine Stationen</div>
272
414
  <div class="engine-grid" id="brainEngineGrid"><div class="empty">Loading...</div></div>
@@ -276,7 +418,8 @@ canvas{display:block;width:100%;height:100%}
276
418
  <!-- ════ Page 3: Trading Flow ═══════════════════════ -->
277
419
  <div class="page" id="page-trading">
278
420
  <div class="section">
279
- <div class="section-title"><span class="icon">&#x1F4C8;</span> Trading Pipeline</div>
421
+ <div class="section-title"><span class="icon">&#x1F4C8;</span> So tradet Trading-Brain</div>
422
+ <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
423
  <div class="pipeline">
281
424
  <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
425
  <div class="pipe-arrow" style="color:var(--green)">&#x27A1;</div>
@@ -290,9 +433,9 @@ canvas{display:block;width:100%;height:100%}
290
433
  </div>
291
434
  </div>
292
435
  <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>
436
+ <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>
437
+ <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>
438
+ <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
439
  </div>
297
440
  <div class="section" style="margin-top:16px">
298
441
  <div class="section-title"><span class="icon">&#x1F3ED;</span> Trading Engines</div>
@@ -303,7 +446,8 @@ canvas{display:block;width:100%;height:100%}
303
446
  <!-- ════ Page 4: Marketing Flow ═════════════════════ -->
304
447
  <div class="page" id="page-marketing">
305
448
  <div class="section">
306
- <div class="section-title"><span class="icon">&#x1F4E3;</span> Marketing Pipeline</div>
449
+ <div class="section-title"><span class="icon">&#x1F4E3;</span> So lernt Marketing-Brain</div>
450
+ <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
451
  <div class="pipeline">
308
452
  <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
453
  <div class="pipe-arrow" style="color:var(--magenta)">&#x27A1;</div>
@@ -328,19 +472,21 @@ canvas{display:block;width:100%;height:100%}
328
472
  <!-- ════ Page 5: Cross-Brain & Borg ═════════════════ -->
329
473
  <div class="page" id="page-crossbrain">
330
474
  <div class="section">
331
- <div class="section-title"><span class="icon">&#x1F517;</span> Cross-Brain Kommunikation</div>
475
+ <div class="section-title"><span class="icon">&#x1F517;</span> So kommunizieren die Brains</div>
476
+ <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
477
  <div class="card canvas-wrap" style="height:280px">
333
478
  <canvas id="crossBrainCanvas"></canvas>
334
479
  </div>
335
480
  </div>
336
481
  <div class="grid grid-2">
337
482
  <div class="section">
338
- <div class="section-title"><span class="icon">&#x1F47E;</span> Borg Sync</div>
483
+ <div class="section-title"><span class="icon">&#x1F47E;</span> Borg Sync — Geteiltes Wissen</div>
339
484
  <div class="card" id="borgCard">
485
+ <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
486
  <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">
341
487
  <div>
342
488
  <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>
489
+ <div id="borgStatus" style="font-size:13px;color:var(--text-dim)">Nicht verfügbar</div>
344
490
  </div>
345
491
  <button class="btn" id="borgToggle" disabled>Toggle</button>
346
492
  </div>
@@ -348,30 +494,61 @@ canvas{display:block;width:100%;height:100%}
348
494
  </div>
349
495
  </div>
350
496
  <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>
497
+ <div class="section-title"><span class="icon">&#x1F4DC;</span> Korrelationen — Was hängt zusammen?</div>
498
+ <div class="card"><div id="correlationList"><div class="empty">Noch keine Korrelationen gefunden</div></div></div>
353
499
  </div>
354
500
  </div>
355
501
  <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>
502
+ <div class="section-title"><span class="icon">&#x1F4C3;</span> Sync Verlauf</div>
503
+ <div class="card"><div id="borgHistory"><div class="empty">Noch kein Sync passiert</div></div></div>
358
504
  </div>
359
505
  </div>
360
506
 
361
- <!-- ════ Page 6: Infrastruktur ══════════════════════ -->
507
+ <!-- ════ Page 6: Activity (Self-Mod + Missions) ═════ -->
508
+ <div class="page" id="page-activity">
509
+ <!-- Self-Modification -->
510
+ <div class="section">
511
+ <div class="section-title"><span class="icon">&#x1F527;</span> Brain verbessert sich selbst</div>
512
+ <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>
513
+ <div class="grid grid-4" id="selfModStats">
514
+ <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>
515
+ <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>
516
+ <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>
517
+ <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>
518
+ </div>
519
+ <div class="card" style="padding:0;margin-top:12px">
520
+ <div style="max-height:300px;overflow-y:auto" id="selfModFeed"><div class="empty">Brain hat sich noch nicht selbst verbessert</div></div>
521
+ </div>
522
+ </div>
523
+
524
+ <!-- Mission Tracker -->
525
+ <div class="section">
526
+ <div class="section-title"><span class="icon">&#x1F680;</span> Aktive Recherche-Missionen</div>
527
+ <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>
528
+ <div class="grid grid-3" id="missionStats">
529
+ <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>
530
+ <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>
531
+ <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>
532
+ </div>
533
+ <div id="missionList" style="margin-top:12px"><div class="empty">Keine aktiven Missionen</div></div>
534
+ </div>
535
+ </div>
536
+
537
+ <!-- ════ Page 7: Infrastruktur ══════════════════════ -->
362
538
  <div class="page" id="page-infra">
363
539
  <div class="grid grid-2">
364
540
  <div class="section">
365
- <div class="section-title"><span class="icon">&#x1F6E1;</span> Watchdog</div>
541
+ <div class="section-title"><span class="icon">&#x1F6E1;</span> Watchdog — Hält alles am Laufen</div>
366
542
  <div class="card" id="watchdogCard"><div class="empty">Loading...</div></div>
367
543
  </div>
368
544
  <div class="section">
369
- <div class="section-title"><span class="icon">&#x1F9E9;</span> Plugins</div>
545
+ <div class="section-title"><span class="icon">&#x1F9E9;</span> Plugins — Erweiterungen</div>
370
546
  <div class="card" id="pluginCard"><div class="empty">Loading...</div></div>
371
547
  </div>
372
548
  </div>
373
549
  <div class="section">
374
- <div class="section-title"><span class="icon">&#x1F3ED;</span> Alle Engines</div>
550
+ <div class="section-title"><span class="icon">&#x1F3ED;</span> Alle Engines auf einen Blick</div>
551
+ <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>
375
552
  <div class="engine-grid" id="allEngineGrid"><div class="empty">Loading...</div></div>
376
553
  </div>
377
554
  <div class="section">
@@ -385,10 +562,22 @@ canvas{display:block;width:100%;height:100%}
385
562
 
386
563
  <script>
387
564
  // ── State ─────────────────────────────────────────────────
388
- const state = { ecosystem:null, engines:[], watchdog:[], plugins:[], borg:null, analytics:null, llm:null, thoughts:[], connected:false, lastThoughtTime:0 };
565
+ const state = {
566
+ ecosystem:null, engines:[], watchdog:[], plugins:[], borg:null, analytics:null,
567
+ llm:null, thoughts:[], connected:false, lastThoughtTime:0,
568
+ errors:null, selfmod:null, missions:null, knowledge:null
569
+ };
389
570
 
390
571
  // ── Navigation ────────────────────────────────────────────
391
- const titles = { overview:'Ecosystem Overview', learning:'Der Lern-Kreislauf', trading:'Trading Flow', marketing:'Marketing Flow', crossbrain:'Cross-Brain & Borg', infra:'Infrastruktur' };
572
+ const titles = {
573
+ overview:'Ecosystem Overview',
574
+ learning:'Der Lern-Kreislauf',
575
+ trading:'Trading Flow',
576
+ marketing:'Marketing Flow',
577
+ crossbrain:'Cross-Brain & Borg',
578
+ activity:'Aktivität & Missionen',
579
+ infra:'Infrastruktur'
580
+ };
392
581
  document.querySelectorAll('.nav-item').forEach(item => {
393
582
  item.addEventListener('click', () => {
394
583
  document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
@@ -410,12 +599,16 @@ function connectSSE() {
410
599
  es.addEventListener('analytics', e => { state.analytics = JSON.parse(e.data); renderAnalytics(); });
411
600
  es.addEventListener('llm', e => { state.llm = JSON.parse(e.data); renderLLM(); });
412
601
  es.addEventListener('thought', e => { addThought(JSON.parse(e.data)); });
602
+ es.addEventListener('errors', e => { state.errors = JSON.parse(e.data); renderErrors(); });
603
+ es.addEventListener('selfmod', e => { state.selfmod = JSON.parse(e.data); renderSelfMod(); });
604
+ es.addEventListener('missions', e => { state.missions = JSON.parse(e.data); renderMissions(); });
605
+ es.addEventListener('knowledge', e => { state.knowledge = JSON.parse(e.data); renderKnowledge(); });
413
606
  es.onerror = () => { state.connected = false; updateConnection(); };
414
607
  }
415
608
 
416
609
  function updateConnection() {
417
610
  const b = document.getElementById('connectionBadge');
418
- b.textContent = state.connected ? 'Connected' : 'Disconnected';
611
+ b.textContent = state.connected ? 'Verbunden' : 'Getrennt';
419
612
  b.className = 'badge ' + (state.connected ? 'badge-ok' : 'badge-err');
420
613
  }
421
614
 
@@ -426,8 +619,12 @@ async function loadInitial() {
426
619
  state.ecosystem = data.ecosystem; state.engines = data.engines || [];
427
620
  state.watchdog = data.watchdog || []; state.plugins = data.plugins || [];
428
621
  state.borg = data.borg; state.analytics = data.analytics; state.llm = data.llm;
622
+ state.errors = data.errors; state.selfmod = data.selfmod;
623
+ state.missions = data.missions; state.knowledge = data.knowledge;
429
624
  if (data.thoughts) { state.thoughts = data.thoughts; renderThoughts(); }
430
- renderEcosystem(); renderEngines(); renderWatchdog(); renderPlugins(); renderBorg(); renderAnalytics(); renderLLM();
625
+ renderEcosystem(); renderEngines(); renderWatchdog(); renderPlugins();
626
+ renderBorg(); renderAnalytics(); renderLLM(); renderErrors();
627
+ renderSelfMod(); renderMissions(); renderKnowledge();
431
628
  } catch {}
432
629
  }
433
630
 
@@ -443,12 +640,12 @@ function addThought(t) {
443
640
  function renderThoughts() {
444
641
  const el = document.getElementById('thoughtStream');
445
642
  const cnt = document.getElementById('thoughtCount');
446
- if (!state.thoughts.length) { el.innerHTML = '<div class="empty">Waiting for thoughts...</div>'; cnt.textContent = ''; return; }
643
+ if (!state.thoughts.length) { el.innerHTML = '<div class="empty">Warte auf Gedanken...</div>'; cnt.textContent = ''; return; }
447
644
  cnt.textContent = `(${state.thoughts.length})`;
448
645
  el.innerHTML = state.thoughts.slice(0, 50).map(t => {
449
646
  const time = new Date(t.timestamp).toLocaleTimeString('de-DE', { hour:'2-digit', minute:'2-digit', second:'2-digit' });
450
647
  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' : '';
648
+ const sigLabel = t.significance === 'breakthrough' ? 'Durchbruch!' : t.significance === 'notable' ? 'Bemerkenswert' : '';
452
649
  return `<div class="thought-item">
453
650
  <span class="thought-time">${time}</span>
454
651
  <span class="thought-engine" style="color:var(--cyan)">${t.engine}</span>
@@ -463,7 +660,7 @@ function updatePulse() {
463
660
  const dot = document.getElementById('pulseDot');
464
661
  const label = document.getElementById('pulseLabel');
465
662
  const age = Date.now() - state.lastThoughtTime;
466
- if (state.lastThoughtTime === 0) { dot.className = 'pulse-dot off'; label.textContent = 'Waiting...'; return; }
663
+ if (state.lastThoughtTime === 0) { dot.className = 'pulse-dot off'; label.textContent = 'Warte...'; return; }
467
664
  if (age < 30000) { dot.className = 'pulse-dot'; label.textContent = 'Brain arbeitet'; }
468
665
  else if (age < 120000) { dot.className = 'pulse-dot idle'; label.textContent = 'Idle'; }
469
666
  else { dot.className = 'pulse-dot off'; label.textContent = 'Ruhig'; }
@@ -474,57 +671,203 @@ setInterval(updatePulse, 5000);
474
671
  function renderLLM() {
475
672
  const el = document.getElementById('llmCard');
476
673
  const s = state.llm;
477
- if (!s) { el.innerHTML = '<div class="empty">Kein LLM Service</div>'; return; }
674
+ if (!s) { el.innerHTML = '<div class="empty">Kein KI-Service aktiv</div>'; return; }
478
675
 
479
676
  const hourPct = s.tokensThisHour && s.budgetRemainingHour != null ? Math.min(100, (s.tokensThisHour / (s.tokensThisHour + s.budgetRemainingHour)) * 100) : 0;
480
677
  const dayPct = s.tokensToday && s.budgetRemainingDay != null ? Math.min(100, (s.tokensToday / (s.tokensToday + s.budgetRemainingDay)) * 100) : 0;
481
678
 
482
679
  el.innerHTML = `
483
680
  <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>
681
+ <div class="llm-stat"><div class="llm-stat-value">${s.totalCalls ?? 0}</div><div class="llm-stat-label">KI-Anfragen</div></div>
682
+ <div class="llm-stat"><div class="llm-stat-value">${formatK(s.totalTokens ?? 0)}</div><div class="llm-stat-label">Tokens verbraucht</div></div>
683
+ <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>
684
+ <div class="llm-stat"><div class="llm-stat-value">${s.callsThisHour ?? 0}</div><div class="llm-stat-label">Anfragen/Stunde</div></div>
685
+ <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>
686
+ <div class="llm-stat"><div class="llm-stat-value">${s.errors ?? 0}</div><div class="llm-stat-label">KI-Fehler</div></div>
490
687
  </div>
491
688
  <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>
689
+ <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
690
  <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>
691
+ <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
692
  <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
693
  </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>` : ''}
694
+ ${s.model ? `<div style="margin-top:10px;font-size:10px;color:var(--text-dim)">KI-Modell: ${s.model}</div>` : ''}
695
+ ${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
696
  `;
500
697
  }
501
698
 
699
+ // ── Error Log ─────────────────────────────────────────────
700
+ function renderErrors() {
701
+ const el = document.getElementById('errorFeed');
702
+ const cnt = document.getElementById('errorCount');
703
+ const d = state.errors;
704
+ if (!d) { el.innerHTML = '<div class="empty">Keine Fehler — alles läuft!</div>'; cnt.textContent = ''; return; }
705
+ const errors = d.errors || d;
706
+ if (!Array.isArray(errors) || !errors.length) { el.innerHTML = '<div class="empty">Keine Fehler — alles läuft!</div>'; cnt.textContent = ''; return; }
707
+ cnt.textContent = `(${errors.length})`;
708
+ el.innerHTML = errors.slice(0, 20).map(e => {
709
+ const time = e.timestamp ? new Date(e.timestamp).toLocaleTimeString('de-DE', { hour:'2-digit', minute:'2-digit' }) : '';
710
+ const level = e.resolved ? 'warn' : 'err';
711
+ const msg = e.message || e.error_message || e.title || 'Unbekannter Fehler';
712
+ const source = e.source || e.project || '';
713
+ return `<div class="error-item">
714
+ <span class="thought-time">${time}</span>
715
+ <span class="error-level ${level}">${e.resolved ? 'Gelöst' : 'Fehler'}</span>
716
+ ${source ? `<span style="font-size:11px;color:var(--cyan);min-width:60px">${escHtml(source)}</span>` : ''}
717
+ <span class="error-msg">${escHtml(msg)}</span>
718
+ </div>`;
719
+ }).join('');
720
+ }
721
+
722
+ // ── Self-Mod Activity ─────────────────────────────────────
723
+ function renderSelfMod() {
724
+ const d = state.selfmod;
725
+ if (!d || !d.status) {
726
+ setText('sm-total', 0); setText('sm-applied', 0); setText('sm-testing', 0); setText('sm-failed', 0);
727
+ document.getElementById('selfModFeed').innerHTML = '<div class="empty">Brain hat sich noch nicht selbst verbessert</div>';
728
+ return;
729
+ }
730
+ const s = d.status;
731
+ setText('sm-total', s.totalModifications || 0);
732
+ const byStatus = s.byStatus || {};
733
+ setText('sm-applied', byStatus.applied || 0);
734
+ setText('sm-testing', (byStatus.testing || 0) + (byStatus.generating || 0));
735
+ setText('sm-failed', (byStatus.failed || 0) + (byStatus.rejected || 0));
736
+
737
+ const hist = d.history || [];
738
+ const el = document.getElementById('selfModFeed');
739
+ if (!hist.length) { el.innerHTML = '<div class="empty">Noch keine Verbesserungen</div>'; return; }
740
+ el.innerHTML = hist.map(m => {
741
+ const statusMap = { applied:'Angewendet', testing:'Wird getestet', ready:'Bereit', proposed:'Vorgeschlagen', generating:'Generiert', failed:'Fehlgeschlagen', rejected:'Abgelehnt', rolled_back:'Zurückgesetzt' };
742
+ 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';
743
+ 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' }) : '';
744
+ return `<div class="mod-item">
745
+ <span class="mod-status ${statusClass}">${statusMap[m.status] || m.status}</span>
746
+ <div style="flex:1">
747
+ <div class="mod-title">${escHtml(m.title || 'Verbesserung')}</div>
748
+ <div class="mod-detail">${escHtml(m.problem_description || '')} ${time ? `<span style="float:right">${time}</span>` : ''}</div>
749
+ ${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>` : ''}
750
+ </div>
751
+ </div>`;
752
+ }).join('');
753
+ }
754
+
755
+ // ── Mission Tracker ───────────────────────────────────────
756
+ function renderMissions() {
757
+ const d = state.missions;
758
+ if (!d || !d.status) {
759
+ setText('ms-active', 0); setText('ms-completed', 0); setText('ms-sources', 0);
760
+ document.getElementById('missionList').innerHTML = '<div class="empty">Keine aktiven Missionen</div>';
761
+ return;
762
+ }
763
+ const s = d.status;
764
+ setText('ms-active', s.activeMissions || 0);
765
+ setText('ms-completed', s.completedMissions || 0);
766
+ setText('ms-sources', s.totalSources || 0);
767
+
768
+ const list = d.list || [];
769
+ const el = document.getElementById('missionList');
770
+ if (!list.length) { el.innerHTML = '<div class="empty">Keine aktiven Missionen</div>'; return; }
771
+ const phases = ['decomposing','gathering','hypothesizing','analyzing','synthesizing'];
772
+ const phaseLabels = { decomposing:'Aufteilen', gathering:'Sammeln', hypothesizing:'Ideen bilden', analyzing:'Analysieren', synthesizing:'Zusammenfassen' };
773
+ el.innerHTML = list.slice(0, 10).map(m => {
774
+ const statusIdx = phases.indexOf(m.status);
775
+ const phaseHtml = phases.map((p, i) => {
776
+ const cls = m.status === 'complete' ? 'done' : m.status === 'failed' ? (i <= statusIdx ? 'fail' : '') : (i < statusIdx ? 'done' : i === statusIdx ? 'running' : '');
777
+ return `<div class="mission-phase ${cls}" title="${phaseLabels[p] || p}"></div>`;
778
+ }).join('');
779
+ const statusText = m.status === 'complete' ? 'Fertig' : m.status === 'failed' ? 'Fehlgeschlagen' : phaseLabels[m.status] || m.status;
780
+ const depth = m.depth === 'deep' ? 'Tiefgehend' : m.depth === 'quick' ? 'Schnell' : 'Standard';
781
+ return `<div class="mission-card">
782
+ <div class="mission-topic">${escHtml(m.topic || 'Mission')}</div>
783
+ <div style="font-size:11px;color:var(--text-dim)">${statusText} — ${depth} — ${m.sourceCount || 0} Quellen</div>
784
+ <div class="mission-phases">${phaseHtml}</div>
785
+ <div class="mission-meta">
786
+ <span>Gestartet: ${m.createdAt ? new Date(m.createdAt).toLocaleString('de-DE', { day:'2-digit', month:'2-digit', hour:'2-digit', minute:'2-digit' }) : '?'}</span>
787
+ ${m.completedAt ? `<span>Fertig: ${new Date(m.completedAt).toLocaleString('de-DE', { day:'2-digit', month:'2-digit', hour:'2-digit', minute:'2-digit' })}</span>` : ''}
788
+ </div>
789
+ </div>`;
790
+ }).join('');
791
+ }
792
+
793
+ // ── Knowledge Growth ──────────────────────────────────────
794
+ function renderKnowledge() {
795
+ const d = state.knowledge;
796
+ if (!d) return;
797
+ // Totals
798
+ if (d.totals) {
799
+ setText('kn-principles', d.totals.principles || d.totals.rules || 0);
800
+ setText('kn-hypotheses', d.totals.hypotheses || 0);
801
+ setText('kn-experiments', d.totals.experiments || 0);
802
+ setText('kn-errors', d.totals.errorsSolved || d.totals.solutions || 0);
803
+ }
804
+ // Time series chart
805
+ const ts = d.timeSeries || [];
806
+ if (!ts.length) return;
807
+ drawKnowledgeChart(ts);
808
+ }
809
+
810
+ function drawKnowledgeChart(data) {
811
+ const svg = document.getElementById('knowledgeSvg');
812
+ if (!svg || !data.length) return;
813
+ const w = 600, h = 180, pad = 30;
814
+ const maxVal = Math.max(1, ...data.map(d => Math.max(d.errors || 0, d.solutions || 0)));
815
+ const xStep = (w - pad * 2) / Math.max(1, data.length - 1);
816
+
817
+ function path(key, color) {
818
+ const pts = data.map((d, i) => {
819
+ const x = pad + i * xStep;
820
+ const y = h - pad - ((d[key] || 0) / maxVal) * (h - pad * 2);
821
+ return `${i === 0 ? 'M' : 'L'}${x},${y}`;
822
+ }).join(' ');
823
+ return `<path d="${pts}" fill="none" stroke="${color}" stroke-width="2" stroke-linecap="round"/>`;
824
+ }
825
+
826
+ // Grid lines
827
+ let grid = '';
828
+ for (let i = 0; i <= 4; i++) {
829
+ const y = pad + (i / 4) * (h - pad * 2);
830
+ grid += `<line x1="${pad}" y1="${y}" x2="${w-pad}" y2="${y}" stroke="rgba(100,140,255,0.08)" stroke-width="1"/>`;
831
+ }
832
+ // X labels (show every few)
833
+ let labels = '';
834
+ const step = Math.max(1, Math.floor(data.length / 7));
835
+ for (let i = 0; i < data.length; i += step) {
836
+ const x = pad + i * xStep;
837
+ const d = data[i].date || '';
838
+ labels += `<text x="${x}" y="${h-5}" text-anchor="middle" fill="var(--text-dim)" font-size="9">${d.slice(5)}</text>`;
839
+ }
840
+
841
+ svg.innerHTML = grid + labels + path('errors', '#ff4466') + path('solutions', '#00ff88');
842
+ }
843
+
502
844
  // ── Render: Ecosystem ─────────────────────────────────────
503
845
  function renderEcosystem() {
504
846
  const eco = state.ecosystem; if (!eco) return;
505
847
  const hb = document.getElementById('healthBadge');
506
848
  const h = eco.health;
507
849
  if (h) {
508
- hb.textContent = h.status === 'healthy' ? 'Healthy' : h.status === 'degraded' ? 'Degraded' : 'Critical';
850
+ hb.textContent = h.status === 'healthy' ? 'Gesund' : h.status === 'degraded' ? 'Eingeschränkt' : 'Kritisch';
509
851
  hb.className = 'badge ' + (h.status === 'healthy' ? 'badge-ok' : h.status === 'degraded' ? 'badge-warn' : 'badge-err');
510
852
  const score = h.score || 0;
511
853
  document.getElementById('gaugeArc').setAttribute('stroke-dasharray', `${(score / 100) * 172} 172`);
512
854
  document.getElementById('gaugeArc').setAttribute('stroke', score > 70 ? 'var(--green)' : score > 40 ? 'var(--orange)' : 'var(--red)');
513
855
  document.getElementById('gaugeValue').textContent = Math.round(score);
514
856
  }
515
- // Brain cards
516
857
  const container = document.getElementById('brainCards');
517
858
  const brainNames = ['brain', 'trading-brain', 'marketing-brain'];
518
859
  const labels = { brain:'Brain', 'trading-brain':'Trading-Brain', 'marketing-brain':'Marketing-Brain' };
860
+ const descs = { brain:'Lernt aus Fehlern, verbessert Code', 'trading-brain':'Paper Trading, Signal-Analyse', 'marketing-brain':'Content-Strategie, Engagement' };
519
861
  const classes = { brain:'brain-brain', 'trading-brain':'brain-trading', 'marketing-brain':'brain-marketing' };
520
862
  container.innerHTML = brainNames.map(name => {
521
863
  const b = (eco.brains || []).find(x => x.name === name) || { name, available:false };
522
864
  return `<div class="card brain-card ${classes[name]}">
523
865
  <div class="brain-status"><span class="dot ${b.available ? 'dot-on' : 'dot-off'}"></span><span class="brain-name">${labels[name]}</span></div>
866
+ <div style="font-size:11px;color:var(--text-dim);margin-bottom:6px">${descs[name]}</div>
524
867
  <div class="brain-meta">
525
868
  <span>${b.available ? 'Online' : 'Offline'}</span>
526
869
  ${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>` : ''}
870
+ ${b.uptime ? `<span>${fmtUp(b.uptime)}</span>` : ''}${b.methods ? `<span>${b.methods} Tools</span>` : ''}
528
871
  </div></div>`;
529
872
  }).join('');
530
873
  drawPeerGraph(eco.brains || []);
@@ -533,7 +876,7 @@ function renderEcosystem() {
533
876
 
534
877
  function renderCorrelations(c) {
535
878
  const el = document.getElementById('correlationList');
536
- if (!c.length) { el.innerHTML = '<div class="empty">No correlations yet</div>'; return; }
879
+ if (!c.length) { el.innerHTML = '<div class="empty">Noch keine Zusammenhänge gefunden</div>'; return; }
537
880
  el.innerHTML = c.slice(0, 10).map(x => `<div style="padding:6px 0;border-bottom:1px solid var(--border);font-size:12px">
538
881
  <span style="color:var(--cyan)">${x.sourceA}/${x.eventA}</span> <span style="color:var(--text-dim)">&#x2194;</span>
539
882
  <span style="color:var(--magenta)">${x.sourceB}/${x.eventB}</span>
@@ -555,7 +898,7 @@ function renderEngines() {
555
898
 
556
899
  function renderGrid(id, engines, showBrain = false) {
557
900
  const el = document.getElementById(id); if (!el) return;
558
- if (!engines.length) { el.innerHTML = '<div class="empty">No engines</div>'; return; }
901
+ if (!engines.length) { el.innerHTML = '<div class="empty">Keine Engines</div>'; return; }
559
902
  el.innerHTML = engines.map(e => {
560
903
  const st = e.lastActivity && (Date.now() - e.lastActivity < 60000) ? 'active' : e.thoughtCount > 0 ? 'idle' : 'off';
561
904
  const lbl = showBrain && e.brain ? `${e.brain}/${e.engine}` : (e.engine || e.name || '?');
@@ -581,48 +924,82 @@ function updateLearningPipeline(engines) {
581
924
  // ── Render: Analytics ─────────────────────────────────────
582
925
  function renderAnalytics() {
583
926
  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); }
927
+ if (a.trading) {
928
+ const t = a.trading;
929
+ setText('tp-signals', num(t.signals));
930
+ setText('tp-trades', num(t.trades));
931
+ setText('tradingWinRate', t.winRate ? (Number(t.winRate)*100).toFixed(1)+'%' : '--');
932
+ setText('tradingEquity', t.equity ? '$'+Number(t.equity).toLocaleString() : '--');
933
+ setText('tradingPositions', num(t.positions));
934
+ }
935
+ if (a.marketing) {
936
+ const m = a.marketing;
937
+ setText('mp-posts', num(m.posts));
938
+ setText('mp-engagement', num(m.engagement));
939
+ setText('marketingCampaigns', num(m.campaigns));
940
+ }
586
941
  }
942
+ 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
943
 
588
944
  // ── Render: Watchdog ──────────────────────────────────────
589
945
  function renderWatchdog() {
590
946
  const el = document.getElementById('watchdogCard');
591
947
  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>';
948
+ if (!d.length) { el.innerHTML = '<div class="empty">Kein Watchdog konfiguriert</div>'; return; }
949
+ el.innerHTML = `<table class="tbl"><thead><tr><th>Dienst</th><th>Status</th><th>PID</th><th>Laufzeit</th><th>Neustarts</th></tr></thead><tbody>` +
950
+ 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?'Gesund':'Problem'):'Gestoppt'}</td><td>${x.pid||'-'}</td><td>${x.uptime?fmtUp(x.uptime/1000):'-'}</td><td>${x.restarts||0}</td></tr>`).join('') + '</tbody></table>';
595
951
  const hc = document.getElementById('healthCheckCard');
596
952
  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>`;
953
+ 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?'Alle Systeme laufen':`${off} Dienste offline`}</div><div style="font-size:12px;color:var(--text-dim);margin-top:4px">${d.length} Dienste überwacht</div></div></div>`;
598
954
  }
599
955
 
600
956
  function renderPlugins() {
601
957
  const el = document.getElementById('pluginCard');
602
958
  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('');
959
+ if (!p.length) { el.innerHTML = '<div class="empty">Keine Plugins installiert</div>'; return; }
960
+ 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
961
  }
606
962
 
607
963
  // ── Render: Borg ──────────────────────────────────────────
608
964
  function renderBorg() {
609
965
  const b = state.borg;
610
966
  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; }
967
+ if (!b || !b.status) { sEl.textContent = 'Nicht verfügbar'; btn.disabled = true; return; }
612
968
  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>`;
969
+ sEl.innerHTML = `<span class="dot ${s.enabled?'dot-on':'dot-off'}" style="margin-right:6px"></span>${s.enabled?'Aktiv':'Deaktiviert'} &mdash; ${s.mode || 'Standard'}`;
970
+ btn.disabled = false; btn.className = s.enabled ? 'btn btn-active' : 'btn'; btn.textContent = s.enabled ? 'Deaktivieren' : 'Aktivieren';
971
+ 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
972
  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>';
973
+ if (!h.length) { hist.innerHTML = '<div class="empty">Noch kein Sync passiert</div>'; return; }
974
+ 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>` +
975
+ 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
976
  }
621
977
  document.getElementById('borgToggle').addEventListener('click', async () => {
622
978
  if (!state.borg?.status) return;
623
979
  try { await fetch('/api/borg/toggle', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({enabled:!state.borg.status.enabled}) }); } catch {}
624
980
  });
625
981
 
982
+ // ── Quick Actions ─────────────────────────────────────────
983
+ document.querySelectorAll('.action-btn').forEach(btn => {
984
+ btn.addEventListener('click', async () => {
985
+ const action = btn.dataset.action;
986
+ btn.classList.add('running');
987
+ btn.querySelector('.action-icon').textContent = '\u23F3';
988
+ try {
989
+ const res = await fetch('/api/action', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ action }) });
990
+ const data = await res.json();
991
+ btn.querySelector('.action-icon').textContent = data.ok ? '\u2705' : '\u274C';
992
+ } catch {
993
+ btn.querySelector('.action-icon').textContent = '\u274C';
994
+ }
995
+ setTimeout(() => {
996
+ btn.classList.remove('running');
997
+ const icons = { 'learning-cycle':'\u{1F504}', 'borg-sync':'\u{1F47E}', 'tech-scan':'\u{1F4E1}', 'health-check':'\u{1F3E5}' };
998
+ btn.querySelector('.action-icon').textContent = icons[action] || '\u26A1';
999
+ }, 2000);
1000
+ });
1001
+ });
1002
+
626
1003
  // ── Canvas: Peer Graph ────────────────────────────────────
627
1004
  function drawPeerGraph(brains) {
628
1005
  const canvas = document.getElementById('peerCanvas'); if (!canvas) return;
@@ -650,11 +1027,10 @@ function drawPeerGraph(brains) {
650
1027
 
651
1028
  // ── Canvas: Cross-Brain + Borg Animation ──────────────────
652
1029
  let particles = [];
653
- let borgPackets = []; // big borg sync packets
1030
+ let borgPackets = [];
654
1031
  function spawnBorgPacket(src, dst, items) {
655
1032
  borgPackets.push({ src, dst, items, progress: 0, speed: 0.004 + Math.random() * 0.003 });
656
1033
  }
657
- // When borg data updates, spawn visual packets from history
658
1034
  let lastBorgHistLen = 0;
659
1035
  function checkBorgPackets() {
660
1036
  const h = state.borg?.history || [];
@@ -685,35 +1061,24 @@ function initCrossBrainCanvas() {
685
1061
  let s=n[Math.random()*n.length|0],d=n[Math.random()*n.length|0];
686
1062
  while(d===s)d=n[Math.random()*n.length|0];
687
1063
  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});
1064
+ 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
1065
  }
690
1066
 
691
1067
  function draw() {
692
1068
  const ctx=canvas.getContext('2d'),w=canvas.width/2,h=canvas.height/2;
693
1069
  ctx.save(); ctx.scale(2,2); ctx.clearRect(0,0,w,h); getPos();
694
1070
  checkBorgPackets();
695
-
696
1071
  const borgEnabled = state.borg?.status?.enabled;
697
1072
  const borgSent = state.borg?.status?.totalSent || 0;
698
1073
  const borgRecv = state.borg?.status?.totalReceived || 0;
699
1074
  const n=Object.keys(positions);
700
-
701
- // Draw connections
702
1075
  for(let i=0;i<n.length;i++) for(let j=i+1;j<n.length;j++) {
703
1076
  const a=positions[n[i]],b=positions[n[j]];
704
- // Borg connections glow brighter when enabled
705
1077
  ctx.beginPath(); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y);
706
1078
  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
- }
1079
+ ctx.lineWidth = borgEnabled ? 2 : 1; ctx.stroke();
1080
+ 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
1081
  }
715
-
716
- // Regular message particles
717
1082
  if(Math.random()<.05&&state.connected) spawnMsg();
718
1083
  particles=particles.filter(p=>p.progress<1);
719
1084
  for(const p of particles) {
@@ -723,56 +1088,33 @@ function initCrossBrainCanvas() {
723
1088
  const g=ctx.createRadialGradient(cx,cy,0,cx,cy,6); g.addColorStop(0,p.color+'40'); g.addColorStop(1,p.color+'00');
724
1089
  ctx.beginPath(); ctx.arc(cx,cy,6,0,Math.PI*2); ctx.fillStyle=g; ctx.fill();
725
1090
  }
726
-
727
- // Borg sync packets — bigger, purple, with item count label
728
1091
  borgPackets=borgPackets.filter(p=>p.progress<1);
729
1092
  for(const bp of borgPackets) {
730
1093
  bp.progress+=bp.speed;
731
1094
  const t=bp.progress;
732
1095
  const sp=positions[bp.src]||positions.brain, dp=positions[bp.dst]||positions.brain;
733
1096
  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
1097
  ctx.beginPath(); ctx.arc(cx,cy,14,0,Math.PI*2);
736
1098
  const gg=ctx.createRadialGradient(cx,cy,0,cx,cy,14);
737
1099
  gg.addColorStop(0,'rgba(170,136,255,0.35)'); gg.addColorStop(1,'rgba(170,136,255,0)');
738
1100
  ctx.fillStyle=gg; ctx.fill();
739
- // Inner packet
740
1101
  ctx.beginPath(); ctx.arc(cx,cy,6,0,Math.PI*2); ctx.fillStyle='#aa88ff'; ctx.fill();
741
1102
  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
- }
1103
+ 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
1104
  }
748
-
749
- // Draw nodes
750
1105
  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
1106
+ 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
1107
  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
1108
+ 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
1109
  ctx.beginPath(); ctx.arc(p.x,p.y,18,0,Math.PI*2);
762
1110
  ctx.fillStyle=p.color+'15'; ctx.strokeStyle=p.color; ctx.lineWidth=2; ctx.fill(); ctx.stroke();
763
- // Inner dot
764
1111
  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);
1112
+ ctx.fillStyle='#fff'; ctx.font='12px Segoe UI,sans-serif'; ctx.textAlign='center'; ctx.fillText(p.label,p.x,p.y+34);
768
1113
  }
769
-
770
- // Borg legend (bottom center)
771
1114
  if(borgEnabled) {
772
1115
  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);
1116
+ ctx.fillText(`BORG AKTIV \u2022 ${borgSent} gesendet \u2022 ${borgRecv} empfangen`, w/2, h-8);
774
1117
  }
775
-
776
1118
  ctx.restore(); requestAnimationFrame(draw);
777
1119
  }
778
1120
  draw();