Files
Winkler, StefanandClaude Opus 4.8 e149a9118f Endpunkt-Status-Icon mit Ereignis-Log und Update-Erkennung ergaenzen
Ein neues Status-Icon im Titelbalken zeigt den Zustand der lokalen
Transkripte und der Serverabfrage; ein Klick oeffnet ein eigenes Fenster
mit persistiertem, zeitgestempeltem Ereignis-/Fehlerprotokoll (loeschbar).
Ausserdem erkennt die App beim Start Erstinstallation vs. Update
(plattformunabhaengig fuer Windows und Linux) und meldet Updates per
nativer Benachrichtigung.

Dazu: Versionierungs-Policy dokumentiert (package.json vor jedem Release
erhoehen, sonst greift weder die Update-Erkennung noch bleiben alte
Release-Dateien in release/ erhalten), sowie zwei neue Dokumente fuer
Endanwender (BENUTZERHANDBUCH.md) und eine Download-Webseite
(PRODUKTSEITE.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 11:07:07 +02:00

366 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Claude Live Dashboard
Ein rahmenloses Always-on-Top-Widget für Windows und Linux, das die Auslastung des
Claude-Plans live anzeigt: 5-Stunden-Fenster, Wochenverbrauch, Reset-Countdown,
Tokenverbrauch je Modell und die Hochrechnung auf das Fensterende.
Die Daten stammen aus den Transkripten, die Claude Code ohnehin unter
`~/.claude/projects/**/*.jsonl` schreibt. Es wird nichts installiert, nichts
mitgeschnitten und standardmäßig keine Netzwerkverbindung aufgebaut.
## Start
Node.js (ab Version 20) wird benötigt.
### Windows
Ist Node nicht im `PATH` (etwa bei nvm-windows ohne aktive Version), genügt der
Versionspfad:
```powershell
$env:PATH = "$env:APPDATA\nvm\v22.22.1;$env:PATH"
npm install
npm start
```
Alternativ `start.cmd` doppelklicken.
Das Tray-Symbol landet unter Windows zunächst im Überlaufbereich hinter dem
`^` in der Taskleiste; per Drag lässt es sich dauerhaft sichtbar machen.
### Linux (Ubuntu)
```bash
sudo apt install nodejs npm # falls noch nicht vorhanden
./start.sh
```
`start.sh` installiert fehlende Abhängigkeiten selbst und startet Electron;
`npm install && npm start` tut dasselbe.
Das Tray-Symbol braucht unter GNOME die Erweiterung **AppIndicator** — beim
Ubuntu-Desktop ist sie vorinstalliert und aktiv. Auf einer Minimalinstallation
oder unter anderen Oberflächen:
```bash
sudo apt install gnome-shell-extension-appindicator
```
Ohne sie läuft das Widget weiter, nur das Symbol in der oberen Leiste fehlt.
Anders als unter Windows ist im StatusNotifierItem-Standard nicht festgelegt,
welcher Klick als Aktivierung zählt — verlässlich ist deshalb das Kontextmenü
(Rechtsklick) mit „Dashboard anzeigen“ als erstem Eintrag.
**Wayland:** Ab Electron 36 wählt Chromium in einer Wayland-Sitzung von sich
aus Wayland — dort darf sich ein Fenster aber weder selbst positionieren noch
dauerhaft in den Vordergrund legen, und genau das ist der Kern dieses Widgets.
Die App startet sich deshalb unter Wayland einmalig selbst mit
`--ozone-platform=x11` neu und läuft über XWayland. Das geschieht automatisch,
es ist nichts einzustellen.
Der Schalter *muss* auf der Kommandozeile stehen: Ozone legt die Plattform
fest, bevor das Main-Skript läuft — `app.commandLine.appendSwitch()` und
`ELECTRON_OZONE_PLATFORM_HINT` kommen beide zu spät. Wer die Automatik
umgehen will, setzt eine der beiden Größen von Hand; dann greift der Neustart
nicht mehr:
```bash
ELECTRON_OZONE_PLATFORM_HINT=wayland ./start.sh # nativ Wayland, ohne Positionierung
```
## Bedienung
| Aktion | Wirkung |
|---|---|
| Kopfzeile ziehen | Fenster verschieben (Position wird gemerkt) |
| Statuspunkt (links vom Zahnrad) | Fehler-/Ereignis-Log öffnen |
| ⚙ | Einstellungen öffnen |
| „Details“ | Modell-Aufschlüsselung, Tempo und Datengrundlage aufklappen |
| `` | Ausblenden — Rückkehr über das Tray-Symbol |
| Tray-Klick | Ein-/Ausblenden |
| Tray-Menü | Deckkraft, Klick-Durchlässigkeit, Autostart, Einstellungen, Beenden |
### Einstellungen
Das Zahnrad in der Kopfzeile öffnet einen Dialog für alle Felder der
`config.json`: Deckkraft, Klick-Durchlässigkeit, Autostart, Serverabfrage,
Bezugsgrößen, Gewichtung und Wochenfenster.
Gespeicherte Änderungen greifen **sofort** — ohne Neustart. Der Dialog liest
und schreibt dieselbe Datei, die sich auch von Hand bearbeiten lässt:
Kommentarfelder (`_hinweis` und Verwandte) und unbekannte Einträge bleiben
dabei unangetastet, weil die vorhandene Datei nur ergänzt und nicht ersetzt
wird. `Strg`+`S` speichert, `Esc` schließt.
Autostart ist kein Feld der Datei, sondern ein Systemzustand — er wird deshalb
sofort beim Umschalten übernommen, unabhängig vom Speichern.
„Klicks durchlassen“ macht das Widget für Mausereignisse transparent — es liegt
dann über der Arbeit, ohne sie zu behindern. Zurückschalten geht über das
Tray-Menü.
### Endpunkt-Status & Ereignis-Log
Der Punkt links vom Zahnrad zeigt den Zustand der beiden Datenquellen —
Symbol *und* Farbe, nie Farbe allein:
| Zustand | Bedeutung |
|---|---|
| ● grün | Beide Quellen funktionieren |
| ◆ gelb | Serverabfrage gestört (App rechnet lokal weiter) |
| ◆ rot | Lokale Transkripte nicht lesbar — die Kerndatenquelle fehlt |
Ein Klick öffnet ein eigenes Fenster mit dem chronologischen, zeitgestempelten
Protokoll aller Störungen (Lesefehler, Dateiüberwachung, Serverabfrage) sowie
App-Ereignissen wie Erstinstallation und Updates. Das Protokoll übersteht
Neustarts und das Speichern der Einstellungen — es liegt in `state.json` — und
lässt sich über „Log löschen“ im selben Fenster zurücksetzen.
## Was angezeigt wird
**Laufende Sitzung** — Auslastung des aktuellen 5-Stunden-Fensters, dazu
verbrauchte Tokens und Tempo.
**Wochenkontingent** — das übergeordnete Limit über alle Modelle, mit exaktem
Reset-Zeitpunkt.
**Nutzungsguthaben** — der Budget-Zustand jenseits des Plan-Kontingents
(verbraucht von Monatslimit). Erscheint nur, wenn der Server ihn meldet.
Darunter die eigentliche Kernaussage: *wie lange das Kontingent bei diesem
Tempo noch reicht* — gerechnet in **aktiver Arbeitszeit**, nicht in
Kalenderzeit. Eine Hochrechnung der Burn-Rate auf fünf Kalendertage wäre
Unsinn, weil niemand durchgehend arbeitet.
## Woher die Werte kommen
Standardmäßig fragt das Dashboard denselben Endpunkt ab, den auch `/usage`
nutzt (`GET /api/oauth/usage` bei `api.anthropic.com`). Damit sind die
Prozentwerte, Schweregrade und Reset-Zeitpunkte **exakt** — sekundengenau und
ohne Schätzung.
Das Zugriffstoken wird aus `~/.claude/.credentials.json` gelesen, nie
gespeichert, nie protokolliert und nur an diesen Host gesendet. Es gibt bewusst
keinen eigenen Refresh-Flow: Läuft das Token ab, pausiert die Abfrage, bis
Claude Code es erneuert hat. Nach drei Fehlversuchen schaltet sie sich für die
Sitzung ab.
Abschalten über `config.json`:
```json
{ "oauth": { "enabled": false } }
```
**Wichtig:** Der Endpunkt ist nicht dokumentiert und kann durch ein Update
brechen. Deshalb rechnet das Dashboard *immer* auch lokal weiter — fällt die
Abfrage aus, läuft es ohne Unterbrechung auf den eigenen Zahlen weiter, nur
eben mit Näherungswerten. Die Anzeige sagt jederzeit, welcher Fall vorliegt:
| Anzeige | Bedeutung |
|---|---|
| **exakt (Server)** | Wert vom Server, entspricht `/usage` — nur mit Stufe 2 |
| **eigener Wert** | `limits` aus `config.json` |
| **kalibriert** | aus mindestens 5 eigenen abgeschlossenen Fenstern abgeleitet |
| **geschätzt** | noch zu wenige Messungen, grober Anhaltspunkt |
Solange die Serverabfrage läuft, kalibriert sich das Dashboard **selbst**: Der
Server nennt den exakten Anteil, lokal ist der gewichtete Verbrauch im selben
Fenster bekannt — daraus folgt die Bezugsgröße unmittelbar. Auch das
Wochenfenster wird aus dem gemeldeten Reset-Zeitpunkt abgeleitet, nicht
geraten.
Die folgenden Abschnitte betreffen nur den Fall, dass die Abfrage **nicht**
verfügbar ist.
### Kalibrieren (Rückfallebene)
Ohne Serverabfrage nimmt das Dashboard das höchste je beobachtete
Fenstervolumen als untere Schranke des Limits. Das ist grob. Besser: den
Prozentwert in **Einstellungen ▸ Nutzung** ablesen und unmittelbar danach:
```powershell
npm run calibrate -- --week 14 # nur rechnen
npm run calibrate -- --week 14 --write # in config.json übernehmen
npm run calibrate -- --block 37 --write # 5-Stunden-Fenster
```
Das Werkzeug teilt den aktuellen Verbrauch durch den angezeigten Anteil und
erhält so die Bezugsgröße exakt. Danach das Dashboard neu starten.
Steht in der Nutzungsanzeige ein fester Reset-Zeitpunkt („Zurücksetzung Mo.,
21:59“), gehört er in `config.json` — sonst passt das Fenster nicht zum
kalibrierten Wert:
```json
{ "weekResetWeekday": 1, "weekResetHour": 21, "weekResetMinute": 59 }
```
(0 = Sonntag, 1 = Montag …) Ohne diese Angabe rechnet das Dashboard mit einem
rollierenden 7-Tage-Fenster und zeigt bewusst keinen Countdown, weil ein
rollierendes Fenster keinen Reset-Zeitpunkt hat.
### Gewichtung
Tokens zählen nicht gleich: Ausgabe wiegt stärker als ein Cache-Treffer, Opus
stärker als Sonnet oder Haiku. Die Faktoren stehen in `config.json`.
Weichen zwei Kalibrierungen mit **unterschiedlichem Modellmix** deutlich
voneinander ab, stimmen diese Gewichte nicht — dann dort nachziehen, statt das
Limit hin- und herzuschieben. Ein einzelner Kalibrierpunkt legt nur den
Maßstab fest, nicht die Gewichte.
## Aufbau
```
src/main/index.js Fenster, Tray, IPC, Autostart
src/main/collector.js Watch-Schleife, Zustandsaufbau
src/main/jsonl.js inkrementeller Reader, Parser, Dedup
src/main/blocks.js 5h-Blöcke, Wochenfenster, Burn-Rate
src/main/limits.js Plan-Erkennung, Kalibrierung, Gewichtung
src/main/oauth-usage.js Serverabfrage, gekapselt und ausfallsicher
src/main/calibrate.js Kalibrierung gegen die echte Anzeige
src/main/store.js state.json, config.json
src/main/paths.js Speicherorte für Konfiguration und Zustand
src/main/autostart.js Anmeldestart je Betriebssystem
src/preload.js contextBridge fürs Widget
src/settings-preload.js contextBridge für den Einstellungsdialog
src/errors-preload.js contextBridge fürs Fehler-/Ereignis-Log
src/renderer/ Widget-Oberfläche
src/settings/ Einstellungsdialog
src/errors/ Fehler-/Ereignis-Log-Fenster
```
Alle Dateizugriffe und Rechnungen passieren im Main-Prozess; der Renderer
bekommt fertige Zahlen und lässt nur den Countdown lokal weiterlaufen.
Zwei Details, die nicht offensichtlich sind:
- **Datei-Offsets werden nicht persistiert.** Innerhalb einer Sitzung sorgen sie
dafür, dass nur das Delta gelesen wird. Über einen Neustart hinweg wären sie
schädlich, weil der Aggregator leer startet und die Historie sonst
übersprungen würde. Ein Vollscan über 15 MB kostet rund 70 ms.
- **Dedup ist nicht optional.** Claude Code schreibt dieselbe Nachricht bei
Retries und beim Kompaktieren mehrfach ins Transkript; ohne Dedup über
`message.id` wären alle Zahlen zu hoch.
## Version & Updates
Die App erkennt beim Start selbst, ob es sich um eine Erstinstallation oder
ein Update handelt: Sie vergleicht `app.getVersion()` (aus `package.json`,
plattformunabhängig für Windows und Linux) mit der zuletzt in `state.json`
gemerkten Version. Bei einer neuen Version erscheint einmalig eine native
Systembenachrichtigung, und das Ereignis landet zeitgestempelt im
Fehler-/Ereignis-Log (siehe oben). Bestehende Konfiguration und Kalibrierung
bleiben davon unberührt — geschrieben wird ausschließlich das eine Feld
`state.json:appVersion`.
**Voraussetzung dafür ist eine bei jedem Release erhöhte Versionsnummer.**
Vor jedem Build deshalb zuerst `version` in `package.json` erhöhen (SemVer:
`1.1.0``1.2.0` für neue Funktionen, `1.1.1` für Fehlerbehebungen). Ohne
diesen Schritt erkennt die App den neuen Build nicht als Update, und der
Installer überschreibt in `release/` stillschweigend die Datei der
vorherigen Version, weil deren Name (`artifactName`) die Versionsnummer
enthält:
```powershell
npm version minor # oder: patch / major — schreibt package.json, kein Tag/Commit nötig
npm run dist
```
`npm version` legt standardmäßig auch einen Git-Commit und -Tag an; ohne das
genügt es, `version` in `package.json` von Hand zu ändern.
## Release bauen
Gebaut wird jeweils auf dem Zielsystem — electron-builder kann `.deb` nicht
sinnvoll von Windows aus erzeugen und umgekehrt keine signierten `.exe` unter
Linux. Beide Linux-Ziele (`AppImage`, `.deb`) brauchen zudem Linux-eigene
Werkzeuge (`mksquashfs` bzw. `fpm`) und lassen sich nicht unter Windows
erzeugen, auch nicht über WSL ohne eine dort eingerichtete Node.js- bzw.
Ruby-Umgebung.
### Windows
```powershell
npm run dist # Installer + portable Fassung nach release/
npm run pack # nur entpackt nach release/win-unpacked (schneller Test)
```
Ergebnis in `release/` (Version aus `package.json`, siehe oben):
| Datei | Zweck |
|---|---|
| `Claude Live Dashboard-<version>-x64.exe` | NSIS-Installer, ~97 MB |
| `Claude Live Dashboard-<version>-portable.exe` | läuft ohne Installation |
Der Installer läuft **ohne Administratorrechte** (`perMachine: false`),
installiert also ins Benutzerprofil. Zielverzeichnis ist wählbar, Desktop- und
Startmenü-Verknüpfung werden angelegt. Bei der Deinstallation bleiben
Konfiguration und Kalibrierung erhalten (`deleteAppDataOnUninstall: false`).
**Nicht signiert.** Ohne Code-Signing-Zertifikat zeigt Windows beim ersten
Start einen SmartScreen-Hinweis („Der Computer wurde durch Windows geschützt“)
— über *Weitere Informationen ▸ Trotzdem ausführen* zu bestätigen. Für eine
Weitergabe an andere wäre ein Zertifikat nötig; für den Eigenbedarf ist es
verzichtbar.
### Linux
```bash
npm run dist:linux # AppImage + .deb nach release/
npm run pack:linux # nur entpackt nach release/linux-unpacked
```
Ergebnis in `release/`:
| Datei | Zweck |
|---|---|
| `Claude Live Dashboard-<version>-x64.AppImage` | läuft ohne Installation |
| `Claude Live Dashboard-<version>-amd64.deb` | Installation per `sudo apt install ./…deb` |
Das AppImage muss einmal ausführbar gemacht werden (`chmod +x`) und braucht
`libfuse2`. Es trägt sich nicht selbst ins Anwendungsmenü ein — der Autostart
über das Tray-Menü funktioniert trotzdem, weil die App den Pfad des Abbilds aus
`APPIMAGE` liest und nicht den temporären Einhängepunkt. Das `.deb` bringt
Menüeintrag und Symbol mit und installiert nach `/opt/Claude Live Dashboard`.
> **Ubuntu 24.04 und AppImage.** Seit 24.04 beschränkt AppArmor unprivilegierte
> User-Namespaces; die Chromium-Sandbox kann dann beim Start fehlschlagen
> (`SUID sandbox helper binary … is not configured correctly`). Zwei Auswege:
> das AppImage mit `--no-sandbox` starten, oder ein AppArmor-Profil unter
> `/etc/apparmor.d/` hinterlegen. Beim `.deb` tritt das nicht auf — dessen
> `postinst` setzt das SUID-Bit auf `chrome-sandbox`.
### Konfiguration und Zustand
Beides liegt im Benutzerprofil, nicht im Programmverzeichnis — dort wäre es
nach der Installation im asar-Archiv und schreibgeschützt:
```
Windows: %APPDATA%\Claude Live Dashboard\config.json
%APPDATA%\Claude Live Dashboard\state.json
Linux: ~/.config/Claude Live Dashboard/config.json
~/.config/Claude Live Dashboard/state.json
```
Der Autostart ist kein Feld dieser Dateien: unter Windows steckt er in der
Registry, unter Linux in `~/.config/autostart/claude-live-dashboard.desktop`.
Beim ersten Start wird `config.json` aus der mitgelieferten Vorlage angelegt.
Erreichbar über das Tray-Menü (*Konfiguration öffnen* / *Datenordner öffnen*).
> Die mitgelieferte Vorlage enthält unter `limits` einen auf **diesem** System
> kalibrierten Wert als Rückfallebene. Für eine Weitergabe an andere sollte er
> entfernt werden — bei aktiver Serverabfrage wird er ohnehin nicht benutzt.
## Gegenprobe
```powershell
npm run dump # Modell-Summen und alle 5h-Blöcke auf der Konsole
npx ccusage blocks # unabhängige Referenz für Blockgrenzen und Summen
```
`npm run dump` gibt außerdem die Dauer des zweiten Polls aus — ohne neue Daten
muss er 0 Bytes lesen und im einstelligen Millisekundenbereich liegen.