diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/Helpers/DiagnosticsHelper.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/Helpers/DiagnosticsHelper.cs
new file mode 100644
index 0000000000..d2e9ddbcb3
--- /dev/null
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Helpers/DiagnosticsHelper.cs
@@ -0,0 +1,66 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.CmdPal.Common.Helpers;
+
+///
+/// Provides utility methods for building diagnostic and error messages.
+///
+public static class DiagnosticsHelper
+{
+ ///
+ /// Builds a comprehensive exception message with timestamp and detailed diagnostic information.
+ ///
+ /// The exception that occurred.
+ /// A hint about which extension caused the exception to help with debugging.
+ /// A string containing the exception details, timestamp, and source information for diagnostic purposes.
+ public static string BuildExceptionMessage(Exception exception, string? extensionHint)
+ {
+ var locationHint = string.IsNullOrWhiteSpace(extensionHint) ? "application" : $"'{extensionHint}' extension";
+
+ // let's try to get a message from the exception or inferred it from the HRESULT
+ // to show at least something
+ var message = exception.Message;
+ if (string.IsNullOrWhiteSpace(message))
+ {
+ var temp = Marshal.GetExceptionForHR(exception.HResult)?.Message;
+ if (!string.IsNullOrWhiteSpace(temp))
+ {
+ message = temp + $" (inferred from HRESULT 0x{exception.HResult:X8})";
+ }
+ }
+
+ if (string.IsNullOrWhiteSpace(message))
+ {
+ message = "[No message available]";
+ }
+
+ // note: keep date time kind and format consistent with the log
+ return $"""
+ ============================================================
+ 😢 An unexpected error occurred in the {locationHint}.
+
+ Summary:
+ Message: {message}
+ Type: {exception.GetType().FullName}
+ Source: {exception.Source ?? "N/A"}
+ Time: {DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fffffff}
+ HRESULT: 0x{exception.HResult:X8} ({exception.HResult})
+
+ Stack Trace:
+ {exception.StackTrace ?? "[No stack trace available]"}
+
+ ------------------ Full Exception Details ------------------
+ {exception}
+
+ ℹ️ If you need further assistance, please include this information in your support request.
+ ℹ️ Before sending, take a quick look to make sure it doesn't contain any personal or sensitive information.
+ ============================================================
+
+ """;
+ }
+}
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/PageViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/PageViewModel.cs
index 7a301c89b0..046c9fae93 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/PageViewModel.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/PageViewModel.cs
@@ -5,6 +5,7 @@
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
+using Microsoft.CmdPal.Common.Helpers;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
@@ -223,9 +224,10 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
extensionHint ??= ExtensionHost.GetExtensionDisplayName() ?? Title;
Task.Factory.StartNew(
() =>
- {
- ErrorMessage += $"A bug occurred in {$"the \"{extensionHint}\"" ?? "an unknown's"} extension's code:\n{ex.Message}\n{ex.Source}\n{ex.StackTrace}\n\n";
- },
+ {
+ var message = DiagnosticsHelper.BuildExceptionMessage(ex, extensionHint);
+ ErrorMessage += message;
+ },
CancellationToken.None,
TaskCreationOptions.None,
Scheduler);
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelCommandManager.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelCommandManager.cs
index 3bd2d8cedf..f55a322792 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelCommandManager.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelCommandManager.cs
@@ -410,8 +410,8 @@ public partial class TopLevelCommandManager : ObservableObject,
void IPageContext.ShowException(Exception ex, string? extensionHint)
{
- var errorMessage = $"A bug occurred in {$"the \"{extensionHint}\"" ?? "an unknown's"} extension's code:\n{ex.Message}\n{ex.Source}\n{ex.StackTrace}\n\n";
- CommandPaletteHost.Instance.Log(errorMessage);
+ var message = DiagnosticsHelper.BuildExceptionMessage(ex, extensionHint ?? "TopLevelCommandManager");
+ CommandPaletteHost.Instance.Log(message);
}
internal bool IsProviderActive(string id)