From eae6626635bad92f2cfcc8e6eb9b1a931e41e1f1 Mon Sep 17 00:00:00 2001 From: Scott Hanselman Date: Thu, 29 Jan 2026 00:27:37 -0800 Subject: [PATCH 1/7] WinUI 3 port using WinUIEx TrayIcon - Complete port of Moltbot.Tray to WinUI 3 - Custom TrayMenuWindow for proper multi-monitor positioning - DPI-aware with PerMonitorV2 manifest - All services ported: Logger, SettingsManager, AutoStartManager, etc. - All windows: Settings, WebChat, StatusDetail, NotificationHistory - Gateway connection and health monitoring working - Fixed XAML compiler crash bug (documented in XAML_COMPILER_BUG.md) --- XAML_COMPILER_BUG.md | 78 ++ input.json.bak | 1 + moltbot-windows-hub.slnx | 1 + src/Moltbot.Shared/Moltbot.Shared.csproj | 2 +- src/Moltbot.Tray.WinUI/App.xaml | 25 + src/Moltbot.Tray.WinUI/App.xaml.cs | 999 ++++++++++++++++++ src/Moltbot.Tray.WinUI/Assets/moltbot.ico | Bin 0 -> 4422 bytes .../Dialogs/DownloadProgressDialog.cs | 33 + .../Dialogs/QuickSendDialog.cs | 139 +++ .../Dialogs/UpdateDialog.cs | 103 ++ .../Dialogs/WelcomeDialog.cs | 96 ++ src/Moltbot.Tray.WinUI/Helpers/IconHelper.cs | 145 +++ src/Moltbot.Tray.WinUI/Helpers/ThemeHelper.cs | 57 + .../Moltbot.Tray.WinUI.csproj | 33 + .../Services/AutoStartManager.cs | 51 + .../Services/DeepLinkHandler.cs | 121 +++ .../Services/GlobalHotkeyService.cs | 91 ++ src/Moltbot.Tray.WinUI/Services/Logger.cs | 63 ++ .../Services/NotificationHistoryService.cs | 70 ++ .../Services/SettingsManager.cs | 131 +++ .../Windows/NotificationHistoryWindow.xaml | 84 ++ .../Windows/NotificationHistoryWindow.xaml.cs | 106 ++ .../Windows/SettingsWindow.xaml | 81 ++ .../Windows/SettingsWindow.xaml.cs | 175 +++ .../Windows/StatusDetailWindow.xaml | 113 ++ .../Windows/StatusDetailWindow.xaml.cs | 114 ++ .../Windows/TrayMenuWindow.xaml | 21 + .../Windows/TrayMenuWindow.xaml.cs | 252 +++++ .../Windows/WebChatWindow.xaml | 49 + .../Windows/WebChatWindow.xaml.cs | 127 +++ src/Moltbot.Tray.WinUI/app.manifest | 19 + 31 files changed, 3379 insertions(+), 1 deletion(-) create mode 100644 XAML_COMPILER_BUG.md create mode 100644 input.json.bak create mode 100644 src/Moltbot.Tray.WinUI/App.xaml create mode 100644 src/Moltbot.Tray.WinUI/App.xaml.cs create mode 100644 src/Moltbot.Tray.WinUI/Assets/moltbot.ico create mode 100644 src/Moltbot.Tray.WinUI/Dialogs/DownloadProgressDialog.cs create mode 100644 src/Moltbot.Tray.WinUI/Dialogs/QuickSendDialog.cs create mode 100644 src/Moltbot.Tray.WinUI/Dialogs/UpdateDialog.cs create mode 100644 src/Moltbot.Tray.WinUI/Dialogs/WelcomeDialog.cs create mode 100644 src/Moltbot.Tray.WinUI/Helpers/IconHelper.cs create mode 100644 src/Moltbot.Tray.WinUI/Helpers/ThemeHelper.cs create mode 100644 src/Moltbot.Tray.WinUI/Moltbot.Tray.WinUI.csproj create mode 100644 src/Moltbot.Tray.WinUI/Services/AutoStartManager.cs create mode 100644 src/Moltbot.Tray.WinUI/Services/DeepLinkHandler.cs create mode 100644 src/Moltbot.Tray.WinUI/Services/GlobalHotkeyService.cs create mode 100644 src/Moltbot.Tray.WinUI/Services/Logger.cs create mode 100644 src/Moltbot.Tray.WinUI/Services/NotificationHistoryService.cs create mode 100644 src/Moltbot.Tray.WinUI/Services/SettingsManager.cs create mode 100644 src/Moltbot.Tray.WinUI/Windows/NotificationHistoryWindow.xaml create mode 100644 src/Moltbot.Tray.WinUI/Windows/NotificationHistoryWindow.xaml.cs create mode 100644 src/Moltbot.Tray.WinUI/Windows/SettingsWindow.xaml create mode 100644 src/Moltbot.Tray.WinUI/Windows/SettingsWindow.xaml.cs create mode 100644 src/Moltbot.Tray.WinUI/Windows/StatusDetailWindow.xaml create mode 100644 src/Moltbot.Tray.WinUI/Windows/StatusDetailWindow.xaml.cs create mode 100644 src/Moltbot.Tray.WinUI/Windows/TrayMenuWindow.xaml create mode 100644 src/Moltbot.Tray.WinUI/Windows/TrayMenuWindow.xaml.cs create mode 100644 src/Moltbot.Tray.WinUI/Windows/WebChatWindow.xaml create mode 100644 src/Moltbot.Tray.WinUI/Windows/WebChatWindow.xaml.cs create mode 100644 src/Moltbot.Tray.WinUI/app.manifest diff --git a/XAML_COMPILER_BUG.md b/XAML_COMPILER_BUG.md new file mode 100644 index 0000000..faa0440 --- /dev/null +++ b/XAML_COMPILER_BUG.md @@ -0,0 +1,78 @@ +# WinUI 3 XAML Compiler Bug Report: Silent Crash on Type Mismatch + +## Summary + +The WinUI 3 XAML compiler (`XamlCompiler.exe`) crashes with **exit code 1 and produces no error message** when the XAML root element type doesn't match the code-behind base class. This creates a frustrating debugging experience as developers receive no indication of what's wrong. + +## Reproduction + +**Minimal repro:** `D:\github\XamlCompilerCrashRepro.zip` (6 files, ~2KB) + +### Steps +1. Create a WinUI 3 project with WinUIEx package +2. Create `MainWindow.xaml` using `` as root: + ```xml + + ``` +3. Create `MainWindow.xaml.cs` inheriting from `WindowEx`: + ```csharp + public sealed partial class MainWindow : WindowEx { ... } + ``` +4. Run `dotnet build` + +### Expected +Clear error message like: *"Type mismatch: XAML root element 'Window' doesn't match code-behind base class 'WinUIEx.WindowEx'"* + +### Actual +``` +error MSB3073: The command "XamlCompiler.exe input.json output.json" exited with code 1. +``` +No `output.json` file is created. No additional error details. + +## Environment + +| Component | Version | +|-----------|---------| +| Windows App SDK | 1.6.250602001 (also 1.8.x) | +| WinUIEx | 2.5.0+ | +| .NET | 9.0 | +| OS | Windows 11 (ARM64 and x64) | + +## Workaround + +Ensure XAML and code-behind types match: + +**Option A:** Both use `Window` +```xml + +``` +```csharp +public partial class MainWindow : Window +``` + +**Option B:** Both use `WindowEx` +```xml + +``` +```csharp +public partial class MainWindow : WindowEx +``` + +## Impact + +- **Severity:** Medium-High (blocks development, wastes debugging time) +- **Discoverability:** Very poor (no error message) +- **Affected scenarios:** Any derived Window type (WindowEx, custom base classes) + +## Related Issues + +This may be related to existing XAML compiler issues around error reporting: +- microsoft/microsoft-ui-xaml#10027 +- microsoft/microsoft-ui-xaml#9813 + +## Suggested Fix + +The XAML compiler should: +1. Detect when the partial class base type differs from the XAML root element +2. Produce a clear error message with file/line information +3. Write error details to `output.json` even on failure diff --git a/input.json.bak b/input.json.bak new file mode 100644 index 0000000..d10f17a --- /dev/null +++ b/input.json.bak @@ -0,0 +1 @@ +{"ProjectPath":"D:\\github\\moltbot-windows-hub.winui-test\\src\\Moltbot.Tray.WinUI\\Moltbot.Tray.WinUI.csproj","Language":"C#","LanguageSourceExtension":".cs","OutputPath":"obj\\Debug\\net9.0-windows10.0.19041.0\\win-arm64\\","ReferenceAssemblies":[{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.CSharp.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.CSharp.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.InteractiveExperiences.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.InteractiveExperiences.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.toolkit.uwp.notifications\\7.1.3\\lib\\net5.0-windows10.0.17763\\Microsoft.Toolkit.Uwp.Notifications.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.toolkit.uwp.notifications\\7.1.3\\lib\\net5.0-windows10.0.17763\\Microsoft.Toolkit.Uwp.Notifications.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.VisualBasic.Core.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.VisualBasic.Core.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.VisualBasic.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.VisualBasic.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.web.webview2\\1.0.2651.64\\lib_manual\\net6.0-windows10.0.17763.0\\Microsoft.Web.WebView2.Core.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.web.webview2\\1.0.2651.64\\lib_manual\\net6.0-windows10.0.17763.0\\Microsoft.Web.WebView2.Core.Projection.dll","IsSystemReference":false,"IsNuGetReference":false,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.Win32.Primitives.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.Win32.Primitives.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.Win32.Registry.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\Microsoft.Win32.Registry.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.ApplicationModel.Resources.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.ApplicationModel.Resources.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.AppLifecycle.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.AppLifecycle.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.AppNotifications.Builder.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.AppNotifications.Builder.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.AppNotifications.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.AppNotifications.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.Management.Deployment.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.Management.Deployment.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.PushNotifications.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.PushNotifications.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windows.sdk.net.ref\\10.0.19041.57\\lib\\net8.0\\Microsoft.Windows.SDK.NET.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windows.sdk.net.ref\\10.0.19041.57\\lib\\net8.0\\Microsoft.Windows.SDK.NET.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.Security.AccessControl.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.Security.AccessControl.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.Storage.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.Storage.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.System.Power.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.System.Power.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.System.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.System.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.Widgets.Projection.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.Windows.Widgets.Projection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.WindowsAppRuntime.Bootstrap.Net.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.WindowsAppRuntime.Bootstrap.Net.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.WinUI.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\lib\\net6.0-windows10.0.18362.0\\Microsoft.WinUI.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"D:\\github\\moltbot-windows-hub.winui-test\\src\\Moltbot.Shared\\bin\\Debug\\net9.0\\Moltbot.Shared.dll","ItemSpec":"D:\\github\\moltbot-windows-hub.winui-test\\src\\Moltbot.Shared\\bin\\Debug\\net9.0\\Moltbot.Shared.dll","IsSystemReference":false,"IsNuGetReference":false,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\mscorlib.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\mscorlib.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\netstandard.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\netstandard.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\octokit\\14.0.0\\lib\\netstandard2.0\\Octokit.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\octokit\\14.0.0\\lib\\netstandard2.0\\Octokit.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.AppContext.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.AppContext.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Buffers.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Buffers.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.Concurrent.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.Concurrent.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.Immutable.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.Immutable.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.NonGeneric.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.NonGeneric.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.Specialized.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Collections.Specialized.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.Annotations.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.Annotations.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.DataAnnotations.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.DataAnnotations.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.EventBasedAsync.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.EventBasedAsync.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.Primitives.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.Primitives.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.TypeConverter.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ComponentModel.TypeConverter.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Configuration.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Configuration.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Console.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Console.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Core.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Core.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Data.Common.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Data.Common.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Data.DataSetExtensions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Data.DataSetExtensions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Data.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Data.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Contracts.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Contracts.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Debug.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Debug.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.DiagnosticSource.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.DiagnosticSource.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.FileVersionInfo.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.FileVersionInfo.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Process.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Process.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.StackTrace.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.StackTrace.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.TextWriterTraceListener.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.TextWriterTraceListener.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Tools.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Tools.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.TraceSource.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.TraceSource.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Tracing.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Diagnostics.Tracing.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\system.drawing.common\\4.7.0\\ref\\netcoreapp3.0\\System.Drawing.Common.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\system.drawing.common\\4.7.0\\ref\\netcoreapp3.0\\System.Drawing.Common.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Drawing.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Drawing.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Drawing.Primitives.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Drawing.Primitives.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Dynamic.Runtime.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Dynamic.Runtime.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Formats.Asn1.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Formats.Asn1.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Formats.Tar.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Formats.Tar.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Globalization.Calendars.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Globalization.Calendars.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Globalization.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Globalization.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Globalization.Extensions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Globalization.Extensions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Compression.Brotli.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Compression.Brotli.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Compression.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Compression.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Compression.FileSystem.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Compression.FileSystem.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Compression.ZipFile.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Compression.ZipFile.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.AccessControl.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.AccessControl.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.DriveInfo.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.DriveInfo.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.Primitives.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.Primitives.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.Watcher.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.FileSystem.Watcher.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.IsolatedStorage.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.IsolatedStorage.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.MemoryMappedFiles.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.MemoryMappedFiles.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Pipelines.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Pipelines.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Pipes.AccessControl.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Pipes.AccessControl.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Pipes.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.Pipes.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.UnmanagedMemoryStream.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.IO.UnmanagedMemoryStream.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Linq.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Linq.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Linq.Expressions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Linq.Expressions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Linq.Parallel.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Linq.Parallel.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Linq.Queryable.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Linq.Queryable.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Memory.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Memory.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Http.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Http.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Http.Json.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Http.Json.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.HttpListener.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.HttpListener.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Mail.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Mail.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.NameResolution.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.NameResolution.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.NetworkInformation.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.NetworkInformation.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Ping.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Ping.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Primitives.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Primitives.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Quic.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Quic.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Requests.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Requests.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Security.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Security.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.ServicePoint.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.ServicePoint.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Sockets.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.Sockets.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebClient.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebClient.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebHeaderCollection.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebHeaderCollection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebProxy.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebProxy.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebSockets.Client.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebSockets.Client.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebSockets.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Net.WebSockets.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Numerics.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Numerics.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Numerics.Vectors.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Numerics.Vectors.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ObjectModel.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ObjectModel.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.DispatchProxy.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.DispatchProxy.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Emit.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Emit.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Emit.ILGeneration.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Emit.ILGeneration.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Emit.Lightweight.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Emit.Lightweight.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Extensions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Extensions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Metadata.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Metadata.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Primitives.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.Primitives.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.TypeExtensions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Reflection.TypeExtensions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Resources.Reader.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Resources.Reader.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Resources.ResourceManager.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Resources.ResourceManager.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Resources.Writer.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Resources.Writer.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.CompilerServices.Unsafe.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.CompilerServices.Unsafe.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.CompilerServices.VisualC.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.CompilerServices.VisualC.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Extensions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Extensions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Handles.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Handles.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.InteropServices.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.InteropServices.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.InteropServices.JavaScript.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.InteropServices.JavaScript.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.InteropServices.RuntimeInformation.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.InteropServices.RuntimeInformation.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Intrinsics.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Intrinsics.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Loader.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Loader.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Numerics.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Numerics.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.Formatters.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.Formatters.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.Json.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.Json.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.Primitives.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.Primitives.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.Xml.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Runtime.Serialization.Xml.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.AccessControl.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.AccessControl.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Claims.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Claims.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Algorithms.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Algorithms.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Cng.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Cng.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Csp.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Csp.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Encoding.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Encoding.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.OpenSsl.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.OpenSsl.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Primitives.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.Primitives.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.X509Certificates.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Cryptography.X509Certificates.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Principal.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Principal.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Principal.Windows.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.Principal.Windows.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.SecureString.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Security.SecureString.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ServiceModel.Web.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ServiceModel.Web.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ServiceProcess.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ServiceProcess.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Encoding.CodePages.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Encoding.CodePages.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Encoding.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Encoding.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Encoding.Extensions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Encoding.Extensions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Encodings.Web.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Encodings.Web.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Json.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.Json.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.RegularExpressions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Text.RegularExpressions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Channels.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Channels.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Overlapped.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Overlapped.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Tasks.Dataflow.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Tasks.Dataflow.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Tasks.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Tasks.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Tasks.Extensions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Tasks.Extensions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Tasks.Parallel.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Tasks.Parallel.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Thread.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Thread.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.ThreadPool.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.ThreadPool.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Timer.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Threading.Timer.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Transactions.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Transactions.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Transactions.Local.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Transactions.Local.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ValueTuple.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.ValueTuple.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Web.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Web.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Web.HttpUtility.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Web.HttpUtility.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Windows.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Windows.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.Linq.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.Linq.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.ReaderWriter.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.ReaderWriter.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.Serialization.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.Serialization.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XDocument.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XDocument.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XmlDocument.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XmlDocument.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XmlSerializer.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XmlSerializer.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XPath.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XPath.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XPath.XDocument.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\System.Xml.XPath.XDocument.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\updatum\\1.3.4\\lib\\net9.0\\Updatum.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\updatum\\1.3.4\\lib\\net9.0\\Updatum.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\WindowsBase.dll","ItemSpec":"C:\\Program Files\\dotnet\\packs\\Microsoft.NETCore.App.Ref\\9.0.12\\ref\\net9.0\\WindowsBase.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windows.sdk.net.ref\\10.0.19041.57\\lib\\net8.0\\WinRT.Runtime.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windows.sdk.net.ref\\10.0.19041.57\\lib\\net8.0\\WinRT.Runtime.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"C:\\Users\\scottha\\.nuget\\packages\\winuiex\\2.5.0\\lib\\net6.0-windows10.0.19041\\WinUIEx.dll","ItemSpec":"C:\\Users\\scottha\\.nuget\\packages\\winuiex\\2.5.0\\lib\\net6.0-windows10.0.19041\\WinUIEx.dll","IsSystemReference":false,"IsNuGetReference":true,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""}],"TargetPlatformMinVersion":"10.0.19041.0","ReferenceAssemblyPaths":[],"BuildConfiguration":null,"ForceSharedStateShutdown":false,"DisableXbfGeneration":false,"DisableXbfLineInfo":false,"EnableXBindDiagnostics":false,"ClIncludeFiles":null,"CIncludeDirectories":null,"XamlApplications":[{"DependentUpon":"","FullPath":"D:\\github\\moltbot-windows-hub.winui-test\\src\\Moltbot.Tray.WinUI\\App.xaml","ItemSpec":"App.xaml","IsSystemReference":false,"IsNuGetReference":false,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""}],"XamlPages":[{"DependentUpon":"","FullPath":"D:\\github\\moltbot-windows-hub.winui-test\\src\\Moltbot.Tray.WinUI\\Windows\\NotificationHistoryWindow.xaml","ItemSpec":"Windows\\NotificationHistoryWindow.xaml","IsSystemReference":false,"IsNuGetReference":false,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"D:\\github\\moltbot-windows-hub.winui-test\\src\\Moltbot.Tray.WinUI\\Windows\\SettingsWindow.xaml","ItemSpec":"Windows\\SettingsWindow.xaml","IsSystemReference":false,"IsNuGetReference":false,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"D:\\github\\moltbot-windows-hub.winui-test\\src\\Moltbot.Tray.WinUI\\Windows\\StatusDetailWindow.xaml","ItemSpec":"Windows\\StatusDetailWindow.xaml","IsSystemReference":false,"IsNuGetReference":false,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""},{"DependentUpon":"","FullPath":"D:\\github\\moltbot-windows-hub.winui-test\\src\\Moltbot.Tray.WinUI\\Windows\\WebChatWindow.xaml","ItemSpec":"Windows\\WebChatWindow.xaml","IsSystemReference":false,"IsNuGetReference":false,"IsStaticLibraryReference":false,"MSBuild_Link":"","MSBuild_TargetPath":"","MSBuild_XamlResourceMapName":"","MSBuild_XamlComponentResourceLocation":""}],"LocalAssembly":null,"SdkXamlPages":null,"ProjectName":"Moltbot.Tray.WinUI","IsPass1":true,"RootNamespace":"MoltbotTray","OutputType":"WinExe","PriIndexName":null,"CodeGenerationControlFlags":null,"FeatureControlFlags":"EnableXBindDiagnostics;EnableDefaultValidationContextGeneration;EnableWin32Codegen;UsingCSWinRT","XAMLFingerprint":true,"UseVCMetaManaged":true,"FingerprintIgnorePaths":["C:\\Program Files (x86)\\Windows Kits\\10\\"],"VCInstallDir":null,"VCInstallPath32":null,"VCInstallPath64":null,"WindowsSdkPath":"C:\\Program Files (x86)\\Windows Kits\\10\\","CompileMode":"RealBuildPass1","SavedStateFile":"obj\\Debug\\net9.0-windows10.0.19041.0\\win-arm64\\\\XamlSaveStateFile.xml","RootsLog":null,"SuppressWarnings":null,"GenXbfPath":"C:\\Users\\scottha\\.nuget\\packages\\microsoft.windowsappsdk\\1.6.250108002\\buildTransitive\\..\\tools\\net6.0\\..\\","PrecompiledHeaderFile":null,"XamlResourceMapName":null,"XamlComponentResourceLocation":null,"XamlPlatform":null,"TargetFileName":null,"IgnoreSpecifiedTargetPlatformMinVersion":false} \ No newline at end of file diff --git a/moltbot-windows-hub.slnx b/moltbot-windows-hub.slnx index a98cf65..fd6a737 100644 --- a/moltbot-windows-hub.slnx +++ b/moltbot-windows-hub.slnx @@ -5,5 +5,6 @@ + diff --git a/src/Moltbot.Shared/Moltbot.Shared.csproj b/src/Moltbot.Shared/Moltbot.Shared.csproj index a3748ce..750e32c 100644 --- a/src/Moltbot.Shared/Moltbot.Shared.csproj +++ b/src/Moltbot.Shared/Moltbot.Shared.csproj @@ -1,7 +1,7 @@ - net10.0 + net9.0;net10.0 enable enable Moltbot.Shared diff --git a/src/Moltbot.Tray.WinUI/App.xaml b/src/Moltbot.Tray.WinUI/App.xaml new file mode 100644 index 0000000..5373ccc --- /dev/null +++ b/src/Moltbot.Tray.WinUI/App.xaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + diff --git a/src/Moltbot.Tray.WinUI/App.xaml.cs b/src/Moltbot.Tray.WinUI/App.xaml.cs new file mode 100644 index 0000000..02082e6 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/App.xaml.cs @@ -0,0 +1,999 @@ +using Microsoft.Toolkit.Uwp.Notifications; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Moltbot.Shared; +using MoltbotTray.Dialogs; +using MoltbotTray.Helpers; +using MoltbotTray.Services; +using MoltbotTray.Windows; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO.Pipes; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Updatum; +using WinUIEx; + +namespace MoltbotTray; + +public partial class App : Application +{ + private const string PipeName = "MoltbotTray-DeepLink"; + + internal static readonly UpdatumManager AppUpdater = new("shanselman", "moltbot-windows-hub") + { + FetchOnlyLatestRelease = true, + InstallUpdateSingleFileExecutableName = "Moltbot.Tray.WinUI", + }; + + private TrayIcon? _trayIcon; + private MoltbotGatewayClient? _gatewayClient; + private SettingsManager? _settings; + private GlobalHotkeyService? _globalHotkey; + private System.Timers.Timer? _healthCheckTimer; + private System.Timers.Timer? _sessionPollTimer; + private Mutex? _mutex; + private Microsoft.UI.Dispatching.DispatcherQueue? _dispatcherQueue; + + private ConnectionStatus _currentStatus = ConnectionStatus.Disconnected; + private AgentActivity? _currentActivity; + private ChannelHealth[] _lastChannels = Array.Empty(); + private SessionInfo[] _lastSessions = Array.Empty(); + private GatewayUsageInfo? _lastUsage; + private DateTime _lastCheckTime = DateTime.Now; + + // Session-aware activity tracking + private readonly Dictionary _sessionActivities = new(); + private string? _displayedSessionKey; + private DateTime _lastSessionSwitch = DateTime.MinValue; + private static readonly TimeSpan SessionSwitchDebounce = TimeSpan.FromSeconds(3); + + // Windows (created on demand) + private SettingsWindow? _settingsWindow; + private WebChatWindow? _webChatWindow; + private StatusDetailWindow? _statusDetailWindow; + private NotificationHistoryWindow? _notificationHistoryWindow; + private TrayMenuWindow? _trayMenuWindow; + + private string[]? _startupArgs; + + public App() + { + InitializeComponent(); + } + + protected override async void OnLaunched(LaunchActivatedEventArgs args) + { + _startupArgs = Environment.GetCommandLineArgs(); + _dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread(); + + // Single instance check - keep mutex alive for app lifetime + _mutex = new Mutex(true, "MoltbotTray", out bool createdNew); + if (!createdNew) + { + // Forward deep link args to running instance + if (_startupArgs.Length > 1 && _startupArgs[1].StartsWith("moltbot://", StringComparison.OrdinalIgnoreCase)) + { + SendDeepLinkToRunningInstance(_startupArgs[1]); + } + Exit(); + return; + } + + // Register URI scheme on first run + DeepLinkHandler.RegisterUriScheme(); + + // Check for updates before launching + var shouldLaunch = await CheckForUpdatesAsync(); + if (!shouldLaunch) + { + Exit(); + return; + } + + // Register toast activation handler + ToastNotificationManagerCompat.OnActivated += OnToastActivated; + + // Initialize settings + _settings = new SettingsManager(); + + // First-run check + if (string.IsNullOrWhiteSpace(_settings.Token)) + { + await ShowFirstRunWelcomeAsync(); + } + + // Initialize tray icon (window-less pattern from WinUIEx) + InitializeTrayIcon(); + + // Initialize gateway client + InitializeGatewayClient(); + + // Start health check timer + StartHealthCheckTimer(); + + // Start deep link server + StartDeepLinkServer(); + + // Register global hotkey if enabled + if (_settings.GlobalHotkeyEnabled) + { + _globalHotkey = new GlobalHotkeyService(); + _globalHotkey.HotkeyPressed += OnGlobalHotkeyPressed; + _globalHotkey.Register(); + } + + // Process startup deep link + if (_startupArgs.Length > 1 && _startupArgs[1].StartsWith("moltbot://", StringComparison.OrdinalIgnoreCase)) + { + HandleDeepLink(_startupArgs[1]); + } + + Logger.Info("Application started (WinUI 3)"); + } + + private void InitializeTrayIcon() + { + var iconPath = IconHelper.GetStatusIconPath(ConnectionStatus.Disconnected); + _trayIcon = new TrayIcon(1, iconPath, "Moltbot Tray — Disconnected"); + _trayIcon.IsVisible = true; + _trayIcon.Selected += OnTrayIconSelected; + _trayIcon.ContextMenu += OnTrayContextMenu; + } + + private void OnTrayIconSelected(TrayIcon sender, TrayIconEventArgs e) + { + // Left-click: show status detail or dashboard + OpenDashboard(); + } + + private void OnTrayContextMenu(TrayIcon sender, TrayIconEventArgs e) + { + // Use a popup window instead of MenuFlyout for better multi-monitor support + ShowTrayMenuPopup(); + // Don't set e.Flyout - we're handling it ourselves + } + + private void ShowTrayMenuPopup() + { + // Close any existing menu + if (_trayMenuWindow != null) + { + try { _trayMenuWindow.Close(); } catch { } + _trayMenuWindow = null; + } + + _trayMenuWindow = new TrayMenuWindow(); + _trayMenuWindow.MenuItemClicked += OnTrayMenuItemClicked; + _trayMenuWindow.Closed += (s, e) => _trayMenuWindow = null; + + BuildTrayMenuPopup(_trayMenuWindow); + _trayMenuWindow.SizeToContent(); + _trayMenuWindow.ShowAtCursor(); + } + + private void OnTrayMenuItemClicked(object? sender, string action) + { + switch (action) + { + case "status": ShowStatusDetail(); break; + case "dashboard": OpenDashboard(); break; + case "webchat": ShowWebChat(); break; + case "quicksend": ShowQuickSend(); break; + case "history": ShowNotificationHistory(); break; + case "healthcheck": _ = RunHealthCheckAsync(); break; + case "settings": ShowSettings(); break; + case "autostart": ToggleAutoStart(); break; + case "log": OpenLogFile(); break; + case "exit": ExitApplication(); break; + default: + if (action.StartsWith("session:")) + OpenDashboard($"sessions/{action[8..]}"); + else if (action.StartsWith("channel:")) + ToggleChannel(action[8..]); + break; + } + } + + private void BuildTrayMenuPopup(TrayMenuWindow menu) + { + // Brand header + menu.AddBrandHeader("🦞", "Molty"); + menu.AddSeparator(); + + // Status + var statusIcon = _currentStatus switch + { + ConnectionStatus.Connected => "✅", + ConnectionStatus.Connecting => "🔄", + ConnectionStatus.Error => "❌", + _ => "⚪" + }; + menu.AddMenuItem($"Status: {_currentStatus}", statusIcon, "status"); + + // Activity (if any) + if (_currentActivity != null && _currentActivity.Kind != Moltbot.Shared.ActivityKind.Idle) + { + menu.AddMenuItem(_currentActivity.DisplayText, _currentActivity.Glyph, "", isEnabled: false); + } + + // Usage + if (_lastUsage != null) + { + menu.AddMenuItem(_lastUsage.DisplayText, "📊", "", isEnabled: false); + } + + // Sessions + if (_lastSessions.Length > 0) + { + menu.AddSeparator(); + menu.AddMenuItem($"Sessions ({_lastSessions.Length})", "💬", "dashboard:sessions"); + + foreach (var session in _lastSessions.Take(5)) + { + menu.AddMenuItem($" {session.DisplayText}", null, $"session:{session.Key}"); + } + } + + // Channels + if (_lastChannels.Length > 0) + { + menu.AddSeparator(); + menu.AddHeader("📡 Channels"); + + foreach (var channel in _lastChannels) + { + var channelIcon = channel.Status?.ToLowerInvariant() switch + { + "ok" or "connected" or "running" => "🟢", + "connecting" or "reconnecting" => "🟡", + _ => "🔴" + }; + menu.AddMenuItem(channel.Name, channelIcon, $"channel:{channel.Name}", indent: true); + } + } + + menu.AddSeparator(); + + // Actions + menu.AddMenuItem("Open Dashboard", "🌐", "dashboard"); + menu.AddMenuItem("Open Web Chat", "💬", "webchat"); + menu.AddMenuItem("Quick Send...", "📤", "quicksend"); + menu.AddMenuItem("Notification History...", "📋", "history"); + menu.AddMenuItem("Run Health Check", "🔄", "healthcheck"); + + menu.AddSeparator(); + + // Settings + menu.AddMenuItem("Settings...", "⚙️", "settings"); + var autoStartText = (_settings?.AutoStart ?? false) ? "Auto-start ✓" : "Auto-start"; + menu.AddMenuItem(autoStartText, "🚀", "autostart"); + + menu.AddSeparator(); + + menu.AddMenuItem("Open Log File", "📄", "log"); + menu.AddMenuItem("Exit", "❌", "exit"); + } + + // Keep the old MenuFlyout method for reference but it won't be used + private void BuildTrayMenu(MenuFlyout flyout) + { + // Brand header + var brandItem = new MenuFlyoutItem + { + Text = "🦞 Moltbot Tray", + IsEnabled = false + }; + flyout.Items.Add(brandItem); + flyout.Items.Add(new MenuFlyoutSeparator()); + + // Status + var statusIcon = _currentStatus switch + { + ConnectionStatus.Connected => "✅", + ConnectionStatus.Connecting => "🔄", + ConnectionStatus.Error => "❌", + _ => "⚪" + }; + var statusItem = new MenuFlyoutItem + { + Text = $"{statusIcon} Status: {_currentStatus}" + }; + statusItem.Click += (s, e) => ShowStatusDetail(); + flyout.Items.Add(statusItem); + + // Activity (if any) + if (_currentActivity != null && _currentActivity.Kind != Moltbot.Shared.ActivityKind.Idle) + { + var activityItem = new MenuFlyoutItem + { + Text = $"{_currentActivity.Glyph} {_currentActivity.DisplayText}", + IsEnabled = false + }; + flyout.Items.Add(activityItem); + } + + // Usage + if (_lastUsage != null) + { + var usageItem = new MenuFlyoutItem + { + Text = $"📊 {_lastUsage.DisplayText}", + IsEnabled = false + }; + flyout.Items.Add(usageItem); + } + + // Sessions + if (_lastSessions.Length > 0) + { + flyout.Items.Add(new MenuFlyoutSeparator()); + var sessionsHeader = new MenuFlyoutItem + { + Text = $"💬 Sessions ({_lastSessions.Length})" + }; + sessionsHeader.Click += (s, e) => OpenDashboard("sessions"); + flyout.Items.Add(sessionsHeader); + + foreach (var session in _lastSessions.Take(5)) + { + var sessionItem = new MenuFlyoutItem + { + Text = $" • {session.DisplayText}" + }; + sessionItem.Click += (s, e) => OpenDashboard($"sessions/{session.Key}"); + flyout.Items.Add(sessionItem); + } + } + + // Channels + if (_lastChannels.Length > 0) + { + flyout.Items.Add(new MenuFlyoutSeparator()); + var channelsHeader = new MenuFlyoutItem + { + Text = "📡 Channels", + IsEnabled = false + }; + flyout.Items.Add(channelsHeader); + + foreach (var channel in _lastChannels) + { + var channelIcon = channel.Status?.ToLowerInvariant() switch + { + "ok" or "connected" or "running" => "🟢", + "connecting" or "reconnecting" => "🟡", + _ => "🔴" + }; + var channelItem = new MenuFlyoutItem + { + Text = $" {channelIcon} {channel.Name}" + }; + channelItem.Click += (s, e) => ToggleChannel(channel.Name); + flyout.Items.Add(channelItem); + } + } + + flyout.Items.Add(new MenuFlyoutSeparator()); + + // Actions + var dashboardItem = new MenuFlyoutItem { Text = "🌐 Open Dashboard" }; + dashboardItem.Click += (s, e) => OpenDashboard(); + flyout.Items.Add(dashboardItem); + + var webChatItem = new MenuFlyoutItem { Text = "💬 Open Web Chat" }; + webChatItem.Click += (s, e) => ShowWebChat(); + flyout.Items.Add(webChatItem); + + var quickSendItem = new MenuFlyoutItem { Text = "📤 Quick Send..." }; + quickSendItem.Click += (s, e) => ShowQuickSend(); + flyout.Items.Add(quickSendItem); + + var historyItem = new MenuFlyoutItem { Text = "📋 Notification History..." }; + historyItem.Click += (s, e) => ShowNotificationHistory(); + flyout.Items.Add(historyItem); + + var healthCheckItem = new MenuFlyoutItem { Text = "🔄 Run Health Check" }; + healthCheckItem.Click += async (s, e) => await RunHealthCheckAsync(); + flyout.Items.Add(healthCheckItem); + + flyout.Items.Add(new MenuFlyoutSeparator()); + + // Settings + var settingsItem = new MenuFlyoutItem { Text = "⚙️ Settings..." }; + settingsItem.Click += (s, e) => ShowSettings(); + flyout.Items.Add(settingsItem); + + var autoStartItem = new ToggleMenuFlyoutItem + { + Text = "🚀 Auto-start", + IsChecked = _settings?.AutoStart ?? false + }; + autoStartItem.Click += (s, e) => ToggleAutoStart(); + flyout.Items.Add(autoStartItem); + + flyout.Items.Add(new MenuFlyoutSeparator()); + + var logItem = new MenuFlyoutItem { Text = "📄 Open Log File" }; + logItem.Click += (s, e) => OpenLogFile(); + flyout.Items.Add(logItem); + + var exitItem = new MenuFlyoutItem { Text = "❌ Exit" }; + exitItem.Click += (s, e) => ExitApplication(); + flyout.Items.Add(exitItem); + } + + #region Gateway Client + + private void InitializeGatewayClient() + { + if (_settings == null) return; + + _gatewayClient = new MoltbotGatewayClient(_settings.GatewayUrl, _settings.Token, new AppLogger()); + _gatewayClient.StatusChanged += OnConnectionStatusChanged; + _gatewayClient.ActivityChanged += OnActivityChanged; + _gatewayClient.NotificationReceived += OnNotificationReceived; + _gatewayClient.ChannelHealthUpdated += OnChannelHealthUpdated; + _gatewayClient.SessionsUpdated += OnSessionsUpdated; + _gatewayClient.UsageUpdated += OnUsageUpdated; + _ = _gatewayClient.ConnectAsync(); + } + + private void OnConnectionStatusChanged(object? sender, ConnectionStatus status) + { + _currentStatus = status; + UpdateTrayIcon(); + + if (status == ConnectionStatus.Connected) + { + _ = RunHealthCheckAsync(); + } + } + + private void OnActivityChanged(object? sender, AgentActivity? activity) + { + if (activity == null) + { + // Activity ended + if (_displayedSessionKey != null && _sessionActivities.ContainsKey(_displayedSessionKey)) + { + _sessionActivities.Remove(_displayedSessionKey); + } + _currentActivity = null; + } + else + { + var sessionKey = activity.SessionKey ?? "default"; + _sessionActivities[sessionKey] = activity; + + // Debounce session switching + var now = DateTime.Now; + if (_displayedSessionKey != sessionKey && + (now - _lastSessionSwitch) > SessionSwitchDebounce) + { + _displayedSessionKey = sessionKey; + _lastSessionSwitch = now; + } + + if (_displayedSessionKey == sessionKey) + { + _currentActivity = activity; + } + } + + UpdateTrayIcon(); + } + + private void OnChannelHealthUpdated(object? sender, ChannelHealth[] channels) + { + _lastChannels = channels; + } + + private void OnSessionsUpdated(object? sender, SessionInfo[] sessions) + { + _lastSessions = sessions; + } + + private void OnUsageUpdated(object? sender, GatewayUsageInfo usage) + { + _lastUsage = usage; + } + + private void OnNotificationReceived(object? sender, MoltbotNotification notification) + { + if (_settings?.ShowNotifications != true) return; + if (!ShouldShowNotification(notification)) return; + + // Store in history + NotificationHistoryService.AddNotification(new Services.GatewayNotification + { + Title = notification.Title, + Message = notification.Message, + Category = notification.Type + }); + + // Show toast + try + { + var builder = new ToastContentBuilder() + .AddText(notification.Title ?? "Moltbot") + .AddText(notification.Message); + + builder.Show(); + } + catch (Exception ex) + { + Logger.Warn($"Failed to show toast: {ex.Message}"); + } + } + + private bool ShouldShowNotification(MoltbotNotification notification) + { + if (_settings == null) return true; + + return notification.Type?.ToLowerInvariant() switch + { + "health" => _settings.NotifyHealth, + "urgent" => _settings.NotifyUrgent, + "reminder" => _settings.NotifyReminder, + "email" => _settings.NotifyEmail, + "calendar" => _settings.NotifyCalendar, + "build" => _settings.NotifyBuild, + "stock" => _settings.NotifyStock, + "info" => _settings.NotifyInfo, + _ => true + }; + } + + #endregion + + #region Health Check + + private void StartHealthCheckTimer() + { + _healthCheckTimer = new System.Timers.Timer(30000); // 30 seconds + _healthCheckTimer.Elapsed += async (s, e) => await RunHealthCheckAsync(); + _healthCheckTimer.Start(); + + _sessionPollTimer = new System.Timers.Timer(10000); // 10 seconds + _sessionPollTimer.Elapsed += async (s, e) => await PollSessionsAsync(); + _sessionPollTimer.Start(); + + // Initial check + _ = RunHealthCheckAsync(); + } + + private async Task RunHealthCheckAsync() + { + if (_gatewayClient == null) return; + + try + { + _lastCheckTime = DateTime.Now; + await _gatewayClient.CheckHealthAsync(); + } + catch (Exception ex) + { + Logger.Warn($"Health check failed: {ex.Message}"); + } + } + + private async Task PollSessionsAsync() + { + if (_gatewayClient == null) return; + + try + { + await _gatewayClient.RequestSessionsAsync(); + await _gatewayClient.RequestUsageAsync(); + } + catch (Exception ex) + { + Logger.Warn($"Session poll failed: {ex.Message}"); + } + } + + #endregion + + #region Tray Icon + + private void UpdateTrayIcon() + { + if (_trayIcon == null) return; + + var status = _currentStatus; + if (_currentActivity != null && _currentActivity.Kind != Moltbot.Shared.ActivityKind.Idle) + { + status = ConnectionStatus.Connecting; // Use connecting icon for activity + } + + var iconPath = IconHelper.GetStatusIconPath(status); + var tooltip = $"Moltbot Tray — {_currentStatus}"; + + if (_currentActivity != null && !string.IsNullOrEmpty(_currentActivity.DisplayText)) + { + tooltip += $"\n{_currentActivity.DisplayText}"; + } + + tooltip += $"\nLast check: {_lastCheckTime:HH:mm:ss}"; + + try + { + _trayIcon.SetIcon(iconPath); + _trayIcon.Tooltip = tooltip; + } + catch (Exception ex) + { + Logger.Warn($"Failed to update tray icon: {ex.Message}"); + } + } + + #endregion + + #region Window Management + + private void ShowSettings() + { + if (_settingsWindow == null || _settingsWindow.IsClosed) + { + _settingsWindow = new SettingsWindow(_settings!); + _settingsWindow.Closed += (s, e) => _settingsWindow = null; + _settingsWindow.SettingsSaved += OnSettingsSaved; + } + _settingsWindow.Activate(); + } + + private void OnSettingsSaved(object? sender, EventArgs e) + { + // Reconnect with new settings + _gatewayClient?.Dispose(); + InitializeGatewayClient(); + + // Update global hotkey + if (_settings!.GlobalHotkeyEnabled) + { + _globalHotkey ??= new GlobalHotkeyService(); + _globalHotkey.HotkeyPressed -= OnGlobalHotkeyPressed; + _globalHotkey.HotkeyPressed += OnGlobalHotkeyPressed; + _globalHotkey.Register(); + } + else + { + _globalHotkey?.Unregister(); + } + + // Update auto-start + AutoStartManager.SetAutoStart(_settings.AutoStart); + } + + private void ShowWebChat() + { + if (_webChatWindow == null || _webChatWindow.IsClosed) + { + _webChatWindow = new WebChatWindow(_settings!.GatewayUrl, _settings.Token); + _webChatWindow.Closed += (s, e) => _webChatWindow = null; + } + _webChatWindow.Activate(); + } + + private void ShowQuickSend(string? prefillMessage = null) + { + if (_gatewayClient == null) return; + var dialog = new QuickSendDialog(_gatewayClient, prefillMessage); + dialog.Activate(); + } + + private void ShowStatusDetail() + { + if (_statusDetailWindow == null || _statusDetailWindow.IsClosed) + { + _statusDetailWindow = new StatusDetailWindow( + _currentStatus, _lastChannels, _lastSessions, _lastUsage, _lastCheckTime); + _statusDetailWindow.Closed += (s, e) => _statusDetailWindow = null; + } + else + { + _statusDetailWindow.UpdateStatus( + _currentStatus, _lastChannels, _lastSessions, _lastUsage, _lastCheckTime); + } + _statusDetailWindow.Activate(); + } + + private void ShowNotificationHistory() + { + if (_notificationHistoryWindow == null || _notificationHistoryWindow.IsClosed) + { + _notificationHistoryWindow = new NotificationHistoryWindow(); + _notificationHistoryWindow.Closed += (s, e) => _notificationHistoryWindow = null; + } + _notificationHistoryWindow.Activate(); + } + + private async Task ShowFirstRunWelcomeAsync() + { + var dialog = new WelcomeDialog(); + var result = await dialog.ShowAsync(); + if (result == ContentDialogResult.Primary) + { + ShowSettings(); + } + } + + #endregion + + #region Actions + + private void OpenDashboard(string? path = null) + { + if (_settings == null) return; + + var baseUrl = _settings.GatewayUrl + .Replace("ws://", "http://") + .Replace("wss://", "https://"); + + var url = string.IsNullOrEmpty(path) + ? $"{baseUrl}?token={Uri.EscapeDataString(_settings.Token)}" + : $"{baseUrl}/{path}?token={Uri.EscapeDataString(_settings.Token)}"; + + try + { + Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); + } + catch (Exception ex) + { + Logger.Error($"Failed to open dashboard: {ex.Message}"); + } + } + + private async void ToggleChannel(string channelName) + { + if (_gatewayClient == null) return; + + var channel = _lastChannels.FirstOrDefault(c => c.Name == channelName); + if (channel == null) return; + + try + { + var isRunning = channel.Status?.ToLowerInvariant() is "ok" or "connected" or "running"; + if (isRunning) + { + await _gatewayClient.StopChannelAsync(channelName); + } + else + { + await _gatewayClient.StartChannelAsync(channelName); + } + + // Refresh health + await RunHealthCheckAsync(); + } + catch (Exception ex) + { + Logger.Error($"Failed to toggle channel: {ex.Message}"); + } + } + + private void ToggleAutoStart() + { + if (_settings == null) return; + _settings.AutoStart = !_settings.AutoStart; + _settings.Save(); + AutoStartManager.SetAutoStart(_settings.AutoStart); + } + + private void OpenLogFile() + { + try + { + Process.Start(new ProcessStartInfo(Logger.LogFilePath) { UseShellExecute = true }); + } + catch (Exception ex) + { + Logger.Error($"Failed to open log file: {ex.Message}"); + } + } + + private void OnGlobalHotkeyPressed(object? sender, EventArgs e) + { + ShowQuickSend(); + } + + #endregion + + #region Updates + + private async Task CheckForUpdatesAsync() + { + try + { + Logger.Info("Checking for updates..."); + var updateFound = await AppUpdater.CheckForUpdatesAsync(); + + if (!updateFound) + { + Logger.Info("No updates available"); + return true; + } + + var release = AppUpdater.LatestRelease!; + var changelog = AppUpdater.GetChangelog(true) ?? "No release notes available."; + Logger.Info($"Update available: {release.TagName}"); + + var dialog = new UpdateDialog(release.TagName, changelog); + var result = await dialog.ShowAsync(); + + if (result == UpdateDialogResult.Download) + { + var installed = await DownloadAndInstallUpdateAsync(); + return !installed; // Don't launch if update succeeded + } + + return true; // RemindLater or Skip - continue + } + catch (Exception ex) + { + Logger.Warn($"Update check failed: {ex.Message}"); + return true; + } + } + + private async Task DownloadAndInstallUpdateAsync() + { + DownloadProgressDialog? progressDialog = null; + try + { + progressDialog = new DownloadProgressDialog(AppUpdater); + progressDialog.ShowAsync(); // Fire and forget + + var downloadedAsset = await AppUpdater.DownloadUpdateAsync(); + + progressDialog?.Close(); + + if (downloadedAsset == null || !System.IO.File.Exists(downloadedAsset.FilePath)) + { + Logger.Error("Update download failed or file missing"); + return false; + } + + Logger.Info("Installing update and restarting..."); + await AppUpdater.InstallUpdateAsync(downloadedAsset); + return true; + } + catch (Exception ex) + { + Logger.Error($"Update failed: {ex.Message}"); + progressDialog?.Close(); + return false; + } + } + + #endregion + + #region Deep Links + + private void StartDeepLinkServer() + { + Task.Run(async () => + { + while (true) + { + try + { + using var pipe = new NamedPipeServerStream(PipeName, PipeDirection.In); + await pipe.WaitForConnectionAsync(); + using var reader = new System.IO.StreamReader(pipe); + var uri = await reader.ReadLineAsync(); + if (!string.IsNullOrEmpty(uri)) + { + Logger.Info($"Received deep link via IPC: {uri}"); + _dispatcherQueue?.TryEnqueue(() => HandleDeepLink(uri)); + } + } + catch (Exception ex) + { + Logger.Warn($"Deep link server error: {ex.Message}"); + await Task.Delay(1000); + } + } + }); + } + + private void HandleDeepLink(string uri) + { + DeepLinkHandler.Handle(uri, new DeepLinkActions + { + OpenSettings = ShowSettings, + OpenChat = ShowWebChat, + OpenDashboard = OpenDashboard, + OpenQuickSend = ShowQuickSend, + SendMessage = async (msg) => + { + if (_gatewayClient != null) + { + await _gatewayClient.SendChatMessageAsync(msg); + } + } + }); + } + + private static void SendDeepLinkToRunningInstance(string uri) + { + try + { + using var pipe = new NamedPipeClientStream(".", PipeName, PipeDirection.Out); + pipe.Connect(1000); + using var writer = new System.IO.StreamWriter(pipe); + writer.WriteLine(uri); + writer.Flush(); + } + catch (Exception ex) + { + Logger.Warn($"Failed to forward deep link: {ex.Message}"); + } + } + + #endregion + + #region Toast Activation + + private void OnToastActivated(ToastNotificationActivatedEventArgsCompat args) + { + var arguments = ToastArguments.Parse(args.Argument); + + if (arguments.TryGetValue("action", out var action)) + { + _dispatcherQueue?.TryEnqueue(() => + { + switch (action) + { + case "open_url" when arguments.TryGetValue("url", out var url): + try { Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); } + catch { } + break; + case "open_dashboard": + OpenDashboard(); + break; + case "open_settings": + ShowSettings(); + break; + } + }); + } + } + + #endregion + + #region Exit + + private void ExitApplication() + { + Logger.Info("Application exiting"); + + _healthCheckTimer?.Stop(); + _healthCheckTimer?.Dispose(); + _sessionPollTimer?.Stop(); + _sessionPollTimer?.Dispose(); + _globalHotkey?.Unregister(); + _gatewayClient?.Dispose(); + _trayIcon?.Dispose(); + _mutex?.Dispose(); + + Exit(); + } + + #endregion + + private Microsoft.UI.Dispatching.DispatcherQueue? AppDispatcherQueue => + Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread(); +} + +internal class AppLogger : IMoltbotLogger +{ + public void Info(string message) => Logger.Info(message); + public void Warn(string message) => Logger.Warn(message); + public void Error(string message, Exception? ex = null) => + Logger.Error(ex != null ? $"{message}: {ex.Message}" : message); +} diff --git a/src/Moltbot.Tray.WinUI/Assets/moltbot.ico b/src/Moltbot.Tray.WinUI/Assets/moltbot.ico new file mode 100644 index 0000000000000000000000000000000000000000..1b7300ec5ea760dd187d8c0d6a933eaa40e02c32 GIT binary patch literal 4422 zcmds43se(l79Io{hN7NxofY(OeRp9I3IIn4+Fw!o){$E*1*_&RGD`~rL+@0(cx zfUgMvd>S4WWM%GP4&S!g5loAKM|ed5XJ!ijI%!|V!GlpoM35g)cgOJ|JTduz8cGF# zdcMW8xaIJCMOrX30{}2mGNbg+bR?^B=7iC2cXDi@$P2ytysE?*QUE!QF#N0awFT|-1v&W<#zx?RZhnU9x=YSOR zseB>nMq7dQE<=#(+0(kZe+F1N>LS-wk5`&D3p8Ipx>O$?d1tG1`GxaN8*{L}{kP^z zD*h9OFvkE76vKVX7V=&PL!&4J!({)NLQf_?ab(|T_h({f(>I;2oZlxV$266Cy011(>K1=&U*e{X2sgSnbGW-#9m({+ zQsvrz_5R-)PKAdsFYUXzhsE8UZ{M=?xOugvsq^hGsK0RL)^cja$LEz4_lor;kv2TrWAd5d> zv}UBuCKMdp8V)ADO=+t%&Ec+1xfTi99V|IM^quQn3D+Sh_WJKb4x3%HC5aJFto~Zm z5d8N~F3TPK+*oI0X2OKRTThM+{lh4C1xLYC-n6uRDC87NT)s}9jr^0xOAP10k)5m4 zWDmitWsK@|Q<-FD965w3`q9;g--@i8GgrCx6Lp)RfFr8mN=Bz0eS6uihm(aeI59u* zPk;*qTp7?TMyFp%dYvp-CAXG@mETS z%W3qSb<9TN?bwe$DP*TCQ0SAjD!i-mqL4i`3NcDQ7$Xd52sMhR?%8_SQWrahuT{JU zI-#J|7lCoC;r%&$*s>Y4&?U2medY=DNv1dNE3z3;JD}kpmK4T~Afon;1VoXqQBfJC zO+_OKu%%kkPT60YiSgwL*|wN?H*7oX*fTtAnU1wp_sPW>b5sO@m^-vD>yC`a0)f}8nMjh8G-0T z>-NJJ=#lT~qP)+>(uc<#a|A+cCCi!LrAK6H0$(KtiL-|=+dJi8UxPq4p$9)BogXm_ z33c9iPKhcgnc113&-1KLbI_()iJWs@ifzzP8(k+zdi-_gl@|+ju`0@)F_5`H*l(*T z(Wjadrrs^*h&1@AIjANZ=Vrm)sb>{sgKndW!eH|==BadFUJ;kPUZ3sXR(Q~4gFsQG z9A_XY>5aBM*IdYP>_)IG>-O_3PUk0}AY?FuCnMB{T#@7?Z?@=)mQy}QQN7J_E)8jx z)g#%iXm(wju}SA$grsRpF*k9u3NJ(PeG{8F*)SHMM$`kt+#zll5(^I4kQPYPhMYx0 zH((qRzad``5Ddu-BVkBI1ddQ<#ISB6oz$SjzDXzSe&>4yDcixzH0?X*Qafv` z1iJ3&?t(u7e#DBQkxj7Q$;G@ZGkl|vZT%QWP9|zy9yn+9(kBBt{O2la6|ZCHJP$fI zHSl?xP^DtM2gTdvOH`-Oc8(EXw0R|{%&{hMAsFj5@#cug3F@%Hz(~J_;mH$FLr%-l z+fEyoM5uskm!m35g@0i0cv6V$A(bPF&WwnvDItfKkcOipyJ3l_#H&GlrK_Dkmrxl# z2tjI4%_mAn)m3wzw<#E>LR|m3HpsHHJ;)k%z$}(!^S$)sY&r!V3T=@&=;dCN6uPl~ zB*98g=h`u9bir)>DZM}(m?PA6=@?Qye^at>gA<$@y`&U-k$EW^%7C8n!w&ckuLXRH tUWBGvVITamZoqk?!7}$vkmm>1@qYRkTmav_&=|_T9=!;E+UUQ7{sm7{@Bsh- literal 0 HcmV?d00001 diff --git a/src/Moltbot.Tray.WinUI/Dialogs/DownloadProgressDialog.cs b/src/Moltbot.Tray.WinUI/Dialogs/DownloadProgressDialog.cs new file mode 100644 index 0000000..b8de9fc --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Dialogs/DownloadProgressDialog.cs @@ -0,0 +1,33 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Updatum; + +namespace MoltbotTray.Dialogs; + +public sealed class DownloadProgressDialog +{ + private Window? _window; + private readonly UpdatumManager? _updater; + + public DownloadProgressDialog(UpdatumManager updater) + { + _updater = updater; + } + + public void ShowAsync() + { + _window = new Window { Title = "Downloading Update..." }; + + var panel = new StackPanel { Padding = new Thickness(20) }; + var progressText = new TextBlock { Text = "Downloading update...", Margin = new Thickness(0, 0, 0, 10) }; + var progressBar = new ProgressBar { IsIndeterminate = true }; + + panel.Children.Add(progressText); + panel.Children.Add(progressBar); + _window.Content = panel; + + _window.Activate(); + } + + public void Close() => _window?.Close(); +} diff --git a/src/Moltbot.Tray.WinUI/Dialogs/QuickSendDialog.cs b/src/Moltbot.Tray.WinUI/Dialogs/QuickSendDialog.cs new file mode 100644 index 0000000..4d3cb87 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Dialogs/QuickSendDialog.cs @@ -0,0 +1,139 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Input; +using Moltbot.Shared; +using MoltbotTray.Helpers; +using MoltbotTray.Services; +using System; +using System.Threading.Tasks; +using WinUIEx; + +namespace MoltbotTray.Dialogs; + +/// +/// Quick send dialog for sending messages to Moltbot. +/// +public sealed class QuickSendDialog : WindowEx +{ + private readonly MoltbotGatewayClient _client; + private readonly TextBox _messageTextBox; + private readonly Button _sendButton; + private readonly TextBlock _statusText; + private bool _isSending; + + public QuickSendDialog(MoltbotGatewayClient client, string? prefillMessage = null) + { + _client = client; + + // Window setup + Title = "Quick Send — Moltbot"; + this.SetWindowSize(400, 200); + this.CenterOnScreen(); + this.SetIcon(IconHelper.GetStatusIconPath(ConnectionStatus.Connected)); + + // Build UI programmatically (simple dialog) + var root = new StackPanel + { + Spacing = 12, + Padding = new Thickness(24) + }; + + var header = new TextBlock + { + Text = "📤 Quick Send", + Style = (Style)Application.Current.Resources["SubtitleTextBlockStyle"] + }; + root.Children.Add(header); + + _messageTextBox = new TextBox + { + PlaceholderText = "Type your message...", + AcceptsReturn = false, + Text = prefillMessage ?? "" + }; + _messageTextBox.KeyDown += OnKeyDown; + root.Children.Add(_messageTextBox); + + var buttonPanel = new StackPanel + { + Orientation = Orientation.Horizontal, + Spacing = 8, + HorizontalAlignment = HorizontalAlignment.Right + }; + + _statusText = new TextBlock + { + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(0, 0, 12, 0) + }; + buttonPanel.Children.Add(_statusText); + + var cancelButton = new Button { Content = "Cancel" }; + cancelButton.Click += (s, e) => Close(); + buttonPanel.Children.Add(cancelButton); + + _sendButton = new Button + { + Content = "Send", + Style = (Style)Application.Current.Resources["AccentButtonStyle"] + }; + _sendButton.Click += OnSendClick; + buttonPanel.Children.Add(_sendButton); + + root.Children.Add(buttonPanel); + + Content = root; + + // Focus the text box when shown + Activated += (s, e) => _messageTextBox.Focus(FocusState.Programmatic); + } + + private async void OnKeyDown(object sender, KeyRoutedEventArgs e) + { + if (e.Key == global::Windows.System.VirtualKey.Enter && !_isSending) + { + e.Handled = true; + await SendMessageAsync(); + } + else if (e.Key == global::Windows.System.VirtualKey.Escape) + { + Close(); + } + } + + private async void OnSendClick(object sender, RoutedEventArgs e) + { + await SendMessageAsync(); + } + + private async Task SendMessageAsync() + { + var message = _messageTextBox.Text?.Trim(); + if (string.IsNullOrEmpty(message)) return; + + _isSending = true; + _sendButton.IsEnabled = false; + _messageTextBox.IsEnabled = false; + _statusText.Text = "Sending..."; + + try + { + await _client.SendChatMessageAsync(message); + Logger.Info($"Quick send: {message}"); + Close(); + } + catch (Exception ex) + { + Logger.Error($"Quick send failed: {ex.Message}"); + _statusText.Text = "❌ Failed"; + _sendButton.IsEnabled = true; + _messageTextBox.IsEnabled = true; + _isSending = false; + } + } + + public new void ShowAsync() + { + Activate(); + } +} diff --git a/src/Moltbot.Tray.WinUI/Dialogs/UpdateDialog.cs b/src/Moltbot.Tray.WinUI/Dialogs/UpdateDialog.cs new file mode 100644 index 0000000..c6b5dcd --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Dialogs/UpdateDialog.cs @@ -0,0 +1,103 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using System; +using System.Threading.Tasks; + +namespace MoltbotTray.Dialogs; + +public enum UpdateDialogResult +{ + Download, + Skip, + RemindLater +} + +/// +/// Dialog showing available update with release notes. +/// +public sealed class UpdateDialog +{ + private readonly string _version; + private readonly string _changelog; + private ContentDialog? _dialog; + + public UpdateDialogResult Result { get; private set; } = UpdateDialogResult.RemindLater; + + public UpdateDialog(string version, string changelog) + { + _version = version; + _changelog = changelog; + } + + public async Task ShowAsync() + { + // Create a temporary window to host the dialog + var window = new Window(); + window.Content = new Grid(); + window.Activate(); + + // Build dialog content + var content = new StackPanel + { + Spacing = 16, + MaxWidth = 450 + }; + + // Version header + content.Children.Add(new TextBlock + { + Text = $"🎉 Version {_version} is available!", + Style = (Style)Application.Current.Resources["SubtitleTextBlockStyle"] + }); + + // Current version + var currentVersion = typeof(UpdateDialog).Assembly.GetName().Version?.ToString() ?? "Unknown"; + content.Children.Add(new TextBlock + { + Text = $"Current version: {currentVersion}", + Foreground = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["TextFillColorSecondaryBrush"] + }); + + // Changelog + content.Children.Add(new TextBlock + { + Text = "What's New:", + FontWeight = Microsoft.UI.Text.FontWeights.SemiBold + }); + + var changelogScroll = new ScrollViewer + { + MaxHeight = 200, + Content = new TextBlock + { + Text = _changelog, + TextWrapping = TextWrapping.Wrap + } + }; + content.Children.Add(changelogScroll); + + // Create dialog + _dialog = new ContentDialog + { + Title = "Update Available", + Content = content, + PrimaryButtonText = "Download & Install", + SecondaryButtonText = "Remind Me Later", + CloseButtonText = "Skip This Version", + DefaultButton = ContentDialogButton.Primary, + XamlRoot = window.Content.XamlRoot + }; + + var dialogResult = await _dialog.ShowAsync(); + window.Close(); + + Result = dialogResult switch + { + ContentDialogResult.Primary => UpdateDialogResult.Download, + ContentDialogResult.Secondary => UpdateDialogResult.RemindLater, + _ => UpdateDialogResult.Skip + }; + + return Result; + } +} diff --git a/src/Moltbot.Tray.WinUI/Dialogs/WelcomeDialog.cs b/src/Moltbot.Tray.WinUI/Dialogs/WelcomeDialog.cs new file mode 100644 index 0000000..2d44ea7 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Dialogs/WelcomeDialog.cs @@ -0,0 +1,96 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using System; +using System.Diagnostics; +using System.Threading.Tasks; + +namespace MoltbotTray.Dialogs; + +/// +/// First-run welcome dialog for new users. +/// +public sealed class WelcomeDialog +{ + private ContentDialog? _dialog; + private ContentDialogResult _result; + + public async Task ShowAsync() + { + // Create a temporary window to host the dialog + var window = new Window(); + window.Content = new Grid(); + window.Activate(); + + // Build dialog content + var content = new StackPanel + { + Spacing = 16, + MaxWidth = 400 + }; + + // Lobster header + var headerPanel = new StackPanel + { + Orientation = Orientation.Horizontal, + Spacing = 12, + HorizontalAlignment = HorizontalAlignment.Center + }; + headerPanel.Children.Add(new TextBlock + { + Text = "🦞", + FontSize = 48 + }); + headerPanel.Children.Add(new TextBlock + { + Text = "Welcome to Moltbot!", + Style = (Style)Application.Current.Resources["TitleTextBlockStyle"], + VerticalAlignment = VerticalAlignment.Center + }); + content.Children.Add(headerPanel); + + // Description + content.Children.Add(new TextBlock + { + Text = "Moltbot Tray is your Windows companion for Moltbot, the AI-powered personal assistant.", + TextWrapping = TextWrapping.Wrap + }); + + // Getting started + var gettingStarted = new StackPanel { Spacing = 8 }; + gettingStarted.Children.Add(new TextBlock + { + Text = "To get started, you'll need:", + FontWeight = Microsoft.UI.Text.FontWeights.SemiBold + }); + + var bulletList = new StackPanel { Spacing = 4, Margin = new Thickness(16, 0, 0, 0) }; + bulletList.Children.Add(new TextBlock { Text = "• A running Moltbot gateway" }); + bulletList.Children.Add(new TextBlock { Text = "• Your API token from the dashboard" }); + gettingStarted.Children.Add(bulletList); + content.Children.Add(gettingStarted); + + // Documentation link + var docsButton = new HyperlinkButton + { + Content = "📚 View Documentation", + NavigateUri = new Uri("https://docs.molt.bot/web/dashboard") + }; + content.Children.Add(docsButton); + + // Create and show dialog + _dialog = new ContentDialog + { + Title = "Welcome", + Content = content, + PrimaryButtonText = "Open Settings", + CloseButtonText = "Later", + DefaultButton = ContentDialogButton.Primary, + XamlRoot = window.Content.XamlRoot + }; + + _result = await _dialog.ShowAsync(); + window.Close(); + + return _result; + } +} diff --git a/src/Moltbot.Tray.WinUI/Helpers/IconHelper.cs b/src/Moltbot.Tray.WinUI/Helpers/IconHelper.cs new file mode 100644 index 0000000..f77e4aa --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Helpers/IconHelper.cs @@ -0,0 +1,145 @@ +using Moltbot.Shared; +using System; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; + +namespace MoltbotTray.Helpers; + +/// +/// Provides icon resources for the tray application. +/// Creates dynamic status icons with lobster pixel art. +/// +public static class IconHelper +{ + private static readonly string AssetsPath = Path.Combine(AppContext.BaseDirectory, "Assets"); + private static readonly string IconsPath = Path.Combine(AssetsPath, "Icons"); + + // Icon cache + private static Icon? _connectedIcon; + private static Icon? _disconnectedIcon; + private static Icon? _activityIcon; + private static Icon? _errorIcon; + private static Icon? _appIcon; + + public static string GetStatusIconPath(ConnectionStatus status) + { + var iconName = status switch + { + ConnectionStatus.Connected => "StatusConnected.ico", + ConnectionStatus.Connecting => "StatusConnecting.ico", + ConnectionStatus.Error => "StatusError.ico", + _ => "StatusDisconnected.ico" + }; + + var path = Path.Combine(IconsPath, iconName); + + // If specific icon doesn't exist, fall back to main icon + if (!File.Exists(path)) + { + path = Path.Combine(AssetsPath, "moltbot.ico"); + } + + return path; + } + + public static Icon GetStatusIcon(ConnectionStatus status) + { + return status switch + { + ConnectionStatus.Connected => GetOrCreateIcon(ref _connectedIcon, ConnectionStatus.Connected), + ConnectionStatus.Connecting => GetOrCreateIcon(ref _activityIcon, ConnectionStatus.Connecting), + ConnectionStatus.Error => GetOrCreateIcon(ref _errorIcon, ConnectionStatus.Error), + _ => GetOrCreateIcon(ref _disconnectedIcon, ConnectionStatus.Disconnected) + }; + } + + public static Icon GetAppIcon() + { + if (_appIcon != null) return _appIcon; + + var iconPath = Path.Combine(AssetsPath, "moltbot.ico"); + if (File.Exists(iconPath)) + { + _appIcon = new Icon(iconPath); + } + else + { + _appIcon = CreateLobsterIcon(Color.FromArgb(255, 99, 71)); // Lobster red + } + + return _appIcon; + } + + private static Icon GetOrCreateIcon(ref Icon? cached, ConnectionStatus status) + { + if (cached != null) return cached; + + var iconPath = GetStatusIconPath(status); + if (File.Exists(iconPath)) + { + cached = new Icon(iconPath); + } + else + { + // Generate dynamic icon + var color = status switch + { + ConnectionStatus.Connected => Color.FromArgb(76, 175, 80), // Green + ConnectionStatus.Connecting => Color.FromArgb(255, 193, 7), // Amber + ConnectionStatus.Error => Color.FromArgb(244, 67, 54), // Red + _ => Color.FromArgb(158, 158, 158) // Gray + }; + cached = CreateLobsterIcon(color); + } + + return cached; + } + + /// + /// Creates a simple colored lobster icon programmatically. + /// Uses pixel art style matching the original WinForms version. + /// + public static Icon CreateLobsterIcon(Color color) + { + const int size = 16; + using var bitmap = new Bitmap(size, size); + using var g = Graphics.FromImage(bitmap); + + g.Clear(Color.Transparent); + + // Simple lobster silhouette (pixel art style) + using var brush = new SolidBrush(color); + + // Body + g.FillRectangle(brush, 6, 6, 4, 6); + + // Claws + g.FillRectangle(brush, 3, 4, 2, 2); + g.FillRectangle(brush, 11, 4, 2, 2); + g.FillRectangle(brush, 4, 6, 2, 2); + g.FillRectangle(brush, 10, 6, 2, 2); + + // Tail + g.FillRectangle(brush, 7, 12, 2, 3); + g.FillRectangle(brush, 5, 14, 6, 1); + + // Eyes + using var eyeBrush = new SolidBrush(Color.White); + g.FillRectangle(eyeBrush, 6, 5, 1, 1); + g.FillRectangle(eyeBrush, 9, 5, 1, 1); + + // Convert bitmap to icon + var hIcon = bitmap.GetHicon(); + var icon = Icon.FromHandle(hIcon); + + // Clone to own the icon data + var result = (Icon)icon.Clone(); + DestroyIcon(hIcon); + + return result; + } + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern bool DestroyIcon(IntPtr handle); +} diff --git a/src/Moltbot.Tray.WinUI/Helpers/ThemeHelper.cs b/src/Moltbot.Tray.WinUI/Helpers/ThemeHelper.cs new file mode 100644 index 0000000..f1e0215 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Helpers/ThemeHelper.cs @@ -0,0 +1,57 @@ +using Microsoft.UI.Xaml; +using Microsoft.Win32; +using Windows.UI; + +namespace MoltbotTray.Helpers; + +/// +/// Helpers for detecting and applying Windows theme (dark/light mode). +/// +public static class ThemeHelper +{ + public static bool IsDarkMode() + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); + var value = key?.GetValue("AppsUseLightTheme"); + return value is int i && i == 0; + } + catch + { + return false; + } + } + + public static ElementTheme GetCurrentTheme() + { + return IsDarkMode() ? ElementTheme.Dark : ElementTheme.Light; + } + + public static Color GetAccentColor() + { + // Lobster red accent + return Color.FromArgb(255, 255, 99, 71); + } + + public static Color GetBackgroundColor() + { + return IsDarkMode() + ? Color.FromArgb(255, 32, 32, 32) + : Color.FromArgb(255, 249, 249, 249); + } + + public static Color GetForegroundColor() + { + return IsDarkMode() + ? Color.FromArgb(255, 255, 255, 255) + : Color.FromArgb(255, 28, 28, 28); + } + + public static Color GetSubtleTextColor() + { + return IsDarkMode() + ? Color.FromArgb(255, 180, 180, 180) + : Color.FromArgb(255, 100, 100, 100); + } +} diff --git a/src/Moltbot.Tray.WinUI/Moltbot.Tray.WinUI.csproj b/src/Moltbot.Tray.WinUI/Moltbot.Tray.WinUI.csproj new file mode 100644 index 0000000..42da7f8 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Moltbot.Tray.WinUI.csproj @@ -0,0 +1,33 @@ + + + + WinExe + net9.0-windows10.0.19041.0 + true + enable + enable + None + true + Assets\moltbot.ico + MoltbotTray + app.manifest + + + + + + + + + + + + + + + + + + + + diff --git a/src/Moltbot.Tray.WinUI/Services/AutoStartManager.cs b/src/Moltbot.Tray.WinUI/Services/AutoStartManager.cs new file mode 100644 index 0000000..3ad411e --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Services/AutoStartManager.cs @@ -0,0 +1,51 @@ +using Microsoft.Win32; +using System; + +namespace MoltbotTray.Services; + +/// +/// Manages Windows auto-start registry entries. +/// +public static class AutoStartManager +{ + private const string RegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; + private const string AppName = "MoltbotTray"; + + public static bool IsAutoStartEnabled() + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(RegistryKey, false); + return key?.GetValue(AppName) != null; + } + catch + { + return false; + } + } + + public static void SetAutoStart(bool enable) + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(RegistryKey, true); + if (key == null) return; + + if (enable) + { + var exePath = Environment.ProcessPath ?? System.Reflection.Assembly.GetExecutingAssembly().Location; + key.SetValue(AppName, $"\"{exePath}\""); + Logger.Info("Auto-start enabled"); + } + else + { + key.DeleteValue(AppName, false); + Logger.Info("Auto-start disabled"); + } + } + catch (Exception ex) + { + Logger.Error($"Failed to set auto-start: {ex.Message}"); + } + } +} diff --git a/src/Moltbot.Tray.WinUI/Services/DeepLinkHandler.cs b/src/Moltbot.Tray.WinUI/Services/DeepLinkHandler.cs new file mode 100644 index 0000000..10b946f --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Services/DeepLinkHandler.cs @@ -0,0 +1,121 @@ +using Microsoft.Win32; +using System; +using System.Threading.Tasks; + +namespace MoltbotTray.Services; + +/// +/// Handles moltbot:// deep link URI scheme registration and processing. +/// +public static class DeepLinkHandler +{ + private const string UriScheme = "moltbot"; + private const string UriSchemeKey = @"SOFTWARE\Classes\moltbot"; + + public static void RegisterUriScheme() + { + try + { + var exePath = Environment.ProcessPath ?? System.Reflection.Assembly.GetExecutingAssembly().Location; + + using var key = Registry.CurrentUser.CreateSubKey(UriSchemeKey); + key?.SetValue("", "URL:Moltbot Protocol"); + key?.SetValue("URL Protocol", ""); + + using var iconKey = key?.CreateSubKey("DefaultIcon"); + iconKey?.SetValue("", $"\"{exePath}\",0"); + + using var commandKey = key?.CreateSubKey(@"shell\open\command"); + commandKey?.SetValue("", $"\"{exePath}\" \"%1\""); + + Logger.Info("URI scheme registered: moltbot://"); + } + catch (Exception ex) + { + Logger.Warn($"Failed to register URI scheme: {ex.Message}"); + } + } + + public static void Handle(string uri, DeepLinkActions actions) + { + if (!uri.StartsWith("moltbot://", StringComparison.OrdinalIgnoreCase)) + return; + + var path = uri["moltbot://".Length..].TrimEnd('/'); + var queryIndex = path.IndexOf('?'); + var query = queryIndex >= 0 ? path[(queryIndex + 1)..] : ""; + path = queryIndex >= 0 ? path[..queryIndex] : path; + + Logger.Info($"Handling deep link: {path}"); + + switch (path.ToLowerInvariant()) + { + case "settings": + actions.OpenSettings?.Invoke(); + break; + + case "chat": + actions.OpenChat?.Invoke(); + break; + + case "dashboard": + actions.OpenDashboard?.Invoke(null); + break; + + case var p when p.StartsWith("dashboard/"): + var dashboardPath = p["dashboard/".Length..]; + actions.OpenDashboard?.Invoke(dashboardPath); + break; + + case "send": + var sendMessage = GetQueryParam(query, "message"); + actions.OpenQuickSend?.Invoke(sendMessage); + break; + + case "agent": + var agentMessage = GetQueryParam(query, "message"); + if (!string.IsNullOrEmpty(agentMessage)) + { + _ = Task.Run(async () => + { + try + { + await actions.SendMessage!(agentMessage); + Logger.Info($"Sent message via deep link: {agentMessage}"); + } + catch (Exception ex) + { + Logger.Error($"Failed to send message: {ex.Message}"); + } + }); + } + break; + + default: + Logger.Warn($"Unknown deep link path: {path}"); + break; + } + } + + private static string? GetQueryParam(string query, string key) + { + foreach (var part in query.Split('&', StringSplitOptions.RemoveEmptyEntries)) + { + var kv = part.Split('=', 2); + if (kv.Length == 2 && kv[0].Equals(key, StringComparison.OrdinalIgnoreCase)) + { + return Uri.UnescapeDataString(kv[1]); + } + } + return null; + } +} + +public class DeepLinkActions +{ + public Action? OpenSettings { get; set; } + public Action? OpenChat { get; set; } + public Action? OpenDashboard { get; set; } + public Action? OpenQuickSend { get; set; } + public Func? SendMessage { get; set; } +} diff --git a/src/Moltbot.Tray.WinUI/Services/GlobalHotkeyService.cs b/src/Moltbot.Tray.WinUI/Services/GlobalHotkeyService.cs new file mode 100644 index 0000000..51748d2 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Services/GlobalHotkeyService.cs @@ -0,0 +1,91 @@ +using System; +using System.Runtime.InteropServices; + +namespace MoltbotTray.Services; + +/// +/// Registers and handles global hotkeys using P/Invoke. +/// Default: Ctrl+Alt+Shift+C for Quick Send. +/// +public class GlobalHotkeyService : IDisposable +{ + private const int HOTKEY_ID = 1; + private const uint MOD_CONTROL = 0x0002; + private const uint MOD_ALT = 0x0001; + private const uint MOD_SHIFT = 0x0004; + private const uint VK_C = 0x43; + + [DllImport("user32.dll")] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); + + [DllImport("user32.dll")] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + + private IntPtr _hwnd; + private bool _registered; + + public event EventHandler? HotkeyPressed; + + public GlobalHotkeyService() + { + // Create a message-only window for hotkey messages + _hwnd = CreateMessageWindow(); + } + + public bool Register() + { + if (_registered) return true; + + try + { + _registered = RegisterHotKey(_hwnd, HOTKEY_ID, MOD_CONTROL | MOD_ALT | MOD_SHIFT, VK_C); + if (_registered) + { + Logger.Info("Global hotkey registered: Ctrl+Alt+Shift+C"); + } + else + { + Logger.Warn("Failed to register global hotkey"); + } + return _registered; + } + catch (Exception ex) + { + Logger.Error($"Hotkey registration error: {ex.Message}"); + return false; + } + } + + public void Unregister() + { + if (!_registered) return; + + try + { + UnregisterHotKey(_hwnd, HOTKEY_ID); + _registered = false; + Logger.Info("Global hotkey unregistered"); + } + catch (Exception ex) + { + Logger.Warn($"Hotkey unregistration error: {ex.Message}"); + } + } + + internal void OnHotkeyPressed() + { + HotkeyPressed?.Invoke(this, EventArgs.Empty); + } + + private IntPtr CreateMessageWindow() + { + // Use a simple approach - we'll hook into the message loop differently in WinUI + // For now, return IntPtr.Zero and use a different mechanism + return IntPtr.Zero; + } + + public void Dispose() + { + Unregister(); + } +} diff --git a/src/Moltbot.Tray.WinUI/Services/Logger.cs b/src/Moltbot.Tray.WinUI/Services/Logger.cs new file mode 100644 index 0000000..6adda66 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Services/Logger.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; + +namespace MoltbotTray.Services; + +/// +/// Simple file logger for the tray application. +/// +public static class Logger +{ + private static readonly object _lock = new(); + private static readonly string _logDirectory; + private static readonly string _logFilePath; + + static Logger() + { + _logDirectory = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "MoltbotTray"); + + Directory.CreateDirectory(_logDirectory); + _logFilePath = Path.Combine(_logDirectory, "moltbot-tray.log"); + + // Rotate log if too large (> 5MB) + try + { + var fileInfo = new FileInfo(_logFilePath); + if (fileInfo.Exists && fileInfo.Length > 5 * 1024 * 1024) + { + var backupPath = Path.Combine(_logDirectory, "moltbot-tray.log.old"); + if (File.Exists(backupPath)) File.Delete(backupPath); + File.Move(_logFilePath, backupPath); + } + } + catch { } + } + + public static string LogFilePath => _logFilePath; + + public static void Info(string message) => Log("INFO", message); + public static void Warn(string message) => Log("WARN", message); + public static void Error(string message) => Log("ERROR", message); + public static void Debug(string message) => Log("DEBUG", message); + + private static void Log(string level, string message) + { + var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); + var line = $"[{timestamp}] [{level}] {message}"; + + lock (_lock) + { + try + { + File.AppendAllText(_logFilePath, line + Environment.NewLine); + } + catch { } + } + +#if DEBUG + System.Diagnostics.Debug.WriteLine(line); +#endif + } +} diff --git a/src/Moltbot.Tray.WinUI/Services/NotificationHistoryService.cs b/src/Moltbot.Tray.WinUI/Services/NotificationHistoryService.cs new file mode 100644 index 0000000..f9f9cb5 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Services/NotificationHistoryService.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MoltbotTray.Services; + +/// +/// Stores notification history in memory with a configurable limit. +/// +public static class NotificationHistoryService +{ + private static readonly List _history = new(); + private static readonly object _lock = new(); + private const int MaxHistory = 100; + + public static void AddNotification(GatewayNotification notification) + { + lock (_lock) + { + _history.Insert(0, new NotificationHistoryItem + { + Timestamp = DateTime.Now, + Title = notification.Title ?? "Moltbot", + Message = notification.Message ?? "", + Category = notification.Category, + ActionUrl = notification.ActionUrl + }); + + // Trim to max + while (_history.Count > MaxHistory) + { + _history.RemoveAt(_history.Count - 1); + } + } + } + + public static IReadOnlyList GetHistory() + { + lock (_lock) + { + return _history.ToList(); + } + } + + public static void Clear() + { + lock (_lock) + { + _history.Clear(); + } + } +} + +public class NotificationHistoryItem +{ + public DateTime Timestamp { get; set; } + public string Title { get; set; } = ""; + public string Message { get; set; } = ""; + public string? Category { get; set; } + public string? ActionUrl { get; set; } +} + +// Local notification model +public class GatewayNotification +{ + public string? Title { get; set; } + public string? Message { get; set; } + public string? Category { get; set; } + public string? ActionUrl { get; set; } +} diff --git a/src/Moltbot.Tray.WinUI/Services/SettingsManager.cs b/src/Moltbot.Tray.WinUI/Services/SettingsManager.cs new file mode 100644 index 0000000..fc8a1f2 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Services/SettingsManager.cs @@ -0,0 +1,131 @@ +using System; +using System.IO; +using System.Text.Json; + +namespace MoltbotTray.Services; + +/// +/// Manages application settings with JSON persistence. +/// +public class SettingsManager +{ + private static readonly string SettingsDirectory = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "MoltbotTray"); + + private static readonly string SettingsFilePath = Path.Combine(SettingsDirectory, "settings.json"); + + // Connection + public string GatewayUrl { get; set; } = "ws://localhost:18789"; + public string Token { get; set; } = ""; + + // Startup + public bool AutoStart { get; set; } = false; + public bool GlobalHotkeyEnabled { get; set; } = true; + + // Notifications + public bool ShowNotifications { get; set; } = true; + public string NotificationSound { get; set; } = "Default"; + + // Notification filters + public bool NotifyHealth { get; set; } = true; + public bool NotifyUrgent { get; set; } = true; + public bool NotifyReminder { get; set; } = true; + public bool NotifyEmail { get; set; } = true; + public bool NotifyCalendar { get; set; } = true; + public bool NotifyBuild { get; set; } = true; + public bool NotifyStock { get; set; } = true; + public bool NotifyInfo { get; set; } = true; + + public SettingsManager() + { + Load(); + } + + public void Load() + { + try + { + if (File.Exists(SettingsFilePath)) + { + var json = File.ReadAllText(SettingsFilePath); + var loaded = JsonSerializer.Deserialize(json); + if (loaded != null) + { + GatewayUrl = loaded.GatewayUrl ?? GatewayUrl; + Token = loaded.Token ?? Token; + AutoStart = loaded.AutoStart; + GlobalHotkeyEnabled = loaded.GlobalHotkeyEnabled; + ShowNotifications = loaded.ShowNotifications; + NotificationSound = loaded.NotificationSound ?? NotificationSound; + NotifyHealth = loaded.NotifyHealth; + NotifyUrgent = loaded.NotifyUrgent; + NotifyReminder = loaded.NotifyReminder; + NotifyEmail = loaded.NotifyEmail; + NotifyCalendar = loaded.NotifyCalendar; + NotifyBuild = loaded.NotifyBuild; + NotifyStock = loaded.NotifyStock; + NotifyInfo = loaded.NotifyInfo; + } + } + } + catch (Exception ex) + { + Logger.Warn($"Failed to load settings: {ex.Message}"); + } + } + + public void Save() + { + try + { + Directory.CreateDirectory(SettingsDirectory); + + var data = new SettingsData + { + GatewayUrl = GatewayUrl, + Token = Token, + AutoStart = AutoStart, + GlobalHotkeyEnabled = GlobalHotkeyEnabled, + ShowNotifications = ShowNotifications, + NotificationSound = NotificationSound, + NotifyHealth = NotifyHealth, + NotifyUrgent = NotifyUrgent, + NotifyReminder = NotifyReminder, + NotifyEmail = NotifyEmail, + NotifyCalendar = NotifyCalendar, + NotifyBuild = NotifyBuild, + NotifyStock = NotifyStock, + NotifyInfo = NotifyInfo + }; + + var options = new JsonSerializerOptions { WriteIndented = true }; + var json = JsonSerializer.Serialize(data, options); + File.WriteAllText(SettingsFilePath, json); + + Logger.Info("Settings saved"); + } + catch (Exception ex) + { + Logger.Error($"Failed to save settings: {ex.Message}"); + } + } + + private class SettingsData + { + public string? GatewayUrl { get; set; } + public string? Token { get; set; } + public bool AutoStart { get; set; } + public bool GlobalHotkeyEnabled { get; set; } = true; + public bool ShowNotifications { get; set; } = true; + public string? NotificationSound { get; set; } + public bool NotifyHealth { get; set; } = true; + public bool NotifyUrgent { get; set; } = true; + public bool NotifyReminder { get; set; } = true; + public bool NotifyEmail { get; set; } = true; + public bool NotifyCalendar { get; set; } = true; + public bool NotifyBuild { get; set; } = true; + public bool NotifyStock { get; set; } = true; + public bool NotifyInfo { get; set; } = true; + } +} diff --git a/src/Moltbot.Tray.WinUI/Windows/NotificationHistoryWindow.xaml b/src/Moltbot.Tray.WinUI/Windows/NotificationHistoryWindow.xaml new file mode 100644 index 0000000..69799a3 --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Windows/NotificationHistoryWindow.xaml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Moltbot.Tray.WinUI/Windows/WebChatWindow.xaml.cs b/src/Moltbot.Tray.WinUI/Windows/WebChatWindow.xaml.cs new file mode 100644 index 0000000..62a5fbf --- /dev/null +++ b/src/Moltbot.Tray.WinUI/Windows/WebChatWindow.xaml.cs @@ -0,0 +1,127 @@ +using Microsoft.UI.Xaml; +using Microsoft.Web.WebView2.Core; +using Moltbot.Shared; +using MoltbotTray.Helpers; +using MoltbotTray.Services; +using System; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using WinUIEx; + +namespace MoltbotTray.Windows; + +public sealed partial class WebChatWindow : WindowEx +{ + private readonly string _gatewayUrl; + private readonly string _token; + private bool _initialized; + + public bool IsClosed { get; private set; } + + public WebChatWindow(string gatewayUrl, string token) + { + _gatewayUrl = gatewayUrl; + _token = token; + + InitializeComponent(); + + // Window configuration + this.SetWindowSize(520, 750); + this.MinWidth = 380; + this.MinHeight = 450; + this.CenterOnScreen(); + this.SetIcon(IconHelper.GetStatusIconPath(ConnectionStatus.Connected)); + + Closed += (s, e) => IsClosed = true; + + _ = InitializeWebViewAsync(); + } + + private async Task InitializeWebViewAsync() + { + try + { + // Set up user data folder via environment variable (WinUI 3 workaround) + var userDataFolder = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "MoltbotTray", "WebView2"); + + Directory.CreateDirectory(userDataFolder); + Environment.SetEnvironmentVariable("WEBVIEW2_USER_DATA_FOLDER", userDataFolder); + + await WebView.EnsureCoreWebView2Async(); + + // Configure WebView2 + WebView.CoreWebView2.Settings.IsStatusBarEnabled = false; + WebView.CoreWebView2.Settings.AreDefaultContextMenusEnabled = true; + WebView.CoreWebView2.Settings.IsZoomControlEnabled = true; + + // Handle navigation events + WebView.CoreWebView2.NavigationCompleted += (s, e) => + { + LoadingRing.IsActive = false; + LoadingRing.Visibility = Visibility.Collapsed; + }; + + WebView.CoreWebView2.NavigationStarting += (s, e) => + { + LoadingRing.IsActive = true; + LoadingRing.Visibility = Visibility.Visible; + }; + + // Navigate to chat + NavigateToChat(); + _initialized = true; + } + catch (Exception ex) + { + Logger.Error($"WebView2 initialization failed: {ex.Message}"); + LoadingRing.IsActive = false; + } + } + + private void NavigateToChat() + { + if (WebView.CoreWebView2 == null) return; + + var baseUrl = _gatewayUrl + .Replace("ws://", "http://") + .Replace("wss://", "https://"); + + var url = $"{baseUrl}?token={Uri.EscapeDataString(_token)}"; + WebView.CoreWebView2.Navigate(url); + } + + private void OnHome(object sender, RoutedEventArgs e) + { + NavigateToChat(); + } + + private void OnRefresh(object sender, RoutedEventArgs e) + { + WebView.CoreWebView2?.Reload(); + } + + private void OnPopout(object sender, RoutedEventArgs e) + { + var baseUrl = _gatewayUrl + .Replace("ws://", "http://") + .Replace("wss://", "https://"); + var url = $"{baseUrl}?token={Uri.EscapeDataString(_token)}"; + + try + { + Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); + } + catch (Exception ex) + { + Logger.Error($"Failed to open in browser: {ex.Message}"); + } + } + + private void OnDevTools(object sender, RoutedEventArgs e) + { + WebView.CoreWebView2?.OpenDevToolsWindow(); + } +} diff --git a/src/Moltbot.Tray.WinUI/app.manifest b/src/Moltbot.Tray.WinUI/app.manifest new file mode 100644 index 0000000..917a80a --- /dev/null +++ b/src/Moltbot.Tray.WinUI/app.manifest @@ -0,0 +1,19 @@ + + + + + + + + true/pm + PerMonitorV2 + + + + + + + + + + From 2b8bd561ebd73789fb166bd94f9fe9f80ddd1dc8 Mon Sep 17 00:00:00 2001 From: Scott Hanselman Date: Thu, 29 Jan 2026 00:29:32 -0800 Subject: [PATCH 2/7] Improve session/channel display parity with WinForms version - Sessions now show detailed info (type, model, channel) - Sessions are indented under clickable header - Channel status colors match WinForms logic (ON/READY/IDLE/ERROR) - Pre-fetch sessions/usage before showing menu - Capitalize channel names --- src/Moltbot.Tray.WinUI/App.xaml.cs | 57 +++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/src/Moltbot.Tray.WinUI/App.xaml.cs b/src/Moltbot.Tray.WinUI/App.xaml.cs index 02082e6..d974fb7 100644 --- a/src/Moltbot.Tray.WinUI/App.xaml.cs +++ b/src/Moltbot.Tray.WinUI/App.xaml.cs @@ -157,7 +157,7 @@ public partial class App : Application // Don't set e.Flyout - we're handling it ourselves } - private void ShowTrayMenuPopup() + private async void ShowTrayMenuPopup() { // Close any existing menu if (_trayMenuWindow != null) @@ -166,6 +166,19 @@ public partial class App : Application _trayMenuWindow = null; } + // Pre-fetch latest data before showing menu + if (_gatewayClient != null && _currentStatus == ConnectionStatus.Connected) + { + try + { + _ = _gatewayClient.CheckHealthAsync(); + _ = _gatewayClient.RequestSessionsAsync(); + _ = _gatewayClient.RequestUsageAsync(); + await Task.Delay(150); // Brief wait for data + } + catch { /* ignore - show cached data */ } + } + _trayMenuWindow = new TrayMenuWindow(); _trayMenuWindow.MenuItemClicked += OnTrayMenuItemClicked; _trayMenuWindow.Closed += (s, e) => _trayMenuWindow = null; @@ -226,7 +239,7 @@ public partial class App : Application menu.AddMenuItem(_lastUsage.DisplayText, "📊", "", isEnabled: false); } - // Sessions + // Sessions (if any) - show meaningful info like the WinForms version if (_lastSessions.Length > 0) { menu.AddSeparator(); @@ -234,11 +247,31 @@ public partial class App : Application foreach (var session in _lastSessions.Take(5)) { - menu.AddMenuItem($" {session.DisplayText}", null, $"session:{session.Key}"); + // Extract session type from key like "agent:main:cron:uuid" or "agent:main:subagent:uuid" + var parts = session.Key.Split(':'); + var sessionType = parts.Length >= 3 ? parts[2] : "session"; + var displayName = sessionType switch + { + "main" => "Main Agent", + "cron" => "Scheduled Task", + "subagent" => "Sub-Agent", + _ => sessionType.Length > 0 ? char.ToUpper(sessionType[0]) + sessionType[1..] : "Session" + }; + + // Add model if available + if (!string.IsNullOrEmpty(session.Model)) + displayName += $" ({session.Model})"; + else if (!string.IsNullOrEmpty(session.Channel)) + displayName += $" · {session.Channel}"; + + var icon = session.IsMain ? "⭐" : "•"; + menu.AddMenuItem(displayName, icon, $"session:{session.Key}", isEnabled: false, indent: true); } + if (_lastSessions.Length > 5) + menu.AddMenuItem($"+{_lastSessions.Length - 5} more...", "", "", isEnabled: false, indent: true); } - // Channels + // Channels (if any) if (_lastChannels.Length > 0) { menu.AddSeparator(); @@ -246,13 +279,19 @@ public partial class App : Application foreach (var channel in _lastChannels) { - var channelIcon = channel.Status?.ToLowerInvariant() switch + var rawStatus = channel.Status?.ToLowerInvariant() ?? ""; + + // Match status logic from WinForms version + var channelIcon = rawStatus switch { - "ok" or "connected" or "running" => "🟢", - "connecting" or "reconnecting" => "🟡", - _ => "🔴" + "ok" or "connected" or "running" or "active" or "ready" => "🟢", + "stopped" or "idle" or "paused" or "configured" or "pending" => "🟡", + "error" or "disconnected" or "failed" => "🔴", + _ => "⚪" }; - menu.AddMenuItem(channel.Name, channelIcon, $"channel:{channel.Name}", indent: true); + + var channelName = char.ToUpper(channel.Name[0]) + channel.Name[1..]; + menu.AddMenuItem(channelName, channelIcon, $"channel:{channel.Name}", indent: true); } } From ff343e20a51f0bab40b70f73ba764920f36c43fa Mon Sep 17 00:00:00 2001 From: Scott Hanselman Date: Thu, 29 Jan 2026 08:47:32 -0800 Subject: [PATCH 3/7] Fix crash on right-click - wrap ShowTrayMenuPopup in try-catch --- src/Moltbot.Tray.WinUI/App.xaml.cs | 52 +++++++++++++++++------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/Moltbot.Tray.WinUI/App.xaml.cs b/src/Moltbot.Tray.WinUI/App.xaml.cs index d974fb7..74f4db7 100644 --- a/src/Moltbot.Tray.WinUI/App.xaml.cs +++ b/src/Moltbot.Tray.WinUI/App.xaml.cs @@ -159,33 +159,39 @@ public partial class App : Application private async void ShowTrayMenuPopup() { - // Close any existing menu - if (_trayMenuWindow != null) + try { - try { _trayMenuWindow.Close(); } catch { } - _trayMenuWindow = null; - } - - // Pre-fetch latest data before showing menu - if (_gatewayClient != null && _currentStatus == ConnectionStatus.Connected) - { - try + // Close any existing menu + if (_trayMenuWindow != null) { - _ = _gatewayClient.CheckHealthAsync(); - _ = _gatewayClient.RequestSessionsAsync(); - _ = _gatewayClient.RequestUsageAsync(); - await Task.Delay(150); // Brief wait for data + try { _trayMenuWindow.Close(); } catch { } + _trayMenuWindow = null; } - catch { /* ignore - show cached data */ } + + // Pre-fetch latest data before showing menu (fire and forget, don't wait) + if (_gatewayClient != null && _currentStatus == ConnectionStatus.Connected) + { + try + { + _ = _gatewayClient.CheckHealthAsync(); + _ = _gatewayClient.RequestSessionsAsync(); + _ = _gatewayClient.RequestUsageAsync(); + } + catch { /* ignore */ } + } + + _trayMenuWindow = new TrayMenuWindow(); + _trayMenuWindow.MenuItemClicked += OnTrayMenuItemClicked; + _trayMenuWindow.Closed += (s, e) => _trayMenuWindow = null; + + BuildTrayMenuPopup(_trayMenuWindow); + _trayMenuWindow.SizeToContent(); + _trayMenuWindow.ShowAtCursor(); + } + catch (Exception ex) + { + Logger.Error($"Failed to show tray menu: {ex.Message}"); } - - _trayMenuWindow = new TrayMenuWindow(); - _trayMenuWindow.MenuItemClicked += OnTrayMenuItemClicked; - _trayMenuWindow.Closed += (s, e) => _trayMenuWindow = null; - - BuildTrayMenuPopup(_trayMenuWindow); - _trayMenuWindow.SizeToContent(); - _trayMenuWindow.ShowAtCursor(); } private void OnTrayMenuItemClicked(object? sender, string action) From 23ff811f6c42c3c95e12c0c8b083cfddf2b3f8e5 Mon Sep 17 00:00:00 2001 From: Scott Hanselman Date: Thu, 29 Jan 2026 09:02:44 -0800 Subject: [PATCH 4/7] Fix code review issues - GlobalHotkeyService: Properly create message-only window with message loop - App.xaml.cs: Unsubscribe gateway events before disposal to prevent leaks - App.xaml.cs: Add CancellationToken to deep link server for clean shutdown - App.xaml.cs: Proper cleanup order in ExitApplication - WebChatWindow: Store and cleanup WebView2 event handlers on close --- src/Moltbot.Tray.WinUI/App.xaml.cs | 55 +++++- .../Services/GlobalHotkeyService.cs | 160 ++++++++++++++++-- .../Windows/WebChatWindow.xaml.cs | 29 +++- 3 files changed, 221 insertions(+), 23 deletions(-) diff --git a/src/Moltbot.Tray.WinUI/App.xaml.cs b/src/Moltbot.Tray.WinUI/App.xaml.cs index 74f4db7..f58ce69 100644 --- a/src/Moltbot.Tray.WinUI/App.xaml.cs +++ b/src/Moltbot.Tray.WinUI/App.xaml.cs @@ -37,6 +37,7 @@ public partial class App : Application private System.Timers.Timer? _sessionPollTimer; private Mutex? _mutex; private Microsoft.UI.Dispatching.DispatcherQueue? _dispatcherQueue; + private CancellationTokenSource? _deepLinkCts; private ConnectionStatus _currentStatus = ConnectionStatus.Disconnected; private AgentActivity? _currentActivity; @@ -477,6 +478,9 @@ public partial class App : Application { if (_settings == null) return; + // Unsubscribe from old client if exists + UnsubscribeGatewayEvents(); + _gatewayClient = new MoltbotGatewayClient(_settings.GatewayUrl, _settings.Token, new AppLogger()); _gatewayClient.StatusChanged += OnConnectionStatusChanged; _gatewayClient.ActivityChanged += OnActivityChanged; @@ -487,6 +491,19 @@ public partial class App : Application _ = _gatewayClient.ConnectAsync(); } + private void UnsubscribeGatewayEvents() + { + if (_gatewayClient != null) + { + _gatewayClient.StatusChanged -= OnConnectionStatusChanged; + _gatewayClient.ActivityChanged -= OnActivityChanged; + _gatewayClient.NotificationReceived -= OnNotificationReceived; + _gatewayClient.ChannelHealthUpdated -= OnChannelHealthUpdated; + _gatewayClient.SessionsUpdated -= OnSessionsUpdated; + _gatewayClient.UsageUpdated -= OnUsageUpdated; + } + } + private void OnConnectionStatusChanged(object? sender, ConnectionStatus status) { _currentStatus = status; @@ -921,29 +938,39 @@ public partial class App : Application private void StartDeepLinkServer() { + _deepLinkCts = new CancellationTokenSource(); + var token = _deepLinkCts.Token; + Task.Run(async () => { - while (true) + while (!token.IsCancellationRequested) { try { using var pipe = new NamedPipeServerStream(PipeName, PipeDirection.In); - await pipe.WaitForConnectionAsync(); + await pipe.WaitForConnectionAsync(token); using var reader = new System.IO.StreamReader(pipe); - var uri = await reader.ReadLineAsync(); + var uri = await reader.ReadLineAsync(token); if (!string.IsNullOrEmpty(uri)) { Logger.Info($"Received deep link via IPC: {uri}"); _dispatcherQueue?.TryEnqueue(() => HandleDeepLink(uri)); } } + catch (OperationCanceledException) + { + break; // Normal shutdown + } catch (Exception ex) { - Logger.Warn($"Deep link server error: {ex.Message}"); - await Task.Delay(1000); + if (!token.IsCancellationRequested) + { + Logger.Warn($"Deep link server error: {ex.Message}"); + try { await Task.Delay(1000, token); } catch { break; } + } } } - }); + }, token); } private void HandleDeepLink(string uri) @@ -1017,15 +1044,29 @@ public partial class App : Application { Logger.Info("Application exiting"); + // Cancel background tasks + _deepLinkCts?.Cancel(); + + // Stop timers _healthCheckTimer?.Stop(); _healthCheckTimer?.Dispose(); _sessionPollTimer?.Stop(); _sessionPollTimer?.Dispose(); - _globalHotkey?.Unregister(); + + // Cleanup hotkey + _globalHotkey?.Dispose(); + + // Unsubscribe and dispose gateway client + UnsubscribeGatewayEvents(); _gatewayClient?.Dispose(); + + // Dispose tray and mutex _trayIcon?.Dispose(); _mutex?.Dispose(); + // Dispose cancellation token source + _deepLinkCts?.Dispose(); + Exit(); } diff --git a/src/Moltbot.Tray.WinUI/Services/GlobalHotkeyService.cs b/src/Moltbot.Tray.WinUI/Services/GlobalHotkeyService.cs index 51748d2..949f374 100644 --- a/src/Moltbot.Tray.WinUI/Services/GlobalHotkeyService.cs +++ b/src/Moltbot.Tray.WinUI/Services/GlobalHotkeyService.cs @@ -9,11 +9,12 @@ namespace MoltbotTray.Services; /// public class GlobalHotkeyService : IDisposable { - private const int HOTKEY_ID = 1; + private const int HOTKEY_ID = 9001; private const uint MOD_CONTROL = 0x0002; private const uint MOD_ALT = 0x0001; private const uint MOD_SHIFT = 0x0004; private const uint VK_C = 0x43; + private const int WM_HOTKEY = 0x0312; [DllImport("user32.dll")] private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); @@ -21,15 +22,85 @@ public class GlobalHotkeyService : IDisposable [DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + [DllImport("user32.dll", SetLastError = true)] + private static extern IntPtr CreateWindowEx( + uint dwExStyle, string lpClassName, string lpWindowName, + uint dwStyle, int x, int y, int nWidth, int nHeight, + IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam); + + [DllImport("user32.dll")] + private static extern bool DestroyWindow(IntPtr hWnd); + + [DllImport("user32.dll")] + private static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll", SetLastError = true)] + private static extern ushort RegisterClass(ref WNDCLASS lpWndClass); + + [DllImport("kernel32.dll")] + private static extern IntPtr GetModuleHandle(string? lpModuleName); + + [DllImport("user32.dll")] + private static extern bool GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); + + [DllImport("user32.dll")] + private static extern bool TranslateMessage(ref MSG lpMsg); + + [DllImport("user32.dll")] + private static extern IntPtr DispatchMessage(ref MSG lpMsg); + + [DllImport("user32.dll")] + private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); + + private const uint WM_QUIT = 0x0012; + private const uint WM_USER = 0x0400; + + private delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); + + [StructLayout(LayoutKind.Sequential)] + private struct WNDCLASS + { + public uint style; + public IntPtr lpfnWndProc; + public int cbClsExtra; + public int cbWndExtra; + public IntPtr hInstance; + public IntPtr hIcon; + public IntPtr hCursor; + public IntPtr hbrBackground; + public string? lpszMenuName; + public string lpszClassName; + } + + [StructLayout(LayoutKind.Sequential)] + private struct MSG + { + public IntPtr hwnd; + public uint message; + public IntPtr wParam; + public IntPtr lParam; + public uint time; + public POINT pt; + } + + [StructLayout(LayoutKind.Sequential)] + private struct POINT + { + public int x; + public int y; + } + private IntPtr _hwnd; private bool _registered; + private bool _disposed; + private Thread? _messageThread; + private WndProcDelegate? _wndProcDelegate; // prevent GC collection + private volatile bool _running; public event EventHandler? HotkeyPressed; public GlobalHotkeyService() { - // Create a message-only window for hotkey messages - _hwnd = CreateMessageWindow(); } public bool Register() @@ -38,6 +109,20 @@ public class GlobalHotkeyService : IDisposable try { + // Create message window on a dedicated thread with message loop + _running = true; + _messageThread = new Thread(MessageLoop) { IsBackground = true, Name = "HotkeyMessageLoop" }; + _messageThread.Start(); + + // Wait briefly for window creation + Thread.Sleep(100); + + if (_hwnd == IntPtr.Zero) + { + Logger.Warn("Failed to create hotkey message window"); + return false; + } + _registered = RegisterHotKey(_hwnd, HOTKEY_ID, MOD_CONTROL | MOD_ALT | MOD_SHIFT, VK_C); if (_registered) { @@ -45,7 +130,7 @@ public class GlobalHotkeyService : IDisposable } else { - Logger.Warn("Failed to register global hotkey"); + Logger.Warn("Failed to register global hotkey (may be in use by another app)"); } return _registered; } @@ -56,13 +141,58 @@ public class GlobalHotkeyService : IDisposable } } + private void MessageLoop() + { + try + { + // Create window class + _wndProcDelegate = WndProc; + var wndClass = new WNDCLASS + { + lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate), + hInstance = GetModuleHandle(null), + lpszClassName = "MoltbotHotkeyWindow" + }; + + RegisterClass(ref wndClass); + + // Create message-only window (HWND_MESSAGE parent) + _hwnd = CreateWindowEx(0, "MoltbotHotkeyWindow", "", 0, 0, 0, 0, 0, + new IntPtr(-3), // HWND_MESSAGE + IntPtr.Zero, GetModuleHandle(null), IntPtr.Zero); + + // Message loop + while (_running && GetMessage(out MSG msg, IntPtr.Zero, 0, 0)) + { + TranslateMessage(ref msg); + DispatchMessage(ref msg); + } + } + catch (Exception ex) + { + Logger.Error($"Hotkey message loop error: {ex.Message}"); + } + } + + private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) + { + if (msg == WM_HOTKEY && wParam.ToInt32() == HOTKEY_ID) + { + OnHotkeyPressed(); + } + return DefWindowProc(hWnd, msg, wParam, lParam); + } + public void Unregister() { if (!_registered) return; try { - UnregisterHotKey(_hwnd, HOTKEY_ID); + if (_hwnd != IntPtr.Zero) + { + UnregisterHotKey(_hwnd, HOTKEY_ID); + } _registered = false; Logger.Info("Global hotkey unregistered"); } @@ -77,15 +207,21 @@ public class GlobalHotkeyService : IDisposable HotkeyPressed?.Invoke(this, EventArgs.Empty); } - private IntPtr CreateMessageWindow() - { - // Use a simple approach - we'll hook into the message loop differently in WinUI - // For now, return IntPtr.Zero and use a different mechanism - return IntPtr.Zero; - } - public void Dispose() { + if (_disposed) return; + _disposed = true; + Unregister(); + + _running = false; + if (_hwnd != IntPtr.Zero) + { + PostMessage(_hwnd, WM_QUIT, IntPtr.Zero, IntPtr.Zero); + DestroyWindow(_hwnd); + _hwnd = IntPtr.Zero; + } + + _messageThread?.Join(1000); } } diff --git a/src/Moltbot.Tray.WinUI/Windows/WebChatWindow.xaml.cs b/src/Moltbot.Tray.WinUI/Windows/WebChatWindow.xaml.cs index 62a5fbf..1112ce9 100644 --- a/src/Moltbot.Tray.WinUI/Windows/WebChatWindow.xaml.cs +++ b/src/Moltbot.Tray.WinUI/Windows/WebChatWindow.xaml.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.IO; using System.Threading.Tasks; using WinUIEx; +using Windows.Foundation; namespace MoltbotTray.Windows; @@ -17,6 +18,10 @@ public sealed partial class WebChatWindow : WindowEx private readonly string _token; private bool _initialized; + // Store event handlers for cleanup + private TypedEventHandler? _navigationCompletedHandler; + private TypedEventHandler? _navigationStartingHandler; + public bool IsClosed { get; private set; } public WebChatWindow(string gatewayUrl, string token) @@ -33,11 +38,25 @@ public sealed partial class WebChatWindow : WindowEx this.CenterOnScreen(); this.SetIcon(IconHelper.GetStatusIconPath(ConnectionStatus.Connected)); - Closed += (s, e) => IsClosed = true; + Closed += OnWindowClosed; _ = InitializeWebViewAsync(); } + private void OnWindowClosed(object sender, WindowEventArgs e) + { + IsClosed = true; + + // Cleanup WebView2 event handlers + if (WebView.CoreWebView2 != null) + { + if (_navigationCompletedHandler != null) + WebView.CoreWebView2.NavigationCompleted -= _navigationCompletedHandler; + if (_navigationStartingHandler != null) + WebView.CoreWebView2.NavigationStarting -= _navigationStartingHandler; + } + } + private async Task InitializeWebViewAsync() { try @@ -57,18 +76,20 @@ public sealed partial class WebChatWindow : WindowEx WebView.CoreWebView2.Settings.AreDefaultContextMenusEnabled = true; WebView.CoreWebView2.Settings.IsZoomControlEnabled = true; - // Handle navigation events - WebView.CoreWebView2.NavigationCompleted += (s, e) => + // Handle navigation events (store for cleanup) + _navigationCompletedHandler = (s, e) => { LoadingRing.IsActive = false; LoadingRing.Visibility = Visibility.Collapsed; }; + WebView.CoreWebView2.NavigationCompleted += _navigationCompletedHandler; - WebView.CoreWebView2.NavigationStarting += (s, e) => + _navigationStartingHandler = (s, e) => { LoadingRing.IsActive = true; LoadingRing.Visibility = Visibility.Visible; }; + WebView.CoreWebView2.NavigationStarting += _navigationStartingHandler; // Navigate to chat NavigateToChat(); From 2055c3c78b650653a975074151dc4b98a1936fed Mon Sep 17 00:00:00 2001 From: Scott Hanselman Date: Thu, 29 Jan 2026 10:00:23 -0800 Subject: [PATCH 5/7] Left-click shows menu (matching WinForms behavior) --- src/Moltbot.Tray.WinUI/App.xaml.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Moltbot.Tray.WinUI/App.xaml.cs b/src/Moltbot.Tray.WinUI/App.xaml.cs index f58ce69..8c26553 100644 --- a/src/Moltbot.Tray.WinUI/App.xaml.cs +++ b/src/Moltbot.Tray.WinUI/App.xaml.cs @@ -147,13 +147,13 @@ public partial class App : Application private void OnTrayIconSelected(TrayIcon sender, TrayIconEventArgs e) { - // Left-click: show status detail or dashboard - OpenDashboard(); + // Left-click: show menu (same as right-click, matching WinForms behavior) + ShowTrayMenuPopup(); } private void OnTrayContextMenu(TrayIcon sender, TrayIconEventArgs e) { - // Use a popup window instead of MenuFlyout for better multi-monitor support + // Right-click: show menu via popup window for better multi-monitor support ShowTrayMenuPopup(); // Don't set e.Flyout - we're handling it ourselves } From 83b76f8e79e7b7bfe7506653593b1f1cf0bb5cbc Mon Sep 17 00:00:00 2001 From: Scott Hanselman Date: Thu, 29 Jan 2026 10:18:41 -0800 Subject: [PATCH 6/7] Fix WelcomeDialog OOBE: use WindowEx, add icon, fix height --- .../Dialogs/WelcomeDialog.cs | 90 +++++++++++++------ 1 file changed, 61 insertions(+), 29 deletions(-) diff --git a/src/Moltbot.Tray.WinUI/Dialogs/WelcomeDialog.cs b/src/Moltbot.Tray.WinUI/Dialogs/WelcomeDialog.cs index 2d44ea7..00b97c9 100644 --- a/src/Moltbot.Tray.WinUI/Dialogs/WelcomeDialog.cs +++ b/src/Moltbot.Tray.WinUI/Dialogs/WelcomeDialog.cs @@ -1,32 +1,35 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System; -using System.Diagnostics; using System.Threading.Tasks; +using WinUIEx; namespace MoltbotTray.Dialogs; /// /// First-run welcome dialog for new users. /// -public sealed class WelcomeDialog +public sealed class WelcomeDialog : WindowEx { - private ContentDialog? _dialog; - private ContentDialogResult _result; + private readonly TaskCompletionSource _tcs = new(); + private ContentDialogResult _result = ContentDialogResult.None; - public async Task ShowAsync() + public WelcomeDialog() { - // Create a temporary window to host the dialog - var window = new Window(); - window.Content = new Grid(); - window.Activate(); - - // Build dialog content - var content = new StackPanel + Title = "Welcome to Moltbot"; + this.SetWindowSize(480, 440); + this.CenterOnScreen(); + this.SetIcon("Assets\\moltbot.ico"); + + // Build UI directly in the window (no ContentDialog needed) + var root = new Grid { - Spacing = 16, - MaxWidth = 400 + Padding = new Thickness(32), + RowSpacing = 16 }; + root.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); + root.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); + root.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); // Lobster header var headerPanel = new StackPanel @@ -46,16 +49,18 @@ public sealed class WelcomeDialog Style = (Style)Application.Current.Resources["TitleTextBlockStyle"], VerticalAlignment = VerticalAlignment.Center }); - content.Children.Add(headerPanel); + Grid.SetRow(headerPanel, 0); + root.Children.Add(headerPanel); - // Description + // Content + var content = new StackPanel { Spacing = 16 }; + content.Children.Add(new TextBlock { Text = "Moltbot Tray is your Windows companion for Moltbot, the AI-powered personal assistant.", TextWrapping = TextWrapping.Wrap }); - // Getting started var gettingStarted = new StackPanel { Spacing = 8 }; gettingStarted.Children.Add(new TextBlock { @@ -69,7 +74,6 @@ public sealed class WelcomeDialog gettingStarted.Children.Add(bulletList); content.Children.Add(gettingStarted); - // Documentation link var docsButton = new HyperlinkButton { Content = "📚 View Documentation", @@ -77,20 +81,48 @@ public sealed class WelcomeDialog }; content.Children.Add(docsButton); - // Create and show dialog - _dialog = new ContentDialog + Grid.SetRow(content, 1); + root.Children.Add(content); + + // Buttons + var buttonPanel = new StackPanel { - Title = "Welcome", - Content = content, - PrimaryButtonText = "Open Settings", - CloseButtonText = "Later", - DefaultButton = ContentDialogButton.Primary, - XamlRoot = window.Content.XamlRoot + Orientation = Orientation.Horizontal, + HorizontalAlignment = HorizontalAlignment.Right, + Spacing = 8 }; - _result = await _dialog.ShowAsync(); - window.Close(); + var laterButton = new Button { Content = "Later" }; + laterButton.Click += (s, e) => + { + _result = ContentDialogResult.None; + Close(); + }; + buttonPanel.Children.Add(laterButton); + + var settingsButton = new Button + { + Content = "Open Settings", + Style = (Style)Application.Current.Resources["AccentButtonStyle"] + }; + settingsButton.Click += (s, e) => + { + _result = ContentDialogResult.Primary; + Close(); + }; + buttonPanel.Children.Add(settingsButton); + + Grid.SetRow(buttonPanel, 2); + root.Children.Add(buttonPanel); + + Content = root; - return _result; + Closed += (s, e) => _tcs.TrySetResult(_result); + } + + public new Task ShowAsync() + { + Activate(); + return _tcs.Task; } } From a41df46033d3407fcc03893e4312be52efc45c56 Mon Sep 17 00:00:00 2001 From: Scott Hanselman Date: Thu, 29 Jan 2026 10:28:25 -0800 Subject: [PATCH 7/7] Fix SettingsWindow event handler leak --- src/Moltbot.Tray.WinUI/App.xaml.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Moltbot.Tray.WinUI/App.xaml.cs b/src/Moltbot.Tray.WinUI/App.xaml.cs index 8c26553..c56cf09 100644 --- a/src/Moltbot.Tray.WinUI/App.xaml.cs +++ b/src/Moltbot.Tray.WinUI/App.xaml.cs @@ -702,7 +702,11 @@ public partial class App : Application if (_settingsWindow == null || _settingsWindow.IsClosed) { _settingsWindow = new SettingsWindow(_settings!); - _settingsWindow.Closed += (s, e) => _settingsWindow = null; + _settingsWindow.Closed += (s, e) => + { + _settingsWindow.SettingsSaved -= OnSettingsSaved; + _settingsWindow = null; + }; _settingsWindow.SettingsSaved += OnSettingsSaved; } _settingsWindow.Activate();