11using System . Threading ;
22using Avalonia ;
3+ #if AVALONIA_DIAGNOSTICS_ENABLED
34using AvaloniaUI . DiagnosticsProtocol ;
5+ #endif
46using UniGetUI . Avalonia . Infrastructure ;
57using UniGetUI . Core . Data ;
68using UniGetUI . Core . Logging ;
@@ -11,10 +13,22 @@ namespace UniGetUI.Avalonia;
1113
1214internal sealed class Program
1315{
16+ private const string DevToolsEnvVar = "UNIGETUI_AVALONIA_DEVTOOLS" ;
17+
18+ private enum DevToolsRuntimeMode
19+ {
20+ Auto ,
21+ Enabled ,
22+ Disabled ,
23+ }
24+
1425 // Kept alive for the lifetime of the process to enforce single-instance
1526 // ReSharper disable once NotAccessedField.Local
1627 private static Mutex ? _singleInstanceMutex ;
1728
29+ private static DevToolsRuntimeMode _devToolsRuntimeMode = DevToolsRuntimeMode . Auto ;
30+ private static string _devToolsRuntimeModeSource = "default" ;
31+
1832 [ STAThread ]
1933 public static void Main ( string [ ] args )
2034 {
@@ -61,6 +75,10 @@ public static void Main(string[] args)
6175 return ;
6276 }
6377
78+ ( _devToolsRuntimeMode , _devToolsRuntimeModeSource ) = ResolveDevToolsRuntimeMode ( args ) ;
79+ Logger . Info (
80+ $ "Avalonia DevTools runtime mode: { _devToolsRuntimeMode } (source: { _devToolsRuntimeModeSource } )") ;
81+
6482 // ── Single-instance enforcement ────────────────────────────────────
6583 _singleInstanceMutex = new Mutex (
6684 initiallyOwned : true ,
@@ -263,22 +281,173 @@ private static void ReportFatalException(Exception ex)
263281 catch { /* best-effort */ }
264282 }
265283
284+ private static ( DevToolsRuntimeMode Mode , string Source ) ResolveDevToolsRuntimeMode (
285+ string [ ] args )
286+ {
287+ if ( TryGetDevToolsModeFromCli ( args , out DevToolsRuntimeMode cliMode ) )
288+ {
289+ return ( cliMode , "cli" ) ;
290+ }
291+
292+ string ? envValue = Environment . GetEnvironmentVariable ( DevToolsEnvVar ) ;
293+ if ( TryParseDevToolsRuntimeMode ( envValue , out DevToolsRuntimeMode envMode ) )
294+ {
295+ return ( envMode , "env" ) ;
296+ }
297+
298+ if ( ! string . IsNullOrWhiteSpace ( envValue ) )
299+ {
300+ Logger . Warn (
301+ $ "Ignoring invalid { DevToolsEnvVar } value '{ envValue } '. Expected one of: auto, on, off, true, false, 1, 0.") ;
302+ }
303+
304+ return ( DevToolsRuntimeMode . Auto , "default" ) ;
305+ }
306+
307+ private static bool TryGetDevToolsModeFromCli (
308+ IEnumerable < string > args ,
309+ out DevToolsRuntimeMode mode )
310+ {
311+ bool found = false ;
312+ mode = DevToolsRuntimeMode . Auto ;
313+
314+ foreach ( string rawArg in args )
315+ {
316+ string arg = rawArg . Trim ( ) ;
317+
318+ if ( arg . Equals ( "--enable-devtools" , StringComparison . OrdinalIgnoreCase ) )
319+ {
320+ mode = DevToolsRuntimeMode . Enabled ;
321+ found = true ;
322+ continue ;
323+ }
324+
325+ if ( arg . Equals ( "--disable-devtools" , StringComparison . OrdinalIgnoreCase ) )
326+ {
327+ mode = DevToolsRuntimeMode . Disabled ;
328+ found = true ;
329+ continue ;
330+ }
331+
332+ const string modePrefix = "--devtools-mode=" ;
333+ if ( ! arg . StartsWith ( modePrefix , StringComparison . OrdinalIgnoreCase ) )
334+ {
335+ continue ;
336+ }
337+
338+ string modeValue = arg [ modePrefix . Length ..] . Trim ( ) ;
339+ if ( TryParseDevToolsRuntimeMode ( modeValue , out DevToolsRuntimeMode parsedMode ) )
340+ {
341+ mode = parsedMode ;
342+ found = true ;
343+ }
344+ else
345+ {
346+ Logger . Warn (
347+ $ "Ignoring invalid --devtools-mode value '{ modeValue } '. Expected one of: auto, enabled, disabled.") ;
348+ }
349+ }
350+
351+ return found ;
352+ }
353+
354+ private static bool TryParseDevToolsRuntimeMode (
355+ string ? value ,
356+ out DevToolsRuntimeMode mode )
357+ {
358+ mode = DevToolsRuntimeMode . Auto ;
359+ if ( string . IsNullOrWhiteSpace ( value ) )
360+ {
361+ return false ;
362+ }
363+
364+ switch ( value . Trim ( ) . ToLowerInvariant ( ) )
365+ {
366+ case "auto" :
367+ mode = DevToolsRuntimeMode . Auto ;
368+ return true ;
369+ case "enabled" :
370+ case "enable" :
371+ case "on" :
372+ case "true" :
373+ case "1" :
374+ mode = DevToolsRuntimeMode . Enabled ;
375+ return true ;
376+ case "disabled" :
377+ case "disable" :
378+ case "off" :
379+ case "false" :
380+ case "0" :
381+ mode = DevToolsRuntimeMode . Disabled ;
382+ return true ;
383+ default :
384+ return false ;
385+ }
386+ }
387+
266388 public static AppBuilder BuildAvaloniaApp ( )
267389 {
268390 var builder = AppBuilder . Configure < App > ( )
269391 . UsePlatformDetect ( )
270392 . LogToTrace ( ) ;
271393
272- #if DEBUG
273- builder = builder . WithDeveloperTools ( options =>
394+ #if AVALONIA_DIAGNOSTICS_ENABLED
395+ bool isWsl = IsRunningInWsl ( ) ;
396+ bool shouldEnableDevTools = _devToolsRuntimeMode switch
397+ {
398+ DevToolsRuntimeMode . Enabled => true ,
399+ DevToolsRuntimeMode . Disabled => false ,
400+ _ => ! isWsl ,
401+ } ;
402+
403+ if ( _devToolsRuntimeMode == DevToolsRuntimeMode . Auto && isWsl )
404+ {
405+ Logger . Warn ( "Avalonia DevTools auto mode disabled on WSL to avoid avdt runner crashes." ) ;
406+ }
407+
408+ if ( _devToolsRuntimeMode == DevToolsRuntimeMode . Enabled && isWsl )
409+ {
410+ Logger . Warn ( "Avalonia DevTools explicitly enabled on WSL. This configuration may be unstable." ) ;
411+ }
412+
413+ if ( shouldEnableDevTools )
274414 {
275- options . ApplicationName = "UniGetUI.Avalonia" ;
276- options . ConnectOnStartup = true ;
277- options . EnableDiscovery = true ;
278- options . DiagnosticLogger = DiagnosticLogger . CreateConsole ( ) ;
279- } ) ;
415+ builder = builder . WithDeveloperTools ( options =>
416+ {
417+ options . ApplicationName = "UniGetUI.Avalonia" ;
418+ options . ConnectOnStartup = true ;
419+ options . EnableDiscovery = true ;
420+ options . DiagnosticLogger = DiagnosticLogger . CreateConsole ( ) ;
421+ } ) ;
422+ Logger . Info (
423+ $ "Avalonia DevTools enabled (mode: { _devToolsRuntimeMode } , source: { _devToolsRuntimeModeSource } ).") ;
424+ }
425+ else
426+ {
427+ Logger . Info (
428+ $ "Avalonia DevTools disabled (mode: { _devToolsRuntimeMode } , source: { _devToolsRuntimeModeSource } ).") ;
429+ }
430+ #else
431+ if ( _devToolsRuntimeMode != DevToolsRuntimeMode . Auto )
432+ {
433+ Logger . Warn (
434+ "Avalonia DevTools runtime toggle was requested, but diagnostics support is not included in this build." ) ;
435+ }
280436#endif
281437
282438 return builder ;
283439 }
440+
441+ #if AVALONIA_DIAGNOSTICS_ENABLED
442+ private static bool IsRunningInWsl ( )
443+ {
444+ if ( ! OperatingSystem . IsLinux ( ) )
445+ return false ;
446+
447+ if ( ! string . IsNullOrWhiteSpace ( Environment . GetEnvironmentVariable ( "WSL_DISTRO_NAME" ) ) )
448+ return true ;
449+
450+ return ! string . IsNullOrWhiteSpace ( Environment . GetEnvironmentVariable ( "WSL_INTEROP" ) ) ;
451+ }
452+ #endif
284453}
0 commit comments