Skip to content

Improve AppHost debug console output for TS and C##16795

Merged
adamint merged 8 commits into
microsoft:mainfrom
adamint:dev/adamint/extension-debug-console-output
May 6, 2026
Merged

Improve AppHost debug console output for TS and C##16795
adamint merged 8 commits into
microsoft:mainfrom
adamint:dev/adamint/extension-debug-console-output

Conversation

@adamint
Copy link
Copy Markdown
Member

@adamint adamint commented May 5, 2026

Description

Several related fixes for VS Code extension AppHost debug-console output and startup failure handling.

1. Filter debugger noise from the parent debug console

When a C# AppHost runs as a child debug session, the .NET debugger writes module-load messages, exception-thrown notifications, banner text, launch-profile messages, and other console/debug DAP output into the Aspire parent debug console.

This PR filters that noise while keeping real runtime output. Low-level AppHost logs (trce/dbug, Trace/Debug) are dropped, while severe output (fail/crit, Error/Critical, uncaught exceptions, fatal lines, and continuations) is preserved and shown on stderr.

image

2. Surface guest AppHost failures before launch

TypeScript/Node AppHosts can fail in a pre-launch step, such as tsc --noEmit, before the AppHost and backchannel are started. Previously the extension could stay stuck at Connecting to AppHost... without showing the compilation error.

Now the CLI checks that failure path before waiting for the extension launcher, displays the captured guest output, and completes the backchannel wait with an error so the run exits cleanly.

image

3. Clean up AppHost debug-console output

CLI stdout/stderr from the extension host is now buffered by line and decoded as UTF-8, so output is not split mid-line or mid-emoji. Captured DisplayLines output is sent through the extension backchannel without also being written to captured stdout/stderr, which avoids duplicate lines and keeps failure details ordered before follow-up error/log messages.

Stderr is no longer blindly prefixed as an error by the extension; CLI/Spectre already adds the appropriate error prefix when output is actually an error.

image

4. Fix smaller extension-host UX issues

This also stops aspire describe --follow from restarting forever when it exits before producing data, anchors CodeLens state/actions above single-resource fluent chains, and renders the AppHost/log summary without terminal-style indentation or blank separator rows in extension-host mode.

Verified with:

  • ./dotnet.sh build src/Aspire.Cli/Aspire.Cli.csproj /p:SkipNativeBuild=true
  • npm run compile-tests
  • npm run unit-test | grep -A3 "AspireCodeLensProvider resource lens anchoring"

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
    • No

When a project AppHost is launched as a child debug session of the Aspire parent session, the .NET debugger emits chatty 'console' category output (module load lines, exception-thrown notifications, debugger banner, launch profile messages) into the parent session's debug console. The same is true for trace/debug-level structured log lines forwarded from the AppHost. This noise drowns out the Aspire-relevant output users actually care about.

Add AppHostParentOutputFilter that:

- Drops 'debug' DAP category output entirely.

- For 'console' category, drops everything except severe runtime output (uncaught exceptions, fatal/critical/error lines, indented continuations of those).

- For 'stdout'/'stderr' from the AppHost: drops trce/dbug/Trace/Debug structured log entries (and their indented continuations); promotes fail/crit/Error/Critical entries (and continuations) to 'stderr' so they show up colored.

Wire it through AspireDebugSession.sendAppHostMessage and broaden the AppHostOutputHandler signature in adapterTracker so the raw DAP category reaches the filter. Tests cover the noise/keep cases including localized debugger banner text and Node.js exception shapes.
Copilot AI review requested due to automatic review settings May 5, 2026 19:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces noise in the VS Code Aspire parent debug console when an AppHost is launched as a child debug session by filtering debug-adapter “output” events and suppressing low-signal debugger chatter while preserving/promoting severe runtime output.

Changes:

  • Added AppHostParentOutputFilter to drop debug output, aggressively filter console output, and suppress/promote AppHost stdout/stderr log lines based on severity (including indented continuations).
  • Updated AppHost output tracking so the raw DAP category value reaches the filter (instead of being coerced to only stdout/stderr).
  • Added unit tests covering noise vs. keep cases (including localized debugger banner lines and Node.js exception shapes).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
extension/src/test/dotnetDebugger.test.ts Adds unit tests validating AppHost output filtering behavior (drop noise, keep/promote fatal output, keep normal output).
extension/src/debugger/AspireDebugSession.ts Introduces and uses AppHostParentOutputFilter to filter/mirror AppHost debug-session output into the parent debug console.
extension/src/debugger/adapterTracker.ts Broadens AppHost output callback to pass through the raw DAP category for filtering.

Comment thread extension/src/debugger/adapterTracker.ts
Comment thread extension/src/debugger/adapterTracker.ts
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16795

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 16795"

… DAP category typing

- Narrow isSevereRuntimeOutputLine to anchored fatal markers; bare \bword\b matches were promoting benign user stdout (e.g. 'Failed payment retry queued', file paths containing 'error') to stderr.
- Narrow simple log-format regex to require dotted .NET-style category names so user prints like 'Status: Error: connection refused' aren't misclassified as Microsoft.Extensions.Logging output.
- Reset continuation state when DAP category changes between events so dropped/error block context doesn't leak across streams.
- Scope output filtering to C# AppHosts (.cs / .csproj) as a positive opt-in. Node and any future languages (Python/Go/etc.) pass through unmodified.
- Fix DapOutputCategory to include undefined (per DAP spec, output event 'category' is optional) and remove unsafe 'as string' cast in adapterTracker.
- Add regression tests for the false-positive cases above and for category-change continuation reset.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

@adamint adamint changed the title Filter AppHost debugger noise from Aspire parent debug console Improve AppHost debug console output in the Aspire extension May 5, 2026
@adamint adamint changed the title Improve AppHost debug console output in the Aspire extension Improve AppHost debug console output for TS and C# May 5, 2026
Copy link
Copy Markdown
Member

@danegsta danegsta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posted 1 code review comment.

private _continuingErrorBlock = false;
private _lastCategory: string | undefined;

filter(output: string, category: string | undefined): AppHostParentOutput | undefined {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DAP category is optional, and adapterTracker.ts documents that a missing category should be treated as console, but this filter currently leaves undefined unchanged. That lets category-less C# AppHost debug-adapter output bypass the category === 'console' && !isSevereOutput suppression path and get mirrored as stdout, so debugger noise can reappear. Normalize once at the boundary (for example, const normalizedCategory = category ?? 'console') and use that for state tracking and line classification.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 382009c. I now normalize category ?? 'console' once at the top of AppHostParentOutputFilter.filter and propagate that normalized value through _lastCategory, the hasErrorOutput seed, and getLineCategory / shouldMirrorConsoleOutput / getCurrentCategory (whose parameter type is now string since they only see normalized values). Added a regression test in dotnetDebugger.test.ts covering both undefined-category debugger noise (suppressed) and undefined-category severe runtime output (kept and promoted to stderr) so the console-suppression path can no longer be bypassed.

…ilter

The DAP spec marks the OutputEvent 'category' field as optional and
states that a missing category should be treated as 'console'. The
filter previously left undefined unchanged, so category-less debug
adapter chatter from the C# AppHost bypassed the
debug console as stdout — re-introducing the noise this filter is
meant to suppress.

Normalize once at the boundary of AppHostParentOutputFilter.filter and
propagate the normalized value through state tracking and per-line
classification. Tighten the internal helpers' parameter type from
'string | undefined' to 'string' now that they only receive normalized
values. Add a regression test covering missing-category debugger noise
and missing-category severe runtime output.

Addresses review feedback from @danegsta on PR microsoft#16795.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@adamint adamint requested a review from danegsta May 5, 2026 23:05
@adamint adamint enabled auto-merge (squash) May 6, 2026 03:24
@adamint
Copy link
Copy Markdown
Member Author

adamint commented May 6, 2026

/backport to release/13.3

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

Started backporting to release/13.3 (link to workflow run)

@aspire-repo-bot
Copy link
Copy Markdown
Contributor

@adamint backporting to release/13.3 failed, the patch most likely resulted in conflicts. Please backport manually!

git am output
$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Applying: Filter AppHost debugger noise from Aspire parent debug console
Using index info to reconstruct a base tree...
M	extension/src/debugger/AspireDebugSession.ts
M	extension/src/debugger/adapterTracker.ts
M	extension/src/test/dotnetDebugger.test.ts
Falling back to patching base and 3-way merge...
Auto-merging extension/src/debugger/AspireDebugSession.ts
CONFLICT (content): Merge conflict in extension/src/debugger/AspireDebugSession.ts
Auto-merging extension/src/debugger/adapterTracker.ts
CONFLICT (content): Merge conflict in extension/src/debugger/adapterTracker.ts
Auto-merging extension/src/test/dotnetDebugger.test.ts
CONFLICT (content): Merge conflict in extension/src/test/dotnetDebugger.test.ts
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0001 Filter AppHost debugger noise from Aspire parent debug console
Error: The process '/usr/bin/git' failed with exit code 128

Link to workflow output

@adamint adamint merged commit b708068 into microsoft:main May 6, 2026
836 of 855 checks passed
@github-actions github-actions Bot added this to the 13.4 milestone May 6, 2026
adamint added a commit to adamint/aspire that referenced this pull request May 6, 2026
Backports the CLI portions of microsoft#16795 to release/13.3.

Includes AppHost summary formatting for extension-host output, serialized extension interaction output, and guest AppHost pre-launch failure surfacing.
joperezr pushed a commit that referenced this pull request May 6, 2026
Backports the CLI portions of #16795 to release/13.3.

Includes AppHost summary formatting for extension-host output, serialized extension interaction output, and guest AppHost pre-launch failure surfacing.
nellshamrell pushed a commit to nellshamrell/aspire that referenced this pull request May 18, 2026
* Filter AppHost debugger noise from Aspire parent debug console

When a project AppHost is launched as a child debug session of the Aspire parent session, the .NET debugger emits chatty 'console' category output (module load lines, exception-thrown notifications, debugger banner, launch profile messages) into the parent session's debug console. The same is true for trace/debug-level structured log lines forwarded from the AppHost. This noise drowns out the Aspire-relevant output users actually care about.

Add AppHostParentOutputFilter that:

- Drops 'debug' DAP category output entirely.

- For 'console' category, drops everything except severe runtime output (uncaught exceptions, fatal/critical/error lines, indented continuations of those).

- For 'stdout'/'stderr' from the AppHost: drops trce/dbug/Trace/Debug structured log entries (and their indented continuations); promotes fail/crit/Error/Critical entries (and continuations) to 'stderr' so they show up colored.

Wire it through AspireDebugSession.sendAppHostMessage and broaden the AppHostOutputHandler signature in adapterTracker so the raw DAP category reaches the filter. Tests cover the noise/keep cases including localized debugger banner text and Node.js exception shapes.

* Address review feedback: narrow filter regexes, scope to C# only, fix DAP category typing

- Narrow isSevereRuntimeOutputLine to anchored fatal markers; bare \bword\b matches were promoting benign user stdout (e.g. 'Failed payment retry queued', file paths containing 'error') to stderr.
- Narrow simple log-format regex to require dotted .NET-style category names so user prints like 'Status: Error: connection refused' aren't misclassified as Microsoft.Extensions.Logging output.
- Reset continuation state when DAP category changes between events so dropped/error block context doesn't leak across streams.
- Scope output filtering to C# AppHosts (.cs / .csproj) as a positive opt-in. Node and any future languages (Python/Go/etc.) pass through unmodified.
- Fix DapOutputCategory to include undefined (per DAP spec, output event 'category' is optional) and remove unsafe 'as string' cast in adapterTracker.
- Add regression tests for the false-positive cases above and for category-change continuation reset.

* Improve extension AppHost output handling and CodeLens anchors

* Surface guest AppHost failures in extension flow

* Render AppHost summary flush in extension host

* Tighten AppHost output error detection

* Normalize undefined DAP category to 'console' in AppHostParentOutputFilter

The DAP spec marks the OutputEvent 'category' field as optional and
states that a missing category should be treated as 'console'. The
filter previously left undefined unchanged, so category-less debug
adapter chatter from the C# AppHost bypassed the
debug console as stdout — re-introducing the noise this filter is
meant to suppress.

Normalize once at the boundary of AppHostParentOutputFilter.filter and
propagate the normalized value through state tracking and per-line
classification. Tighten the internal helpers' parameter type from
'string | undefined' to 'string' now that they only receive normalized
values. Add a regression test covering missing-category debugger noise
and missing-category severe runtime output.

Addresses review feedback from @danegsta on PR microsoft#16795.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
joperezr added a commit that referenced this pull request May 21, 2026
* [release/13.3] Stabilizing builds in preparation for 13.3 release (#16566)

* [release/13.3] Stabilizing builds in preparation for 13.3 release

- Flip StabilizePackageVersion default to true in eng/Versions.props
- Drop the compute_version_suffix step from ci.yml so PR builds use the stabilized version
- Pin Aspire.AppHost.Sdk import to 13.3.0 in RepoTesting.targets
- Pin all stabilizable Aspire packages to 13.3.0 in Directory.Packages.Helix.props
  (packages whose csproj sets SuppressFinalPackageVersion=true keep $(PackageVersion))
- Skip preview-only AppHosts (Kusto, Foundry, Keycloak, Kubernetes, Maui) in the
  TypeScript polyglot validation script (see #15335)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Skip tests blocked by suppressed-package stabilization gap

Two test buckets cannot run on a stabilized branch because they exercise NuGet
restore against Aspire.Hosting.* packages that have SuppressFinalPackageVersion=true
and therefore only ship as prerelease (e.g. 13.3.0-dev.<sha>) — but the stabilized
build asks for >= 13.3.0 stable.

Polyglot SDK Validation:
- Add 'Aspire.Hosting' to the skip list in test-typescript-playground.sh (it
  transitively depends on Aspire.Hosting.Azure.Kubernetes via aspire.config.json).
- Apply the same skip block to test-python-playground.sh and test-java-playground.sh
  (the 13.2 PR only updated the TypeScript script).

Cli.EndToEnd-KubernetesDeploy* (11 files):
- Mark each [Fact] with [ActiveIssue(#15335)]. The proper fix is the dynamic
  version computation tracked by #15335 (PR #15681). When that lands the
  ActiveIssue tags can be removed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove MarkupString from SpanDetails and StructuredLogDetails resource strings (#16584)

Replace HTML-embedded resource strings with plain label strings and
move the <strong> formatting into Razor markup directly. This eliminates
the need for MarkupString casts and string.Format for these toolbar items.

* [release/13.3] Ensure compute environment prepare waits for validation (#16583)

* Ensure compute environment prepare waits for validation

When Foundry is used with another compute environment, the compute environments get confused about who takes ownership of which compute.

Make all compute-environment prepare pipeline steps depend on the shared validate-compute-environments step so before-start cannot race environment validation.

Add diagnostics coverage for a mixed Foundry hosted-agent and Azure Container Apps app.

Cover deployment target lookup returning null for a different compute environment.

* Fix tests

---------

Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>

* [release/13.3] Normalize App Service Application Insights Bicep identifiers (#16564)

* Initial plan

* Normalize app service app insights bicep identifiers

Agent-Logs-Url: https://github.com/microsoft/aspire/sessions/e848458a-5173-4241-b442-80d01de3d5c2

Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>

* Preserve app insights bicep suffix separators

Agent-Logs-Url: https://github.com/microsoft/aspire/sessions/e848458a-5173-4241-b442-80d01de3d5c2

Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>

* Address PR feedback

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>
Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>

* [release/13.3] Fix TypeScript AppHost package manager detection (#16598)

* Fix TypeScript package manager detection

Treat package-lock.json as an npm marker and limit parent directory package manager probing to the AppHost directory's direct parent. Log the marker used to select the TypeScript AppHost package manager.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix TypeScript AppHost path comparisons

Use OS-appropriate path comparison when deciding whether to skip root and home parent directories for package manager detection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Preserve same-directory yarn marker precedence

Keep yarn markers ahead of package-lock.json within the same candidate directory while still allowing a local npm lockfile to beat parent-directory yarn markers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove yarn directory package manager hint

Only use file-based yarn markers for TypeScript AppHost package manager detection and update the resolver test accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address TypeScript toolchain review feedback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Sebastien Ros <sebastienros@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Fix Windows detached AppHost launcher (#16572)

* Fix Windows detached AppHost launcher

Use the Windows DETACHED_PROCESS creation flag when launching the detached child CLI process so aspire start is not tied to the launching console lifetime. Keep the existing new process group and restricted handle inheritance behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Clarify Windows detach launcher comment

Document that the detached Windows flag combination follows established daemonization patterns used by libuv/Node.js and GitHub CLI, without over-claiming Docker parity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove Windows detach unit test

Remove the unit test coverage for the Windows detached process creation flags while keeping the implementation change and manual repro validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: David Fowler <davidfowl@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Validate build-only container references in the pipeline (#16582)

* Validate build-only container references in the pipeline

Add the publish/deploy validation step and implement the opt-out by clearing its RequiredBySteps during pipeline configuration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix tests

* PR feedback

Move DisableBuildOnlyContainerValidation to the Pipeline.

* PR feedback

* Fix tests

* Address build-only container validation feedback

Ensure manifest publishing runs the build-only container validation step and strengthen tests to cover mixed consumed and unconsumed build-only containers.

* Revert publish-manifest changes.

* Apply suggestion from @eerhardt

---------

Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Normalize CLI yes/no prompts (#16597)

* Normalize CLI yes/no prompts

Use single-key confirmation prompts for CLI yes/no choices so y/n answers are accepted without arrow-key selections while preserving [Y/n] and [y/N] defaults.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Prefer local hive versions in aspire add

Treat the configured local hive as a local build channel so aspire add keeps generated AppHosts on the same CLI/SDK version and writes the local NuGet source when needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Revert "Prefer local hive versions in aspire add"

This reverts commit 682178778ffedf19ddbffc863b88a714b2658f05.

---------

Co-authored-by: Sebastien Ros <sebastienros@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Publish native Aspire CLI tool packages (#16611)

* fix(publishing): stage native CLI tool packages

Download RID-specific Aspire.Cli tool packages from native build artifacts and stage them in the shipping packages directory so publishing can include them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(publishing): validate CLI package RIDs

Compare discovered CLI archives and RID-specific tool packages against the expected clipack RIDs, require exactly one pointer package, and summarize publish output without listing every NuGet package.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Ankit Jain <radical@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Rename pipeline --log-level to --pipeline-log-level to avoid CLI log overlap (#16596)

* Rename pipeline --log-level to --pipeline-log-level to avoid CLI log overlap

The pipeline commands (do, publish, deploy, destroy) had a --log-level option
that collided with the global CLI --log-level/-l option. When a user passed
--log-level Debug to control pipeline verbosity, Program.ParseLoggingOptions()
also picked it up and cranked CLI internal logging to Debug, flooding output
with mixed noise.

Rename the pipeline-specific option to --pipeline-log-level so the two
concerns are cleanly separated:
- --log-level / -l (global, recursive) controls CLI internal logging
- --pipeline-log-level (pipeline commands only) controls pipeline step output

The value is still forwarded as --log-level to the AppHost process, which is
correct since the AppHost has its own --log-level parameter.

Also adds tests verifying the separation and argument forwarding.

* Rename s_logLevelOption to s_pipelineLogLevelOption

* [release/13.3] Fallback to junctions if either creating OR evaluating symlinks fails (#16618)

* Fallback to junctions if either creating OR evaluating symlinks fails

* Update src/Aspire.Cli/Utils/ReparsePoint.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update outdated test verified results

* Regenerate the verified file

---------

Co-authored-by: David Negstad <David.Negstad@microsoft.com>
Co-authored-by: David Negstad <50252651+danegsta@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* [release/13.3] Fix TypeScript AppHost generated port ranges (#16649)

* Fix TypeScript AppHost generated port ranges

Use a shared AppHost profile port generator for CLI templates, init, and TypeScript AppHost scaffolding so generated dashboard and service profile ports avoid the Windows ephemeral range. Add regression coverage for the generated TypeScript apphost.run.json ports.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* PR feedback

---------

Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Fix unbounded collection growth in TelemetryRepository (#16590)

* Fix unbounded collection growth in TelemetryRepository and related types

- Add MaxResourceCount option to TelemetryLimitOptions (default 10,000)
  to cap _resources growth. Throws on limit exceeded.
- Clear _logScopes, _logPropertyKeys on ClearStructuredLogs (full clear)
  and remove per-resource property keys on per-resource clear.
- Clear _traceScopes, _tracePropertyKeys, _spanLinks on ClearTraces
  (full clear) and clean up span links and property keys per-resource.
- Clear _meters alongside _instruments in OtlpResource.ClearMetrics.
- Add internal const limits on TelemetryRepository for resource views
  (10,000), instruments (10,000), dimensions (10,000), known attribute
  value keys (10,000), and values per key (10,000).
- Enforce instrument limit in OtlpResource.AddMetrics.
- Enforce resource view limit in OtlpResource.GetView.
- Enforce dimension limit in OtlpInstrument.FindScope.
- Cap KnownAttributeValues keys and per-key value lists in
  OtlpInstrument.CreateDimensionScope.
- Add clarifying comments to fields describing their bounds.

* Add limit enforcement tests and fix uncaught exceptions from resource limit

- Add TelemetryLimitTests with 5 tests for resource and instrument limits
- Add maxResourceCount parameter to CreateRepository test helper
- Wrap GetOrAddResource calls in GetPeerResource (return null), CalculateTraceUninstrumentedPeers, and OnPeerChanged with try/catch
- Fix _meters comment to not claim an unenforced bound
- Document TOCTOU soft-cap behavior on resource limit check

* Reset HasTraces/HasLogs and clear unviewed error logs on full clear

- ClearTraces full-clear now resets HasTraces on all resources
- ClearStructuredLogs full-clear now resets HasLogs on all resources and clears _resourceUnviewedErrorLogs

* Remove redundant per-telemetry-type resource limit tests

* Add scope and instrument limits with TryGetValue pattern

- Add MaxScopeCount limit to TryGetOrAddScope, using TryGetValue instead
  of GetValueRefOrAddDefault to avoid add-then-remove on overflow
- Refactor instrument add in OtlpResource to use TryGetValue + count check
  before inserting, removing the add-then-remove pattern
- Fix AddLogs failure count: count log records, not scopes
- Fix AddMetrics failure count: count data points, not metrics
- Add tests for resource limit, scope limit, and correct failure counting

* Move Ingress and Gateway extension methods to Aspire.Hosting namespace (#16633)

KubernetesGatewayExtensions and KubernetesIngressExtensions were in
the Aspire.Hosting.Kubernetes namespace, requiring users to add an
explicit using directive. Move them to Aspire.Hosting to match the
convention used by other extension methods like
KubernetesEnvironmentExtensions and KubernetesServiceExtensions.

Co-authored-by: Mitch Denny <mitch@mitchdenny.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove obsolete ATS export shims (#16628)

Remove obsolete internal compatibility shims from the ATS export surface so generated polyglot SDKs only expose the unified methods.

Co-authored-by: Sebastien Ros <sebastienros@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Add BrowserLogs tracked browser sessions (#16637)

* Add BrowserLogs CDP transport seam

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use CDP pipe for BrowserLogs owned browsers

Switch owned tracked-browser launches to a private CDP pipe, keep WebSocket adoption as an opt-in seam, and add session/persistent process lifetime configuration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove BrowserLogs persistent lifetime

BrowserLogs pipe-launched browsers are always session scoped because Chromium exits when the CDP pipe closes. Remove the public lifetime option and mark public BrowserLogs types experimental.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Split BrowserLogs pipe launcher partials

Move platform-specific native launch logic into Windows and Unix partial classes while keeping the shared launcher entry points in the common file.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use posix_spawn for BrowserLogs Unix pipe launches

Replace the managed fork/exec launcher with posix_spawn file actions so Chromium still receives CDP pipe fds 3 and 4 without running managed code in a forked child.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Move BrowserLogs to Aspire.Hosting.Browsers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Move BrowserLogs tests to Browsers assembly

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update CI snapshots after BrowserLogs move

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update TypeScript capabilities snapshot

Remove the BrowserLogs capability from the Hosting assembly scanner snapshot now that BrowserLogs lives in Aspire.Hosting.Browsers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove BrowserLogs friend assembly access

Stop relying on InternalsVisibleTo for the Browsers package and its tests by source-sharing the BrowserLogs implementation into the test assembly and replacing Hosting-internal runtime dependencies with public-compatible behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Restore BrowserLogs health report publishing

Add a public CustomResourceSnapshot helper for publishing health reports without InternalsVisibleTo and use it to restore BrowserLogs session and last-error health report rows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address BrowserLogs localization feedback

Add translator comments for BrowserLogs resource strings with format placeholders and regenerate XLF files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix review findings in BrowserLogs

- Fix null-forgiveness on screenshot Data property to throw
  InvalidOperationException instead of ArgumentNullException
- Guard _stopCts.Cancel() against ObjectDisposedException when
  MonitorAsync cleanup races with StopAsync
- Block '..' path traversal in SanitizePathSegment

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: David Fowler <davidfowl@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Mitch Denny <mitch@mitchdenny.com>

* [release/13.3] Gateway TLS without hostname (FQDN discovery) + TS AppHost endpoint fix (#16585)

* Support Gateway TLS without pre-known hostname (FQDN discovery)

When WithTls() is called without WithHostname(), the Gateway now:
1. Generates an HTTPS listener without a hostname restriction
2. After Helm deploy, polls Gateway status for the assigned address
3. Patches the HTTPS listener to add the discovered hostname
4. Creates a bootstrap self-signed TLS secret with the discovered FQDN
5. cert-manager then detects the hostname and issues a real certificate

This enables a single-deploy TLS workflow for controllers like AGC that
assign FQDNs automatically (e.g., *.alb.azure.com), without requiring
users to deploy once to discover the FQDN and then redeploy with it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use helm field-manager for Gateway hostname patch to avoid conflicts

After patching the Gateway hostname via JSON patch, re-apply the full
Gateway YAML with --server-side --field-manager=helm --force-conflicts
to transfer field ownership back to Helm. This prevents SSA conflicts
when the user later redeploys with an explicit hostname via WithHostname().

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix endpoint resource lookup for TS AppHost RPC bridge

Use ResourceNameComparer on the deploymentTargets dictionary so that
endpoint references created through the TypeScript AppHost RPC bridge
(which may use a different resource instance) resolve correctly by
resource name. This matches the pattern already used in
KubernetesEnvironmentContext._kubernetesComponents.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix test assertion for YAML quoted protocol values

The YAML serializer quotes string values like protocol: "HTTPS" on CI.
Use a more flexible assertion that matches both quoted and unquoted forms.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address all automated review feedback

1. Address type validation: Parse full Gateway JSON status, prefer
   Hostname-type addresses, fall back to DNS-like values, skip IPs.
2. Use -o json instead of jsonpath: Parse full Gateway JSON for both
   address discovery and listener index detection. More reliable.
3. Use JsonSerializer + --patch-file: Build JSON patch operations with
   proper serialization, write to temp file to avoid shell escaping.
4. Minimal manifest for field ownership: Read current Gateway JSON,
   strip server fields (status, resourceVersion, managedFields), keep
   only apiVersion/kind/metadata(name,namespace)/spec for SSA apply.
5. Temp file pattern: Use CreateTempSubdirectory consistently.
6. Add SAN to bootstrap certs: Add SubjectAlternativeNameBuilder with
   DNS name in both DiscoverFqdnAndBootstrapTlsAsync and the existing
   BootstrapTlsSecretsAsync. Modern TLS clients require SAN.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Preserve annotations and labels in Gateway ownership transfer

The minimal manifest used for server-side apply field ownership transfer
was missing annotations and labels, causing AGC annotations like
alb.networking.azure.io/alb-name to be stripped. Now copies annotations
and labels from the current Gateway metadata.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add E2E test for K8S Gateway TLS deployment with HTTP-01

Tests the full flow: provision AKS with ALB controller, install cert-manager
with gatewayHTTPRoute HTTP-01 solver, create a project with AddKubernetesEnvironment
+ AddGateway + WithTls (no hostname), deploy with aspire deploy, and verify
FQDN discovery, certificate issuance, and HTTPS access.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use --enable-alb in az aks create and AMD VM SKU

Consolidate ALB enablement into the az aks create command instead of a
separate az aks update step. Use Standard_D2as_v5 (AMD) for quota
compatibility with E2E test subscription.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E test: use --enable-gateway-api --enable-application-load-balancer

Per the official AGC quickstart docs, use the correct flags:
- --enable-gateway-api: enables Gateway API CRDs
- --enable-application-load-balancer: enables ALB controller addon
- --network-plugin azure: required Azure CNI
- Standard_D2as_v5: AMD VM SKU for quota compatibility
- Use the add-on's auto-created aks-appgateway subnet instead of
  creating one manually

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Wait for ALB controller pods to be Running before checking GatewayClass

The ALB controller pods need time to initialize after cluster creation.
Poll until pods are Running and GatewayClass azure-alb-external exists,
with up to 10 minutes timeout.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix ClusterIssuer: parentRefs requires name and namespace

cert-manager requires parentRefs to include a name. Use 'ingress' to
match the Gateway name from AddGateway('ingress'), and include the
namespace to match the Helm deploy namespace.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E test AppHost: add using directive and pragma suppressions

The injected AppHost code needs:
- using Aspire.Hosting.Kubernetes for AddGateway extension methods
- #pragma warning disable ASPIRECOMPUTE003 for AddContainerRegistry
Both prepended to the top of the file alongside ASPIREPIPELINES001.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E test: capture webfrontend variable from starter template

The starter template generates builder.AddProject('webfrontend') without
assigning to a variable. The Gateway route needs a reference to it, so
inject 'var webfrontend =' before the AddProject call.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Refactor FQDN discovery polling to use Polly retry pipeline

Replace the manual for-loop retry with a Polly ResiliencePipeline
using constant 5s backoff, 60 max attempts, and result-based retry
(retries when result is null). Polly.Core is already a transitive
dependency via Aspire.Hosting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Mitch Denny <mitch@mitchdenny.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Fix Python starter TypeScript health check build (#16647)

* Fix Python starter health check template

Update the Python starter TypeScript AppHost to use the supported withHttpHealthCheck options object and align its root build script with AppHost-only type checking. Add E2E coverage that verifies the generated starter builds successfully.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use fail-fast helper for Python starter build test

Update the Python React template E2E build verification to use the existing fail-fast command helper so npm build failures are surfaced immediately.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Verify TypeScript templates build

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add build script aliases to TypeScript AppHost scaffold

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use AppHost tsconfig for TypeScript AppHost lint

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use AppHost tsconfig name for Python starter

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Sebastien Ros <sebastienros@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix sticky 'Finding apphosts' notification in VS Code extension (#16665)

The 'Finding apphosts' message was displayed via DisplayMessage, which
the extension renders as a sticky vscode.window.showInformationMessage
toast that has no programmatic dismissal. Fold it into the surrounding
ShowStatusAsync status text so it rides on the existing progress
notification (auto-dismissed via the finally block) instead.

Co-authored-by: Adam Ratzman <adam@adamratzman.com>

* [release/13.3] API Review Feedback (#16674)

* API Review Feedback

Addressing feedback from https://github.com/microsoft/aspire/pull/16602

Rename JS experimental ID, refactor AKS/EF resource APIs

Renames ASPIREEXTENSION001 to ASPIREJAVASCRIPT001 for JavaScript APIs, resources, and tests. Refactors AKS-related code to Aspire.Hosting.Azure.Kubernetes, makes AksSkuTier internal, and defaults AKS SKU tier to Free. Renames EFMigrationResource.ContextTypeName to DbContextTypeName throughout. Adds missing using directives, Experimental attributes, and AspireValue metadata. Updates tests and samples for new names and diagnostics.

* Remove unused enum

* Change more dbContextTypeName instances.

* Update CodeGeneration snapshots for new WellKnownPipelineSteps entries

Adding [AspireValue("WellKnownPipelineSteps")] to BeforeStart and
CheckContainerRuntime causes the language code generators to emit them
in the WellKnownPipelineSteps exported value catalog. Update the
TwoPassScanningGeneratedAspire snapshots for Go, Java, Python, Rust, and
TypeScript to include the two new entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
Co-authored-by: Jose Perez Rodriguez <joperezr@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Normalize *.localhost dashboard URLs to localhost for CLI HTTP requests (#16708)

* Normalize *.localhost dashboard URLs to localhost for HTTP requests

DNS resolvers typically don't implement RFC 6761 for localhost subdomains,
so hosts like 'myapp.dev.localhost' fail to resolve. This adds
NormalizeDashboardUrl to McpToolHelpers which rewrites *.localhost API
base URLs to localhost before making HTTP requests, while preserving the
original hostname in dashboard display URLs (used in JSON output hyperlinks).

- Add NormalizeDashboardUrl and IsLocalhostTld to McpToolHelpers
- Normalize API base URL in TelemetryCommandHelpers and McpToolHelpers
- Preserve original *.dev.localhost hostname in dashboard display URLs
- Add unit tests for logs/traces with dev.localhost backchannel URLs
- Add E2E test variant using dev.localhost dashboard URL

* Refactor E2E test to use aspire ps --format json for dashboard URL

* Fix E2E test: use --frontend-url and extract dashboard URL from logs

- Use --frontend-url instead of invalid --dashboard-url for aspire dashboard run
- Extract dashboard login URL from log output instead of aspire ps (which
  cannot discover standalone dashboards)
- Pass login?t=xxx URL to aspire otel traces for proper token exchange
- dev.localhost variant passes *.localhost to --frontend-url to exercise
  NormalizeDashboardUrl end-to-end

* Fix E2E test: extract URL from dashboard run output, use --allow-anonymous

- Add --allow-anonymous to avoid token exchange issues in standalone mode
- Extract dashboard URL from 'Now listening on:' in aspire dashboard run output
- Avoids needing login token exchange which fails in container E2E tests

* Fix E2E test: use auth with login token from dashboard run output

- Remove --allow-anonymous to verify authentication works end-to-end
- Extract login URL (with ?t=xxx token) from aspire dashboard run output
- CLI exchanges login token for API key via validateToken endpoint

* Add echo of OTEL_DASHBOARD_URL for debugging visibility

* Add AppHost otel traces tests with dev.localhost variant

- Add AppHostOtelTracesReturnsTraces and _DevLocalhost variants
- New tests create Starter project, start AppHost, generate traces, verify otel traces output
- DevLocalhost variant uses useDevLocalhost flag in AspireNewAsync to test URL normalization
- Add useDevLocalhost parameter to AspireNewAsync helper

* Fix standalone dashboard tests and add dev.localhost otel logs test

- Fix grep regex to use [a-f0-9]+ for token to avoid Spectre Console link duplication
- Remove AppHost otel traces tests (covered by OtelLogs tests)
- Add OtelLogsReturnsStructuredLogsFromStarterApp_DevLocalhost test

* Use DASHBOARD__FRONTEND__BROWSERTOKEN instead of parsing URL from logs

Spectre Console OSC 8 escape sequences in redirected output cause grep
to capture a doubled URL. Instead, set a known browser token via env var
and construct the dashboard URL directly.

* Fix AspireStartAsync sed pattern to match *.localhost dashboard URLs

The sed pattern for extracting dashboardUrl from JSON only matched
'localhost' literally. With dev.localhost subdomains (e.g.
dashboard.dev.localhost:18888), the pattern failed to match, causing
'aspire start did not return a dashboard URL'. Broadened to [a-z.]*localhost.

* Preserve original *.localhost hostname in display URLs for --dashboard-url path

The --dashboard-url code path was normalizing the URL and using it for
both HTTP requests and JSON output hyperlinks. Now it preserves the
original hostname (e.g. dashboard.dev.localhost) for display URLs while
still normalizing to localhost for HTTP requests, matching the
backchannel path behavior.

Also adds remarks to NormalizeDashboardUrl explaining the RFC 6761 DNS
resolution motivation, and tests for the --dashboard-url display URL
preservation.

* Address review comments: normalize URL in StaticDashboardInfoProvider, fix error messages, fix E2E test

- Normalize apiBaseUrl in StaticDashboardInfoProvider so aspire agent mcp
  --dashboard-url with *.dev.localhost URLs works correctly
- Use displayDashboardUrl in error messages so users see the URL they typed
- Fix E2E test to pass frontendUrl to aspire otel traces, actually exercising
  the NormalizeDashboardUrl code path end-to-end

* Add test asserting error messages show original *.dev.localhost URL

* Add E2E tests for aspire agent mcp list_structured_logs

* Rename DashboardOtelTracesTests to DashboardRunTests and add agent mcp tests

- Rename class and file to DashboardRunTests
- Add E2E tests for aspire agent mcp --dashboard-url against standalone dashboard
- Extract CallAgentMcpToolAsync helper to CliE2EAutomatorHelpers
- Use shared helper in AgentMcpLogsTests

* [release/13.3] Fix aspire init template install for non-stable CLI builds (#16654) (#16672)

* [release/13.3] Fix aspire init template install for non-stable CLI builds (#16654)

�spire init ran `dotnet new install Aspire.ProjectTemplates@<cliVersion+sha>`
with `nugetConfigFile: null` and `nugetSource: null`, bypassing the channel
feed wiring used by `aspire new`. For non-stable CLI builds (staging/daily/PR),
`Aspire.ProjectTemplates@<cliVersion+sha>` is only available on a per-commit
darc feed (e.g. `darc-pub-microsoft-aspire-<sha8>`), so install failed with
exit code 103 in any C# repo containing a `.sln`.

Extract the channel-aware template package resolution and install logic out of
`DotNetTemplateFactory.ApplyTemplateAsync` and into `TemplateNuGetConfigService`
as `ResolveTemplatePackageAsync` and `InstallTemplatePackageAsync`. Both
`DotNetTemplateFactory` and `InitCommand` now consume the helper. The
existing `aspire new` install path is preserved bit-for-bit (extraction is
mechanical; `IncludePrHives: true` keeps PR-hive widening behavior).

For `aspire init` this means:
- The version sent to `dotnet new install` is now the channel-resolved one
  (e.g. `13.3.0`), not the raw `+sha` build metadata.
- Init now honors the global `channel` configuration, matching `aspire new`.
- On install failure, captured stdout/stderr is displayed before the error.
- `ChannelNotFoundException` and `EmptyChoicesException` produce friendly
  errors instead of bubbling to the top-level "unexpected error" handler.
- PR hives are intentionally NOT included in init's channel discovery so a
  developer with stale `~/.aspire/hives/*` doesn't get a different template
  than they'd get on a clean machine.

Notes:
- `TemplateNuGetConfigService` is a singleton; `IDotNetCliRunner` is
  transient and is therefore passed as a method parameter to
  `InstallTemplatePackageAsync` instead of being injected.
- New regression tests cover: explicit channel passes the temp NuGet config,
  implicit channel leaves it null, PR hives don't widen init, and channel
  resolution failures produce friendly errors.

Fixes #16654

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR review feedback (#16672)

Multi-model code review caught the following issues:

1. Restore original order of operations in DotNetTemplateFactory.ApplyTemplateAsync.
   The first refactor moved extraArgsCallback ahead of template package resolution,
   which changed prompt/error precedence for `aspire new` (extra-args prompts
   like Redis-cache, test-framework, xUnit-version would now run before channel
   lookup, and answers would be discarded if resolution failed afterward).
   Restored the BEFORE order from release/13.3: ResolveTemplatePackageAsync
   first, then extraArgsCallback, then InstallTemplatePackageAsync. Updated the
   in-source comment to be accurate.

2. Catch NuGetPackageCacheException in InitCommand.DropCSharpProjectSkeletonAsync.
   The pre-extraction init code went straight to `dotnet new install` and
   never invoked a NuGet search, so feed search failures (offline, inaccessible
   feed, etc.) couldn't bubble up. After the extraction init now performs the
   search and was missing the catch, surfacing the failure as an unhandled
   "unexpected error". Added the catch with the same friendly-error treatment
   as ChannelNotFoundException / EmptyChoicesException.

3. Use TemplatingStrings.TemplateInstallationFailed in InitCommand for parity
   with `aspire new`. The previous ad-hoc string omitted the log file path,
   making post-mortem diagnosis harder.

4. Added a comment in InstallTemplatePackageAsync clarifying that the temporary
   NuGet config is intentionally disposed at the end of the install (only
   `dotnet new install` consumes it; the subsequent `dotnet new <template>`
   call uses the already-installed template hive and ambient NuGet config).

5. Added regression test InitCommand_WhenChannelTemplateSearchFails_DisplaysFriendlyError
   covering the new NuGetPackageCacheException catch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Make AtsJsonCodeWriter shared internal helper (#16752)

Move the JSON code writer out of Aspire.TypeSystem so it is not exposed as public API. Link the shared internal helper into each CLI and code generation project that uses it.

Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Validate TypeScript AppHosts before startup (#16755)

* Validate TypeScript AppHost before start

Add a pre-execute runtime hook and use it to run TypeScript type validation before starting or publishing TypeScript AppHosts. Watch mode validates on every restart so startup is not blocked by existing errors while editing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address TypeScript AppHost review feedback

Clarify the PreExecute contract and make Bun typecheck/watch commands use project-local binaries via bun run instead of bun x.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix TypeScript AppHost E2E type checks

Use Yarn run for project-local TypeScript tools so arguments are forwarded correctly, and update the TypeScript publish E2E fixture to use the typed dashboard options shape.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix Kubernetes TypeScript E2E type check

Update the Kubernetes TypeScript deploy E2E fixture to use the generated withHelm options shape so it passes runtime type validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use project-local Bun nodemon in watch

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Sebastien Ros <sebastienros@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update dependencies from https://github.com/microsoft/dcp build 0.23.4 On relative base path root Microsoft.DeveloperControlPlane.darwin-amd64 , Microsoft.DeveloperControlPlane.darwin-arm64 , Microsoft.DeveloperControlPlane.linux-amd64 , Microsoft.DeveloperControlPlane.linux-arm64 , Microsoft.DeveloperControlPlane.linux-musl-amd64 , Microsoft.DeveloperControlPlane.windows-amd64 , Microsoft.DeveloperControlPlane.windows-arm64 From Version 0.23.3 -> To Version 0.23.4 (#16757)

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>

* [release/13.3] Fix HostUrl with container tunnel (#16786)

* Fix HostUrl with container tunnel

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Scope HostUrl matching to host endpoints

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: David Negstad <David.Negstad@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Avoid AppHost discovery when config path is valid (#16680)

* Avoid AppHost discovery when config path is valid

Validate configured AppHost paths before using them and skip recursive discovery for normal CLI resolution when the configured path is already a valid AppHost. Preserve candidate listing behavior so extension commands can still enumerate all AppHost candidates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Restore silent: true for fast-path settings lookup

Reverts an unintended verbosity change so users with a stale legacy
.aspire/settings.json don't see a 'AppHost was specified but doesn't
exist' warning on every aspire run when the CLI is going to fall
back to discovery anyway.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add ProjectLocator tests for fast-path coverage requested in review

- Add Throw-mode variant of UseOrFindAppHostProjectFileUsesValidSettingsWithoutScanning
  to prove recursive discovery is also skipped for non-interactive/JSON callers.
- Add fast-path test with a configured guest AppHost (apphost.ts) and a throwing
  language discovery to cover the production guest-AppHost scenario from the issue.
- Add a parameterized fallback test that verifies an existing-but-invalid configured
  AppHost (IsUnsupported / IsPossiblyUnbuildable) falls back to discovery.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: adamint <adamratzman1@gmail.com>

* [release/13.3] Reject Yarn Classic for TypeScript AppHosts (#16792)

* Reject Yarn Classic for TypeScript AppHosts

Yarn Classic is not supported for TypeScript AppHosts because its command behavior differs from supported package managers and can break Aspire argument forwarding.

Detect Yarn Classic through packageManager declarations and Yarn v1 lockfiles, then fail early with guidance to use Yarn 4 or later, npm, pnpm, or Bun.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update yarn tests to v4

* Update tes dockerfiles

---------

Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Fix dashboard error in .NET 11 preview 4 (#16761)

* Run dashboard in .NET 11

* Update

* Update

* Fix Aspire new empty AppHost language picker (#16666) (#16776)

* Fix Aspire new empty AppHost language picker

Keep a single interactive Empty AppHost template entry while retaining direct language-specific subcommands for non-interactive creation. Filter the language picker by enabled AppHost languages and add missing Python/Rust shortcut template IDs. Update NewCommand tests and E2E helper selection for the new flow.



* Address empty AppHost prompt review feedback



* Include hidden templates in non-interactive suggestions



* Stop persisting new command language selection



* Allow language option on new subcommands



---------



(cherry picked from commit 8bd4b60535047220a6b396e99ad16f25036b39ce)

Co-authored-by: Maddy Montaquila (Leger) <maddyleger1@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Fix Python debug working directory in VS Code (#16575) (#16779)

* Fix Python debug working directory in VS Code (#16575)

When a Python app runs under the VS Code Aspire extension's debugger, os.getcwd() returned the AppHost directory instead of the Python app directory, and .WithWorkingDirectory(...) only updated the dashboard without affecting the actual debug cwd.

Add a working_directory field to PythonLaunchConfiguration that flows through DCP to the VS Code extension, where it now sets debugConfiguration.cwd. Path computation is moved inside the WithDebugSupport annotator lambda so a later .WithWorkingDirectory(...) override is respected at debug time.

Also drops the previous Module-entrypoint hack that smuggled the working directory through program_path.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Address Copilot review feedback for Python debug working directory

- Keep ProgramPath populated with the working directory for non-Script
  (Module + Executable) entrypoints to preserve backward compatibility
  with older VS Code extensions that derive cwd from program_path and
  don't yet understand the new working_directory field.
- Update the comment to mention both Module and Executable entrypoints.
- Update the existing module test to reflect the kept ProgramPath value.
- Add Executable-entrypoint coverage: one test asserting working_directory
  flows through and another asserting WithWorkingDirectory overrides are
  respected on the launch configuration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Adam Ratzman <adam@adamratzman.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Adam Ratzman <adamratzman1@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix notification action closure over scoped services (#16763)

* [release/13.3] Fix Foundry hosted agent endpoint resolution (#16809)

* Fix hosted agent endpoint resolution

Resolve hosted-agent environment endpoint references through compute environment deployment expressions during publish so aspire deploy does not wait on endpoint allocation snapshots. Throw for unsupported internal referenced endpoints and add regression coverage for direct and nested endpoint expressions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address hosted agent review comments

Fix endpoint resolution diagnostics, reuse the shared formatting helper, keep upgraded endpoint TLS values consistent with the effective scheme, and document endpoint property resolution behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Refine endpoint property documentation

Clarify that compute environment endpoint property expressions are generally useful whenever callers need environment-specific reference expressions, not only for deployment publishers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Require --yes with --non-interactive for destroy cmd (#16806)

Added validation to enforce --yes when --non-interactive is used with the destroy command, returning a localized error if omitted. Introduced a new NonInteractiveRequiresYes resource and updated all localization files. Expanded DestroyCommandTests to cover new validation, multiple CLI permutations, and error scenarios for failed destroy activities.

Fix #16623

Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>

* Consolidate Helm chart options on WithHelm(...) (#16759) (#16802)

* Drop nuget.config alongside single-file apphost.cs in `aspire init` (#16636) (#16822)

* chore: whitespace change to trigger deployment test repro



* Drop nuget.config alongside single-file apphost.cs in `aspire init`

Deployment E2E tests on main were failing 12 of 13 with:

    Unhandled exception: The SDK 'Aspire.AppHost.Sdk/<v>' specified
    could not be found. /tmp/.../apphost.csproj
    The package installation failed with exit code 5.

After PR #15918 redesigned `aspire init` to drop a single-file
`apphost.cs` (with `#:sdk Aspire.AppHost.Sdk@<version>`) and an
`aspire.config.json` instead of a full `.csproj` project, the
generated workspace contains no `nuget.config`. The local hive
(where the dev SDK lives, e.g. `~/.aspire/hives/local/packages`)
is therefore invisible to MSBuild, so the SDK directive cannot be
resolved.

Any subsequent operation that triggers MSBuild restore fails:

* `aspire add <pkg>` (which runs `dotnet package add --file
  apphost.cs`) — this is the failure mode the deployment E2E tests
  hit.
* `dotnet run --file apphost.cs`
* `aspire start`

Fix: when `aspire init` drops the single-file C# skeleton, also
drop a workspace-local `nuget.config` listing every local hive
under `~/.aspire/hives/<name>/packages` as a NuGet package source.
We don't add package source mapping restrictions, so transitive
dependencies still resolve from inherited sources (typically
nuget.org) via the normal NuGet source hierarchy. Behavior for
users without any local hive is unchanged (no `nuget.config` is
written).



* Use shared TemplateNuGetConfigService for init nuget.config

Address PR review feedback (davidfowl, radical) by replacing the inline
ad-hoc nuget.config creation in InitCommand with a call to the shared
TemplateNuGetConfigService — the same path used by 'aspire new' for
template output.

This delegates to NuGetConfigMerger, which:

* Resolves the user's configured channel (from 'aspire config get channel'),
  so it works for any non-stable hive — local-*, dev-*, pr-*, run-*,
  staging — not just channels named 'local'.
* Creates a new nuget.config or merges missing sources into an existing
  one, so additional hives added later (e.g. via subsequent aspire
  commands) are handled the same way they are for templates.
* No-ops for stable/implicit channels, matching prior behavior of doing
  nothing for the default user case.



* Add silent CreateOrUpdateNuGetConfigWithoutPromptAsync overload

The previous refactor used PromptToCreateOrUpdateNuGetConfigAsync, which
in the in-place case (workingDir == outputPath, the case for aspire init)
prompts the user with 'Create NuGet.config for selected channels?'. The
existing E2E and unit tests for aspire init don't expect any prompt, so
they hung waiting for the next expected text.

Add a new public method CreateOrUpdateNuGetConfigWithoutPromptAsync that
always uses the silent merge path, and switch InitCommand to call it.
This keeps the same shared NuGetConfigMerger create-or-merge semantics
without changing the interactive UX of aspire init.

Also register TemplateNuGetConfigService in the test DI container so
InitCommand can resolve it from CliTestHelper.



* Avoid 'NuGet.config' substring in init's confirmation message

The AspireInitAsync E2E test helper detects the NuGet.config Y/n prompt
by looking for the literal substring 'NuGet.config' on screen. The shared
NuGetConfigPrompter (used in the silent path) emits a confirmation message
that also contains 'NuGet.config', causing the helper to false-match the
message as a prompt and get out of sync with subsequent prompts (most
notably the agent-init Y/n).

Fix: in TemplateNuGetConfigService.CreateOrUpdateNuGetConfigWithoutPromptAsync,
bypass NuGetConfigPrompter and call NuGetConfigMerger directly so no
built-in confirmation message is emitted. Return a bool indicating whether
a config was written, and let InitCommand emit a neutral message
('Created package sources file') that does not contain the trigger
substring.



* Quarantine flaky StopNonInteractiveTests E2E tests

Three consecutive PR CI reruns failed with different transient timeouts in:
  - StopNonInteractiveMultipleAppHostsShowsError (3m timeout on 'AppHost started successfully')
  - StopAllAppHostsFromUnrelatedDirectory (8m20s timeout on success prompt)

Both go through 'aspire new' + 'aspire start' (unrelated to the init/nuget.config changes in this PR). Tracking issue: #16643.



---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Honor configured channel in 'aspire update' (#16808)

* Honor configured channel in 'aspire update'

'aspire update' previously consulted only the explicit --channel/--quality
option and otherwise silently selected the implicit channel (or prompted only
if PR hives were present). The local and global 'channel' configuration values
were never read, so a user who ran 'aspire config set channel staging' (or had
it saved by 'aspire update --self') would still get the implicit/NuGet-config
based channel on subsequent 'aspire update' runs.

UpdateCommand.ExecuteAsync now resolves the channel using the documented
precedence:

  1. explicit --channel / hidden --quality
  2. local app config 'channel' (aspire.config.json / .aspire/settings.json)
  3. global config 'channel' (~/.aspire/settings.global.json)
  4. interactive channel prompt when PR hives are present
  5. implicit/default channel as the documented fallback

Local-vs-global precedence comes for free because RegisterSettingsFiles loads
the global settings file before the local one, so IConfiguration (and
IConfigurationService.GetConfigurationAsync) returns the local value when both
exist. A configured channel that does not match any available channel now
surfaces a ChannelNotFoundException instead of being silently ignored.

The existing UpdateCommand_WithoutHives_UsesImplicitChannelWithoutPrompting
test is preserved (no configured channel still falls back to the implicit
channel) and joined by new regression coverage:

  * UpdateCommand_LocalConfiguredChannel_IsUsed
  * UpdateCommand_GlobalConfiguredChannel_IsUsed
  * UpdateCommand_ExplicitChannelOverridesConfiguredChannel
  * UpdateCommand_LocalConfiguredChannel_OverridesGlobalConfiguredChannel
  * UpdateCommand_WithoutHives_ConfiguredChannel_TakesPrecedenceOverImplicitFallback
  * UpdateCommand_ConfiguredChannelNotInChannelList_ThrowsChannelNotFound

Fixes #16650

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Resolve `aspire update` channel config relative to AppHost project directory

Addresses Copilot reviewer feedback on PR #16716. The previous fix moved
channel resolution to read from `IConfiguration`, but `IConfiguration` is
rooted at `Environment.CurrentDirectory` at startup via
`ConfigurationHelper.RegisterSettingsFiles`. That means
`aspire update --apphost <path-to-other-app>/AppHost.csproj` ignored the
target app's local `aspire.config.json` and read config from the caller's
cwd tree instead, so the documented "local app-config in the project tree"
precedence was still broken for explicit `--apphost` updates.

Add `IConfigurationService.GetConfigurationFromDirectoryAsync(key, startDirectory)`
which walks up from a caller-supplied directory for the nearest
`aspire.config.json`, then falls back to the global settings file. The
process-wide IConfiguration is intentionally not consulted, so the lookup
is never anchored to the launch cwd.

`UpdateCommand` now passes `projectFile.Directory` to scope the channel
lookup to the resolved AppHost project's tree.

Three new tests cover:
- Project in another directory uses its own local config
- Project-local config wins over cwd config
- Project-local config without `channel` falls back to global

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Mitch Denny <mitch@mitchdenny.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [release/13.3] Use plain dotnet run for extension Run Without Debugging (#16803)

* Use plain dotnet run for extension Run Without Debugging

* Honor IDE-advertised SupportedLaunchConfigurations for project resources

ExtensionUtils.SupportsDebugging treated 'project' launch type as implicitly supported by every IDE, even when the IDE explicitly advertised a SupportedLaunchConfigurations list that did not include 'project'.

This caused project resources to fail to start in VS Code when the C# extension was not installed: the AppHost routed them to the extension via DCP, and the extension returned 400 UnsupportedLaunchConfiguration because it has no project debugger registered without C#.

Now the implicit-project rule only applies when the IDE did not send DEBUG_SESSION_INFO at all (the Visual Studio scenario). When the IDE sent an explicit list, honor it for every launch type including 'project' — IDEs that can launch project resources must advertise 'project' in their list. The VS Code extension already does this correctly when C# is installed.

Resources whose launch type is not in the advertised list now fall to ExecutionType.Process, so the AppHost spawns dotnet itself and the resource starts (without a debugger attached, which is correct since the IDE has no debugger to attach).

* Remove NoExtensionLaunch flag

DotNetAppHostProject only needed NoExtensionLaunch to prevent the
extension from launching the apphost during pipeline (publish/exec)
flows. Since the extension launch path now uses plain 'dotnet run' for
Run Without Debugging, the flag is unused — pipeline commands already
take a different code path.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Adam Ratzman <adam@adamratzman.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Backport CLI AppHost debug console output fixes (#16795) (#16816)

Backports the CLI portions of #16795 to release/13.3.

Includes AppHost summary formatting for extension-host output, serialized extension interaction output, and guest AppHost pre-launch failure surfacing.

* Fix #15986: emit apphost.run.json from aspire init single-file skeleton (#16812) (#16821)

* Add CLI E2E repro for #15986: dotnet run apphost.cs after aspire init

Demonstrates that 'dotnet run apphost.cs' against the single-file C#
AppHost dropped by interactive 'aspire init' fails because the launch
profile env vars (ASPNETCORE_URLS, ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL,
ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL) are missing — aspire init does not
write apphost.run.json and the .NET file-based runner only honours that
file (not aspire.config.json) for launch profiles.

This commit intentionally adds a failing test; the fix follows in a
subsequent commit on the same PR.



* Fix #15986: emit apphost.run.json from aspire init single-file skeleton

After 'aspire init' drops the C# single-file AppHost ('apphost.cs' +
'aspire.config.json' + 'NuGet.config'), running 'dotnet run apphost.cs'
crashed at startup because no launch profile was applied:

  Failed to configure dashboard resource because ASPNETCORE_URLS
  environment variable was not set.
  Failed to configure dashboard resource because
  ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL and
  ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL are not set.

The dashboard / OTLP / resource service env vars normally come from a
launch profile. When the AppHost is launched via 'aspire run' the CLI
injects them from 'aspire.config.json'. When launched via the .NET
file-based runner ('dotnet run apphost.cs') only '<file>.run.json'
(here 'apphost.run.json') is honoured, and the init flow was not
producing it.

Fix: in InitCommand.DropCSharpSingleFileSkeletonAsync, generate the
profile ports once and pass them into both the existing
'aspire.config.json' writer and a new 'apphost.run.json' writer so the
two files agree on the dashboard URLs. The 'apphost.run.json' shape
mirrors the existing aspire-apphost-singlefile MSBuild template
(commandName=Project, dotnetRunMessages=true, launchBrowser=true,
ASPNETCORE_ENVIRONMENT/DOTNET_ENVIRONMENT=Development, dashboard /
OTLP / resource service URLs).

The aspire-apphost-singlefile MSBuild template is unaffected since it
already ships 'apphost.run.json' alongside its other artifacts. No
other call site of DropAspireConfig is changed (the new ports parameter
is optional and defaults to the previous self-generation behaviour).

Adds InitCommand_SingleFileSkeleton_CreatesAppHostRunJsonWithDashboardEnvVars
unit test and updates the SingleFileAppHostInitDotnetRunTests E2E
repro added in the previous commit.

Fixes #15986



* Add CLI E2E test for #15986: aspire init then dotnet run apphost.cs

Drives the user-facing flow that #15986 broke:

1. `aspire init` (interactive, default C# selection).
2. Inspect the bind-mounted workspace from the host: assert
   `apphost.cs`, `aspire.config.json`, and `apphost.run.json` all
   exist, and that `apphost.run.json`'s `https` profile carries the
   dashboard / OTLP / resource-service env vars (full schema is covered by
   `InitCommand_SingleFileSkeleton_CreatesAppHostRunJsonWithDashboardEnvVars`).
3. `dotnet run apphost.cs` and wait for
   `Distributed application started.`.
4. Ctrl+C and exit cleanly.

Before the fix, `apphost.run.json` was never written, the precondition
in step 2 fails fast with an explicit pointer to #15986, and step 3
would crash at startup with the dashboard `OptionsValidationException`
about missing `ASPNETCORE_URLS` / `ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL`
(verified on this branch — the test-only commit pushed earlier failed in
CI with exactly that error before the fix landed in this PR).



* Trigger CI revalidation (whitespace only)

* Address PR feedback: shared JSON options + ports always agree

James review feedback on #16812:

1. Use shared JsonSourceGenerationContext.RelaxedEscaping (which already has WriteIndented = true and UnsafeRelaxedJsonEscaping) instead of inline 'new JsonSerializerOptions { WriteIndented = true }' at both ToJsonString call sites in InitCommand.

2. Make divergence between aspire.config.json and apphost.run.json impossible by construction. DropAspireConfig now returns the effective ports (newly generated, or read back from a pre-existing profiles section), and DropCSharpSingleFileSkeletonAsync threads those into DropAppHostRunJson — so even if aspire.config.json was hand-edited or pre-existed, both files always describe the same dashboard / OTLP / resource service endpoints.

Added unit test InitCommand_SingleFileSkeleton_AppHostRunJsonAdoptsPortsFromExistingAspireConfig that pre-seeds aspire.config.json with profiles and asserts apphost.run.json adopts those exact ports.

Also dropped the E2E 'Distributed application started.' wait timeout from 7 minutes to 1 minute — even a cold dotnet build of the bare single-file AppHost completes well inside that budget; if it's not started by then, fail fast.



* Strengthen inline comments at JSON literals (PR #16812 review nits)

James left two nit comments asking for short explanatory comments at the JSON literal blocks. Beef up the comment at the apphost.run.json literal in DropAppHostRunJson explaining what shape it mirrors and why; the existing comment in DropAspireConfig now also calls out that each profile carries the dashboard URL plus the OTLP / resource-service env vars consumed by DashboardOptionsValidator at AppHost startup.



* Address PR feedback: preserve user profiles + use KnownConfigNames

Two more JamesNK review comments on PR #16812:

1. Behavioural regression (line 481): the previous patch overwrote any pre-existing 'profiles' section in aspire.config.json whenever TryReadAppHostProfilePorts couldn't parse all six expected ports (e.g. user-customised config, https-only setup, missing one of the env vars). The original implementation preserved existing profiles unconditionally — this is restoring that safety. New behaviour:

  - profiles is null -> write fresh, return those ports

  - profiles parses cleanly -> adopt those ports, return them (existing behaviour)

  - profiles exists but doesn't match the expected shape -> PRESERVE the user's profiles untouched, generate fresh ports just for apphost.run.json (accepted edge-case divergence — better than silent data loss)

Added InitCommand_SingleFileSkeleton_PreservesUnparseableExistingProfiles to lock the preservation behaviour in.

2. Use KnownConfigNames constants (line 546): replaced literal 'ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL', 'ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL', 'ASPIRE_ALLOW_UNSECURED_TRANSPORT' strings throughout InitCommand.cs (in DropAspireConfig, DropAppHostRunJson, and TryReadAppHostProfilePorts) with KnownConfigNames.DashboardOtlpGrpcEndpointUrl / .ResourceServiceEndpointUrl / .AllowUnsecuredTransport. Test fixtures keep literal strings since they document the on-disk JSON shape from the user's perspective.



---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Bump patch version from 13.3.0 to 13.3.1 (#16951)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: joperezr <13854455+joperezr@users.noreply.github.com>

* [create-pull-request] automated change (#16602)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update dependencies from https://github.com/microsoft/dcp build 0.23.5 On relative base path root Microsoft.DeveloperControlPlane.darwin-amd64 , Microsoft.DeveloperControlPlane.darwin-arm64 , Microsoft.DeveloperControlPlane.linux-amd64 , Microsoft.DeveloperControlPlane.linux-arm64 , Microsoft.DeveloperControlPlane.linux-musl-amd64 , Microsoft.DeveloperControlPlane.windows-amd64 , Microsoft.DeveloperControlPlane.windows-arm64 From Version 0.23.4 -> To Version 0.23.5 (#16944)

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>

* [release/13.3] Skip compute env validation in run mode (#16940) (#16952)

* Skip Azure compute env validation in run mode (#16940)

The validate-azure-container-apps and validate-azure-app-service pipeline
steps run in 'before-start', which fires for both 'aspire run' and publish.
In run mode, AddAzureContainerAppEnvironment/AddAzureAppServiceEnvironment
do not add their environment resources to the model. Any compute resource
that ends up with a PublishAs* customization annotation (for example via
WithAnnotation) therefore trips the 'no environment resources' branch at
'aspire run' time, even though the user did add an environment.

PublishAs* annotations only affect publish/deploy output, so skip the
validation entirely when ExecutionContext.IsPublishMode is false.

Fixes #16940.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix Docker and K8s too

---------

Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Backport of https://github.com/microsoft/aspire/pull/16988 into release/13.3 (#16993)

* Fix WaitFor() for tunnel-dependent containers

# Conflicts:
#	src/Aspire.Hosting/Dcp/ContainerCreator.cs
#	src/Aspire.Hosting/Dcp/DcpExecutor.cs
#	tests/Aspire.Hosting.Tests/Dcp/TestKubernetesService.cs

* Fix code review issues

* Do not dispose externally-provided ContainerCreator instance

* Add application cancellation token for container tunnel creation

* Improve error reporting for container tunnel (#16537)

* Improve error reporting for container tunnel

Fixes https://github.…
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants