Skip to main content

Mountain/Binary/Main/
Entry.rs

1#![allow(unused_imports)]
2
3//! # Entry (Binary/Main)
4//!
5//! ## RESPONSIBILITIES
6//!
7//! Main application entry point that orchestrates the complete application
8//! lifecycle. This function coordinates:
9//! - Tokio runtime creation and management
10//! - CLI argument parsing
11//! - Application state initialization
12//! - Tauri application builder setup
13//! - Service initialization (Vine, Cocoon, Configuration)
14//! - Graceful shutdown handling
15//!
16//! ## ARCHITECTURAL ROLE
17//!
18//! The Entry module is the **primary entry point** in Mountain's architecture:
19//!
20//! ```text
21//! main.rs ──► Binary::Main::Entry::Fn()
22//!                                    │
23//!                                    ▼
24//! AppLifecycle ──► Service Initialization ──► Tauri App Run
25//!                                           │
26//!                                           ▼
27//!                                   Graceful Shutdown
28//! ```
29//!
30//! ## KEY COMPONENTS
31//!
32//! - **Fn()**: Main entry point exported as `Binary::Main::Fn()`
33//! - Tokio runtime management
34//! - Application state initialization via StateBuild
35//! - Tauri builder configuration via TauriBuild
36//! - Service orchestration (Vine, Cocoon, Configuration)
37//! - Event-driven lifecycle management
38//!
39//! ## ERROR HANDLING
40//!
41//! - Panics on fatal errors (Tokio runtime failure, Tauri build failure)
42//! - Logs errors for service initialization failures
43//! - Graceful degradation for non-critical service failures
44//!
45//! ## LOGGING
46//!
47//! Uses the TraceStep! macro for checkpoint logging at TRACE level.
48//! Additional logging at DEBUG, INFO, WARN, and ERROR levels throughout.
49//!
50//! ## PERFORMANCE CONSIDERATIONS
51//!
52//! - Tokio multi-threaded runtime for optimal performance
53//! - Asynchronous service initialization
54//! - Lazy initialization where possible
55//!
56//! ## TODO
57//! - [ ] Add crash recovery mechanism
58//! - [ ] Implement proper error dialog for startup failures
59//! - [ ] Add startup performance metrics
60
61use std::sync::{
62	Arc,
63	atomic::{AtomicBool, Ordering},
64};
65
66use tauri::{App, Manager, RunEvent, Wry};
67use Echo::Scheduler::{Scheduler::Scheduler, SchedulerBuilder::SchedulerBuilder};
68
69use crate::dev_log;
70use crate::{
71	// Crate root imports
72	ApplicationState::State::ApplicationState::ApplicationState,
73	Binary::Build::DnsCommands::{
74		StartupTime::init_dns_startup_time,
75		dns_get_forward_allowlist::dns_get_forward_allowlist,
76		dns_get_health_status::dns_get_health_status,
77		dns_get_server_info::dns_get_server_info,
78		dns_get_zone_info::dns_get_zone_info,
79		dns_health_check::dns_health_check,
80		dns_resolve::dns_resolve,
81		dns_test_resolution::dns_test_resolution,
82	},
83	// Binary submodule imports
84	Binary::Build::LocalhostPlugin::LocalhostPlugin as LocalhostPluginFn,
85	Binary::Build::LoggingPlugin::LoggingPlugin as LoggingPluginFn,
86	Binary::Build::Scheme::{self, DnsPort, init_service_registry, land_scheme_handler, register_land_service},
87	Binary::Build::ServiceRegistry::ServiceRegistry as ServiceRegistryFn,
88	Binary::Build::TauriBuild::TauriBuild as TauriBuildFn,
89	Binary::Build::WindowBuild::WindowBuild as WindowBuildFn,
90	Binary::Extension::ExtensionPopulate::ExtensionPopulate as ExtensionPopulateFn,
91	Binary::Extension::ScanPathConfigure::ScanPathConfigure as ScanPathConfigureFn,
92	Binary::Initialize::CliParse::Parse as CliParseFn,
93	Binary::Initialize::LogLevel::Resolve as ResolveLogLevel,
94	Binary::Initialize::PortSelector::BuildUrl as BuildPortUrl,
95	Binary::Initialize::PortSelector::Select as SelectPort,
96	Binary::Initialize::StateBuild::Build as BuildStateFn,
97	Binary::Register::AdvancedFeaturesRegister::AdvancedFeaturesRegister as AdvancedFeaturesRegisterFn,
98	Binary::Register::CommandRegister::CommandRegister as CommandRegisterFn,
99	Binary::Register::IPCServerRegister::IPCServerRegister as IPCServerRegisterFn,
100	Binary::Register::StatusReporterRegister::StatusReporterRegister as StatusReporterRegisterFn,
101	Binary::Register::WindSyncRegister::WindSyncRegister as WindSyncRegisterFn,
102	Binary::Service::CocoonStart::CocoonStart as CocoonStartFn,
103	Binary::Service::ConfigurationInitialize::ConfigurationInitialize as ConfigurationInitializeFn,
104	Binary::Service::VineStart::VineStart as VineStartFn,
105	Binary::Shutdown::RuntimeShutdown::RuntimeShutdown as RuntimeShutdownFn,
106	Binary::Shutdown::SchedulerShutdown::SchedulerShutdown as SchedulerShutdownFn,
107	Command,
108	Environment::MountainEnvironment::MountainEnvironment,
109	ProcessManagement::InitializationData,
110	RunTime::ApplicationRunTime::ApplicationRunTime,
111	Track,
112};
113use super::AppLifecycle::AppLifecycleSetup;
114
115// Note: Tauri commands are used with fully qualified paths in generate_handler
116// because the __cmd_* macros generated by #[tauri::command] are module-local.
117
118/// Logs a checkpoint message at TRACE level.
119macro_rules! TraceStep {
120	($($arg:tt)*) => {{
121		dev_log!("lifecycle", $($arg)*);
122	}};
123}
124
125/// The main function that orchestrates the application lifecycle.
126///
127/// This function:
128/// 1. Creates a Tokio runtime
129/// 2. Parses CLI arguments
130/// 3. Builds application state
131/// 4. Creates a scheduler
132/// 5. Selects a port for the local server
133/// 6. Resolves the log level
134/// 7. Sets up the Tauri builder
135/// 8. Configures the application lifecycle
136/// 9. Runs the Tauri application
137/// 10. Handles graceful shutdown
138pub fn Fn() {
139	// Open `Mountain.dev.log` up front. Forces `InitFileSink` to create
140	// the session log header on disk before any other code can panic, so
141	// an early crash still leaves a file with a timestamp + pid + tag
142	// context for post-mortem. Env vars are read from the shell here (the
143	// `.env.Land` load below may add MORE keys but never overrides
144	// Trace / Record because `set_var` only runs when a
145	// key is currently unset). Harmless to call: the inner `OnceLock`
146	// gates repeat invocations.
147	crate::IPC::DevLog::InitEager::Fn();
148
149	// -------------------------------------------------------------------------
150	// [Boot] [Env] Enhance the process environment with the user's
151	// interactive-shell PATH / NVM_DIR / HOMEBREW_PREFIX / JAVA_HOME / …
152	// before any child process is spawned. macOS GUI launches (Finder,
153	// Dock, Spotlight, `open <bundle>.app`) start the app with a minimal
154	// env where Homebrew, NVM, and similar are not on PATH; without this
155	// step the Cocoon node binary, language servers, and `git` calls
156	// from extensions all fall back to system defaults (or fail).
157	//
158	// No-op when launched from a TTY (terminal already has the right
159	// env) or when the shell probe fails / times out.
160	// -------------------------------------------------------------------------
161	crate::Environment::Utility::EnhanceShellEnvironment::Fn();
162
163	// -------------------------------------------------------------------------
164	// [Boot] [Env] Load .env.Land into process env so standalone binary
165	// invocations pick up Product*, Tier*, Network* vars without requiring
166	// the shell to pre-source the env file. Search order matches
167	// TierEnvironment.sh: cwd .env.Land → parent .env.Land → cwd
168	// .env.Land.Sample → parent .env.Land.Sample → repo-layout probe from
169	// the binary's canonical path (for `target/debug/...` launches where
170	// cwd is arbitrary).
171	// -------------------------------------------------------------------------
172	{
173		fn LoadEnvFile(Path:&std::path::Path) -> bool {
174			let Ok(Content) = std::fs::read_to_string(Path) else {
175				return false;
176			};
177			for Line in Content.lines() {
178				let Trimmed = Line.trim();
179				if Trimmed.is_empty() || Trimmed.starts_with('#') {
180					continue;
181				}
182				if let Some((Key, Value)) = Trimmed.split_once('=') {
183					let CleanKey = Key.trim();
184					let CleanValue = Value.trim().trim_matches('"').trim_matches('\'');
185					if std::env::var_os(CleanKey).is_none() {
186						// SAFETY: set_var is called once per key during bootstrap
187						// before any threads read env (Tokio runtime starts later
188						// in this function).
189						unsafe { std::env::set_var(CleanKey, CleanValue) };
190					}
191				}
192			}
193			true
194		}
195
196		let mut Candidates:Vec<std::path::PathBuf> = Vec::new();
197		if let Ok(Cwd) = std::env::current_dir() {
198			Candidates.push(Cwd.join(".env.Land"));
199			if let Some(Parent) = Cwd.parent() {
200				Candidates.push(Parent.join(".env.Land"));
201			}
202			Candidates.push(Cwd.join(".env.Land.Sample"));
203			if let Some(Parent) = Cwd.parent() {
204				Candidates.push(Parent.join(".env.Land.Sample"));
205			}
206		}
207		// Repo-layout probe: Target/debug/<bin> → four hops up lands at Land/.
208		if let Ok(Exe) = std::env::current_exe() {
209			let Ancestors:Vec<&std::path::Path> = Exe.ancestors().collect();
210			for Candidate in Ancestors.iter().take(6) {
211				Candidates.push(Candidate.join(".env.Land"));
212				Candidates.push(Candidate.join(".env.Land.Sample"));
213			}
214		}
215
216		let mut Loaded = false;
217		for Candidate in Candidates {
218			if Candidate.exists() && LoadEnvFile(&Candidate) {
219				crate::dev_log!("lifecycle", "[Boot] [Env] Loaded env from {}", Candidate.display());
220				Loaded = true;
221				break;
222			}
223		}
224		if !Loaded {
225			crate::dev_log!(
226				"lifecycle",
227				"[Boot] [Env] No .env.Land / .env.Land.Sample found - using defaults"
228			);
229		}
230	}
231
232	// -------------------------------------------------------------------------
233	// [Boot] [Tier] Resolved tier banner (Plan A Wave 1.7 runtime banner)
234	// -------------------------------------------------------------------------
235	crate::LandFixTier::LogResolvedTiers();
236
237	// -------------------------------------------------------------------------
238	// [Boot] [Profile] Self-report (BATCH-13 step 6)
239	//
240	// Build.sh exports `Browser`/`Mountain`/`Electron`/`Bundle`/`Compiler`/
241	// `Profile` into the shell that invokes cargo. `build.rs` captures
242	// those into `cargo:rustc-env=LAND_*` so they're baked into the binary -
243	// runtime env lookups don't survive launching the binary from Finder /
244	// another shell. `option_env!` falls back to "unknown" when the build
245	// ran outside Build.sh (e.g. plain `cargo build`).
246	// -------------------------------------------------------------------------
247	{
248		let NamedProfile = option_env!("Profile").unwrap_or("unknown");
249
250		let Workbench = option_env!("Pack").unwrap_or("Unknown");
251
252		let Bundle = option_env!("Bundle").unwrap_or("");
253
254		let Compiler = option_env!("Compiler").unwrap_or("default");
255
256		dev_log!(
257			"lifecycle",
258			"[LandFix:Profile] Active profile={} workbench={} bundle={} compiler={}",
259			NamedProfile,
260			Workbench,
261			Bundle,
262			Compiler
263		);
264	}
265
266	// -------------------------------------------------------------------------
267	// [Boot] [Runtime] Tokio runtime creation
268	// -------------------------------------------------------------------------
269	TraceStep!("[Boot] [Runtime] Building Tokio runtime...");
270
271	let Runtime = tokio::runtime::Builder::new_multi_thread()
272		.enable_all()
273		.build()
274		.expect("FATAL: Cannot build Tokio runtime.");
275
276	TraceStep!("[Boot] [Runtime] Tokio runtime built.");
277
278	Runtime.block_on(async {
279		// ---------------------------------------------------------------------
280		// [Boot] [Telemetry] Hydrate runtime env from compile-baked
281		// Constants so spawned children (Cocoon Node, Sky webview)
282		// see the same telemetry config Mountain itself was built
283		// with - even when the user invokes the bare binary without
284		// sourcing `.env.Land.PostHog`. Idempotent + debug-only.
285		// Must run BEFORE PostHogPlugin::Initialize so the client
286		// reads the same effective env as the children.
287		// ---------------------------------------------------------------------
288		crate::Binary::Build::PostHogPlugin::HydrateRuntimeEnvironment::Fn();
289
290		// ---------------------------------------------------------------------
291		// [Boot] [PostHog] Initialize telemetry client first so any
292		// error captured during the rest of boot lands in the project.
293		// No-op in release builds or when Report=false.
294		// ---------------------------------------------------------------------
295		crate::Binary::Build::PostHogPlugin::Initialize::Fn().await;
296
297		// ---------------------------------------------------------------------
298		// [Boot] [Common::Telemetry] Initialize the shared dual-pipe
299		// stack so library crates linked into Mountain (Echo, Mist,
300		// Common) emit through the same client. The HydrateRuntime
301		// Environment step above populated the env so this picks up
302		// the same Authorize/Beam/Capture values Mountain's plugin
303		// already loaded. Idempotent.
304		// ---------------------------------------------------------------------
305		CommonLibrary::Telemetry::Initialize::Fn(CommonLibrary::Telemetry::Tier::Tier::Mountain).await;
306
307		// ---------------------------------------------------------------------
308		// [Boot] [Args] CLI parsing (using CliParse module)
309		// ---------------------------------------------------------------------
310		let _WorkspaceConfigurationPath = CliParseFn();
311		let _InitialFolders:Vec<String> = vec![];
312
313		// ---------------------------------------------------------------------
314		// [Boot] [State] ApplicationState (using StateBuild module)
315		// ---------------------------------------------------------------------
316		dev_log!("lifecycle", "[Boot] [State] Building ApplicationState...");
317
318		// Create application state directly (StateBuild::Build with default config)
319		let AppState = ApplicationState::default();
320
321		// -------------------------------------------------------------------
322		// [Boot] [Workspace] Seed initial workspace folders so every extension
323		// that calls `vscode.workspace.findFiles(...)` at activation has
324		// something to walk. Precedence: --folder flags → positional dirs →
325		// Open env → CWD fallback. See
326		// CliParse::ParseWorkspaceFolders.
327		// -------------------------------------------------------------------
328		{
329			let InitialFolderPaths = crate::Binary::Initialize::CliParse::ParseWorkspaceFolders();
330			if InitialFolderPaths.is_empty() {
331				dev_log!(
332					"lifecycle",
333					"[Boot] [Workspace] No initial folders resolved - editor will open in \"no folder\" mode."
334				);
335			} else {
336				use crate::ApplicationState::DTO::WorkspaceFolderStateDTO::WorkspaceFolderStateDTO;
337				let mut Folders:Vec<WorkspaceFolderStateDTO> = Vec::new();
338				for (Index, Path) in InitialFolderPaths.iter().enumerate() {
339					let Uri = match url::Url::from_directory_path(Path) {
340						Ok(U) => U,
341						Err(()) => {
342							dev_log!(
343								"lifecycle",
344								"warn: [Boot] [Workspace] Failed to build URL for {}; skipping",
345								Path.display()
346							);
347							continue;
348						},
349					};
350					let Name = Path
351						.file_name()
352						.and_then(|N| N.to_str())
353						.map(str::to_string)
354						.unwrap_or_else(|| Path.display().to_string());
355					match WorkspaceFolderStateDTO::New(Uri, Name, Index) {
356						Ok(Dto) => Folders.push(Dto),
357						Err(Error) => {
358							dev_log!(
359								"lifecycle",
360								"warn: [Boot] [Workspace] Failed to build folder DTO for {}: {}",
361								Path.display(),
362								Error
363							);
364						},
365					}
366				}
367				if !Folders.is_empty() {
368					// Seed state directly; Cocoon is not yet spawned at this
369					// point, so there is no sidecar to notify. The initial
370					// workspace makes it to Cocoon via `InitializeExtensionHost`'s
371					// `workspace` payload during its handshake instead.
372					AppState.Workspace.SetWorkspaceFolders(Folders);
373					dev_log!(
374						"lifecycle",
375						"[Boot] [Workspace] Seeded {} workspace folder(s).",
376						InitialFolderPaths.len()
377					);
378				}
379			}
380		}
381
382		dev_log!(
383			"lifecycle",
384			"[Boot] [State] ApplicationState created with {} workspace folders.",
385			AppState.Workspace.WorkspaceFolders.lock().map(|f| f.len()).unwrap_or(0)
386		);
387
388		// Create Arc for application state to be managed by Tauri
389		let AppStateArcForClosure = Arc::new(AppState.clone());
390
391		// ---------------------------------------------------------------------
392		// [Boot] [Runtime] Scheduler handles (using RuntimeBuild module)
393		// ---------------------------------------------------------------------
394		let Scheduler = Arc::new(SchedulerBuilder::Create().Build());
395		let SchedulerForClosure = Scheduler.clone();
396		TraceStep!("[Boot] [Echo] Scheduler handles prepared.");
397
398		// ---------------------------------------------------------------------
399		// [Boot] [Localhost] Port selection (using PortSelector module)
400		// ---------------------------------------------------------------------
401		let ServerPort = SelectPort();
402		let LocalhostUrl = BuildPortUrl(ServerPort);
403
404		// ---------------------------------------------------------------------
405		// [Boot] [Logging] Log level resolution (using LogLevel module)
406		// ---------------------------------------------------------------------
407		let log_level = ResolveLogLevel();
408
409		// ---------------------------------------------------------------------
410		// [Boot] [Tauri] Builder setup (using TauriBuild module)
411		// ---------------------------------------------------------------------
412		let Builder = TauriBuildFn();
413
414		Builder
415			.plugin(LoggingPluginFn(log_level))
416			.plugin(LocalhostPluginFn(ServerPort))
417			.manage(AppStateArcForClosure.clone())
418			.setup({
419				let LocalhostUrl = LocalhostUrl.clone();
420				let ServerPortForClosure = ServerPort;
421				move |app:&mut App| {
422					dev_log!("lifecycle", "[Lifecycle] [Setup] Setup hook started.");
423					dev_log!("lifecycle", "[Lifecycle] [Setup] LocalhostUrl={}", LocalhostUrl);
424
425					// ---------------------------------------------------------
426					// [Service Registry] Initialize service registry for land:// routing
427					// ---------------------------------------------------------
428					dev_log!(
429						"lifecycle",
430						"[Lifecycle] [Setup] Initializing ServiceRegistry for land:// scheme..."
431					);
432					let service_registry = ServiceRegistryFn::new();
433					init_service_registry(service_registry.clone());
434
435					// ---------------------------------------------------------
436					// [Service Registry] Register local HTTP services
437					// ---------------------------------------------------------
438					// Register the main code editor service
439					dev_log!(
440						"lifecycle",
441						"[Lifecycle] [Setup] Registering code.editor.land service on port {}",
442						ServerPortForClosure
443					);
444					register_land_service("code.editor.land", ServerPortForClosure);
445
446					// Register API editor service (same port for now, can be separate later)
447					register_land_service("api.editor.land", ServerPortForClosure);
448
449					// Register assets editor service (same port for now, can be separate later)
450					register_land_service("assets.editor.land", ServerPortForClosure);
451
452					// Make the registry available as managed state for Tauri commands
453					app.manage(service_registry);
454					dev_log!(
455						"lifecycle",
456						"[Lifecycle] [Setup] ServiceRegistry initialized and services registered."
457					);
458
459					// ---------------------------------------------------------
460					// [DNS Server] Start the Hickory DNS server
461					// ---------------------------------------------------------
462					// The DNS server must start BEFORE any webview loads to ensure
463					// that land:// protocol_resolution is available
464					dev_log!("lifecycle", "[Lifecycle] [Setup] Starting DNS server on preferred port 5380...");
465					let dns_port = Mist::start(5380).unwrap_or_else(|e| {
466						dev_log!(
467							"lifecycle",
468							"warn: [Lifecycle] [Setup] Failed to start DNS server on port 5380: {}",
469							e
470						);
471						// Fallback to random port if preferred port fails
472						Mist::start(0).unwrap_or_else(|e| {
473							dev_log!(
474								"lifecycle",
475								"error: [Lifecycle] [Setup] Completely failed to start DNS server: {}",
476								e
477							);
478							0 // Return 0 as error indicator
479						})
480					});
481
482					if dns_port == 0 {
483						dev_log!(
484							"lifecycle",
485							"warn: [Lifecycle] [Setup] DNS server failed to start, land:// protocol will not be \
486							 available"
487						);
488					} else {
489						dev_log!(
490							"lifecycle",
491							"[Lifecycle] [Setup] DNS server started successfully on port {}",
492							dns_port
493						);
494						// Initialize DNS startup time for tracking
495						crate::Binary::Build::DnsCommands::StartupTime::init_dns_startup_time();
496					}
497
498					// Register DnsPort as managed state for Tauri commands
499					app.manage(DnsPort(dns_port));
500
501					let AppHandle = app.handle().clone();
502					TraceStep!("[Lifecycle] [Setup] AppHandle acquired.");
503
504					// ---------------------------------------------------------
505					// Setup application lifecycle through AppLifecycle module
506					// ---------------------------------------------------------
507					let AppStateArcFromClosure = AppStateArcForClosure.clone();
508
509					if let Err(e) = AppLifecycleSetup(
510						app,
511						AppHandle.clone(),
512						LocalhostUrl.clone(),
513						SchedulerForClosure.clone(),
514						AppStateArcFromClosure,
515					) {
516						dev_log!("lifecycle", "error: [Lifecycle] [Setup] Failed to setup lifecycle: {}", e);
517					}
518
519					Ok(())
520				}
521			})
522			.register_asynchronous_uri_scheme_protocol("land", |_ctx, request, responder| {
523				// Implemented: delegate to synchronous scheme handler
524				let response = crate::Binary::Build::Scheme::land_scheme_handler(&request);
525				responder.respond(response);
526			})
527			.register_asynchronous_uri_scheme_protocol("vscode-file", |ctx, request, responder| {
528				// VS Code Electron workbench uses vscode-file:// to load assets.
529				// Maps to embedded frontend assets from Sky/Target.
530				let AppHandle = ctx.app_handle().clone();
531				std::thread::spawn(move || {
532					let response = crate::Binary::Build::Scheme::VscodeFileSchemeHandler(&AppHandle, &request);
533					responder.respond(response);
534				});
535			})
536			.register_asynchronous_uri_scheme_protocol("vscode-webview", |ctx, request, responder| {
537				// VS Code's `WebviewElement` wraps every extension webview in
538				// an iframe whose `src` is `vscode-webview://<authority>/index.html?...`.
539				// Without this handler the iframe stays blank and every
540				// extension that uses `webviewView` / `WebviewPanel` /
541				// `CustomEditor` (Roo Code, Claude, GitLens, custom editors)
542				// is dead. The handler serves the three-file `pre/`
543				// directory (`index.html`, `service-worker.js`, `fake.html`);
544				// extension HTML itself comes through later via the workbench's
545				// `swMessage` postMessage channel, not this scheme.
546				let AppHandle = ctx.app_handle().clone();
547				std::thread::spawn(move || {
548					let response = crate::Binary::Build::Scheme::VscodeWebviewSchemeHandler(&AppHandle, &request);
549					responder.respond(response);
550				});
551			})
552			.register_asynchronous_uri_scheme_protocol("vscode-webview-resource", |ctx, request, responder| {
553				// `vscode-webview-resource://<auth>/<path>` is the URI shape
554				// stock VS Code emits from `webview.asWebviewUri(...)`. The
555				// service worker inside `pre/index.html` would normally
556				// intercept these and proxy through the host. Land disables
557				// that SW (see Output `PatchWebviewIframeServiceWorker`)
558				// because WKWebView refuses SW registration on the
559				// `vscode-webview://` custom protocol; instead we register
560				// this scheme directly so any extension that hard-codes
561				// the URI form (or didn't go through Cocoon's `asWebviewUri`
562				// rewrite) still resolves. Strip the `<auth>` and forward
563				// the path to `VscodeFileSchemeHandler` by rewriting the
564				// URI to `vscode-file://vscode-app/<path>`.
565				let AppHandle = ctx.app_handle().clone();
566				std::thread::spawn(move || {
567					let Original = request.uri().to_string();
568					let RewrittenUri = match Original.strip_prefix("vscode-webview-resource://") {
569						Some(After) => {
570							let Rest = After.find('/').map(|I| &After[I..]).unwrap_or("/");
571							format!("vscode-file://vscode-app{}", Rest)
572						},
573						None => "vscode-file://vscode-app/".to_string(),
574					};
575					crate::dev_log!(
576						"scheme-assets",
577						"[LandFix:VscodeWebviewResource] {} -> {}",
578						Original,
579						RewrittenUri
580					);
581					let mut Builder = tauri::http::request::Request::builder().uri(&RewrittenUri);
582					for (Name, Value) in request.headers().iter() {
583						Builder = Builder.header(Name, Value);
584					}
585					let Forwarded = Builder
586						.method(request.method().clone())
587						.body(request.body().clone())
588						.unwrap_or_else(|_| request.clone());
589					let response = crate::Binary::Build::Scheme::VscodeFileSchemeHandler(&AppHandle, &Forwarded);
590					responder.respond(response);
591				});
592			})
593			.register_asynchronous_uri_scheme_protocol("vscode-resource", |ctx, request, responder| {
594				// Legacy stock-VS Code resource scheme. Same handling as
595				// `vscode-webview-resource` - rewrite to `vscode-file://`
596				// and dispatch through the existing file handler.
597				let AppHandle = ctx.app_handle().clone();
598				std::thread::spawn(move || {
599					let Original = request.uri().to_string();
600					let RewrittenUri = match Original.strip_prefix("vscode-resource://") {
601						Some(After) => {
602							let Rest = After.find('/').map(|I| &After[I..]).unwrap_or("/");
603							format!("vscode-file://vscode-app{}", Rest)
604						},
605						None => "vscode-file://vscode-app/".to_string(),
606					};
607					crate::dev_log!("scheme-assets", "[LandFix:VscodeResource] {} -> {}", Original, RewrittenUri);
608					let mut Builder = tauri::http::request::Request::builder().uri(&RewrittenUri);
609					for (Name, Value) in request.headers().iter() {
610						Builder = Builder.header(Name, Value);
611					}
612					let Forwarded = Builder
613						.method(request.method().clone())
614						.body(request.body().clone())
615						.unwrap_or_else(|_| request.clone());
616					let response = crate::Binary::Build::Scheme::VscodeFileSchemeHandler(&AppHandle, &Forwarded);
617					responder.respond(response);
618				});
619			})
620			.plugin(tauri_plugin_dialog::init())
621			.plugin(tauri_plugin_fs::init())
622			.invoke_handler(tauri::generate_handler![
623				crate::Binary::Tray::SwitchTrayIcon::SwitchTrayIcon,
624				crate::Binary::IPC::WorkbenchConfigurationCommand::MountainGetWorkbenchConfiguration,
625				Command::TreeView::GetTreeViewChildren::GetTreeViewChildren,
626				Command::LanguageFeature::MountainProvideHover::MountainProvideHover,
627				Command::LanguageFeature::MountainProvideCompletions::MountainProvideCompletions,
628				Command::LanguageFeature::MountainProvideDefinition::MountainProvideDefinition,
629				Command::LanguageFeature::MountainProvideReferences::MountainProvideReferences,
630				Command::SourceControlManagement::GetAllSourceControlManagementState::GetAllSourceControlManagementState,
631				Command::Keybinding::GetResolvedKeybinding::GetResolvedKeybinding,
632				Track::FrontendCommand::DispatchFrontendCommand::DispatchFrontendCommand,
633				Track::UIRequest::ResolveUIRequest::ResolveUIRequest,
634				Track::Webview::MountainWebviewPostMessageFromGuest::MountainWebviewPostMessageFromGuest,
635				crate::Binary::IPC::MessageReceiveCommand::MountainIPCReceiveMessage,
636				crate::Binary::IPC::StatusGetCommand::MountainIPCGetStatus,
637				crate::Binary::IPC::InvokeCommand::MountainIPCInvoke,
638				crate::Binary::IPC::WindConfigurationCommand::MountainGetWindDesktopConfiguration,
639				crate::Binary::IPC::ConfigurationUpdateCommand::MountainUpdateConfigurationFromWind,
640				crate::Binary::IPC::ConfigurationSyncCommand::MountainSynchronizeConfiguration,
641				crate::Binary::IPC::ConfigurationStatusCommand::MountainGetConfigurationStatus,
642				crate::Binary::IPC::IPCStatusCommand::MountainGetIPCStatus,
643				crate::Binary::IPC::IPCStatusHistoryCommand::MountainGetIPCStatusHistory,
644				crate::Binary::IPC::IPCStatusReportingStartCommand::MountainStartIPCStatusReporting,
645				crate::Binary::IPC::PerformanceStatsCommand::MountainGetPerformanceStats,
646				crate::Binary::IPC::CacheStatsCommand::MountainGetCacheStats,
647				crate::Binary::IPC::CollaborationSessionCommand::MountainCreateCollaborationSession,
648				crate::Binary::IPC::CollaborationSessionCommand::MountainGetCollaborationSessions,
649				crate::Binary::IPC::DocumentSyncCommand::MountainAddDocumentForSync,
650				crate::Binary::IPC::DocumentSyncCommand::MountainGetSyncStatus,
651				crate::Binary::IPC::UpdateSubscriptionCommand::MountainSubscribeToUpdates,
652				crate::Binary::IPC::ConfigurationDataCommand::GetConfigurationData,
653				crate::Binary::IPC::ConfigurationDataCommand::SaveConfigurationData,
654				crate::Binary::IPC::WorkspaceFolderCommand::MountainWorkspaceOpenFolder,
655				crate::Binary::IPC::WorkspaceFolderCommand::MountainWorkspaceListFolders,
656				crate::Binary::IPC::WorkspaceFolderCommand::MountainWorkspaceCloseAllFolders,
657				crate::Binary::Build::DnsCommands::dns_get_server_info::dns_get_server_info,
658				crate::Binary::Build::DnsCommands::dns_get_zone_info::dns_get_zone_info,
659				crate::Binary::Build::DnsCommands::dns_get_forward_allowlist::dns_get_forward_allowlist,
660				crate::Binary::Build::DnsCommands::dns_get_health_status::dns_get_health_status,
661				crate::Binary::Build::DnsCommands::dns_resolve::dns_resolve,
662				crate::Binary::Build::DnsCommands::dns_test_resolution::dns_test_resolution,
663				crate::Binary::Build::DnsCommands::dns_health_check::dns_health_check,
664				// Process commands (direct Tauri invoke from ProcessPolyfill)
665				crate::Binary::IPC::ProcessCommand::process_get_exec_path::process_get_exec_path,
666				crate::Binary::IPC::ProcessCommand::process_get_platform::process_get_platform,
667				crate::Binary::IPC::ProcessCommand::process_get_arch::process_get_arch,
668				crate::Binary::IPC::ProcessCommand::process_get_pid::process_get_pid,
669				crate::Binary::IPC::ProcessCommand::process_get_shell_env::process_get_shell_env,
670				crate::Binary::IPC::ProcessCommand::process_get_memory_info::process_get_memory_info,
671				// Health check commands (direct Tauri invoke from SharedProcessProxy)
672				crate::Binary::IPC::HealthCommand::cocoon_extension_host_health::cocoon_extension_host_health,
673				crate::Binary::IPC::HealthCommand::cocoon_search_service_health::cocoon_search_service_health,
674				crate::Binary::IPC::HealthCommand::cocoon_debug_service_health::cocoon_debug_service_health,
675				crate::Binary::IPC::HealthCommand::shared_process_service_health::shared_process_service_health,
676				crate::Binary::IPC::RenderDevLogCommand::RenderDevLog,
677				// LAND-PATCH B7-S6 P14.5: Vine notification broadcast
678				// subscription. `vine_subscribe_notifications` opens a
679				// Tauri Channel that drains the process-wide
680				// `Vine::Client` broadcast into the webview; Effect-TS
681				// `VineNotificationsLive` Layer wraps it as a
682				// `Stream<NotificationFrame>`. `vine_subscriber_count`
683				// is a diagnostic for verifying registrations didn't
684				// leak across reloads.
685				crate::Binary::IPC::VineSubscribeCommand::vine_subscribe_notifications,
686				crate::Binary::IPC::VineSubscribeCommand::vine_subscriber_count,
687			])
688			.build(tauri::generate_context!())
689			.expect("FATAL: Error while building Mountain Tauri application")
690			.run(move |app_handle:&tauri::AppHandle, event:tauri::RunEvent| {
691				// Debug-only: log selected lifecycle events
692				if cfg!(debug_assertions) {
693					match &event {
694						RunEvent::MainEventsCleared => {},
695						RunEvent::WindowEvent { .. } => {},
696						_ => dev_log!("lifecycle", "[Lifecycle] [RunEvent] {:?}", event),
697					}
698				}
699
700				if let RunEvent::ExitRequested { api, .. } = event {
701					// Shutdown runs once. The graceful path ends with
702					// `app_handle.exit(0)`, which Tauri re-delivers as a
703					// second `ExitRequested { code: Some(0) }`. On re-entry
704					// we must NOT `prevent_exit` or spawn the shutdown task
705					// again - Cocoon has already been SIGKILLed and the
706					// second pass would log spurious "tcp connect error"
707					// warnings trying to notify a dead sidecar.
708					static SHUTTING_DOWN:AtomicBool = AtomicBool::new(false);
709					if SHUTTING_DOWN.swap(true, Ordering::SeqCst) {
710						return;
711					}
712
713					dev_log!(
714						"lifecycle",
715						"warn: [Lifecycle] [Shutdown] Exit requested. Starting graceful shutdown..."
716					);
717					api.prevent_exit();
718
719					let SchedulerHandle = Scheduler.clone();
720					let app_handle_clone = app_handle.clone();
721
722					tokio::spawn(async move {
723						dev_log!("lifecycle", "[Lifecycle] [Shutdown] Shutting down ApplicationRunTime...");
724						let _ = RuntimeShutdownFn(&app_handle_clone).await;
725
726						dev_log!("lifecycle", "[Lifecycle] [Shutdown] Stopping Echo scheduler...");
727						let _ = SchedulerShutdownFn(SchedulerHandle).await;
728
729						dev_log!("lifecycle", "[Lifecycle] [Shutdown] Done. Exiting process.");
730						app_handle_clone.exit(0);
731					});
732				}
733			});
734
735		dev_log!("lifecycle", "[Lifecycle] [Exit] Mountain application has shut down.");
736	});
737}