Skip to content

Add Aspire-owned terminal service and dashboard terminal experience #19888

Description

@copilot-swe-agent

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 #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.
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 aspireCLI from the same bundle as the dashboard, enabling commands such asaspire 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions