diff --git a/ROADMAP.md b/ROADMAP.md index cde4c3a..7074c9c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -105,9 +105,9 @@ Alles aus Phase 1-16 ist implementiert und funktionsfaehig: |-----|-----------| | TypeScript strict mode | Niedrig | | E2E Tests (Playwright) | Mittel | -| Cargo warnings eliminieren | Niedrig | +| ✅ Cargo warnings eliminieren | Erledigt — 0 Warnings | | Dead Code in alten Panels | Niedrig | -| Bridge Error-Handling verbessern | Mittel | +| ✅ Bridge Error-Handling verbessern | Erledigt — Global Handler, Parse-Logging, .catch() | --- diff --git a/scripts/claude-bridge.js b/scripts/claude-bridge.js index a350056..32dfee2 100644 --- a/scripts/claude-bridge.js +++ b/scripts/claude-bridge.js @@ -875,18 +875,18 @@ function handleCommand(msg) { case 'check-ollama': { // Ollama-Verfügbarkeit prüfen - checkOllamaAvailability().then(status => { - sendResponse(msg.id, status); - }); + checkOllamaAvailability() + .then(status => sendResponse(msg.id, status)) + .catch(err => sendError(msg.id, `Ollama-Check fehlgeschlagen: ${err.message}`)); break; } case 'set-ollama-config': { if (msg.endpoint) ollamaEndpoint = msg.endpoint; if (msg.model) ollamaModel = msg.model; - checkOllamaAvailability().then(status => { - sendResponse(msg.id, { ...status, endpoint: ollamaEndpoint, model: ollamaModel }); - }); + checkOllamaAvailability() + .then(status => sendResponse(msg.id, { ...status, endpoint: ollamaEndpoint, model: ollamaModel })) + .catch(err => sendError(msg.id, `Ollama-Config fehlgeschlagen: ${err.message}`)); break; } @@ -997,7 +997,7 @@ checkOllamaAvailability().then(status => { if (status.available) { process.stderr.write(`🧠 Ollama verfügbar: ${status.models.length} Modelle (${ollamaEndpoint})\n`); } -}); +}).catch(() => { /* Ollama nicht erreichbar — kein Problem */ }); // ============ Main ============ @@ -1088,6 +1088,19 @@ process.on('SIGTERM', () => { clearInterval(keepAlive); cleanupDaemon(); process process.on('SIGINT', () => { clearInterval(keepAlive); cleanupDaemon(); process.exit(0); }); process.on('exit', () => { cleanupDaemon(); }); +// Globale Fehler-Handler — Bridge darf nicht still abstürzen +process.on('uncaughtException', (err) => { + process.stderr.write(`❌ Unbehandelter Fehler: ${err.message}\n${err.stack}\n`); + sendEvent('bridge-error', { type: 'uncaughtException', message: err.message, stack: err.stack }); + sendMonitorEvent('error', `Bridge Crash: ${err.message}`, { stack: err.stack }); +}); +process.on('unhandledRejection', (reason) => { + const msg = reason instanceof Error ? reason.message : String(reason); + process.stderr.write(`❌ Unhandled Promise Rejection: ${msg}\n`); + sendEvent('bridge-error', { type: 'unhandledRejection', message: msg }); + sendMonitorEvent('error', `Unhandled Rejection: ${msg}`, {}); +}); + // Bereit-Signal (im stdio-Modus sofort senden, im Daemon-Modus pro Client bei Connect) if (!IS_DAEMON) { sendEvent('ready', { version: '1.2.0', pid: process.pid, model: currentModel, availableModels: AVAILABLE_MODELS }); diff --git a/src-tauri/src/claude.rs b/src-tauri/src/claude.rs index 2787911..82ec8ba 100644 --- a/src-tauri/src/claude.rs +++ b/src-tauri/src/claude.rs @@ -234,8 +234,9 @@ fn connect_uds(app: &AppHandle, daemon_pid: Option) -> Result<(), String> { std::thread::spawn(move || { let reader = BufReader::new(reader_stream); for line in reader.lines().map_while(Result::ok) { - if let Ok(msg) = serde_json::from_str::(&line) { - handle_bridge_message(&app_handle, msg); + match serde_json::from_str::(&line) { + Ok(msg) => handle_bridge_message(&app_handle, msg), + Err(e) => println!("⚠️ Bridge-Nachricht nicht parsbar: {} — {}", e, &line[..line.len().min(100)]), } } println!("⚠️ UDS-Verbindung getrennt — versuche Reconnect..."); @@ -364,8 +365,9 @@ fn start_bridge_stdio(app: &AppHandle, script_path: &std::path::Path) -> Result< std::thread::spawn(move || { let reader = BufReader::new(stdout); for line in reader.lines().map_while(Result::ok) { - if let Ok(msg) = serde_json::from_str::(&line) { - handle_bridge_message(&app_handle, msg); + match serde_json::from_str::(&line) { + Ok(msg) => handle_bridge_message(&app_handle, msg), + Err(e) => println!("⚠️ Bridge-Nachricht nicht parsbar: {} — {}", e, &line[..line.len().min(100)]), } } println!("⚠️ Bridge stdout geschlossen"); diff --git a/src-tauri/src/db.rs b/src-tauri/src/db.rs index 0520782..ae97dd9 100644 --- a/src-tauri/src/db.rs +++ b/src-tauri/src/db.rs @@ -517,7 +517,8 @@ impl Database { Ok(()) } - /// Lädt alle Sessions (neueste zuerst) + /// Lädt alle Sessions (neueste zuerst) — Convenience-Wrapper + #[allow(dead_code)] pub fn load_sessions(&self, limit: usize) -> SqlResult> { self.load_sessions_filtered(limit, None) } diff --git a/src-tauri/src/knowledge.rs b/src-tauri/src/knowledge.rs index 4565573..107fedf 100644 --- a/src-tauri/src/knowledge.rs +++ b/src-tauri/src/knowledge.rs @@ -60,6 +60,7 @@ impl KbCache { } } + #[allow(dead_code)] fn invalidate_expired(&mut self) { self.entries.retain(|_, v| v.created_at.elapsed() < self.ttl); }