File size: 10,624 Bytes
74f57c5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# GUI-Architektur β€” 3 Standalone GTK3 Apps

Stand: 2026-03-04

## 1. Shared Base Module (`~/Projekte/shared-gui/gui_base.py`)

Gemeinsame Grundlage fuer alle drei GUIs. Importiert `theme.py` aus ClaudeCodePanel.

### BaseApp Klasse

```python
class BaseApp(Gtk.Window):
    def __init__(self, title, width, height, icon_name=None)
```

Bereitgestellte Features:
- **Window Setup**: Titel, Groesse, Icon, `destroy`-Signal
- **HeaderBar**: Gtk.HeaderBar mit Titel + optionalem Subtitle
- **StatusBar**: Unten, CSS-Klasse `.status-bar`, mit `set_status(text, css_class)` Methode
- **Theme**: Automatisches Laden von Catppuccin CSS via `theme.py`, COSMIC dark/light Watcher
- **CSS Provider**: Gemeinsam fuer alle Widgets, erweiterbar via `add_css(css_string)`
- **Refresh Timer**: `start_refresh(interval_seconds, callback)` β€” GLib.timeout_add_seconds
- **Main Box**: Vertikaler Gtk.Box (`self.content_box`) zwischen Header und StatusBar

### Theme-Modul Wiederverwendung

`gui_base.py` importiert direkt aus ClaudeCodePanel:
```python
sys.path.insert(0, str(Path.home() / "Projekte/ClaudeCodePanel"))
from theme import build_css, setup_theme_watcher, get_palette, is_dark_mode
```

### Gemeinsame CSS-Klassen (aus theme.py)

Alle Apps erben automatisch:
- `.panel-header`, `.stat-value`, `.stat-label` β€” Ueberschriften + Statistiken
- `.section-frame`, `.section-title` β€” Karten/Sektionen
- `.status-bar`, `.status-saved`, `.status-error` β€” Statusleiste
- `.shortcut-btn` β€” Aktionsbuttons
- `.monitor-value`, `.cost-value` β€” Monospace-Werte

Zusaetzlich definiert gui_base.py:
- `.base-card` β€” Standardkarte (border-radius 8px, card-bg, border)
- `.base-toolbar` β€” Toolbar-Leiste (mantle-bg, border-radius 8px)
- `.base-badge` β€” Kleine Status-Badges (border-radius 12px)

---

## 2. Design-Specs pro GUI

### 2.1 Sidecar-GUI (`~/Projekte/Sidecar/gui/`)

**Zweck:** Visuelles Dashboard fuer den Sidecar Daemon β€” Rules, Sessions, Findings.

**Layout:**
```
+-----------------------------------------------+
| [HeaderBar] Sidecar Control Panel    [Reload]  |
+-----------------------------------------------+
| [Notebook]                                     |
| +-------------------------------------------+  |
| | Tab: Status  | Tab: Rules | Tab: Findings |  |
| +-------------------------------------------+  |
|                                                 |
| STATUS TAB:                                     |
|   Daemon: running  PID: 12345  Uptime: 2h 15m  |
|   Rules: 22   Findings: 5   Plugins: 3          |
|                                                 |
| RULES TAB:                                      |
|   [SearchEntry filter]                          |
|   +------------------------------------------+ |
|   | Name        | Group    | Enabled | Fires  | |
|   | cli_first   | enforce  |   [x]   |   12   | |
|   | gate_rm_rf  | gate     |   [x]   |    3   | |
|   +------------------------------------------+ |
|   [Enable] [Disable] [Snooze 30m]              |
|                                                 |
| FINDINGS TAB:                                   |
|   [ScrolledWindow mit Finding-Cards]            |
|   Time | Rule | Severity | Message              |
+-----------------------------------------------+
| [StatusBar] Connected via /tmp/claude-sidecar.sock |
+-----------------------------------------------+
```

**Widgets:**
- `Gtk.Notebook` mit 3 Tabs
- Status-Tab: Grid mit Labels (key-value), aktualisiert via Refresh
- Rules-Tab: `Gtk.ListBox` mit Rows, SearchEntry fuer Filter, Toggle-Buttons
- Findings-Tab: `Gtk.ListBox` mit farbcodierten Karten (Severity β†’ Farbe)

**Datenquellen:**
- Primaer: Unix Socket `/tmp/claude-sidecar.sock` (JSON-Protokoll, wie sidecar-ctl)
- Kommandos: `status`, `rules`, `findings`, `enable`, `disable`, `snooze`, `reload`
- Socket-Kommunikation non-blocking via `GLib.io_add_watch` auf Socket-FD

**Refresh:** 5 Sekunden (Status + Rules), Findings on-demand

**Interaktion:**
- Rules: Klick auf Row β†’ Enable/Disable Toggle, Rechtsklick β†’ Snooze
- Findings: Nur Anzeige, scrollbar
- Reload-Button in HeaderBar

---

### 2.2 Tools-GUI (`~/Projekte/ClaudeCodePanel/tools-gui/`)

**Zweck:** Session-History + Kosten-Tracking fuer Claude Code.

**Layout:**
```
+-----------------------------------------------+
| [HeaderBar] Claude Code Tools           [Ref]  |
+-----------------------------------------------+
| [Notebook]                                     |
| +-------------------------------------------+  |
| | Tab: Sessions | Tab: Costs | Tab: Tools   |  |
| +-------------------------------------------+  |
|                                                 |
| SESSIONS TAB:                                   |
|   [SearchEntry]  [ComboBox: Sortierung]         |
|   +------------------------------------------+ |
|   | Projekt      | Letztes Msg | Kosten | Res | |
|   | Sidecar      | vor 2h      | $0.12  | [>] | |
|   | ClaudePanel  | vor 1d      | $0.45  | [>] | |
|   +------------------------------------------+ |
|                                                 |
| COSTS TAB:                                      |
|   Heute: $1.23   Woche: $8.50   Monat: $32.10  |
|   [BarChart via DrawingArea β€” letzte 7 Tage]    |
|   Top Tools: Read(45) Edit(23) Bash(18)         |
|                                                 |
| TOOLS TAB:                                      |
|   Tool-Usage Breakdown (ListBox)                |
|   Skill-Usage + Missed Skills                   |
+-----------------------------------------------+
| [StatusBar] 12 Sessions | $1.23 heute           |
+-----------------------------------------------+
```

**Widgets:**
- Sessions-Tab: `Gtk.ListBox` mit Session-Rows, SearchEntry, ComboBox fuer Sortierung
- Costs-Tab: Stat-Labels oben, `Gtk.DrawingArea` fuer 7-Tage-Balkendiagramm (Cairo), Tool-Rankings
- Tools-Tab: `Gtk.ListBox` mit Tool-Usage, Skill-Usage

**Datenquellen:**
- `monitor.py` Funktionen: `get_daily_cost()`, `get_top_tools()`, `get_recent_sessions()`, `get_usage_timeline()`, `get_provider_costs()`, `get_skill_usage()`, `get_missed_skills_summary()`
- Import: `sys.path.insert(0, "~/Projekte/ClaudeCodePanel")` + `from monitor import ...`

**Refresh:** 30 Sekunden (passend zum TTL-Cache in monitor.py)

---

### 2.3 Florian-GUI (`~/Projekte/MyAIGame/florian-gui/`)

**Zweck:** TTS Control Panel β€” Voice-Auswahl, Test, Speed/Pitch, Audio-Playback.

**Layout:**
```
+-----------------------------------------------+
| [HeaderBar] Florian TTS Control        [Play]  |
+-----------------------------------------------+
|                                                 |
| Voice: [ComboBox: florian|katja|conrad|...]     |
|                                                 |
| Speed:  [=====|========] 1.0x                   |
| Pitch:  [=====|========] +0Hz                   |
|                                                 |
| Format: ( ) mp3  ( ) wav  ( ) opus  ( ) flac    |
|                                                 |
| Text:                                           |
| +------------------------------------------+   |
| | Guten Tag, ich bin Florian und teste     |   |
| | die Sprachausgabe.                        |   |
| +------------------------------------------+   |
|                                                 |
| [  Speak  ]         [Stop]                      |
|                                                 |
| +------------------------------------------+   |
| | Audio-Wellenform / Fortschrittsbalken    |   |
| +------------------------------------------+   |
|                                                 |
| Server: localhost:5050 [Health: OK]             |
+-----------------------------------------------+
| [StatusBar] Ready β€” Florian (de-DE)             |
+-----------------------------------------------+
```

**Widgets:**
- `Gtk.ComboBoxText` fuer Voice-Auswahl (aus `/v1/audio/voices` Endpoint)
- `Gtk.Scale` fuer Speed (0.25 β€” 4.0, Step 0.25) und Pitch (-20Hz β€” +20Hz)
- `Gtk.RadioButton` Gruppe fuer Format
- `Gtk.TextView` fuer Text-Eingabe (mehrzeilig)
- `Gtk.Button` Speak + Stop
- `Gtk.ProgressBar` fuer Audio-Playback
- Health-Indikator (Label mit Farbcode)

**Datenquellen:**
- HTTP API: `http://localhost:5050`
  - `GET /v1/audio/voices` β†’ Voice-Liste
  - `POST /v1/audio/speech` β†’ Audio-Bytes (body: `{input, voice, speed, response_format}`)
  - `GET /health` β†’ Server-Status
- HTTP via `Gio.InputStream` / subprocess `curl` + GLib.spawn_async (kein threading!)

**Audio-Playback:**
- Tempfile schreiben β†’ `subprocess.Popen(["mpv", "--no-video", tmpfile])` via `GLib.spawn_async`
- Stop = Kill des mpv-Prozesses

**Refresh:** Health-Check alle 10 Sekunden

---

## 3. Dateistruktur pro Projekt

### shared-gui/
```
~/Projekte/shared-gui/
  gui_base.py          # BaseApp + Theme-Integration + gemeinsame CSS
```

### Sidecar-GUI
```
~/Projekte/Sidecar/gui/
  main.py              # Entry-Point, SidecarApp(BaseApp)
  socket_client.py     # Non-blocking Unix Socket Client (GLib.io_add_watch)
  tabs/
    status_tab.py      # Daemon-Status Anzeige
    rules_tab.py       # Rules ListBox + Filter + Enable/Disable
    findings_tab.py    # Findings ListBox
```

### Tools-GUI
```
~/Projekte/ClaudeCodePanel/tools-gui/
  main.py              # Entry-Point, ToolsApp(BaseApp)
  tabs/
    sessions_tab.py    # Session-ListBox + Search + Sort
    costs_tab.py       # Kosten-Stats + Cairo BarChart
    tools_tab.py       # Tool-Usage + Skill-Usage
```

### Florian-GUI
```
~/Projekte/MyAIGame/florian-gui/
  main.py              # Entry-Point, FlorianApp(BaseApp)
  tts_client.py        # HTTP Client (Gio/subprocess, non-blocking)
  audio_player.py      # mpv-basierter Player (GLib.spawn_async)
```

---

## 4. Constraints

| Constraint | Detail |
|-----------|--------|
| **Toolkit** | GTK 3.0 via PyGObject (`gi.require_version("Gtk", "3.0")`) |
| **Theme** | Catppuccin Mocha (dark) / Latte (light) via `theme.py` |
| **Desktop** | COSMIC β€” `is_dark_mode()` liest `~/.config/cosmic/CosmicTheme.Mode/v1/is_dark` |
| **Event Loop** | GLib Main Loop β€” KEIN threading, KEIN asyncio im GUI-Thread |
| **Timer** | `GLib.timeout_add_seconds()` fuer Refresh, Return `True` fuer Repeat |
| **Non-Blocking I/O** | Socket: `GLib.io_add_watch`, HTTP: `GLib.spawn_async` mit Callback |
| **CSS** | Alle Styles via `Gtk.CssProvider`, keine inline-Styles |
| **GLib.idle_add** | Nur als One-Shot (`return False`), NIE mit `return True` |
| **Python** | 3.11+ (match/case erlaubt, aber nicht erforderlich) |
| **Abhaengigkeiten** | PyGObject >= 3.42, gir1.2-gtk-3.0 (keine zusaetzlichen Pakete) |