Files
ai-control/src-tauri/src/lib.rs
T
marcus hinz b9d006184a Projekt-Identität und -Config neu: .ai-control/config.json mit UUID und Name
- Projekt-Config zieht von ai-control.json nach .ai-control/config.json um,
  das Icon liegt daneben und synct mit dem Projekt.
- Jedes Projekt trägt eine UUID (id) und den Anzeigenamen (name) in der
  Config; die UUID ist Registry-Schlüssel und project-Parameter aller
  Commands, der Name reine Darstellung.
- Pool-Zuordnung ist maschinenlokal und liegt in der projects.json-Registry,
  nicht mehr in der syncbaren Projekt-Config.
- open_terminal prüft die ID im Ordner gegen die Registry (verschobene oder
  ersetzte Ordner scheitern laut).
- Import übernimmt eine mitgebrachte ID, legt Arbeitsordner und Archiv-Home
  an und zieht die Archiv-Permission nach.
- Migration beim App-Start: Alt-Datei umziehen, Pool in die Registry,
  Icons aus ~/.config/ai-control/icons ins Projekt, Registry auf UUIDs.
- ProjectConfig reicht unbekannte Keys per serde(flatten) durch den
  Round-Trip (Regressionstest config_roundtrip_erhaelt_fremde_keys).
2026-07-20 11:01:33 +02:00

109 lines
4.1 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::project_config(&project)
.expect("Projekt-Config nicht lesbar")
.terminal
.icon
.map(|i| {
domain::project::resolve_icon_path(&domain::paths::Paths::real(), &project, &i)
.expect("Projekt nicht registriert")
.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");
}
}
}