Compare commits

...

2 commits

Author SHA1 Message Date
Eddy
c882e23445 Fix: Bridge-Prozess im State speichern (verhindert Drop/Kill)
Child-Objekt wurde am Ende von start_bridge() gedroppt — das schloss
die Pipes und beendete den Node-Prozess. Jetzt wird child im
ClaudeState gespeichert und lebt solange die App läuft.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 21:10:38 +02:00
Eddy
59e5b2ad77 Fix: Bridge-Prozess im Projektverzeichnis starten (node_modules)
current_dir() auf Projektroot setzen damit Node.js die
node_modules/@anthropic-ai/sdk findet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:57:31 +02:00
3 changed files with 35 additions and 11 deletions

View file

@ -24,6 +24,10 @@ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
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 ============
let client = null;
@ -275,9 +279,14 @@ 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
process.on('SIGTERM', () => { process.exit(0); });
process.on('SIGINT', () => { process.exit(0); });
process.on('SIGTERM', () => { clearInterval(keepAlive); process.exit(0); });
process.on('SIGINT', () => { clearInterval(keepAlive); process.exit(0); });
// Bereit-Signal
sendEvent('ready', {

View file

@ -53,6 +53,7 @@ struct BridgeMessage {
/// Globaler State für die Bridge
pub struct ClaudeState {
pub bridge_process: Option<std::process::Child>,
pub bridge_stdin: Option<std::process::ChildStdin>,
pub request_counter: u64,
pub agents: Vec<AgentStatus>,
@ -61,6 +62,7 @@ pub struct ClaudeState {
impl Default for ClaudeState {
fn default() -> Self {
Self {
bridge_process: None,
bridge_stdin: None,
request_counter: 0,
agents: vec![],
@ -93,8 +95,16 @@ pub fn start_bridge(app: &AppHandle) -> Result<(), String> {
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")
.arg(&script_path)
.current_dir(project_dir)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
@ -103,14 +113,26 @@ pub fn start_bridge(app: &AppHandle) -> Result<(), String> {
let stdin = child.stdin.take().ok_or("Kein stdin verfügbar")?;
let stdout = child.stdout.take().ok_or("Kein stdout verfügbar")?;
let stderr = child.stderr.take();
// State speichern
// State speichern — child MUSS am Leben bleiben!
let state = app.state::<Arc<Mutex<ClaudeState>>>();
{
let mut state = state.lock().unwrap();
state.bridge_process = Some(child);
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
let app_handle = app.clone();
std::thread::spawn(move || {

View file

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