Migrate dashboard terminals from xterm.js to Hex1b web terminal - #19974
Migrate dashboard terminals from xterm.js to Hex1b web terminal#19974Mitch Denny (mitchdenny) wants to merge 11 commits into
Conversation
Pair the published HWT1 browser client with Hex1b, preserve remote terminal ownership and graphics state, and isolate terminal shadow-DOM keyboard input from dashboard shortcuts. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6019354f-1f14-4f5b-9068-1179bc66b58e
Pair Hex1b and @hex1b/web-terminal at 0.167.0-alpha.1519.1.b8be265. Enable package-owned automatic renderer selection and safe OSC 8 hyperlinks, including destinations restored across reconnect. Regenerate the complete browser distribution and update localized errors, documentation, and targeted regression coverage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6019354f-1f14-4f5b-9068-1179bc66b58e
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 19974Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 19974" |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The broad browser-terminal migration has unresolved moderate CI, regression-coverage, and shortcut-handling issues requiring human review.
Review tier: Balanced
Findings: 3
New issues introduced by this change (3)
| Severity | Finding |
|---|---|
eng/github-ci/test-trigger-map.yml — This new Layer 2 routing rule has no focused real-map selector test, so a later edit can silently… |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — The tests added here mock WebTerminal.mount, so they cannot catch failures in the new… |
|
src/Aspire.Dashboard/wwwroot/js/app.js — Following shadowRoot.activeElement before evaluating the host bypasses the existing… |
What changed in this PR
Migrates dashboard terminals from xterm.js to the GPU-backed Hex1b web terminal while preserving reconnect, input, resize, graphics, and hyperlink behavior.
Changes:
- Adds the HMP1-to-HWT1 bridge and Hex1b terminal integration.
- Vendors pinned browser assets and removes obsolete xterm.js assets.
- Adds component, protocol, JavaScript, localization, asset-verification, and CI coverage.
| File | Description |
|---|---|
tests/Infrastructure.Tests/WorkflowScripts/DashboardTerminalScriptTests.cs |
Runs terminal asset script regressions. |
tests/Aspire.Dashboard.Tests/Shared/TerminalTestHost.cs |
Provides the terminal integration test host. |
tests/Aspire.Dashboard.Components.Tests/Shared/TestNavigationManager.cs |
Supports navigation and PathBase tests. |
tests/Aspire.Dashboard.Components.Tests/Pages/ConsoleLogsTerminalTests.cs |
Updates terminal page coverage. |
tests/Aspire.Dashboard.Components.Tests/JavaScript/KeyboardShortcuts.test.mjs |
Tests shadow-DOM shortcut handling. |
tests/Aspire.Dashboard.Components.Tests/Controls/TerminalViewTests.cs |
Tests terminal lifecycle and errors. |
src/Aspire.Dashboard/wwwroot/js/xterm/xterm.min.css |
Removes obsolete xterm styling. |
src/Aspire.Dashboard/wwwroot/js/xterm/addon-fit.min.js |
Removes the obsolete xterm fit add-on. |
src/Aspire.Dashboard/wwwroot/js/README.md |
Documents terminal assets and compatibility. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/package.json |
Vendors Hex1b package metadata. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/LICENSE |
Vendors the Hex1b license. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/wire-types.js.map |
Vendors the wire-types source map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/wire-types.js |
Vendors emitted wire types. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/wire-types.d.ts |
Vendors wire-type declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/webgpu-backend.d.ts.map |
Vendors the WebGPU declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/webgpu-backend.d.ts |
Vendors WebGPU declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/webgl2-backend.d.ts.map |
Vendors the WebGL2 declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/webgl2-backend.d.ts |
Vendors WebGL2 declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/web-terminal.d.ts.map |
Vendors the terminal API declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/web-terminal.d.ts |
Vendors terminal API declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/validation.js.map |
Vendors the validation source map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/validation.js |
Vendors validation helpers. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/validation.d.ts.map |
Vendors the validation declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/validation.d.ts |
Vendors validation declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/types.js |
Vendors emitted public types. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-worker.d.ts.map |
Vendors the worker declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-worker.d.ts |
Vendors worker declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-theme.js.map |
Vendors the theme source map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-theme.js |
Vendors terminal theme support. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-theme.d.ts.map |
Vendors the theme declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-theme.d.ts |
Vendors theme declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-sizing.js.map |
Vendors the sizing source map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-sizing.js |
Vendors terminal sizing logic. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-sizing.d.ts.map |
Vendors the sizing declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-sizing.d.ts |
Vendors sizing declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-font.js |
Vendors terminal font loading. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-font.d.ts.map |
Vendors the font declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/terminal-font.d.ts |
Vendors font declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/selection-ui.js |
Vendors terminal selection UI. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/selection-ui.d.ts.map |
Vendors the selection UI declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/selection-ui.d.ts |
Vendors selection UI declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/selection-input.js |
Vendors selection input handling. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/selection-input.d.ts.map |
Vendors the selection-input declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/selection-input.d.ts |
Vendors selection-input declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/renderer.d.ts.map |
Vendors the renderer declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/renderer.d.ts |
Vendors renderer declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/renderer-options.js.map |
Vendors the renderer-options source map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/renderer-options.js |
Vendors renderer option validation. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/renderer-options.d.ts.map |
Vendors the renderer-options declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/renderer-options.d.ts |
Vendors renderer-option declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/render-backend.js.map |
Vendors the render-backend source map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/render-backend.js |
Vendors renderer abstractions. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/render-backend.d.ts.map |
Vendors the render-backend declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/render-backend.d.ts |
Vendors render-backend declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/protocol.d.ts.map |
Vendors the protocol declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/protocol.d.ts |
Vendors protocol declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/mouse-input.d.ts.map |
Vendors the mouse-input declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/mouse-input.d.ts |
Vendors mouse-input declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/input-policy.js |
Vendors input routing policy. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/input-policy.d.ts.map |
Vendors the input-policy declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/input-policy.d.ts |
Vendors input-policy declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/index.js.map |
Vendors the public entry source map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/index.js |
Vendors the public module entry. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/index.d.ts.map |
Vendors the public API declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/index.d.ts |
Vendors public API declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/hyperlinks.js.map |
Vendors the hyperlink source map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/hyperlinks.js |
Vendors safe hyperlink handling. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/hyperlinks.d.ts.map |
Vendors the hyperlink declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/hyperlinks.d.ts |
Vendors hyperlink declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/history-state.d.ts.map |
Vendors the history-state declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/history-state.d.ts |
Vendors history-state declarations. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/fonts/cascadia-mono-nf/README.md |
Vendors terminal font provenance. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/fonts/cascadia-mono-nf/LICENSE.txt |
Vendors the terminal font license. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/backend-selection.js.map |
Vendors the backend-selection source map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/backend-selection.js |
Vendors GPU backend selection. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/backend-selection.d.ts.map |
Vendors the backend-selection declaration map. |
src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/dist/backend-selection.d.ts |
Vendors backend-selection declarations. |
src/Aspire.Dashboard/wwwroot/js/app.js |
Updates shortcut handling for shadow DOM. |
src/Aspire.Dashboard/wwwroot/fonts/cascadia-mono-nf/README.md |
Removes obsolete font metadata. |
src/Aspire.Dashboard/Terminal/DefaultTerminalConnectionResolver.cs |
Updates terminal transport documentation. |
src/Aspire.Dashboard/scripts/verify-terminal-assets.mjs |
Verifies vendored package bytes. |
src/Aspire.Dashboard/scripts/update-terminal-assets.mjs |
Reproducibly updates vendored assets. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hant.xlf |
Updates Traditional Chinese localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.zh-Hans.xlf |
Updates Simplified Chinese localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.tr.xlf |
Updates Turkish localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ru.xlf |
Updates Russian localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pt-BR.xlf |
Updates Portuguese localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.pl.xlf |
Updates Polish localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ko.xlf |
Updates Korean localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.ja.xlf |
Updates Japanese localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.it.xlf |
Updates Italian localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.fr.xlf |
Updates French localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.es.xlf |
Updates Spanish localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.de.xlf |
Updates German localization. |
src/Aspire.Dashboard/Resources/xlf/ConsoleLogs.cs.xlf |
Updates Czech localization. |
src/Aspire.Dashboard/Resources/ConsoleLogs.resx |
Adds terminal labels and errors. |
src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs |
Adds generated terminal resource accessors. |
src/Aspire.Dashboard/package.json |
Adds Hex1b and asset scripts. |
src/Aspire.Dashboard/package-lock.json |
Locks the paired Hex1b package. |
src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs |
Updates terminal page behavior. |
src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor |
Integrates the migrated terminal view. |
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.css |
Styles the terminal and error states. |
src/Aspire.Dashboard/Components/Controls/TerminalView.razor |
Hosts the Hex1b terminal UI. |
src/Aspire.Dashboard/Aspire.Dashboard.csproj |
Configures terminal assets for publishing. |
eng/github-ci/test-trigger-map.yml |
Adds terminal-related CI routing. |
docs/specs/with-terminal.md |
Documents architecture and browser requirements. |
Directory.Packages.props |
Pins the paired Hex1b version. |
Files not reviewed (2)
- src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs: Generated file
- src/Aspire.Dashboard/package-lock.json: Generated file
Suppressed comments (1)
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js:143
- This integration leaves several user-visible strings inside the terminal unlocalized. The package's default shadow-DOM UI renders
Copy,Copying…,Return to live, and “N rows above live” (dist/web-terminal.js:168-169, 436-438anddist/selection-ui.js:107), while this adapter localizes only the textarea label. That means non-English dashboard users now get English controls/status text; provide localized strings/custom host UI (or add an upstream localization hook) before enabling the default UI.
const client = await WebTerminal.mount(state.element, {
url: state.wsUrl,
signal: controller.signal,
label: state.label,
sizing: state.sizing,
| - paths: | ||
| - src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js | ||
| - src/Aspire.Dashboard/wwwroot/js/app.js | ||
| - src/Aspire.Dashboard/package.json | ||
| - src/Aspire.Dashboard/package-lock.json | ||
| - src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/** | ||
| - tests/Aspire.Dashboard.Components.Tests/JavaScript/** | ||
| targets: [test:Infrastructure.Tests] |
| const client = await WebTerminal.mount(state.element, { | ||
| url: state.wsUrl, | ||
| signal: controller.signal, | ||
| label: state.label, | ||
| sizing: state.sizing, | ||
| // Let the package fall back to WebGL2 for unavailable WebGPU | ||
| // capabilities, including ordinary HTTP. Other initialization | ||
| // errors and runtime GPU loss must still surface as failures. | ||
| // https://github.com/mitchdenny/hex1b/pull/491 | ||
| renderer: "auto", |
| while (currentElement.shadowRoot?.activeElement) { | ||
| currentElement = currentElement.shadowRoot.activeElement; |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Use the exact paired npm and NuGet release containing retained KGP image and partial ANSI checkpoint replay fixes. Cover late viewers, reconnects, placement-only animation, and split graphics commands through the dashboard bridge. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6019354f-1f14-4f5b-9068-1179bc66b58e
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Moderate accessibility and CI-routing regression coverage issues remain unresolved.
Review tier: Balanced
Findings: 3
Pre-existing issues (3)
| Severity | Finding |
|---|---|
src/Aspire.Dashboard/wwwroot/js/app.js — Following shadowRoot.activeElement before evaluating the host bypasses the existing… View comment |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — The tests added here mock WebTerminal.mount, so they cannot catch failures in the new… View comment |
|
eng/github-ci/test-trigger-map.yml — This new Layer 2 routing rule has no focused real-map selector test, so a later edit can silently… View comment |
Files not reviewed (2)
- src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs: Generated file
- src/Aspire.Dashboard/package-lock.json: Generated file
Suppressed comments (2)
eng/github-ci/test-trigger-map.yml:106
- This adds curated selector behavior without a focused real-map regression in
TestTriggerMapTests.AuditedLoosePathCases. Add representative terminal adapter, vendored asset, and JavaScript-test paths asserting the exacttest:Infrastructure.Teststarget so future glob or target changes cannot silently fall back toALLor stop selecting the Node regressions.
- paths:
- src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js
- src/Aspire.Dashboard/wwwroot/js/app.js
- src/Aspire.Dashboard/package.json
- src/Aspire.Dashboard/package-lock.json
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js:143
- This mount localizes only the hidden input label, but the enabled package UI still renders hard-coded English text such as “Copy”, “Copying…”, “Return to live”, “N rows above live”, and the hyperlink hint (
dist/web-terminal.js:167-169,dist/selection-ui.js:107,dist/mouse-input.js:42). This violates the dashboard’s localization pattern used for the surrounding terminal controls and errors; provide localized package strings or a dashboard-owned localized UI before shipping.
const client = await WebTerminal.mount(state.element, {
url: state.wsUrl,
signal: controller.signal,
label: state.label,
sizing: state.sizing,
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6019354f-1f14-4f5b-9068-1179bc66b58e
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Browser-only coverage and recoverable error handling remain unresolved on the sole terminal UI path.
Review tier: Balanced
Findings: 3
Pre-existing issues (3)
| Severity | Finding |
|---|---|
src/Aspire.Dashboard/wwwroot/js/app.js — Following shadowRoot.activeElement before evaluating the host bypasses the existing… View comment |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — The tests added here mock WebTerminal.mount, so they cannot catch failures in the new… View comment |
|
eng/github-ci/test-trigger-map.yml — This new Layer 2 routing rule has no focused real-map selector test, so a later edit can silently… View comment |
Files not reviewed (2)
- src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs: Generated file
- src/Aspire.Dashboard/package-lock.json: Generated file
Suppressed comments (3)
Previously missed (2) — in code that hasn't changed since the last review.
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js:188
- After
onInputErrorsets this state, no successful input or clipboard callback clears it; the only general clearing paths remount/reconnect the terminal. A transient clipboard denial therefore leaves the error banner visible indefinitely even after the user retries successfully. Add a dismiss/expiry or a success-state callback so recoverable input errors can clear without reconnecting the terminal.
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js:143 - The default
WebTerminalinspection UI introduced here renders user-visible English strings such as “Copy”, “Return to live”, and “N rows above live” inside its shadow DOM (selection-ui.js/web-terminal.js). No localized labels or replacement UI are supplied, so these controls bypass the dashboard’s localization resources for every non-English culture. Please add a package localization contract (or fully replace the default inspection UI) and source these labels from the dashboard resources.
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js:148
- The Node lifecycle tests replace
WebTerminal.mount, so they never exercise the real module worker, transferableOffscreenCanvas, static-asset/CSP loading, or either GPU renderer. This migration removes the xterm fallback and makes those browser-only paths the sole terminal UI; add focused Dashboard Playwright coverage that mounts the real client (at least through WebGL2) and verifies rendering/input/reconnect.
// Let the package fall back to WebGL2 for unavailable WebGPU
// capabilities, including ordinary HTTP. Other initialization
// errors and runtime GPU loss must still surface as failures.
// https://github.com/mitchdenny/hex1b/pull/491
renderer: "auto",
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6019354f-1f14-4f5b-9068-1179bc66b58e
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The broad terminal migration has unresolved CI-routing and localization concerns requiring human review.
Review tier: Balanced
Findings: 3
Pre-existing issues (3)
| Severity | Finding |
|---|---|
src/Aspire.Dashboard/wwwroot/js/app.js — Following shadowRoot.activeElement before evaluating the host bypasses the existing… View comment |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — The tests added here mock WebTerminal.mount, so they cannot catch failures in the new… View comment |
|
eng/github-ci/test-trigger-map.yml — This new Layer 2 routing rule has no focused real-map selector test, so a later edit can silently… View comment |
Files not reviewed (2)
- src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs: Generated file
- src/Aspire.Dashboard/package-lock.json: Generated file
Suppressed comments (2)
eng/github-ci/test-trigger-map.yml:110
- This new Layer 2 routing rule has no focused real-map regression case, so a later glob/target change can silently stop running the Node suite. Add a representative terminal asset/script path and the expected
test:Infrastructure.Teststarget toTestTriggerMapTests.AuditedLoosePathCases(the existing convention attests/Infrastructure.Tests/TestTriggerMap/TestTriggerMapTests.cs:361-385).
- paths:
- src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js
- src/Aspire.Dashboard/wwwroot/js/app.js
- src/Aspire.Dashboard/package.json
- src/Aspire.Dashboard/package-lock.json
- src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/**
- tests/Aspire.Dashboard.Components.Tests/JavaScript/**
targets: [test:Infrastructure.Tests]
reason: DashboardTerminalScriptTests executes the terminal lifecycle JavaScript and reads the paired package assets outside its MSBuild graph.
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js:143
- Mounting with the package's default selection/hyperlink UI introduces user-visible English-only text (
Copy/Copying…inselection-ui.js:107andCtrl/Cmd+click to open linkinmouse-input.js:42). The surrounding dashboard terminal UI localizes its labels throughConsoleLogs.resxand even passes a localized input label here (TerminalView.razor.cs:80,215-217). Please expose/localize these package strings (or own the selection UI) before embedding it so non-English dashboard cultures do not get mixed-language controls.
const client = await WebTerminal.mount(state.element, {
url: state.wsUrl,
signal: controller.signal,
label: state.label,
sizing: state.sizing,
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Moderate CI-routing, browser-integration, and shortcut issues remain, along with TerminalHost ownership wording nits.
Review tier: Balanced
Findings: 4
Pre-existing issues (4)
| Severity | Finding |
|---|---|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — This migration leaves terminal output inaccessible to screen readers: the mounted client renders… View comment |
|
src/Aspire.Dashboard/wwwroot/js/app.js — Following shadowRoot.activeElement before evaluating the host bypasses the existing… View comment |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — The tests added here mock WebTerminal.mount, so they cannot catch failures in the new… View comment |
|
eng/github-ci/test-trigger-map.yml — This new Layer 2 routing rule has no focused real-map selector test, so a later edit can silently… View comment |
Files not reviewed (2)
- src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs: Generated file
- src/Aspire.Dashboard/package-lock.json: Generated file
Suppressed comments (5)
eng/github-ci/test-trigger-map.yml:109
- This curated routing change has no focused real-map regression test. The existing structural checks only prove that the glob matches files and the target exists; they would not catch these dashboard paths being routed to the wrong test project. Add an audited loose-path case in
TestTriggerMapTeststhat asserts representative adapter, package, and vendored-asset paths selecttest:Infrastructure.Tests.
- paths:
- src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js
- src/Aspire.Dashboard/wwwroot/js/app.js
- src/Aspire.Dashboard/package.json
- src/Aspire.Dashboard/package-lock.json
- src/Aspire.Dashboard/wwwroot/js/hex1b-web-terminal/**
- tests/Aspire.Dashboard.Components.Tests/JavaScript/**
targets: [test:Infrastructure.Tests]
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js:267
- The new worker/GPU/shadow-DOM clipboard integration is covered only by Node mocks and bUnit; the existing dashboard Playwright suite has no terminal scenario. Failures in actual module-worker creation, OffscreenCanvas transfer, WebGL2 fallback, or browser focus/clipboard behavior would therefore pass CI. Add focused Playwright smoke coverage that mounts the terminal and exercises the browser integration path.
const client = await WebTerminal.mount(state.element, {
url: state.wsUrl,
signal: controller.signal,
label: state.label,
sizing: state.sizing,
onSelectionUI: createSelectionUI(state, current),
src/Aspire.Dashboard/Terminal/TerminalWebSocketProxy.cs:14
- This endpoint serves
WithTerminal()sessions brokered by the per-replicaAspire.TerminalHost; it is not the AppHost-owned terminal model from the unrelated spike. Calling it AppHost-owned makes the ownership and disposal boundary misleading. Describe it as TerminalHost-brokered instead.
/// Presents an AppHost-owned HMP1 terminal to a browser using Hex1b's HWT1 adapter.
src/Aspire.Dashboard/Terminal/TerminalWebSocketProxy.cs:183
- The upstream terminal session is brokered by the per-replica
Aspire.TerminalHost, not owned by the AppHost. This wording obscures which process survives when the browser mirror is disposed; use the TerminalHost ownership boundary here as well.
// disposing it disconnects the peer, not the AppHost-owned terminal.
src/Aspire.Dashboard/wwwroot/js/app.js:208
- Descending into the focused shadow root before preserving the host classification regresses the existing
fluent-selecthandling. When a Fluent select delegates focus to an internal button/div,currentElementbecomes that internal control, so line 213 returns false and printable keys such asr,s, ormtrigger dashboard navigation while the select is active. Check a focused Fluent host withisInputElementbefore descending, and add a Fluent-select/internal-control case to the shortcut test.
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Review feedback on the PR: the discovery helper added to BundleDiscovery is not connected to any production runtime path. That is correct — there is no caller, because the types that would consume it (TerminalService / Hex1bTerminalProcessOptions) have not landed yet. Shipping an unused API into the three assemblies that source-link BundleDiscovery is not worth it, so remove it along with the test that covered only that helper. Bundle-relative discovery belongs with the change that actually calls it, which issue microsoft#19976 already sequences after microsoft#19974/microsoft#19887. This leaves the PR to the part that stands on its own: publish, sign, and stage hex1bpty.exe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PW1pn92QD5DQ94i8ML1XJD
Refresh the complete published browser distribution and version documentation. Drain complete WebSocket snapshots in the disconnect regression test rather than assuming a snapshot fits one receive buffer. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6019354f-1f14-4f5b-9068-1179bc66b58e
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Deterministic renderer failures reconnect-loop, OSC title behavior is lost, and the documented compatibility and existing review gates remain unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 6
New issues introduced by this change (2)
| Severity | Finding |
|---|---|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor — This drops the existing OSC 0/1/2 title behavior: the header is now always ResourceName, even… |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — Every mount failure is retried, including deterministic capability, font, worker, and GPU… |
Pre-existing issues (4)
| Severity | Finding |
|---|---|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — This migration leaves terminal output inaccessible to screen readers: the mounted client renders… View comment |
|
src/Aspire.Dashboard/wwwroot/js/app.js — Following shadowRoot.activeElement before evaluating the host bypasses the existing… View comment |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — The tests added here mock WebTerminal.mount, so they cannot catch failures in the new… View comment |
|
eng/github-ci/test-trigger-map.yml — This new Layer 2 routing rule has no focused real-map selector test, so a later edit can silently… View comment |
Files not reviewed (2)
- src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs: Generated file
- src/Aspire.Dashboard/package-lock.json: Generated file
| </div> | ||
| <div class="terminal-frame"> | ||
| <div class="terminal-titlebar"> | ||
| <span class="terminal-title">@(ResourceName ?? Loc[nameof(Resources.ConsoleLogs.ConsoleLogsViewTerminalOption)].Value)</span> |
| state.pendingSizing = null; | ||
| releaseClient(state); | ||
| notifyToolbar(state); | ||
| scheduleReconnect(state, generation); |
Adapt terminal controls and theme tokens to Fluent UI v5, and preserve dropdown and terminal keyboard focus handling. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6019354f-1f14-4f5b-9068-1179bc66b58e
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Alt-selection routing, workload title integration, and repeatable browser coverage remain unresolved, with additional compatibility gates still open.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 6
New issues introduced by this change (1)
| Severity | Finding |
|---|---|
src/Aspire.Dashboard/wwwroot/js/README.md — This leaves the browser-only migration without repeatable browser coverage. The PR's… |
Pre-existing issues (6)
| Severity | Finding |
|---|---|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — Every mount failure is retried, including deterministic capability, font, worker, and GPU… View comment |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor — This drops the existing OSC 0/1/2 title behavior: the header is now always ResourceName, even… View comment |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — This migration leaves terminal output inaccessible to screen readers: the mounted client renders… View comment |
|
src/Aspire.Dashboard/wwwroot/js/app.js — Following shadowRoot.activeElement before evaluating the host bypasses the existing… View comment |
|
src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js — The tests added here mock WebTerminal.mount, so they cannot catch failures in the new… View comment |
|
eng/github-ci/test-trigger-map.yml — This new Layer 2 routing rule has no focused real-map selector test, so a later edit can silently… View comment |
Files not reviewed (2)
- src/Aspire.Dashboard/Resources/ConsoleLogs.Designer.cs: Generated file
- src/Aspire.Dashboard/package-lock.json: Generated file
Suppressed comments (1)
src/Aspire.Dashboard/Components/Controls/TerminalView.razor:17
- The title-update merge gate remains unmet: this always renders the static resource name even though the paired client now exposes current title and
onTitleChange, so OSC title updates never reach the dashboard header. Propagate title notifications through the adapter/component state and use the resource name only when the workload title is empty.
<span class="terminal-title">@(ResourceName ?? Loc[nameof(Resources.ConsoleLogs.ConsoleLogsViewTerminalOption)].Value)</span>
| state, PathBase asset URLs, deployment asset presence, and exact version parity | ||
| between `Directory.Packages.props`, the npm manifest/lockfile, and the vendored | ||
| package. Complete installed-package byte comparison belongs to the separate | ||
| acquisition verification command above. Neither suite substitutes for a browser |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |


Summary
Replace the dashboard's xterm.js terminal with Hex1b for Sixel/KGP graphics, replay on reconnect, OSC 8 links and selection-adjacent copy controls. Copying returns focus to the terminal for immediate paste. Console logs are unchanged.
Current paired NuGet/npm version:
0.167.0-alpha.1547.1.798b26c. The Terminals playground also includes a shell-firstnotcurses-democontainer.Before merge
Tracker: mitchdenny/hex1b#515. Close out these compatibility issues before merging:
Implementation, validation and known limitations
Screenshots: selection controls, terminal chrome and graphics