Files
ai-control/src-tauri/src/lib.rs
T
marcus hinz 9a99bca466 Modul-Split: Fachlogik nach domain/, OS-Code nach platform/, Tauri-Verdrahtung in app.rs/commands.rs
- lib.rs nur noch Prozessrollen-Dispatch + Panic-Tracer
- KWin-Script als KDE-Pendant zur GNOME-Extension (Popup ans Zeiger-
  Rechteck), wird von deb/rpm mit ausgeliefert
- SNI-Tray auf ksni (pure Rust), appindicator-Depends entfallen
2026-07-15 20:10:33 +02:00

107 lines
4.0 KiB
Rust

//! Einstieg: Argument-Dispatch auf die drei Prozessrollen eines Binaries —
//! Haupt-App (Tray), Terminal-Prozess (`--terminal <projekt>`) und
//! MCP-stdio-Server (`--mcp-panel`). Fachlogik liegt in domain/, OS-Aufrufe
//! in platform/, Tauri-Verdrahtung in app.rs/commands.rs.
mod app;
mod commands;
mod domain;
mod mcp;
mod platform;
mod terminal;
/// Panic-Tracer: erzwingt bei jedem Panic einen vollständigen Backtrace
/// (unabhängig von RUST_BACKTRACE), gibt ihn klar abgegrenzt auf stderr aus und
/// schreibt ihn zusätzlich in eine kopierbare Datei (Pfad pro Prozess, damit
/// Haupt- und Terminal-Prozesse sich nicht überschreiben).
fn install_panic_tracer() {
std::panic::set_hook(Box::new(|info| {
let bt = std::backtrace::Backtrace::force_capture();
let dump = format!(
"\n========== ai-control PANIC (pid {}) ==========\n{info}\n\n{bt}\n========== END ==========\n",
std::process::id()
);
eprintln!("{dump}");
let path =
std::env::temp_dir().join(format!("ai-control-panic-{}.log", std::process::id()));
if std::fs::write(&path, &dump).is_ok() {
eprintln!("Backtrace kopierbar in: {}", path.display());
}
}));
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
install_panic_tracer();
let mut args = std::env::args().skip(1);
let first = args.next();
// `app --mcp-panel`: reiner MCP-stdio-Server (write_panel), kein Tauri/GTK.
// Von claude als Tool-Server gestartet.
if first.as_deref() == Some("--mcp-panel") {
mcp::run_mcp_panel();
return;
}
// AppImage ist installationsfrei und kann die GNOME-Popup-Extension nicht
// ausrollen/aktivieren. Unter GNOME daher auf das deb-/rpm-Paket verweisen und
// beenden. KDE/XFCE zeigen das Tray ohne Extension — dort läuft die AppImage.
#[cfg(target_os = "linux")]
if std::env::var_os("APPIMAGE").is_some() && platform::is_gnome() {
rfd::MessageDialog::new()
.set_level(rfd::MessageLevel::Warning)
.set_title("ai-control")
.set_description(
"Die AppImage-Fassung wird unter GNOME nicht unterstützt: Das Tray-Icon \
braucht eine GNOME-Shell-Extension, die nur das deb-/rpm-Paket \
installiert. Bitte das deb- bzw. rpm-Paket verwenden.",
)
.set_buttons(rfd::MessageButtons::Ok)
.show();
std::process::exit(1);
}
// generate_context! darf pro Crate nur einmal expandieren (_EMBED_INFO_PLIST).
let context = tauri::generate_context!();
match first.as_deref() {
// `app --terminal <projekt>`: eigener Prozess pro Terminal-Fenster,
// damit jedes Terminal ein eigenes Dock-Icon bekommt.
Some("--terminal") => {
let project = args.next().expect("--terminal braucht einen Projektnamen");
// Eigene Wayland-app_id pro Terminal-Prozess -> eigener Dock-Eintrag
// (muss vor dem GTK-Init stehen; No-op außerhalb Linux).
platform::set_app_id(&format!("aicontrol-{project}"));
let icon = domain::project::terminal_config(&project)
.expect("Projekt-Config nicht lesbar")
.icon
.map(|i| {
domain::project::resolve_icon_path(&domain::paths::Paths::real(), &i)
.to_string_lossy()
.into_owned()
});
app::terminal_builder(project)
.build(context)
.expect("error while building tauri application")
// Das Dock-Icon erst nach dem App-Start setzen: in setup() gesetzt
// überschreibt macOS es beim Anlegen des Dock-Tiles wieder.
.run(move |app, event| {
if let tauri::RunEvent::Ready = event {
if let Some(icon) = icon.as_deref() {
platform::set_dock_icon(icon);
}
platform::activate_self(app);
}
});
}
_ => {
// Feste Wayland-app_id fürs Hauptfenster (vor GTK-Init) — GNOME ordnet
// dem offenen Fenster über ai-control.desktop das App-Icon zu.
platform::set_app_id("ai-control");
app::main_builder()
.run(context)
.expect("error while running tauri application");
}
}
}