1use std::sync::Arc;
68
69use tauri::Manager;
70use Echo::Scheduler::Scheduler::Scheduler;
71
72use crate::dev_log;
73use crate::{
74 ApplicationState::ApplicationState,
76 Binary::Build::WindowBuild::WindowBuild as WindowBuildFn,
78 Binary::Extension::ExtensionPopulate::ExtensionPopulate as ExtensionPopulateFn,
79 Binary::Extension::ScanPathConfigure::ScanPathConfigure as ScanPathConfigureFn,
80 Binary::Register::AdvancedFeaturesRegister::AdvancedFeaturesRegister as AdvancedFeaturesRegisterFn,
81 Binary::Register::CommandRegister::CommandRegister as CommandRegisterFn,
82 Binary::Register::IPCServerRegister::IPCServerRegister as IPCServerRegisterFn,
83 Binary::Register::StatusReporterRegister::StatusReporterRegister as StatusReporterRegisterFn,
84 Binary::Register::WindSyncRegister::WindSyncRegister as WindSyncRegisterFn,
85 Binary::Service::CocoonStart::CocoonStart as CocoonStartFn,
86 Binary::Service::ConfigurationInitialize::ConfigurationInitialize as ConfigurationInitializeFn,
87 Binary::Service::VineStart::VineStart as VineStartFn,
88 Binary::Tray::EnableTray as EnableTrayFn,
89 Environment::MountainEnvironment::MountainEnvironment,
90 RunTime::ApplicationRunTime::ApplicationRunTime,
91};
92
93macro_rules! TraceStep {
95 ($($arg:tt)*) => {{
96 dev_log!("lifecycle", $($arg)*);
97 }};
98}
99
100pub fn AppLifecycleSetup(
127 app:&mut tauri::App,
128 app_handle:tauri::AppHandle,
129 localhost_url:String,
130 scheduler:Arc<Scheduler>,
131 app_state:Arc<ApplicationState>,
132) -> Result<(), Box<dyn std::error::Error>> {
133 dev_log!("lifecycle", "[Lifecycle] [Setup] Setup hook started.");
134 dev_log!("lifecycle", "[Lifecycle] [Setup] LocalhostUrl={}", localhost_url);
135
136 let app_handle_for_setup = app_handle.clone();
137 TraceStep!("[Lifecycle] [Setup] AppHandle acquired.");
138
139 dev_log!("lifecycle", "[UI] [Tray] Initializing system tray...");
143 if let Err(Error) = EnableTrayFn::enable_tray(app) {
144 dev_log!("lifecycle", "error: [UI] [Tray] Failed to enable tray: {}", Error);
145 }
146
147 dev_log!("lifecycle", "[Lifecycle] [Commands] Registering native commands...");
151 if let Err(e) = CommandRegisterFn(&app_handle_for_setup, &app_state) {
152 dev_log!("lifecycle", "error: [Lifecycle] [Commands] Failed to register commands: {}", e);
153 }
154 dev_log!("lifecycle", "[Lifecycle] [Commands] Native commands registered.");
155
156 dev_log!("lifecycle", "[Lifecycle] [IPC] Initializing Mountain IPC Server...");
160 if let Err(e) = IPCServerRegisterFn(&app_handle_for_setup) {
161 dev_log!("lifecycle", "error: [Lifecycle] [IPC] Failed to register IPC server: {}", e);
162 }
163
164 dev_log!("lifecycle", "[UI] [Window] Building main window...");
168 let MainWindow = WindowBuildFn(app, localhost_url.clone());
169 dev_log!("lifecycle", "[UI] [Window] Main window ready.");
170
171 #[cfg(debug_assertions)]
172 {
173 dev_log!("lifecycle", "[UI] [Window] Debug build: opening DevTools.");
174 MainWindow.open_devtools();
175 }
176
177 {
181 let PathResolver = app.path();
182 let AppDataDir = PathResolver.app_data_dir().unwrap_or_default();
183 let LogDir = PathResolver.app_log_dir().unwrap_or_default();
184 let HomeDir = PathResolver.home_dir().unwrap_or_default();
185
186 crate::IPC::WindServiceHandlers::set_userdata_base_dir(AppDataDir.to_string_lossy().to_string());
189
190 let SkyTargetDir = PathResolver.resource_dir().unwrap_or_else(|_| {
194 #[cfg(debug_assertions)]
200 {
201 std::env::current_exe()
202 .ok()
203 .and_then(|Exe| Exe.parent().map(|P| P.to_path_buf()))
204 .unwrap_or_default()
205 .join("../../../Sky/Target")
206 }
207 #[cfg(not(debug_assertions))]
208 {
209 std::path::PathBuf::new()
210 }
211 });
212 crate::IPC::WindServiceHandlers::set_static_application_root(SkyTargetDir.to_string_lossy().to_string());
213 dev_log!(
214 "lifecycle",
215 "[Lifecycle] [Dirs] Static application root: {}",
216 SkyTargetDir.display()
217 );
218
219 let Dirs = [
221 AppDataDir.join("User"),
223 AppDataDir.join("User/globalStorage"),
224 AppDataDir.join("User/workspaceStorage"),
225 AppDataDir.join("User/workspaceStorage/vscode-chat-images"),
226 AppDataDir.join("User/extensions"),
227 AppDataDir.join("User/profiles/__default__profile__"),
228 AppDataDir.join("User/snippets"),
229 AppDataDir.join("User/prompts"),
230 AppDataDir.join("User/caches"),
231 AppDataDir.join("CachedConfigurations/defaults/__default__profile__-configurationDefaultsOverrides"),
233 LogDir.join("window1"),
235 SkyTargetDir.join("Static/Application/extensions"),
238 HomeDir.join(".claude/agents"),
240 HomeDir.join(".copilot/agents"),
241 ];
242 for Dir in &Dirs {
243 if let Err(Error) = std::fs::create_dir_all(Dir) {
244 dev_log!(
245 "lifecycle",
246 "warn: [Lifecycle] [Dirs] Failed to create {}: {}",
247 Dir.display(),
248 Error
249 );
250 }
251 }
252
253 let DefaultFiles:&[(&std::path::Path, &str)] = &[
255 (&AppDataDir.join("User/settings.json"), "{}"),
256 (&AppDataDir.join("User/keybindings.json"), "[]"),
257 (&AppDataDir.join("User/tasks.json"), "{}"),
258 (&AppDataDir.join("User/extensions.json"), "[]"),
259 (&AppDataDir.join("User/mcp.json"), "{}"),
260 ];
261 for (FilePath, DefaultContent) in DefaultFiles {
262 if !FilePath.exists() {
263 let _ = std::fs::write(FilePath, DefaultContent);
264 }
265 }
266
267 if let Ok(mut Path) = app_state.GlobalMementoPath.lock() {
269 *Path = AppDataDir.join("User/globalStorage/global.json");
270 dev_log!("lifecycle", "[Lifecycle] [Dirs] GlobalMementoPath: {}", Path.display());
271 }
272 dev_log!(
273 "lifecycle",
274 "[Lifecycle] [Dirs] Userdata directories ensured at {}",
275 AppDataDir.display()
276 );
277 }
278
279 dev_log!("lifecycle", "[Backend] [Env] Creating MountainEnvironment...");
283 let Environment = Arc::new(MountainEnvironment::Create(app_handle_for_setup.clone(), app_state.clone()));
284 dev_log!("lifecycle", "[Backend] [Env] MountainEnvironment ready.");
285
286 dev_log!("lifecycle", "[Backend] [Runtime] Creating ApplicationRunTime...");
290 let Runtime = Arc::new(ApplicationRunTime::Create(scheduler.clone(), Environment.clone()));
291 app_handle_for_setup.manage(Runtime.clone());
292 dev_log!("lifecycle", "[Backend] [Runtime] ApplicationRunTime managed.");
293
294 if let Err(e) = StatusReporterRegisterFn(&app_handle_for_setup, Runtime.clone()) {
298 dev_log!(
299 "lifecycle",
300 "error: [Lifecycle] [IPC] Failed to initialize status reporter: {}",
301 e
302 );
303 }
304
305 if let Err(e) = AdvancedFeaturesRegisterFn(&app_handle_for_setup, Runtime.clone()) {
309 dev_log!(
310 "lifecycle",
311 "error: [Lifecycle] [IPC] Failed to initialize advanced features: {}",
312 e
313 );
314 }
315
316 if let Err(e) = WindSyncRegisterFn(&app_handle_for_setup, Runtime.clone()) {
320 dev_log!(
321 "lifecycle",
322 "error: [Lifecycle] [IPC] Failed to initialize wind advanced sync: {}",
323 e
324 );
325 }
326
327 let PostSetupAppHandle = app_handle_for_setup.clone();
331 let PostSetupEnvironment = Environment.clone();
332
333 tauri::async_runtime::spawn(async move {
334 dev_log!("lifecycle", "[Lifecycle] [PostSetup] Starting...");
335 let PostSetupStart = crate::IPC::DevLog::NowNano();
336 let AppStateForSetup = PostSetupEnvironment.ApplicationState.clone();
337 TraceStep!("[Lifecycle] [PostSetup] AppState cloned.");
338
339 let ConfigStart = crate::IPC::DevLog::NowNano();
341 let _ = ConfigurationInitializeFn(&PostSetupEnvironment).await;
342 crate::otel_span!("lifecycle:config:initialize", ConfigStart);
343
344 AppStateForSetup.Workspace.SetTrustStatus(true);
346
347 let ExtScanStart = crate::IPC::DevLog::NowNano();
349 let _ = ScanPathConfigureFn(&AppStateForSetup);
350
351 let _ = ExtensionPopulateFn(PostSetupAppHandle.clone(), &AppStateForSetup).await;
353 crate::otel_span!("lifecycle:extensions:scan", ExtScanStart);
354
355 let VineStart = crate::IPC::DevLog::NowNano();
357 let _ = VineStartFn(
358 PostSetupAppHandle.clone(),
359 "127.0.0.1:50051".to_string(),
360 "127.0.0.1:50052".to_string(),
361 )
362 .await;
363 crate::otel_span!("lifecycle:vine:start", VineStart);
364
365 let CocoonStart = crate::IPC::DevLog::NowNano();
367 let _ = CocoonStartFn(&PostSetupAppHandle, &PostSetupEnvironment).await;
368 crate::otel_span!("lifecycle:cocoon:start", CocoonStart);
369
370 crate::otel_span!("lifecycle:postsetup:complete", PostSetupStart);
371 dev_log!("lifecycle", "[Lifecycle] [PostSetup] Complete. System ready.");
372 });
373
374 Ok(())
375}