microsoft / microsoft/aspire

Add Aspire-owned terminal service and dashboard terminal experience

Closed
#19,888 0 comments 0 reactions 1 assignee Claimed by @mitchdenny View on GitHub
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 12h
Merged PRs (30d)
201

Description

## Summary

Add an Aspire-owned terminal abstraction and dashboard experience that supports interactive login/setup flows, resource terminals, container shells, automation, and an Aspire dashboard shell.

The implementation spike in https://github.com/microsoft/aspire/pull/19887 proves the end-to-end transport and initial dashboard UX. This issue tracks turning that spike into a supported design without exposing Hex1b types in Aspire's public API.

## Scenarios

There are three related but distinct terminal experiences:

1. **Terminal as a resource's primary experience** — attach to a resource that is itself a TUI or REPL so it can be used and tested from the dashboard.
2. **Terminal attached to an interaction** — briefly expose a running process when the user must observe or interact with it, especially CLI login, consent, and setup flows such as `az login`, `az acr login`, or `devtunnel user login`.
3. **Persistent terminal panel** — open an AppHost shell, shell into a container, or attach to another resource for investigation. This is not a modal interaction and persists while the user moves around the dashboard.

The login scenario is the first integration to validate. Many login CLIs update global state, so completing the flow once allows later invocations to continue without another prompt. Dev tunnels should be an initial end-to-end use case, including selecting or logging into the appropriate provider for tunnel authorization.

## Proposed architecture

### `TerminalService`

Introduce a terminal service, initially internal while the API is refined, with the intent to make it public once its shape is proven.

The service should support both terminal sources:

- Launch a new process attached to a PTY, e.g. `CreateTerminal(processStartInfo)`.
- Resolve an `IAspireTerminal` for a DCP-managed resource terminal so the same viewing and automation APIs work for resources Aspire already orchestrates.

```csharp
IAspireTerminal terminal = terminalService.CreateTerminal(
new AspireTerminalProcessOptions
{
FileName = "devtunnel",
Arguments = ["user", "login"],
WorkingDirectory = appHostDirectory,
EnvironmentVariables = environmentVariables,
Columns = 120,
Rows = 32
});

await terminal.ShowAsync(
new AspireTerminalDisplayOptions
{
Title = "Dev tunnel login"
},
cancellationToken);
```

Names and exact signatures are illustrative. The API should model terminal creation and capabilities rather than leak the underlying implementation.

### `IAspireTerminal`

`IAspireTerminal` abstracts Hex1b and owns terminal lifetime, state, input, output, and automation. The initial automation surface should include:

- Wait for visible text with timeout/cancellation.
- Send text and common keys such as Enter, Escape, Tab, and Ctrl+C.
- Observe process exit and exit code.
- Resize the terminal.
- Show or focus the terminal in the dashboard.

The Aspire API should intentionally remain smaller than Hex1b's full terminal model. Rich 2D cell searches and other Hex1b-specific functionality should stay internal; an escape hatch can be considered for first-party or advanced scenarios without putting Hex1b types in Aspire's public signatures.

The same `IAspireTerminal` instance must be usable by a person in the dashboard, the Aspire CLI, or an agent so application code does not need separate human and automation paths.

### Interaction service integration

The interaction service should accept or reference an `IAspireTerminal` for short-lived, contextual interactions. The terminal session belongs to `TerminalService`; the interaction controls when and where it is shown rather than defining the low-level terminal implementation.

This is intended for flows that block an operation until the user completes a CLI prompt. It is separate from the persistent terminal panel and from a resource whose terminal is its primary experience.

### Resource integration

Define a capability/interface that resources can implement to advertise terminal support. A container resource is the first motivating example: implementing the capability adds the appropriate command and enables a shell experience without hard-coding container behavior into the dashboard.

The same model should cover DCP-attached terminals and may apply to any resource that can provide a terminal, not only containers.

## Dashboard UX

Add a non-modal terminal panel at the bottom of the dashboard:

- Open/focus it with `Ctrl+``.
- Support tabs for multiple terminal sessions.
- Allow collapse, docking, and detaching into a separate window.
- Keep sessions and Hex1b terminal state alive while navigating around the dashboard.
- Let `IAspireTerminal.ShowAsync(...)` reveal or focus a session.

If `Ctrl+`` is pressed when no terminal is running, start an **Aspire Shell** in the AppHost working directory. The shell should use the `aspire` CLI from the same bundle as the dashboard, enabling commands such as `aspire describe` against the current application.

A Hex1b-based Aspire REPL may back this experience and could potentially be shared with a future `aspire repl` CLI command, but that reuse is exploratory rather than a requirement for the first version.

## Lifecycle and security

- AppHost-owned processes start lazily or explicitly through automation and are cleaned up deterministically on completion, cancellation, or AppHost shutdown.
- Persistent panel sessions survive dashboard navigation and can be reattached without losing terminal state.
- Multiple viewers may observe a session; input must be serialized through the single terminal instance.
- Startup failures and non-zero exits are surfaced rather than converted into successful interaction results.
- Terminal output is not persisted by default because it may contain credentials or other sensitive data.
- Remote terminal access through a tunneled dashboard must rely on the dashboard/dev-tunnel authorization boundary and must not bypass it.
- Process launch, PTY management, HMP1, and Hex1b remain behind Aspire-owned abstractions.

## Acceptance criteria

- An AppHost can run an interactive login CLI and display it in the dashboard through the interaction service.
- Dev tunnel login is validated as an end-to-end scenario, including the resulting global login state being usable by later invocations.
- The Aspire public API does not expose Hex1b types.
- AppHost-owned and DCP-attached terminals share the `IAspireTerminal` abstraction and automation surface.
- A capable resource, initially a container, can expose a persistent shell through a resource capability/interface.
- The dashboard provides a persistent, tabbed, non-modal terminal panel that preserves state across navigation.
- `Ctrl+`` opens the panel and starts/focuses Aspire Shell when appropriate.
- A minimal automation client can wait for prompt text and send text/keys to the same session a human can view.
- Cancellation, completion, process exit, reconnect, and AppHost shutdown clean up sessions and child processes deterministically.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.