diff --git a/src/Aspire.Cli/Commands/DashboardCommand.cs b/src/Aspire.Cli/Commands/DashboardCommand.cs
new file mode 100644
index 00000000000..93494971696
--- /dev/null
+++ b/src/Aspire.Cli/Commands/DashboardCommand.cs
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.CommandLine;
+using System.Globalization;
+using Aspire.Cli.Configuration;
+using Aspire.Cli.Interaction;
+using Aspire.Cli.Layout;
+using Aspire.Cli.Processes;
+using Aspire.Cli.Resources;
+using Aspire.Cli.Telemetry;
+using Aspire.Cli.Utils;
+using Microsoft.Extensions.Logging;
+
+namespace Aspire.Cli.Commands;
+
+///
+/// Command that starts a standalone Aspire Dashboard instance.
+///
+internal sealed class DashboardCommand : BaseCommand
+{
+ internal override HelpGroup HelpGroup => HelpGroup.Monitoring;
+
+ private readonly IInteractionService _interactionService;
+ private readonly ILayoutDiscovery _layoutDiscovery;
+ private readonly ILogger _logger;
+
+ private static readonly Option s_detachOption = new("--detach")
+ {
+ Description = DashboardCommandStrings.DetachOptionDescription
+ };
+
+ public DashboardCommand(
+ IInteractionService interactionService,
+ ILayoutDiscovery layoutDiscovery,
+ IFeatures features,
+ ICliUpdateNotifier updateNotifier,
+ CliExecutionContext executionContext,
+ ILogger logger,
+ AspireCliTelemetry telemetry)
+ : base("dashboard", DashboardCommandStrings.Description, features, updateNotifier, executionContext, interactionService, telemetry)
+ {
+ _interactionService = interactionService;
+ _layoutDiscovery = layoutDiscovery;
+ _logger = logger;
+
+ Options.Add(s_detachOption);
+ TreatUnmatchedTokensAsErrors = false;
+ }
+
+ protected override async Task ExecuteAsync(ParseResult parseResult, CancellationToken cancellationToken)
+ {
+ var layout = _layoutDiscovery.DiscoverLayout();
+ if (layout is null)
+ {
+ _interactionService.DisplayError(DashboardCommandStrings.BundleNotAvailable);
+ return ExitCodeConstants.DashboardFailure;
+ }
+
+ var managedPath = layout.GetManagedPath();
+ if (managedPath is null || !File.Exists(managedPath))
+ {
+ _interactionService.DisplayError(DashboardCommandStrings.BundleNotAvailable);
+ return ExitCodeConstants.DashboardFailure;
+ }
+
+ var dashboardArgs = new List { "dashboard" };
+ dashboardArgs.AddRange(parseResult.UnmatchedTokens);
+
+ var detach = parseResult.GetValue(s_detachOption);
+
+ if (detach)
+ {
+ return ExecuteDetached(managedPath, dashboardArgs);
+ }
+
+ return await ExecuteForegroundAsync(managedPath, dashboardArgs, cancellationToken).ConfigureAwait(false);
+ }
+
+ private int ExecuteDetached(string managedPath, List dashboardArgs)
+ {
+ _logger.LogDebug("Starting dashboard in detached mode: {ManagedPath}", managedPath);
+
+ var process = DetachedProcessLauncher.Start(managedPath, dashboardArgs, Directory.GetCurrentDirectory());
+
+ _interactionService.DisplayMessage(KnownEmojis.Rocket,
+ string.Format(CultureInfo.CurrentCulture, DashboardCommandStrings.DashboardStarted, process.Id));
+
+ return ExitCodeConstants.Success;
+ }
+
+ private async Task ExecuteForegroundAsync(string managedPath, List dashboardArgs, CancellationToken cancellationToken)
+ {
+ _logger.LogDebug("Starting dashboard in foreground: {ManagedPath}", managedPath);
+
+ using var process = LayoutProcessRunner.Start(managedPath, dashboardArgs, redirectOutput: false);
+
+ try
+ {
+ await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+ if (!process.HasExited)
+ {
+ process.Kill(entireProcessTree: true);
+ }
+
+ return ExitCodeConstants.Success;
+ }
+
+ if (process.ExitCode != 0)
+ {
+ _interactionService.DisplayError(
+ string.Format(CultureInfo.CurrentCulture, DashboardCommandStrings.DashboardExitedWithError, process.ExitCode));
+ }
+
+ return process.ExitCode == 0 ? ExitCodeConstants.Success : ExitCodeConstants.DashboardFailure;
+ }
+}
diff --git a/src/Aspire.Cli/Commands/RootCommand.cs b/src/Aspire.Cli/Commands/RootCommand.cs
index 38b24cf00df..7a0c06743f8 100644
--- a/src/Aspire.Cli/Commands/RootCommand.cs
+++ b/src/Aspire.Cli/Commands/RootCommand.cs
@@ -131,6 +131,7 @@ public RootCommand(
AgentCommand agentCommand,
TelemetryCommand telemetryCommand,
ExportCommand exportCommand,
+ DashboardCommand dashboardCommand,
DocsCommand docsCommand,
SecretCommand secretCommand,
SdkCommand sdkCommand,
@@ -222,6 +223,7 @@ public RootCommand(
Subcommands.Add(telemetryCommand);
Subcommands.Add(exportCommand);
Subcommands.Add(docsCommand);
+ Subcommands.Add(dashboardCommand);
Subcommands.Add(secretCommand);
#if DEBUG
diff --git a/src/Aspire.Cli/Program.cs b/src/Aspire.Cli/Program.cs
index 55881912e73..e16c047691e 100644
--- a/src/Aspire.Cli/Program.cs
+++ b/src/Aspire.Cli/Program.cs
@@ -454,6 +454,7 @@ internal static async Task BuildApplicationAsync(string[] args, CliStartu
builder.Services.AddTransient();
builder.Services.AddTransient();
builder.Services.AddTransient();
+ builder.Services.AddTransient();
builder.Services.AddTransient();
builder.Services.AddTransient();
builder.Services.AddTransient();
diff --git a/src/Aspire.Cli/Resources/DashboardCommandStrings.Designer.cs b/src/Aspire.Cli/Resources/DashboardCommandStrings.Designer.cs
new file mode 100644
index 00000000000..a3003f980fa
--- /dev/null
+++ b/src/Aspire.Cli/Resources/DashboardCommandStrings.Designer.cs
@@ -0,0 +1,79 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Aspire.Cli.Resources {
+ using System;
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ public class DashboardCommandStrings {
+
+ private static System.Resources.ResourceManager resourceMan;
+
+ private static System.Globalization.CultureInfo resourceCulture;
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal DashboardCommandStrings() {
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.Equals(null, resourceMan)) {
+ System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Cli.Resources.DashboardCommandStrings", typeof(DashboardCommandStrings).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ public static string Description {
+ get {
+ return ResourceManager.GetString("Description", resourceCulture);
+ }
+ }
+
+ public static string DetachOptionDescription {
+ get {
+ return ResourceManager.GetString("DetachOptionDescription", resourceCulture);
+ }
+ }
+
+ public static string BundleNotAvailable {
+ get {
+ return ResourceManager.GetString("BundleNotAvailable", resourceCulture);
+ }
+ }
+
+ public static string DashboardStarted {
+ get {
+ return ResourceManager.GetString("DashboardStarted", resourceCulture);
+ }
+ }
+
+ public static string DashboardExitedWithError {
+ get {
+ return ResourceManager.GetString("DashboardExitedWithError", resourceCulture);
+ }
+ }
+
+ }
+}
diff --git a/src/Aspire.Cli/Resources/DashboardCommandStrings.resx b/src/Aspire.Cli/Resources/DashboardCommandStrings.resx
new file mode 100644
index 00000000000..8d8d4a4cbb4
--- /dev/null
+++ b/src/Aspire.Cli/Resources/DashboardCommandStrings.resx
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Start the Aspire dashboard
+
+
+ Run the dashboard in the background
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+ Dashboard started (PID {0}).
+
+
+ Dashboard exited with exit code {0}.
+
+
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.cs.xlf
new file mode 100644
index 00000000000..60d19618023
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.cs.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.de.xlf
new file mode 100644
index 00000000000..59d268e4782
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.de.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.es.xlf
new file mode 100644
index 00000000000..486feaf2354
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.es.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.fr.xlf
new file mode 100644
index 00000000000..4cd7f16a4b6
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.fr.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.it.xlf
new file mode 100644
index 00000000000..feae1bd9393
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.it.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.ja.xlf
new file mode 100644
index 00000000000..be2d45829bb
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.ja.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.ko.xlf
new file mode 100644
index 00000000000..bb58ec56ae9
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.ko.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.pl.xlf
new file mode 100644
index 00000000000..fbeaac64a66
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.pl.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.pt-BR.xlf
new file mode 100644
index 00000000000..9c3b7353465
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.pt-BR.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.ru.xlf
new file mode 100644
index 00000000000..df0ef1b1bca
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.ru.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.tr.xlf
new file mode 100644
index 00000000000..dcab25db754
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.tr.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.zh-Hans.xlf
new file mode 100644
index 00000000000..c67b5c84195
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.zh-Hans.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.zh-Hant.xlf
new file mode 100644
index 00000000000..ad377eb8214
--- /dev/null
+++ b/src/Aspire.Cli/Resources/xlf/DashboardCommandStrings.zh-Hant.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+ The Aspire dashboard requires the CLI bundle. The bundle was not found.
+
+
+
+ Dashboard exited with exit code {0}.
+ Dashboard exited with exit code {0}.
+
+
+
+ Dashboard started (PID {0}).
+ Dashboard started (PID {0}).
+
+
+
+ Start the Aspire dashboard
+ Start the Aspire dashboard
+
+
+
+ Run the dashboard in the background
+ Run the dashboard in the background
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Aspire.Cli.Tests/Commands/DashboardCommandTests.cs b/tests/Aspire.Cli.Tests/Commands/DashboardCommandTests.cs
new file mode 100644
index 00000000000..fa817945071
--- /dev/null
+++ b/tests/Aspire.Cli.Tests/Commands/DashboardCommandTests.cs
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Aspire.Cli.Commands;
+using Aspire.Cli.Resources;
+using Aspire.Cli.Tests.TestServices;
+using Aspire.Cli.Tests.Utils;
+using Microsoft.AspNetCore.InternalTesting;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Aspire.Cli.Tests.Commands;
+
+public class DashboardCommandTests(ITestOutputHelper outputHelper)
+{
+ [Fact]
+ public async Task DashboardCommand_BundleNotAvailable_DisplaysError()
+ {
+ using var workspace = TemporaryWorkspace.Create(outputHelper);
+
+ var testInteractionService = new TestInteractionService();
+
+ var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper, options =>
+ {
+ options.InteractionServiceFactory = _ => testInteractionService;
+ });
+
+ var provider = services.BuildServiceProvider();
+ var command = provider.GetRequiredService();
+ var result = command.Parse("dashboard");
+
+ var exitCode = await result.InvokeAsync().DefaultTimeout();
+
+ Assert.Equal(ExitCodeConstants.DashboardFailure, exitCode);
+ var errorMessage = Assert.Single(testInteractionService.DisplayedErrors);
+ Assert.Equal(DashboardCommandStrings.BundleNotAvailable, errorMessage);
+ }
+
+ [Fact]
+ public async Task DashboardCommand_Help_ReturnsSuccess()
+ {
+ using var workspace = TemporaryWorkspace.Create(outputHelper);
+ var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper);
+ var provider = services.BuildServiceProvider();
+
+ var command = provider.GetRequiredService();
+ var result = command.Parse("dashboard --help");
+
+ var exitCode = await result.InvokeAsync().DefaultTimeout();
+
+ Assert.Equal(ExitCodeConstants.Success, exitCode);
+ }
+}
diff --git a/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs b/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs
index e89b6fdca5c..028e1feeff7 100644
--- a/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs
+++ b/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs
@@ -190,6 +190,7 @@ public static IServiceCollection CreateServiceCollection(TemporaryWorkspace work
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient();