Compare commits

..

No commits in common. "c882e234454d72033e378b2070369418dd631c23" and "c78e7f3dcc12e81a18a0ee5b4957a4b3834edd1d" have entirely different histories.

3 changed files with 11 additions and 35 deletions

View file

@ -24,10 +24,6 @@ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { join } from 'node:path'; import { join } from 'node:path';
import { homedir } from 'node:os'; import { homedir } from 'node:os';
// Prozess am Leben halten — MUSS vor allem anderen stehen
const keepAlive = setInterval(() => {}, 60000);
process.stdin.resume(); // stdin offen halten auch ohne readline
// ============ State ============ // ============ State ============
let client = null; let client = null;
@ -279,14 +275,9 @@ rl.on('line', (line) => {
} }
}); });
// NICHT beenden wenn stdin schließt — wir warten auf weitere Befehle per stdin
rl.on('close', () => {
process.stderr.write('⚠️ stdin geschlossen — Bridge bleibt trotzdem aktiv\n');
});
// Sauber beenden // Sauber beenden
process.on('SIGTERM', () => { clearInterval(keepAlive); process.exit(0); }); process.on('SIGTERM', () => { process.exit(0); });
process.on('SIGINT', () => { clearInterval(keepAlive); process.exit(0); }); process.on('SIGINT', () => { process.exit(0); });
// Bereit-Signal // Bereit-Signal
sendEvent('ready', { sendEvent('ready', {

View file

@ -53,7 +53,6 @@ struct BridgeMessage {
/// Globaler State für die Bridge /// Globaler State für die Bridge
pub struct ClaudeState { pub struct ClaudeState {
pub bridge_process: Option<std::process::Child>,
pub bridge_stdin: Option<std::process::ChildStdin>, pub bridge_stdin: Option<std::process::ChildStdin>,
pub request_counter: u64, pub request_counter: u64,
pub agents: Vec<AgentStatus>, pub agents: Vec<AgentStatus>,
@ -62,7 +61,6 @@ pub struct ClaudeState {
impl Default for ClaudeState { impl Default for ClaudeState {
fn default() -> Self { fn default() -> Self {
Self { Self {
bridge_process: None,
bridge_stdin: None, bridge_stdin: None,
request_counter: 0, request_counter: 0,
agents: vec![], agents: vec![],
@ -95,16 +93,8 @@ pub fn start_bridge(app: &AppHandle) -> Result<(), String> {
println!("🔌 Starte Claude Bridge: {:?}", script_path); println!("🔌 Starte Claude Bridge: {:?}", script_path);
// Arbeitsverzeichnis = Projektroot (wo node_modules liegt)
let project_dir = script_path.parent()
.and_then(|p| p.parent())
.unwrap_or_else(|| std::path::Path::new("."));
println!("📂 Bridge Arbeitsverzeichnis: {:?}", project_dir);
let mut child = Command::new("node") let mut child = Command::new("node")
.arg(&script_path) .arg(&script_path)
.current_dir(project_dir)
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
@ -113,26 +103,14 @@ pub fn start_bridge(app: &AppHandle) -> Result<(), String> {
let stdin = child.stdin.take().ok_or("Kein stdin verfügbar")?; let stdin = child.stdin.take().ok_or("Kein stdin verfügbar")?;
let stdout = child.stdout.take().ok_or("Kein stdout verfügbar")?; let stdout = child.stdout.take().ok_or("Kein stdout verfügbar")?;
let stderr = child.stderr.take();
// State speichern — child MUSS am Leben bleiben! // State speichern
let state = app.state::<Arc<Mutex<ClaudeState>>>(); let state = app.state::<Arc<Mutex<ClaudeState>>>();
{ {
let mut state = state.lock().unwrap(); let mut state = state.lock().unwrap();
state.bridge_process = Some(child);
state.bridge_stdin = Some(stdin); state.bridge_stdin = Some(stdin);
} }
// Stderr in separatem Thread lesen und loggen
if let Some(stderr) = stderr {
std::thread::spawn(move || {
let reader = BufReader::new(stderr);
for line in reader.lines().map_while(Result::ok) {
println!("🔌 Bridge stderr: {}", line);
}
});
}
// Stdout in separatem Thread lesen // Stdout in separatem Thread lesen
let app_handle = app.clone(); let app_handle = app.clone();
std::thread::spawn(move || { std::thread::spawn(move || {

View file

@ -4,8 +4,13 @@
import { marked } from 'marked'; import { marked } from 'marked';
import { tick } from 'svelte'; import { tick } from 'svelte';
marked.setOptions({ breaks: true, gfm: true }); // marked konfigurieren: kein sanitize nötig (lokale App, kein User-Input von extern)
marked.setOptions({
breaks: true,
gfm: true,
});
// Markdown zu HTML konvertieren
function renderMarkdown(text: string): string { function renderMarkdown(text: string): string {
try { try {
return marked.parse(text) as string; return marked.parse(text) as string;
@ -14,6 +19,7 @@
} }
} }
// Auto-Scroll zum Ende
let messagesContainer: HTMLDivElement; let messagesContainer: HTMLDivElement;
async function scrollToBottom() { async function scrollToBottom() {
@ -23,6 +29,7 @@
} }
} }
// Bei neuen Nachrichten scrollen
$: if ($messages.length) scrollToBottom(); $: if ($messages.length) scrollToBottom();
async function sendMessage() { async function sendMessage() {