mod commands; mod ctx; mod event_sink; mod fs_watcher; mod groups; mod memora; mod pty; mod remote; mod sidecar; mod session; mod telemetry; mod watcher; use event_sink::TauriEventSink; use pty::PtyManager; use remote::RemoteManager; use session::SessionDb; use sidecar::{SidecarConfig, SidecarManager}; use fs_watcher::ProjectFsWatcher; use watcher::FileWatcherManager; use std::sync::Arc; use tauri::Manager; pub(crate) struct AppState { pub pty_manager: Arc, pub sidecar_manager: Arc, pub session_db: Arc, pub file_watcher: Arc, pub fs_watcher: Arc, pub ctx_db: Arc, pub memora_db: Arc, pub remote_manager: Arc, _telemetry: telemetry::TelemetryGuard, } #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { // Force dark GTK theme for native dialogs (file chooser, etc.) std::env::set_var("GTK_THEME", "Adwaita:dark"); // Initialize tracing + optional OTLP export (before any tracing macros) let telemetry_guard = telemetry::init(); tauri::Builder::default() .invoke_handler(tauri::generate_handler![ // PTY commands::pty::pty_spawn, commands::pty::pty_write, commands::pty::pty_resize, commands::pty::pty_kill, // Agent/sidecar commands::agent::agent_query, commands::agent::agent_stop, commands::agent::agent_ready, commands::agent::agent_restart, // File watcher commands::watcher::file_watch, commands::watcher::file_unwatch, commands::watcher::file_read, commands::watcher::fs_watch_project, commands::watcher::fs_unwatch_project, commands::watcher::fs_watcher_status, // Session/layout/settings/SSH commands::session::session_list, commands::session::session_save, commands::session::session_delete, commands::session::session_update_title, commands::session::session_touch, commands::session::session_update_group, commands::session::layout_save, commands::session::layout_load, commands::session::settings_get, commands::session::settings_set, commands::session::settings_list, commands::session::ssh_session_list, commands::session::ssh_session_save, commands::session::ssh_session_delete, // Agent persistence (messages, state, metrics, anchors) commands::persistence::agent_messages_save, commands::persistence::agent_messages_load, commands::persistence::project_agent_state_save, commands::persistence::project_agent_state_load, commands::persistence::session_metric_save, commands::persistence::session_metrics_load, commands::persistence::session_anchors_save, commands::persistence::session_anchors_load, commands::persistence::session_anchor_delete, commands::persistence::session_anchors_clear, commands::persistence::session_anchor_update_type, // ctx + Memora commands::knowledge::ctx_init_db, commands::knowledge::ctx_register_project, commands::knowledge::ctx_get_context, commands::knowledge::ctx_get_shared, commands::knowledge::ctx_get_summaries, commands::knowledge::ctx_search, commands::knowledge::memora_available, commands::knowledge::memora_list, commands::knowledge::memora_search, commands::knowledge::memora_get, // Claude profiles/skills commands::claude::claude_list_profiles, commands::claude::claude_list_skills, commands::claude::claude_read_skill, // Groups commands::groups::groups_load, commands::groups::groups_save, commands::groups::discover_markdown_files, // File browser commands::files::list_directory_children, commands::files::read_file_content, commands::files::write_file_content, commands::files::pick_directory, // Remote machines commands::remote::remote_list, commands::remote::remote_add, commands::remote::remote_remove, commands::remote::remote_connect, commands::remote::remote_disconnect, commands::remote::remote_agent_query, commands::remote::remote_agent_stop, commands::remote::remote_pty_spawn, commands::remote::remote_pty_write, commands::remote::remote_pty_resize, commands::remote::remote_pty_kill, // Misc commands::misc::cli_get_group, commands::misc::open_url, commands::misc::frontend_log, ]) .plugin(tauri_plugin_updater::Builder::new().build()) .plugin(tauri_plugin_dialog::init()) .setup(move |app| { // Note: tauri-plugin-log is NOT initialized here because telemetry::init() // already sets up tracing-subscriber (which bridges the `log` crate via // tracing's compatibility layer). Adding plugin-log would panic with // "attempted to set a logger after the logging system was already initialized". // Create TauriEventSink for core managers let sink: Arc = Arc::new(TauriEventSink(app.handle().clone())); // Build sidecar config from Tauri paths let resource_dir = app .handle() .path() .resource_dir() .unwrap_or_else(|e| { log::warn!("Failed to resolve resource_dir: {e}"); std::path::PathBuf::new() }); let dev_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) .parent() .unwrap() .to_path_buf(); let sidecar_config = SidecarConfig { search_paths: vec![ resource_dir.join("sidecar"), dev_root.join("sidecar"), ], }; let pty_manager = Arc::new(PtyManager::new(sink.clone())); let sidecar_manager = Arc::new(SidecarManager::new(sink, sidecar_config)); // Initialize session database let data_dir = dirs::data_dir() .unwrap_or_else(|| std::path::PathBuf::from(".")) .join("bterminal"); let session_db = Arc::new( SessionDb::open(&data_dir).expect("Failed to open session database"), ); let file_watcher = Arc::new(FileWatcherManager::new()); let fs_watcher = Arc::new(ProjectFsWatcher::new()); let ctx_db = Arc::new(ctx::CtxDb::new()); let memora_db = Arc::new(memora::MemoraDb::new()); let remote_manager = Arc::new(RemoteManager::new()); // Start local sidecar match sidecar_manager.start() { Ok(()) => log::info!("Sidecar startup initiated"), Err(e) => log::warn!("Sidecar startup failed (agent features unavailable): {e}"), } app.manage(AppState { pty_manager, sidecar_manager, session_db, file_watcher, fs_watcher, ctx_db, memora_db, remote_manager, _telemetry: telemetry_guard, }); Ok(()) }) .run(tauri::generate_context!()) .expect("error while running tauri application"); }