Problem: Wenn auf NixOS der WebKit-Audio-Stack unvollständig ist
(fehlendes gst-plugin-pipewire, pipewire-pulse, Policy-Datei oder
whisper-cli/piper Binary), hängt die App fest ohne Fehlermeldung —
weder getUserMedia noch die Backend-Prozesse reagieren.
Frontend (VoicePanel.svelte):
- Preflight: prüft ob navigator.mediaDevices überhaupt existiert
- getUserMedia via Promise.race gegen 8s-Timeout (sonst hängt es ewig)
- Kategorisierte Fehler: NotAllowedError → Berechtigung,
NotFoundError → keine Hardware, NotReadableError → PipeWire-Problem
- Neuer 'connecting'-State mit 🔌-Icon — User sieht dass was passiert
- AudioContext-Konstruktor in try/catch
Backend (voice.rs):
- ffmpeg: 20s-Timeout + spezifische Fehlermeldung bei fehlendem Binary
- whisper-cli: 60s-Timeout, kein stilles Hängen mehr
- piper-tts: 30s-Timeout, Spawn-Fehler benennt NixOS-Wrapper
- Temp-Dateien werden bei Timeout auch aufgeräumt
Der uncaughtException-Handler aus f69f566 las err.stack dreimal und
serialisierte ihn zweimal per JSON.stringify. err.stack ist ein lazy
Getter der bei jedem Zugriff neu formatiert wird — bei V8-nahe-OOM
hat genau das den Abort ausgelöst (Crash-Dump Frames 20-24:
ErrorStackGetter → FormatStackTrace → FatalProcessOutOfMemory).
- Handler: err.stack einmal lesen, auf 2000 Zeichen kürzen, try/catch
drumrum. Handler darf nicht selbst crashen.
- Bridge-Start: --max-old-space-size=4096 (Node-Default ~2GB reicht
bei langen Sessions mit großen Thinking-Blocks + Agent-SDK-History
nicht). Betrifft Daemon- UND stdio-Modus.
Tool-Start und Tool-End hatten unterschiedliche IDs: tool-start generierte
eine zufällige UUID, tool-end suchte nach der Backend-ID → kein Match →
alle Tool-Calls blieben ewig auf "running" mit pulsierendem grünen Punkt.
Fix: Backend-ID wird jetzt bei tool-start durchgereicht + Fallback auf
letzten laufenden Tool-Call wenn ID nicht matcht.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wenn eine Session angeklickt wird die zu einem anderen Projekt gehört,
wird jetzt automatisch switch_project aufgerufen (CWD, Context, KB-Filter).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
{#key $chatDetached} um PaneGroup erzwingt kompletten Re-Mount.
PaneForge verlor vorher die Resize-Handler wenn Pane per {#if} entfernt wurde.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lokales Haiku-Equivalent: Bridge erkennt Ollama automatisch beim Start,
local-query Command für einfache Tasks (Commit-Messages, Übersetzungen).
Konfigurierbar über set-ollama-config.
Offline-Queue: Nachrichten werden bei fehlender Verbindung in SQLite
gequeuet und bei Reconnect automatisch gesendet. Commands:
queue_message, list_queued_messages, flush_offline_queue, clear_offline_queue.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MCP-Server-Configs werden beim Bridge-Start aus ~/.claude.json geladen
und per set-mcp-servers Command an die Bridge injiziert. Neue Tauri-Commands:
list_mcp_servers, add_mcp_server, remove_mcp_server für Runtime-Verwaltung.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bridge überlebt jetzt App-Neustarts als eigenständiger Daemon-Prozess.
Kommunikation über Unix Domain Socket statt stdio — async, Auto-Reconnect,
PID-Tracking. Fallback auf stdio-Modus wenn UDS nicht verfügbar.
Neue Commands: get_bridge_status, stop_bridge_daemon.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
stmt.query_map()?.collect() direkt als Return-Expression hält den
Borrow über den Block-End hinaus. Fix: Ergebnis erst in let binden,
dann returnen — so wird der Temporary vor stmt gedroppt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Crash: "byte index 200 is not a char boundary; inside '─' (bytes 198..201)"
Fix: char_indices() statt byte-slice für sicheres Abschneiden bei
Multi-Byte-Zeichen (ä, ü, ─, etc.)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Standard-TTS von Thorsten (männlich) auf Kerstin (weiblich) gewechselt
- text_to_speech nutzt jetzt den voice-Parameter (vorher ignoriert)
- get_tts_voices zeigt alle verfügbaren Stimmen mit Verfügbarkeits-Check
- 5 deutsche Stimmen: Kerstin, Thorsten HQ, Thorsten, Eva, Ramona
- Modell-Suche mit dynamischem Dateinamen pro Stimme
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- db.rs: load_sessions_filtered() ohne shared row_mapper (Borrow-Probleme)
- voice.rs: Modell-Suche auch in ~/.local/share/claude-desktop/models/
und ~/.claude-desktop/models/ (AppImage + Nix-Wrapper Kompatibilität)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sessions werden jetzt nach aktivem Projekt gefiltert (working_dir).
Beim Projektwechsel sieht man nur noch die Sessions die zu diesem
Projekt gehören. Backend: load_sessions_filtered() mit optionalem
WHERE working_dir-Filter. Ohne Projekt: alle Sessions (abwärtskompatibel).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mode-Badge über dem Textfeld zeigt aktiven Agent-Modus (Handlanger/Experten/Auto) mit Verarbeitungsphase
- Plan-Erkennung: erkennt strukturierte Pläne in Claude-Antworten (Mermaid, Sektionen, Schrittlisten)
- Automatisches Senden erkannter Pläne ans Präsentationsfenster als Slides
- PWA Docker Build Pipeline hinzugefügt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
App crashte mit "No GSettings schemas are installed on the system"
weil WebKitGTK die GLib-Schemas nicht finden konnte.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Global Hotkey: Super+C öffnet Claude-Fenster und fokussiert Input von überall
- Clipboard-Watch: Erkennt Code/URLs/Fehler/Pfade in Zwischenablage, zeigt Vorschlag
- tauri-plugin-global-shortcut + tauri-plugin-dialog integriert
- focus-chat-input Event für Hotkey → Input-Fokus
- clipboard-changed Event für Watch → Chat-Vorschlag
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- File-Browser Dialog (tauri-plugin-dialog) für Projektverzeichnis-Auswahl
- Auto-Name aus Verzeichnisname beim Projekt-Hinzufügen
- Nix-Wrapper: GStreamer Core-Plugins (valve) + ffmpeg-headless im PATH
- Nix-Wrapper: Version 0.1.1 mit korrektem gstreamer.out Output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Projekt-Wechsel UI in SessionList: Dropdown, Hinzufügen/Entfernen, auto Sticky-Context
- File-Drop auf Chat: Text als Code-Block, Bilder als Base64, 500KB Limit
- Persistent Memory: auto_load Einträge in Claude-Context injiziert (Cross-Session)
- Memory CRUD Tauri-Commands: save/delete/list/autoload
- Svelte 5 Syntax-Fix: on:click → onclick in SessionList.svelte
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wenn PipeWire nicht läuft (z.B. PulseAudio/xRDP), wird pipewiresrc
auf Rank 0 gesetzt damit WebKitGTK auf pulsesrc zurückfällt.
getUserMedia bekommt 5s Timeout statt endlos zu hängen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Build schlug fehl wegen gemischter Event-Handler-Syntax (Svelte 5
erlaubt kein Mischen von on:click und onclick im selben Component).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- chatDetached Store: Hauptfenster blendet Chat-Pane aus wenn Fenster offen
- Placeholder mit "Zurückholen"-Button statt leerem Pane
- Backend sendet chat-detached/chat-reattached Events ans Hauptfenster
- on_window_event(Destroyed): Automatisches Reattach wenn Fenster geschlossen
- Chat-Window lädt aktive Session + Nachrichten aus DB beim Öffnen
- Mehr Platz für andere Panels wenn Chat herausgelöst
[appimage]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Suchfeld oben: durchsucht alle Einstellungen, Commands, Hooks
- Kategorie-Sidebar: Allgemein, Modell, Commands, Hooks, Berechtigungen, Über
- Commands & Skills: Alle /slash-commands mit Badge (Eingebaut/Custom/Skill)
- Hooks: Toggle-Buttons zum Aktivieren/Deaktivieren
- Permissions: Guard-Rail-Übersicht mit Pattern/Tool/Status
- Debug: Alle DB-Settings unter "Über" aufklappbar
- Bei Suche: Sidebar verschwindet, alle matchenden Sektionen angezeigt
[appimage]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Backend: Finales 100%-Progress-Event nach Download-Loop senden
- Frontend: Explizit auf 100% setzen + 600ms Pause vor Bestätigungsdialog
- Behebt visuellen Bug dass Balken bei ~97% stehen blieb
[appimage]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OpenAI komplett entfernt. Voice läuft jetzt offline mit lokalen Binaries:
- whisper-cli (whisper-cpp 1.8.3) für Speech-to-Text
- piper-tts mit Thorsten-Stimme (Deutsch) für Text-to-Speech
- GStreamer + PipeWire in shell.nix für WebKitGTK Mikrofon-Zugriff
- VoicePanel: Echtgespräch mit VAD-Stille-Erkennung, Interrupt, Loop
- Models in .gitignore (~250MB)
[appimage]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WebKitGTK verweigert standardmäßig alle Permission-Requests (Mikrofon, Kamera).
Jetzt wird in setup() ein permission-request Handler registriert der alles erlaubt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- GST_PLUGIN_SYSTEM_PATH_1_0 mit pipewire im wrapProgram gesetzt
- User-Nachrichten >10 Zeilen werden collapsed ("Eingefuegt: X Zeilen")
- Assistant-Nachrichten weiterhin ab 25 Zeilen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both bridge and frontend now properly escape &, <, > in thinking
content before injecting as innerHTML.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Thinking blocks now look like a proper AI chat app:
- Indigo accent border (left-side, animates on hover/open)
- Dark card background (#161b27) distinct from message
- Custom lightbulb SVG icon + chevron (rotates on open)
- Monospace font for thinking content (JetBrains Mono)
- Max-height 300px with custom scrollbar
- No default disclosure markers (hidden via CSS)
- Summary shows "Überlegung" + line count on the right
- Text-based pattern detection expanded (English + German)
- Bridge escapes HTML in thinking content to prevent XSS
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Long messages (>25 lines) auto-collapse with expand/collapse button
- Cost display uses German format: "16,23$" instead of "$16.230"
- Session stats (tokens, cost, count) persist to DB after each response
via new update_session_stats command — survives app restart
- Small costs shown as cents (e.g. "3,2¢")
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Panels werden erst bei Tab-Aktivierung geladen (dynamic import mit Cache)
→ schnellerer App-Start, weniger initiales DOM
- Auto-Retry mit Backoff (3 Versuche, 2s/5s/10s) bei transienten Fehlern
(Rate-Limit, Netzwerk, 5xx) → keine manuellen Neustarts mehr
- Bridge-Heartbeat alle 30s → Rust erkennt tote Bridge sofort
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WebKitGTK throws various error types (TypeError, OverconstrainedError,
etc.) when getUserMedia is called. Instead of only catching specific
error names, now ALL errors trigger device-enumeration fallback chain:
1. { audio: true }
2. Explicit deviceId from enumerateDevices()
3. { audio: {} } as last resort
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- KB-Cache im RAM: Suchergebnisse 60s gecacht, kein MySQL-Roundtrip pro Nachricht
- Bridge wird beim App-Start sofort gestartet (kein Cold-Start bei erster Nachricht)
- Bridge-Start-Wait von 500ms auf 200ms reduziert
- maxTurns von 25 auf 200 erhoeht (verhindert "maximum turns reached" bei komplexen Tasks)
- invalidate_kb_cache Command fuer manuelles Cache-Leeren
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>