Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
be8c19e
[release/13.3] Stabilizing builds in preparation for 13.3 release (#1…
joperezr Apr 29, 2026
ab9c135
Remove MarkupString from SpanDetails and StructuredLogDetails resourc…
JamesNK Apr 30, 2026
6dcf538
[release/13.3] Ensure compute environment prepare waits for validatio…
aspire-repo-bot[bot] Apr 30, 2026
bb4d2cd
[release/13.3] Normalize App Service Application Insights Bicep ident…
aspire-repo-bot[bot] Apr 30, 2026
7a8d66e
[release/13.3] Fix TypeScript AppHost package manager detection (#16598)
aspire-repo-bot[bot] Apr 30, 2026
82bfeb0
[release/13.3] Fix Windows detached AppHost launcher (#16572)
aspire-repo-bot[bot] Apr 30, 2026
c108d40
[release/13.3] Validate build-only container references in the pipeli…
aspire-repo-bot[bot] Apr 30, 2026
81c6450
[release/13.3] Normalize CLI yes/no prompts (#16597)
aspire-repo-bot[bot] Apr 30, 2026
5b64970
[release/13.3] Publish native Aspire CLI tool packages (#16611)
aspire-repo-bot[bot] Apr 30, 2026
7458985
[release/13.3] Rename pipeline --log-level to --pipeline-log-level to…
JamesNK Apr 30, 2026
75c1090
[release/13.3] Fallback to junctions if either creating OR evaluating…
aspire-repo-bot[bot] May 1, 2026
37f41c0
[release/13.3] Fix TypeScript AppHost generated port ranges (#16649)
aspire-repo-bot[bot] May 1, 2026
529f2ca
[release/13.3] Fix unbounded collection growth in TelemetryRepository…
JamesNK May 1, 2026
cf62314
Move Ingress and Gateway extension methods to Aspire.Hosting namespac…
aspire-repo-bot[bot] May 1, 2026
6b4a7cc
Remove obsolete ATS export shims (#16628)
aspire-repo-bot[bot] May 1, 2026
835723b
[release/13.3] Add BrowserLogs tracked browser sessions (#16637)
aspire-repo-bot[bot] May 1, 2026
44c4e3c
[release/13.3] Gateway TLS without hostname (FQDN discovery) + TS App…
aspire-repo-bot[bot] May 1, 2026
34a86ad
[release/13.3] Fix Python starter TypeScript health check build (#16647)
aspire-repo-bot[bot] May 1, 2026
ee860bd
Fix sticky 'Finding apphosts' notification in VS Code extension (#16665)
aspire-repo-bot[bot] May 1, 2026
bd20f90
[release/13.3] API Review Feedback (#16674)
aspire-repo-bot[bot] May 4, 2026
5bd693a
[release/13.3] Normalize *.localhost dashboard URLs to localhost for …
JamesNK May 4, 2026
f6c2b2a
[release/13.3] Fix aspire init template install for non-stable CLI bu…
joperezr May 5, 2026
67d52e1
Make AtsJsonCodeWriter shared internal helper (#16752)
aspire-repo-bot[bot] May 5, 2026
12f278f
[release/13.3] Validate TypeScript AppHosts before startup (#16755)
aspire-repo-bot[bot] May 5, 2026
9527cff
Update dependencies from https://github.com/microsoft/dcp build 0.23.…
aspire-repo-bot[bot] May 5, 2026
88f2c1f
[release/13.3] Fix HostUrl with container tunnel (#16786)
aspire-repo-bot[bot] May 5, 2026
24721e7
[release/13.3] Avoid AppHost discovery when config path is valid (#16…
adamint May 5, 2026
0529858
[release/13.3] Reject Yarn Classic for TypeScript AppHosts (#16792)
aspire-repo-bot[bot] May 5, 2026
d91b80b
[release/13.3] Fix dashboard error in .NET 11 preview 4 (#16761)
JamesNK May 5, 2026
ca84f3e
Fix Aspire new empty AppHost language picker (#16666) (#16776)
sebastienros May 5, 2026
1fbdc5a
[release/13.3] Fix Python debug working directory in VS Code (#16575)…
aspire-repo-bot[bot] May 5, 2026
6d7482c
Fix notification action closure over scoped services (#16763)
JamesNK May 5, 2026
142627d
[release/13.3] Fix Foundry hosted agent endpoint resolution (#16809)
aspire-repo-bot[bot] May 6, 2026
32f6e7e
Require --yes with --non-interactive for destroy cmd (#16806)
aspire-repo-bot[bot] May 6, 2026
160e5ac
Consolidate Helm chart options on WithHelm(...) (#16759) (#16802)
mitchdenny May 6, 2026
cbbb043
Drop nuget.config alongside single-file apphost.cs in `aspire init` (…
mitchdenny May 6, 2026
9821098
[release/13.3] Honor configured channel in 'aspire update' (#16808)
aspire-repo-bot[bot] May 6, 2026
4fff8a1
[release/13.3] Use plain dotnet run for extension Run Without Debuggi…
aspire-repo-bot[bot] May 6, 2026
c8ddbaf
Backport CLI AppHost debug console output fixes (#16795) (#16816)
adamint May 6, 2026
4517e4a
Fix #15986: emit apphost.run.json from aspire init single-file skelet…
mitchdenny May 6, 2026
52f6f2f
Bump patch version from 13.3.0 to 13.3.1 (#16951)
Copilot May 11, 2026
ddc21b6
[create-pull-request] automated change (#16602)
aspire-repo-bot[bot] May 11, 2026
62a84fb
Update dependencies from https://github.com/microsoft/dcp build 0.23.…
aspire-repo-bot[bot] May 11, 2026
8d77243
[release/13.3] Skip compute env validation in run mode (#16940) (#16952)
aspire-repo-bot[bot] May 11, 2026
277b7e2
Backport of https://github.com/microsoft/aspire/pull/16988 into relea…
karolz-ms May 13, 2026
7d6cc5b
Bump patch version from 13.3.1 to 13.3.2 (#17053)
joperezr May 13, 2026
22af8f2
[release/13.3] Use ASPIRE_APPHOST_LOGLEVEL instead of cascading Loggi…
aspire-repo-bot[bot] May 14, 2026
88e5788
Fix Keycloak HTTPS primary endpoint (#17063)
aspire-repo-bot[bot] May 14, 2026
39bd13b
Bump patch version from 13.3.2 to 13.3.3 (#17088)
Copilot May 14, 2026
b8df57a
Update dependencies from https://github.com/microsoft/dcp build 0.23.…
danegsta May 14, 2026
a4615e7
Materialize Endpoints set in HostResourceWithEndpoints (#17092)
aspire-repo-bot[bot] May 14, 2026
202b001
[release/13.3] Shorten Aspire skill description (#17188)
davidfowl May 17, 2026
7508079
Bump patch version from 13.3.3 to 13.3.4 (#17215)
Copilot May 18, 2026
e03e260
Merge v13.3.4 into main (release back-merge)
joperezr May 20, 2026
8ef1359
Apply #16763 dashboard notification scoped-services fix on top of main
joperezr May 20, 2026
54edc3b
Reconcile naming for forward-bound release-only renames after merge
joperezr May 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Aspire.Cli/Commands/DeployCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected override Task<string[]> GetRunArgumentsAsync(string? fullyQualifiedOut
}

// Add --log-level and --envionment flags if specified
var logLevel = parseResult.GetValue(s_logLevelOption);
var logLevel = parseResult.GetValue(s_pipelineLogLevelOption);

if (!string.IsNullOrEmpty(logLevel))
{
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Cli/Commands/DestroyCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected override Task<string[]> GetRunArgumentsAsync(string? fullyQualifiedOut
baseArgs.AddRange(["--yes", "true"]);
}

var logLevel = parseResult.GetValue(s_logLevelOption);
var logLevel = parseResult.GetValue(s_pipelineLogLevelOption);
if (!string.IsNullOrEmpty(logLevel))
{
baseArgs.AddRange(["--log-level", logLevel!]);
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Cli/Commands/DoCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ protected override async Task<string[]> GetRunArgumentsAsync(string? fullyQualif
}

// Add --log-level and --environment flags if specified
var logLevel = parseResult.GetValue(s_logLevelOption);
var logLevel = parseResult.GetValue(s_pipelineLogLevelOption);
if (!string.IsNullOrEmpty(logLevel))
{
baseArgs.AddRange(["--log-level", logLevel!]);
Expand Down
6 changes: 3 additions & 3 deletions src/Aspire.Cli/Commands/PipelineCommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal abstract class PipelineCommandBase : BaseCommand

private readonly Option<string?> _outputPathOption;

protected static readonly Option<string?> s_logLevelOption = new("--log-level")
protected static readonly Option<string?> s_pipelineLogLevelOption = new("--pipeline-log-level")
{
Description = SharedCommandStrings.PipelineLogLevelOptionDescription
};
Expand Down Expand Up @@ -97,7 +97,7 @@ protected PipelineCommandBase(string name, string description, IDotNetCliRunner

Options.Add(s_appHostOption);
Options.Add(_outputPathOption);
Options.Add(s_logLevelOption);
Options.Add(s_pipelineLogLevelOption);
Options.Add(s_environmentOption);
Options.Add(s_includeExceptionDetailsOption);
Options.Add(s_noBuildOption);
Expand Down Expand Up @@ -281,7 +281,7 @@ protected override async Task<CommandResult> ExecuteAsync(ParseResult parseResul
var publishingActivities = backchannel.GetPublishingActivitiesAsync(cancellationToken);

// Check if debug or trace logging is enabled
var logLevel = parseResult.GetValue(s_logLevelOption);
var logLevel = parseResult.GetValue(s_pipelineLogLevelOption);
var isDebugOrTraceLoggingEnabled = logLevel?.Equals("debug", StringComparison.OrdinalIgnoreCase) == true ||
logLevel?.Equals("trace", StringComparison.OrdinalIgnoreCase) == true;

Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Cli/Commands/PublishCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected override Task<string[]> GetRunArgumentsAsync(string? fullyQualifiedOut
}

// Add --log-level and --envionment flags if specified
var logLevel = parseResult.GetValue(s_logLevelOption);
var logLevel = parseResult.GetValue(s_pipelineLogLevelOption);

if (!string.IsNullOrEmpty(logLevel))
{
Expand Down
16 changes: 10 additions & 6 deletions src/Aspire.Cli/Commands/TelemetryCommandHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ public static async Task<DashboardApiResult> GetDashboardApiAsync(
var loginToken = McpToolHelpers.ExtractLoginToken(dashboardUrl);

// Normalize login URLs (e.g., http://localhost:18888/login?t=abc) to base URL
dashboardUrl = McpToolHelpers.StripLoginPath(dashboardUrl) ?? dashboardUrl;
var displayDashboardUrl = McpToolHelpers.StripLoginPath(dashboardUrl) ?? dashboardUrl;
dashboardUrl = McpToolHelpers.NormalizeDashboardUrl(displayDashboardUrl);

if (!UrlHelper.IsHttpUrl(dashboardUrl))
{
Expand All @@ -235,10 +236,10 @@ public static async Task<DashboardApiResult> GetDashboardApiAsync(
var errorInfo = exchangeResult.FailureKind switch
{
TokenExchangeFailureKind.ConnectionError => new TelemetryErrorInfo(
string.Format(CultureInfo.CurrentCulture, TelemetryCommandStrings.DashboardConnectionFailed, dashboardUrl),
string.Format(CultureInfo.CurrentCulture, TelemetryCommandStrings.DashboardConnectionFailed, displayDashboardUrl),
TelemetryCommandStrings.DashboardConnectionFailedHint),
TokenExchangeFailureKind.ApiNotEnabled => new TelemetryErrorInfo(
string.Format(CultureInfo.CurrentCulture, TelemetryCommandStrings.DashboardApiNotEnabled, dashboardUrl),
string.Format(CultureInfo.CurrentCulture, TelemetryCommandStrings.DashboardApiNotEnabled, displayDashboardUrl),
TelemetryCommandStrings.DashboardApiNotEnabledHint),
_ => new TelemetryErrorInfo(
TelemetryCommandStrings.DashboardLoginTokenFailed,
Expand All @@ -253,7 +254,7 @@ public static async Task<DashboardApiResult> GetDashboardApiAsync(
}

var token = apiKey ?? string.Empty;
return new DashboardApiResult(true, null, dashboardUrl, token, dashboardUrl, 0);
return new DashboardApiResult(true, null, dashboardUrl, token, displayDashboardUrl, 0);
}

var result = await connectionResolver.ResolveConnectionAsync(
Expand Down Expand Up @@ -287,10 +288,13 @@ public static async Task<DashboardApiResult> GetDashboardApiAsync(
return new DashboardApiResult(true, connection, null, null, null, 0);
}

// Extract dashboard base URL (without /login path) for hyperlinks
var apiBaseUrl = McpToolHelpers.NormalizeDashboardUrl(dashboardInfo.ApiBaseUrl);

// Extract dashboard base URL (without /login path) for hyperlinks.
// Preserve the original hostname (e.g. *.dev.localhost) for display URLs.
var extractedDashboardUrl = ExtractDashboardBaseUrl(dashboardInfo.DashboardUrls?.FirstOrDefault());

return new DashboardApiResult(true, connection, dashboardInfo.ApiBaseUrl, dashboardInfo.ApiToken, extractedDashboardUrl, 0);
return new DashboardApiResult(true, connection, apiBaseUrl, dashboardInfo.ApiToken, extractedDashboardUrl, 0);
}

/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion src/Aspire.Cli/Mcp/Tools/IDashboardInfoProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ internal sealed class StaticDashboardInfoProvider(string dashboardUrl, string? a
{
// For unsecured dashboards, apiToken is empty string (no X-API-Key header will be sent)
var apiToken = apiKey ?? string.Empty;
return Task.FromResult((apiToken, dashboardUrl, (string?)dashboardUrl));
// Normalize the API base URL (e.g., rewrite *.localhost to localhost) for HTTP requests,
// but preserve the original URL as the dashboard display URL.
var apiBaseUrl = McpToolHelpers.NormalizeDashboardUrl(dashboardUrl);
return Task.FromResult((apiToken, apiBaseUrl, (string?)dashboardUrl));
}
}
29 changes: 28 additions & 1 deletion src/Aspire.Cli/Mcp/Tools/McpToolHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Globalization;
using System.Web;
using Aspire.Cli.Backchannel;
using Microsoft.Extensions.Logging;
Expand All @@ -26,9 +27,10 @@ internal static class McpToolHelpers
throw new McpProtocolException(McpErrorMessages.DashboardNotAvailable, McpErrorCode.InternalError);
}

var apiBaseUrl = NormalizeDashboardUrl(dashboardInfo.ApiBaseUrl);
var dashboardBaseUrl = StripLoginPath(dashboardInfo.DashboardUrls.FirstOrDefault());

return (dashboardInfo.ApiToken, dashboardInfo.ApiBaseUrl, dashboardBaseUrl);
return (dashboardInfo.ApiToken, apiBaseUrl, dashboardBaseUrl);
}

/// <summary>
Expand Down Expand Up @@ -59,6 +61,31 @@ internal static class McpToolHelpers
return url;
}

/// <summary>
/// Replaces AppHost-scoped <c>*.localhost</c> dashboard hostnames with <c>localhost</c>.
/// </summary>
/// <remarks>
/// DNS resolvers typically don't implement RFC 6761 for localhost subdomains, so hosts
/// like <c>dashboard.dev.localhost</c> fail to resolve when making HTTP requests.
/// Rewriting to <c>localhost</c> ensures the CLI can reach the dashboard API.
/// </remarks>
internal static string NormalizeDashboardUrl(string url)
{
if (Uri.TryCreate(url, UriKind.Absolute, out var uri) && IsLocalhostTld(uri.Host))
{
var port = uri.IsDefaultPort ? string.Empty : ":" + uri.Port.ToString(CultureInfo.InvariantCulture);
var pathAndQuery = uri.PathAndQuery == "/" ? string.Empty : uri.PathAndQuery;
return $"{uri.Scheme}://localhost{port}{pathAndQuery}{uri.Fragment}";
}

return url;
}

private static bool IsLocalhostTld(string host)
{
return host.EndsWith(".localhost", StringComparison.OrdinalIgnoreCase);
}

/// <summary>
/// Extracts the browser token (<c>t</c> query parameter) from a dashboard login URL.
/// Returns <c>null</c> if the URL does not contain a login token.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
<value>Total time: {0}</value>
</data>
<data name="SummaryLogLevelHelp" xml:space="preserve">
<value>For more details, add --log-level debug/trace to the command.</value>
<value>For more details, add --pipeline-log-level debug/trace to the command.</value>
</data>
<data name="PipelineSucceeded" xml:space="preserve">
<value>Pipeline succeeded</value>
Expand Down
9 changes: 9 additions & 0 deletions src/Aspire.Cli/Resources/DestroyCommandStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Aspire.Cli/Resources/DestroyCommandStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@
<data name="Description" xml:space="preserve">
<value>Destroy a previously deployed AppHost environment</value>
</data>
<data name="NonInteractiveRequiresYes" xml:space="preserve">
<value>The destroy command requires --yes when the --non-interactive option is specified.</value>
</data>
<data name="OutputPathArgumentDescription" xml:space="preserve">
<value>The output path containing the deployment artifacts to destroy</value>
</data>
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DestroyCommandStrings.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DestroyCommandStrings.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Aspire.Cli/Resources/xlf/DestroyCommandStrings.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading