Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
7bfe473
Add WithTerminal API: TerminalAnnotation, TerminalHostResource, and e…
mitchdenny Apr 20, 2026
ef27bd6
Add Aspire Terminal Protocol spec, shared codec, and playground
mitchdenny Apr 20, 2026
c69b010
Add terminal protocol test client and verify end-to-end
mitchdenny Apr 20, 2026
8304209
Add DCP model TerminalSpec, backchannel RPC, and CLI terminal command
mitchdenny Apr 20, 2026
cf01d2d
Add WithTerminal custom socket path provider overload
mitchdenny Apr 20, 2026
c488b36
Add Dashboard terminal support: xterm.js, WebSocket proxy, ConsoleLog…
mitchdenny Apr 20, 2026
8711f41
Fix Dashboard terminal: use script tags for xterm.js and int IDs for …
mitchdenny Apr 20, 2026
e271e51
Add production Aspire.TerminalHost and wire into AppHost discovery
mitchdenny Apr 20, 2026
969b605
Fix playground: use custom socket path overload to avoid dual termina…
mitchdenny Apr 20, 2026
9524efc
Redesign terminal host for reconnection with state replay
mitchdenny Apr 20, 2026
ae8bae0
WithTerminal Phase 1: refactor to per-replica UDS pair design
mitchdenny May 4, 2026
cb15b4a
WithTerminal Phase 2: Aspire.TerminalHost on Hex1b HMP v1
mitchdenny May 4, 2026
f2695dc
WithTerminal Phase 4: wire per-replica TerminalSpec into DCP Executab…
mitchdenny May 4, 2026
7019903
WithTerminal Phase 5: backchannel exposes per-replica terminal endpoints
mitchdenny May 5, 2026
da2f87d
WithTerminal Phase 6: aspire terminal CLI command on Hex1b HMP v1
mitchdenny May 5, 2026
1f1a7bd
Phase 7: Dashboard /api/terminal WebSocket proxy + per-replica Termin…
mitchdenny May 5, 2026
029fc2d
Phase 8: WithTerminal end-to-end playground + plain-executable fix
mitchdenny May 5, 2026
1c88a49
Phase 8 fix: TerminalView reacts to resource/replica parameter changes
mitchdenny May 5, 2026
20ea519
WithTerminal: container support + Node.js playground
mitchdenny May 5, 2026
0168642
Terminals playground: nodebox fix - override CMD instead of entrypoint
mitchdenny May 5, 2026
04adae4
Flip producer-side connection direction in Aspire.TerminalHost
mitchdenny May 5, 2026
04056c5
Dashboard terminal: send resize on WebSocket open before render
mitchdenny May 5, 2026
5e3e986
WithTerminal: process-restart support + Stop-regression hardening (Ph…
mitchdenny May 5, 2026
8bd7a7d
Phase 11: CLI wires up HMP1 multi-head primary/secondary protocol
mitchdenny May 6, 2026
ac79a4e
TerminalHost: bridge consumer-side resize to raw DCP HMP1 frame
mitchdenny May 8, 2026
066993b
Update Hex1b to 0.147.0 + transient nuget.org Hex1b-only mapping
mitchdenny May 8, 2026
fa7f1a3
Phase 17 Dashboard: transplant WebMuxerDemo terminal chrome + dumb by…
mitchdenny May 8, 2026
852792d
Phase 17 CLI: split TerminalCommand and lift WebMuxerDemo viewer expe…
mitchdenny May 8, 2026
dbba5e3
Terminals playground: shell2 control resource for Stop bisection + sl…
mitchdenny May 8, 2026
3d9fa86
Update Hex1b 0.147.0 -> 0.150.0; drop transient nuget.org mapping
mitchdenny May 10, 2026
5ea0b0b
Adapt to Hex1b 0.150.0 and rebased main
mitchdenny May 10, 2026
3719394
WithTerminal Phase 18: package Aspire.TerminalHost as per-RID NuGet p…
mitchdenny May 11, 2026
54c13bb
WithTerminal Phase 19: integrate Aspire.TerminalHost into the polyglo…
mitchdenny May 11, 2026
90c3671
docs/specs/with-terminal: fix MD040 fenced-code-language
mitchdenny May 11, 2026
ef95afe
WithTerminal Phase 20: fix CI failures from Phase 18/19
mitchdenny May 11, 2026
431e21e
WithTerminal Phase 22: review feedback cleanup pass 1
mitchdenny May 11, 2026
9790e6f
WithTerminal Phase 22: review feedback documentation pass
mitchdenny May 11, 2026
2458ad2
WithTerminal Phase 23: aspire terminal ps command + per-replica metadata
mitchdenny May 11, 2026
d106e0a
Per-replica TerminalHost: one host process per parent replica
mitchdenny May 11, 2026
931cf9e
chore: whitespace nudge to retrigger CI
mitchdenny May 11, 2026
1f587fe
Defer per-replica TerminalHost creation to BeforeStartEvent
mitchdenny May 11, 2026
8ee668a
Add ATS export for WithTerminal via parameterless dispatcher overload
mitchdenny May 11, 2026
a65c4e4
Fall back to ASPIRE_DASHBOARD_PATH when terminal host path is unset i…
mitchdenny May 11, 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
3 changes: 2 additions & 1 deletion .github/workflows/build-cli-native-archives.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,15 @@ jobs:
-Rid $rid `
-ArchivePath $archive[0].FullName

# Upload DCP, Dashboard, and CLI tool NuGets so test/polyglot jobs can download them
# Upload DCP, Dashboard, TerminalHost, and CLI tool NuGets so test/polyglot jobs can download them
- name: Upload RID-specific NuGets
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: built-nugets-for-${{ matrix.targets.rids }}
path: |
artifacts/packages/${{ inputs.configuration }}/Shipping/Aspire.Hosting.Orchestration.${{ matrix.targets.rids }}.*.nupkg
artifacts/packages/${{ inputs.configuration }}/Shipping/Aspire.Dashboard.Sdk.${{ matrix.targets.rids }}.*.nupkg
artifacts/packages/${{ inputs.configuration }}/Shipping/Aspire.TerminalHost.Sdk.${{ matrix.targets.rids }}.*.nupkg
artifacts/packages/${{ inputs.configuration }}/Shipping/Aspire.Cli.*.nupkg
if-no-files-found: error
retention-days: 15
Expand Down
6 changes: 6 additions & 0 deletions Aspire.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
<Project Path="src/Aspire.Hosting.Valkey/Aspire.Hosting.Valkey.csproj" />
<Project Path="src/Aspire.Hosting.Yarp/Aspire.Hosting.Yarp.csproj" />
<Project Path="src/Aspire.Hosting/Aspire.Hosting.csproj" />
<Project Path="src/Aspire.TerminalHost/Aspire.TerminalHost.csproj" />
<Project Path="src/Aspire.TypeSystem/Aspire.TypeSystem.csproj" />
<Project Path="src/Aspire.ProjectTemplates/Aspire.ProjectTemplates.csproj" />
</Folder>
Expand Down Expand Up @@ -359,6 +360,10 @@
<Project Path="playground/Stress/Stress.Empty/Stress.Empty.csproj" />
<Project Path="playground/Stress/Stress.TelemetryService/Stress.TelemetryService.csproj" />
</Folder>
<Folder Name="/playground/Terminals/">
<Project Path="playground/Terminals/Terminals.AppHost/Terminals.AppHost.csproj" />
<Project Path="playground/Terminals/Terminals.Repl/Terminals.Repl.csproj" />
</Folder>
<Folder Name="/playground/Testing/">
<Project Path="playground/Testing/Testing.Tests/Testing.Tests.csproj" />
</Folder>
Expand Down Expand Up @@ -511,6 +516,7 @@
<Project Path="tests/Aspire.Hosting.SqlServer.Tests/Aspire.Hosting.SqlServer.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.Testing.Tests/Aspire.Hosting.Testing.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj" />
<Project Path="tests/Aspire.TerminalHost.Tests/Aspire.TerminalHost.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.Valkey.Tests/Aspire.Hosting.Valkey.Tests.csproj" />
<Project Path="tests/Aspire.Hosting.Yarp.Tests/Aspire.Hosting.Yarp.Tests.csproj" />
</Folder>
Expand Down
2 changes: 2 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<SkipAspireWorkloadManifest>true</SkipAspireWorkloadManifest>

<DashboardPublishedArtifactsOutputDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'DashboardArtifacts', '$(Configuration)'))</DashboardPublishedArtifactsOutputDir>
<TerminalHostPublishedArtifactsOutputDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'TerminalHostArtifacts', '$(Configuration)'))</TerminalHostPublishedArtifactsOutputDir>
<WorkloadsPackageSource>$(ArtifactsShippingPackagesDir)</WorkloadsPackageSource>

<!-- Issue: https://github.com/microsoft/aspire/issues/8488 -->
Expand All @@ -56,6 +57,7 @@
<!-- TODO: Need to figure out we can automatically detect target framework here. This property
is specified to support dashboard path metadata generation on the inner loop. -->
<AspireDashboardDir>$(MSBuildThisFileDirectory)/artifacts/bin/Aspire.Dashboard/$(Configuration)/net8.0/</AspireDashboardDir>
<AspireTerminalHostDir>$(MSBuildThisFileDirectory)/artifacts/bin/Aspire.TerminalHost/$(Configuration)/net8.0/</AspireTerminalHostDir>
</PropertyGroup>

</Project>
6 changes: 3 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@
<PackageVersion Include="Grpc.AspNetCore" Version="2.76.0" />
<PackageVersion Include="Grpc.Net.ClientFactory" Version="2.76.0" />
<PackageVersion Include="Grpc.Tools" Version="2.78.0" />
<PackageVersion Include="Hex1b" Version="0.133.0" />
<PackageVersion Include="Hex1b.McpServer" Version="0.133.0" />
<PackageVersion Include="Hex1b.Tool" Version="0.133.0" />
<PackageVersion Include="Hex1b" Version="0.150.0" />
<PackageVersion Include="Hex1b.McpServer" Version="0.150.0" />
<PackageVersion Include="Hex1b.Tool" Version="0.150.0" />
<PackageVersion Include="Humanizer.Core" Version="2.14.1" />
<PackageVersion Include="KubernetesClient" Version="18.0.13" />
<PackageVersion Include="JsonPatch.Net" Version="3.3.0" />
Expand Down
156 changes: 156 additions & 0 deletions docs/specs/with-terminal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# `WithTerminal()` — Aspire interactive terminal architecture

**Status:** Implemented for Aspire 13.4 (Windows executables).
**Issue:** [microsoft/aspire#16317](https://github.com/microsoft/aspire/issues/16317)
**DCP integration:** [microsoft/dcp#133](https://github.com/microsoft/dcp/pull/133)

## Goal

Let an Aspire AppHost author opt any executable or container resource into
interactive terminal access:

```csharp
builder.AddProject<Projects.MyAgent>("agent")
.WithReplicas(2)
.WithTerminal();
```

The dashboard then renders an xterm.js terminal per replica, and the CLI
exposes the same session as `aspire terminal agent --replica 0`.

## Process topology

```text
┌────────────────────────────┐
│ AppHost (dotnet run) │
│ - Aspire.Hosting │
│ - DCP control plane │
│ - per-resource: │
│ Aspire.TerminalHost │ (1 process / WithTerminal())
└─────────────┬──────────────┘
│ spawn
┌──────────────────────┐ ┌───────────────────────┐ ┌────────────────────────┐
│ DCP-launched │ PTY (Win) │ TerminalHost │ HMP v1 UDS │ Consumers │
│ replica process │ ─────────────▶ │ (Hex1b HMP v1 broker) │ ─────────────▶ │ - Dashboard │
│ (executable, repl…) │ ◀───── stdin ─ │ │ ◀───── input ─ │ /api/terminal proxy │
└──────────────────────┘ └───────────────────────┘ │ - aspire CLI │
└────────────────────────┘
```

Three actors and three socket roles:

| Actor | Socket | Direction | Lifetime |
|----------------|---------------------|----------------------------------|----------|
| **DCP** | `producerUdsPath` | DCP → host (PTY bytes + control) | Per replica |
| **TerminalHost** | `consumerUdsPath` | host → consumers (broadcast) | Per replica |
| **TerminalHost** | `controlUdsPath` | AppHost → host (lifecycle, stats)| Per resource |

The producer/consumer split lets multiple consumers (dashboard + multiple CLI
sessions) attach simultaneously without coupling DCP to consumer counts.

## Wire protocol

We do **not** define a custom protocol. The terminal traffic uses
[Hex1b](https://github.com/dotnet/hex1b)'s `HMP v1` (Hex Multiplex Protocol,
version 1), which already handles:

- VT byte streaming with backpressure
- Resize requests in both directions
- Hello/StateSync replay so a late-attaching consumer sees the current
scrollback
- Connection lifecycle (close, disconnect, reconnect)
- Authenticated stream factory hooks (we only use Unix-socket transport
today)

The `Hmp1WorkloadAdapter` is what the AppHost-side terminal host uses to
multiplex DCP's PTY traffic to the consumer-facing listener; the
`Hmp1PresentationAdapter` is what consumers (Dashboard WebSocket proxy and
the CLI) use to attach.

## Property contract (gRPC `ResourceService` snapshots)

When `WithTerminal()` is applied to a resource, every replica snapshot
emitted by the dashboard service carries four properties:

| Key | Sensitivity | Meaning |
|---------------------------|-----------------|----------------------------------------------|
| `terminal.enabled` | non-sensitive | Marker. `"true"` when the replica has a PTY. |
| `terminal.replicaIndex` | non-sensitive | 0-based stable index from `DcpInstancesAnnotation`. |
| `terminal.replicaCount` | non-sensitive | Total replicas for the parent resource. |
| `terminal.consumerUdsPath`| **sensitive** | The local UDS that consumers connect to. |

The consumer UDS path is marked `IsSensitive=true` so the dashboard UI masks
the value in the property list. The path still rides the gRPC stream because
the dashboard's WebSocket proxy needs it server-side to resolve
`?resource=&replica=` query parameters into a real socket; the path is never
echoed back to the browser.

## Dashboard `/api/terminal` WebSocket endpoint

Authenticated (`RequireAuthorization(FrontendAuthorizationDefaults.PolicyName)`)
endpoint at `/api/terminal?resource=<displayName>&replica=<index>`.

`TerminalWebSocketProxy` resolves the connection entirely server-side:

1. `ITerminalConnectionResolver.ConnectAsync(resourceName, replicaIndex, ct)`
walks `IDashboardClient.GetResources()`, matches by `DisplayName` +
`TryGetTerminalReplicaInfo`, and connects via
`Hmp1Transports.ConnectUnixSocket(consumerUdsPath, ct)`.
2. The proxy wraps the resulting stream in `Hmp1WorkloadAdapter` and runs
two pumps:
- **Inbound (browser → producer):** binary frames are forwarded as HMP v1
`Input` (keystrokes); text frames are parsed as JSON resize control
messages (`{"type":"resize","cols":N,"rows":N}`).
- **Outbound (producer → browser):** VT bytes from the producer become
binary WebSocket frames; resize hints from the producer become JSON
text frames.
3. Frame type — not content — distinguishes keystroke from control. This
keeps the proxy's parser cheap and avoids ambiguity around binary input
that happens to look like JSON.
4. Multi-fragment WS reads are reassembled in `ReassembledFrame` using
`ArrayPool<byte>`.

The browser never sees `consumerUdsPath` and cannot induce the dashboard
to connect to an arbitrary local socket — it can only ask for
`(resource, replica)` pairs that are present in the resource snapshot
stream.

## CLI

`aspire terminal <resource> [--replica N]` (`Aspire.Cli/Commands/TerminalCommand.cs`)
opens its own `Hmp1PresentationAdapter` against the consumer UDS path
returned by `IBackchannel.GetTerminalInfoAsync(resource, replica)` and
renders frames into the host terminal via Hex1b's `Hex1bTerminal`. When the
resource has more than one replica and the CLI is interactive, it prompts
for a selection; in non-interactive mode the `--replica` flag is required.

## DCP integration

DCP allocates a Windows ConPTY per replica when the spec carries
`terminal.enabled=true` and the supplied `terminal.producerUdsPath`,
`terminal.consumerUdsPath`, and `terminal.controlUdsPath` properties. DCP
opens the producer-side UDS and writes PTY traffic into it; the
TerminalHost owns the consumer-side listener and broadcasts to attached
clients.

Linux / macOS / container PTY support is tracked as Phase 3 follow-ups in
the parent issue; for the 13.4 release, the playground guards
non-Windows code paths with `OperatingSystem.IsWindows()` checks.

## Files of interest

| Concern | File |
|--------------------------------------|---------------------------------------------------------------------|
| Public API entry point | `src/Aspire.Hosting/TerminalResourceBuilderExtensions.cs` |
| Per-resource hidden host resource | `src/Aspire.Hosting/ApplicationModel/TerminalHostResource.cs` |
| DCP wire-up | `src/Aspire.Hosting/Dcp/ExecutableCreator.cs` |
| Backchannel `GetTerminalInfoAsync` | `src/Aspire.Hosting/Backchannel/AuxiliaryBackchannelRpcTarget.cs` |
| Snapshot stamping | `src/Aspire.Hosting/Dashboard/DashboardServiceData.cs` |
| TerminalHost process | `src/Aspire.TerminalHost/` |
| CLI command | `src/Aspire.Cli/Commands/TerminalCommand.cs` |
| Dashboard WebSocket proxy | `src/Aspire.Dashboard/Terminal/TerminalWebSocketProxy.cs` |
| Dashboard resolver | `src/Aspire.Dashboard/Terminal/DefaultTerminalConnectionResolver.cs`|
| `TerminalView` (xterm.js host) | `src/Aspire.Dashboard/Components/Controls/TerminalView.razor.*` |
| Property keys | `src/Shared/Model/KnownProperties.cs` (`Terminal.*`) |
| Playground sample | `playground/Terminals/Terminals.AppHost/AppHost.cs` |
14 changes: 10 additions & 4 deletions eng/Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
BuildTestsOnly - if 'true', builds only test projects, defaults to 'false'
SkipTestProjects - if 'true', skips building test projects, defaults to 'false'
SkipPlaygroundProjects - if 'true', skips building playground projects, defaults to 'false'
SkipBundleDeps - if 'true', skips building eng/dcppack, eng/dashboardpack, Aspire.Dashboard, and Aspire.Cli projects during the main managed build, defaults to 'false'
BuildBundleDepsOnly - if 'true', builds only the RID-specific eng/dcppack and eng/dashboardpack projects for $(TargetRids), plus Aspire.Dashboard for restore, defaults to 'false'
SkipBundleDeps - if 'true', skips building eng/dcppack, eng/dashboardpack, eng/terminalhostpack, Aspire.Dashboard, Aspire.TerminalHost, and Aspire.Cli projects during the main managed build, defaults to 'false'
BuildBundleDepsOnly - if 'true', builds only the RID-specific eng/dcppack, eng/dashboardpack, and eng/terminalhostpack projects for $(TargetRids), plus Aspire.Dashboard and Aspire.TerminalHost for restore, defaults to 'false'
TargetRids - colon separated list of RIDs to build native projects for
-->

Expand All @@ -23,21 +23,25 @@
<TargetRids Condition="'$(TargetRids)' == ''">$(BuildRid)</TargetRids>
</PropertyGroup>

<!-- `$(BuildBundleDepsOnly)` builds only the RID-specific DCP and Dashboard packaging projects
<!-- `$(BuildBundleDepsOnly)` builds only the RID-specific DCP, Dashboard, and TerminalHost packaging projects
needed by the CLI bundle for $(TargetRids). This allows the CLI native archive build to
produce these packages independently without waiting for the full build_packages job. -->
<ItemGroup Condition="'$(BuildBundleDepsOnly)' == 'true'">
<_BundleDependencyTargetRid Include="$(TargetRids.Split(':'))" />
<_BundleDependencyProject Include="@(_BundleDependencyTargetRid -> '$(RepoRoot)eng\dcppack\Aspire.Hosting.Orchestration.%(Identity).csproj')" />
<_BundleDependencyProject Include="@(_BundleDependencyTargetRid -> '$(RepoRoot)eng\dashboardpack\Aspire.Dashboard.Sdk.%(Identity).csproj')" />
<_BundleDependencyProject Include="@(_BundleDependencyTargetRid -> '$(RepoRoot)eng\terminalhostpack\Aspire.TerminalHost.Sdk.%(Identity).csproj')" />
<ProjectToBuild Include="@(_BundleDependencyProject->Exists())" />
<!-- Dashboard is invoked by dashboardpack via MSBuild task (not ProjectReference),
so it must be explicitly included to ensure restore generates its assets file. -->
<ProjectToBuild Include="$(RepoRoot)src\Aspire.Dashboard\Aspire.Dashboard.csproj" />
<!-- TerminalHost is invoked by terminalhostpack via MSBuild task (not ProjectReference),
so it must be explicitly included to ensure restore generates its assets file. -->
<ProjectToBuild Include="$(RepoRoot)src\Aspire.TerminalHost\Aspire.TerminalHost.csproj" />
</ItemGroup>

<!-- `$(BuildTestsOnly)` allows building only test projects, skipping the following directories:
src, playground, eng/dcppack, and eng/dashboardpack. This is useful for reducing disk space
src, playground, eng/dcppack, eng/dashboardpack, and eng/terminalhostpack. This is useful for reducing disk space
usage when only test projects need to be built, such as during test runsheet generation. -->
<ItemGroup Condition="'$(SkipManagedBuild)' != 'true' and '$(BuildTestsOnly)' != 'true' and '$(BuildBundleDepsOnly)' != 'true'">
<!-- Project name validation runs once in the outer build -->
Expand All @@ -48,8 +52,10 @@
<ProjectToBuild Remove="$(RepoRoot)src\Aspire.Cli\Aspire.Cli.Tool.csproj" />
<ProjectToBuild Remove="$(RepoRoot)src\Aspire.Cli\Aspire.Cli.csproj" Condition="'$(SkipBundleDeps)' == 'true'" />
<ProjectToBuild Remove="$(RepoRoot)src\Aspire.Dashboard\Aspire.Dashboard.csproj" Condition="'$(SkipBundleDeps)' == 'true'" />
<ProjectToBuild Remove="$(RepoRoot)src\Aspire.TerminalHost\Aspire.TerminalHost.csproj" Condition="'$(SkipBundleDeps)' == 'true'" />
<ProjectToBuild Include="$(RepoRoot)eng\dcppack\**\*.csproj" Condition="'$(SkipBundleDeps)' != 'true'" />
<ProjectToBuild Include="$(RepoRoot)eng\dashboardpack\**\*.csproj" Condition="'$(SkipBundleDeps)' != 'true'" />
<ProjectToBuild Include="$(RepoRoot)eng\terminalhostpack\**\*.csproj" Condition="'$(SkipBundleDeps)' != 'true'" />

<!-- Exclude only the MAUI client project as it requires the .NET MAUI workload.
Other projects in the AspireWithMaui playground can still be built.
Expand Down
7 changes: 7 additions & 0 deletions eng/Publishing.props
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
Pulling it in here will cause different issues as that file will conflict with Arcade's publishing logic, so as a workaround we define it here.
If you are editing this property, make sure to also edit the one in Directory.Build.props. -->
<DashboardPublishedArtifactsOutputDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'DashboardArtifacts', '$(Configuration)'))</DashboardPublishedArtifactsOutputDir>
<TerminalHostPublishedArtifactsOutputDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'TerminalHostArtifacts', '$(Configuration)'))</TerminalHostPublishedArtifactsOutputDir>
</PropertyGroup>

<ItemGroup>
<_InstallersToPublish Include="$(ArtifactsDir)**\*.wixpack.zip" Condition="'$(PostBuildSign)' == 'true'" />
<_InstallerManifestFilesToPublish Include="$(ArtifactsDir)VSSetup\$(Configuration)\Insertion\**\*.zip" />
<_DashboardFilesToPublish Include="$(DashboardPublishedArtifactsOutputDir)\**\*.zip" />
<_TerminalHostFilesToPublish Include="$(TerminalHostPublishedArtifactsOutputDir)\**\*.zip" />
<_CliInstallScriptsToPublish Include="$(RepoRoot)eng\scripts\get-aspire-cli.sh" />
<_CliInstallScriptsToPublish Include="$(RepoRoot)eng\scripts\get-aspire-cli.ps1" />
</ItemGroup>
Expand Down Expand Up @@ -168,6 +170,11 @@
<PublishFlatContainer>true</PublishFlatContainer>
<RelativeBlobPath>$(_UploadPathRoot)/$(_PackageVersion)/%(Filename)%(Extension)</RelativeBlobPath>
</ItemsToPushToBlobFeed>
<ItemsToPushToBlobFeed Include="@(_TerminalHostFilesToPublish)">
<IsShipping>true</IsShipping>
<PublishFlatContainer>true</PublishFlatContainer>
<RelativeBlobPath>$(_UploadPathRoot)/$(_PackageVersion)/%(Filename)%(Extension)</RelativeBlobPath>
</ItemsToPushToBlobFeed>
<ItemsToPushToBlobFeed Include="@(_CliFileToPublish)">
<IsShipping>false</IsShipping>
<PublishFlatContainer>true</PublishFlatContainer>
Expand Down
Loading
Loading