File size: 11,157 Bytes
bbc65cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# ClaudeCodePanel β€” Wie dein Panel funktioniert

## Die Kurzversion

Dein Panel ist wie ein **Cockpit fuer Claude Code**. Statt 15 Terminal-Fenster
und Config-Dateien zu jonglieren, hast du ein GTK3-Fenster mit 7 Tabs
und ein Tray-Icon das immer da ist. Denk an ein Auto-Armaturenbrett:
Tacho (Monitor), Bordcomputer (Hub), Fehlerlampen (Logs), Navigationsliste (Sessions).

**Stack:** Python 3.12 + PyGObject (GTK3) + Catppuccin Theming + systemd Service

---

## Architektur β€” 14 Module

### panel.py (2373 Zeilen) β€” Der Dirigent
Das Hauptfenster. Baut alle Tabs zusammen, startet die Timer, verwaltet das Tray-Icon.
Wie ein Dirigent: spielt selbst kein Instrument, aber koordiniert alle anderen.

**Key:** `ControlPanel` Klasse mit `_build_*_tab()` Methoden, `_refresh_hub()`, `_refresh_monitor()`.

### monitor.py (729 Zeilen) β€” Der Daten-Butler
Holt alle Zahlen: Kosten, Top-Tools, aktive Sessions, Timeline.
Hat einen TTL-Cache (30 Sekunden) β€” fragt nicht staendig die Festplatte.

**Key:** `get_daily_cost()`, `get_top_tools()`, `get_active_sessions()`. Nutzt MyAIGame's `tui.data.*` Module.

### log_viewer.py (435 Zeilen) β€” Der Protokollant
Zeigt heutige Usage-Eintraege und Coaching-Log. Filterbar nach Tools/Errors/Hooks.

**Key:** `build_logs_tab()`, `refresh_logs()`. Liest `~/.claude/usage/YYYY-MM-DD.jsonl`.

### session_browser.py (1039 Zeilen) β€” Das Telefonbuch
Alle Claude-Sessions durchsuchbar. Zeigt Projekt, Vorschau, Groesse. Resume-Button oeffnet kitty.

**Key:** `build_sessions_tab()`, `_scan_all_sessions()`, `_on_resume_clicked()`.

### process_manager.py (588 Zeilen) β€” Der Hausmeister
Scannt `ps aux` nach Claude-relevanten Prozessen. Zeigt RAM, CPU, Uptime.
Kill-Button pro Prozess + "Kill All Ghosts" fuer Prozesse >24h.

**Key:** `build_processes_tab()`, `_scan_processes()`, Ghost-Detection via `/proc/<pid>/stat`.

### theme.py (620 Zeilen) β€” Der Maler
Erkennt ob COSMIC Desktop dunkel oder hell ist, generiert passendes CSS.
Catppuccin Mocha (dark) / Latte (light). Wechselt live wenn du das System-Theme aenderst.

**Key:** `is_dark_mode()` liest `~/.config/cosmic/com.system76.CosmicTheme.Mode/v1/is_dark`.
`setup_theme_watcher()` nutzt `Gio.FileMonitor` fuer Live-Updates.

### config_io.py (168 Zeilen) β€” Der Tresorwaerter
Liest und schreibt `~/.claude/settings.json` **atomar** β€” nie direkt.
Immer: Backup β†’ Temp-Datei β†’ `os.replace()`. So geht nie was kaputt.

**Key:** `read_settings()`, `write_settings()`, `update_setting("key.path", value)`.

### swarm_tab.py (974 Zeilen) β€” Der Lageplaner
Zeigt die laufende Agent Team Pipeline in Echtzeit. Liest `~/.claude/teams/` und
`~/.claude/tasks/` und stellt Scout→Weaver→Builder→Validator→Pruefer als Karten dar.

**Key:** `build_swarm_tab()`, `_scan_teams()`, `_refresh_swarm()`.

### swarm_visual.py (708 Zeilen) β€” Der Kartograf
Generiert HTML-Seiten mit interaktiven Agent-Kommunikationsgraphen: Hub-and-Spoke-Layout,
Bezier-Kurven, Partikel-Animationen. Wird von swarm_tab.py aufgerufen und in WebKit2 eingebettet.

**Key:** `generate_swarm_html()`, Bezier + Partikel-Rendering via Canvas.

### event_tab.py (426 Zeilen) β€” Der Horcher
Live-Viewer fuer Hook-Events aus `~/.claude/events/YYYY-MM-DD.jsonl`. Filterbar
nach Event-Typ, Auto-Scroll wenn neue Events reinkommen.

**Key:** `build_events_tab()`, `_tail_events()`, Filter-Logik nach Typ/Quelle.

### shortcut_counter_tab.py (450 Zeilen) β€” Der Strichlisten-Fuehrer
Zeigt Keyboard-Shortcut-Statistiken aus der ShortcutCounter-Datenbank. Wie oft hast
du Ctrl+C vs. Ctrl+Z genutzt? Welcher Shortcut spart am meisten Zeit?

**Key:** `build_shortcut_tab()`, liest ShortcutCounter SQLite DB.

### project_dashboard_tab.py (254 Zeilen) β€” Das Fenster
Bettet das Project Dashboard als WebKit2-Webview direkt ins Panel ein, statt
einen Browser oeffnen zu muessen. Ein Tab = ein komplettes Web-Dashboard.

**Key:** `build_project_dashboard_tab()`, `WebKit2.WebView` Setup + Reload-Button.

### utils.py (33 Zeilen) β€” Der Werkzeugkasten
Kleine Hilfsfunktionen die ueberall gebraucht werden (Format-Helpers, Pfad-Utilities).
Klein aber da wenn man ihn braucht.

**Key:** Shared Utilities fuer alle anderen Module.

### tools-gui/ (623 Zeilen) β€” Das Zweite Cockpit
Separates GTK3-Fenster mit 3 eigenen Tabs: Kosten-Analyse, Session-Uebersicht, Tool-Statistiken.
Laeuft als eigenstaendiges Fenster neben dem Hauptpanel (main.py + 3 Tab-Module).

**Key:** `tools-gui/main.py` als Einstiegspunkt, 3 Tab-Module fuer costs/sessions/tools.

---

## Wie die Tabs zusammenhaengen

```
panel.py (Dirigent)
  β”œβ”€β”€ importiert monitor.py        β†’ liefert Daten fuer Hub + Monitor Tab
  β”œβ”€β”€ importiert log_viewer.py     β†’ baut Logs Tab
  β”œβ”€β”€ importiert session_browser.py β†’ baut Sessions Tab
  β”œβ”€β”€ importiert process_manager.py β†’ baut Prozesse Tab
  β”œβ”€β”€ importiert swarm_tab.py      β†’ baut Agent Swarm Tab
  β”œβ”€β”€ importiert swarm_visual.py   β†’ generiert Swarm-Graphen (HTML)
  β”œβ”€β”€ importiert event_tab.py      β†’ baut Events Tab
  β”œβ”€β”€ importiert shortcut_counter_tab.py β†’ baut Shortcut Counter Tab
  β”œβ”€β”€ importiert project_dashboard_tab.py β†’ baut Project Dashboard Tab (WebKit2)
  β”œβ”€β”€ importiert theme.py          β†’ CSS + Theme Watcher
  └── importiert config_io.py      β†’ Settings + Hooks Tabs lesen/schreiben Config
```

Jedes Modul ist **eigenstaendig** β€” kann theoretisch allein funktionieren.
panel.py ist nur der Rahmen der sie zusammenbringt.

---

## Timer-System β€” Das Herzschlag-System

Dein Panel hat 6 Timer die wie Herzschlaege funktionieren. Jeder Timer
ruft periodisch eine Funktion auf die Daten aktualisiert:

| Timer | Intervall | Funktion | Was wird aktualisiert? |
|-------|-----------|----------|----------------------|
| Hub | 30s | `_refresh_hub()` | Kosten, Top-Tools, Sessions |
| Monitor-Start | 15s | `_start_monitor_timer()` | Startet Monitor-Timer |
| Logs | 10s | `refresh_logs()` | Usage + Coaching Eintraege |
| Sessions | 60s | `refresh_sessions()` | Session-Liste |
| Prozesse | 30s | `refresh_processes()` | Prozess-Scan |
| Monitor | 30s | `_refresh_monitor()` | Timeline, Skills |

**Warum gestaffelt?** Damit nicht alle gleichzeitig feuern und die UI einfriert.
Logs sind am schnellsten (10s) weil Usage-Daten sich oft aendern.
Sessions am langsamsten (60s) weil sich Sessions selten aendern.

**Was wenn ein Timer haengt?** Jeder Timer returned `True` um am Leben zu bleiben.
Wenn einer Exception wirft, faengt `try/except` es ab und der Timer laeuft weiter.
Worst case: ein Tab zeigt veraltete Daten, aber das Panel stuerzt nicht ab.

---

## Daten-Flow

```
~/.claude/usage/YYYY-MM-DD.jsonl  ──→  monitor.py (Cache 30s)  ──→  Hub Tab (Kosten, Tools)
                                    └──→  log_viewer.py          ──→  Logs Tab (Eintraege)

~/.claude/projects/*/  ────────────→  monitor.py + session_browser  ──→  Sessions Tab

ps aux ────────────────────────────→  process_manager.py  ──→  Prozesse Tab

~/.claude/settings.json  ──────────→  config_io.py  ──→  Settings + Hooks Tab
```

---

## Theme-System

1. **Detection:** Liest `~/.config/cosmic/com.system76.CosmicTheme.Mode/v1/is_dark`
   - `true` β†’ Catppuccin Mocha (dunkle Palette)
   - `false` β†’ Catppuccin Latte (helle Palette)
   - Datei fehlt β†’ Fallback auf GTK `gtk-application-prefer-dark-theme`

2. **CSS:** `build_css(palette)` generiert ~150 Zeilen CSS aus der Palette

3. **Live-Switch:** `Gio.FileMonitor` beobachtet die COSMIC Config-Datei.
   Aendert sich das System-Theme, wird `apply_theme()` via `GLib.idle_add` aufgerufen.

---

## Config-System β€” Atomare Writes

Warum nicht einfach `json.dump(data, open(file, "w"))`?
Weil: wenn der Prozess mittendrin stirbt, hast du eine kaputte halbe Datei.

**Stattdessen (config_io.py):**
1. **Backup:** `settings.json` β†’ `settings.json.backup-20260302-143000`
2. **Temp:** Schreibe in `settings-XXXX.tmp` (gleicher Ordner)
3. **Rename:** `os.replace(tmp, settings.json)` β€” atomar auf Linux!

Entweder hast du die alte ODER die neue Datei. Nie eine kaputte.

---

## Sprint 2026-03-04 Learnings

### Das Wichtigste zuerst: Deine vorherige Arbeit war solide.

4 von 5 Warnings waren **bereits gefixt** bevor der Sprint anfing (Commit `67a4362`).
Du hast einen 5-Agenten-Sprint geplant fuer... einen einzigen verbleibenden Fix (subprocess.run β†’ Popen).
Das Panel ist zu **95%+ fertig**. Was wirklich noch offen ist: 4 Suggestions (nice-to-have), kein Critical.

### Muster: Erst schauen, dann planen.

Tendency erkannt: Samuel plant gross (5 Agents, detaillierter PLAN-File) **bevor** er den aktuellen Stand prueft.
Regel fuer dich: **`/check-state` vor jedem Sprint-Start.** Eine Minute Status-Check spart eine Stunde Overhead.

Konkret: Bevor du Tasks erstellst, kurz pruefen:
- Welche Punkte der Checkliste sind schon erledigt? (PLAN-File lesen)
- Laeuft der Service gerade fehlerfrei? (`systemctl --user status claude-panel.service`)
- Wie gross ist der echte Rueckstand? (1 Fix β‰  5-Agenten-Aufwand)

### Was gut lief (verstaerken!)

- **Dokumentations-Disziplin:** PLAN-File erstellt, Review-Findings dokumentiert, Entscheidungen festgehalten. Das ist wertvoll.
- **Commit-Hygiene:** Criticals sofort gefixt und committed. Kein "ich mach das spaeter".
- **Code-Review Workflow:** Sonnet Review + MiniMax Zweitmeinung. Zwei Perspektiven fangen mehr.
- **Architektur-Entscheidungen klar begruendet:** `**/*.jsonl` fuer rekursive Suche, `"anthropic"` Key-Aggregation, Fingerprint-Mechanismus β€” alles dokumentiert.

### Was noch aussteht (die echte Restliste)

Nur Suggestions, kein muss:
1. `monitor.py:~662` β€” `sorted()` mit stat()-Lambda vereinfachen
2. `log_viewer.py:~456` β€” unbenutzten `sort_model` Parameter entfernen
3. `panel.py:~812` β€” `_DETECTOR_LAYOUT` Naming-Konvention
4. `log_viewer.py` β€” Status-Farben aus Theme-Palette statt hardcoded

Das Panel laeuft. Diese Fixes machen es sauberer, nicht funktionsfaehiger.

---

## Bekannte Gotchas

1. **CPU Spin-Loop (GEFIXT):** `GLib.idle_add(refresh_logs)` mit `return True` =
   Endlosschleife. Fix: One-Shot Wrapper mit `return False`. Regel: `idle_add`
   Callbacks muessen IMMER `False` returnen.

2. **Ghost-Prozesse:** MCP-Server (opencode-mcp, gemini-mcp) werden pro Session
   gestartet aber nie beendet. Der Prozesse-Tab zeigt sie als "Ghosts" (>24h).

3. **MyAIGame Dependency:** `monitor.py` importiert `tui.data.usage_reader` aus
   `~/Projekte/MyAIGame/`. Wenn das Projekt nicht existiert, fallen Kosten-
   und Tool-Statistiken auf Null zurueck (graceful fallback, kein Crash).

4. **COSMIC-only Theme Detection:** Auf nicht-COSMIC-Desktops funktioniert nur
   der GTK-Fallback. Die Catppuccin-Farben bleiben, aber Live-Switching nur per GTK.

5. **Singleton Lock (GEFIXT):** Frueher konnten mehrere Panel-Instanzen gleichzeitig
   laufen (systemd restart + manueller Start). Fix: `fcntl.flock` auf `/tmp/claude-panel.lock`.
   Zweite Instanz erkennt Lock und beendet sich mit `sys.exit(0)`.