Repository navigation
Add WinUI DevTools support to launch and debug - #295
Draft
Chiara Mooney (chiaramooney) wants to merge 30 commits into
Draft
Chiara Mooney (chiaramooney) wants to merge 30 commits into
Chiara Mooney (chiaramooney) wants to merge 30 commits into
Conversation
The .vscodeignore excluded bin/** and re-included only *.exe, so the DevTools sidecars and their supporting files were dropped from the package. The extension then failed at runtime in any environment that was not a dev checkout. Exclude only bin/**/*.pdb instead, and add verify-vsix-payload.ps1 to the packaging script so a missing payload fails the build rather than shipping. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The DevTools panel needs the same dropdowns, colour picker and form controls the manifest editor already had. Move them into src/shared so both surfaces render identical UI instead of maintaining a second copy. The manifest editor keeps its existing appearance apart from a slightly larger corner radius, which is now shared by both. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Launching a WinApp configuration now starts the app with the native DevTools overlay and opens a DevTools panel in VS Code, replacing the separate native DevTools window. The panel speaks the DevTools JSON-RPC protocol over a named pipe and renders the visual tree, property grid, comments and layout adorners. Controlled by useDevTools in launch.json, which defaults to true. Requires a winapp CLI build that includes the DevTools engine. Also adds noDebug support: with noDebug set, the app launches and the DevTools panel opens without starting a language debugger, so no debugger extension needs to be installed. This covers both Run Without Debugging and an explicit launch.json attribute. Testing: - Unit tests for the protocol, NDJSON framing, JSON-RPC client, binding handlers, source resolution, overlay and launch gating, backed by a fake engine speaking the real wire format. - E2E tests that build a committed WinUI fixture app, launch it with noDebug, and drive the real DevTools panel in VS Code. - A CI step that checks every protocol method used against the schema the CLI ships, in both directions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
DevTools is not in a stable winapp release yet, so CI downloads a CLI that rejects --devtools and every DevTools launch fails with a product-looking error. Probe 'winapp run --help' before building the fixture and skip those specs when the flag is absent, matching how the winapp.new specs skip without a template pack. They start running on their own once a CLI with DevTools ships. Probing before the build also avoids spending several minutes compiling a fixture that cannot be launched. Also make check-devtools-schema say plainly when it finds no bundled schema: it exits 0, so the CI step reported success while checking nothing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The shared helper ran frame discovery and the ready-selector wait against one deadline, so a slow-appearing frame silently shrank the rendering budget the manifest editor specs used to get in full. Keep each phase on its own budget. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
winappCli PR 943 turned --devtools from a bare flag into a valued option taking on, off or headless, and removed --no-overlay. Our bare '--devtools' no longer parses: it swallows whatever argument follows it as the mode, so a launch fails with a message naming an unrelated flag. Send the mode explicitly, mapping noOverlay to headless, which keeps the engine running for the panel while drawing nothing in the app. Pass 'off' explicitly too rather than omitting the flag. The CLI now enables DevTools by default for WinUI projects, so saying nothing would quietly override useDevTools: false. Verified against 0.7.2-nmetulev-devtools.247: unit 1352/1352, DevTools E2E 7/7, and the protocol schema check reports no drift in the 28 methods and 7 events we use. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The enumerate comment implied engines vary in what they return. They do not: the .247 schema still declares VisualNodeList as a oneOf, so both shapes are the current contract rather than support for an older engine. The E2E probe matched a bare --devtools, which an earlier build of the feature branch accepted. Such a build would start the suite and then fail at launch, so match the mode syntax we actually require. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The native DevTools window reads each row as type, #name and the element's own text; ours showed only type and name, so two Buttons were indistinguishable. VisualTree.getPreviews supplies the caption and is public, but we were not calling it. The webview asks only for the rows on screen, debounced, because a caption is a live read of the element. Rows now ellipsize instead of scrolling the tree sideways, matching the CLI change, with the full label on the row tooltip. Comment.list already returned the element's file and line and we dropped both. An editor can do better than the native window here, so the comment shows file:line and opens it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The DevTools panel is a client of an engine that still lives on an unmerged branch in another repo, so it drifts underneath us on roughly a weekly cadence. Every sync so far has rediscovered the same traps: download-cli.ps1 only sees releases, the npm-package artifact omits the schema so the drift gate goes quiet, the branch's commit dates are 2026, and the gate compares method names but not shapes. Capture the six passes as a skill: pull the build, diff the schema, re-check the run --devtools contract, sweep the native window for layout and feature changes, audit unused capabilities, then validate. The parity pass carries a file-to-file map between the engine's DevToolsWindow.*.inc fragments and our webview fragments, and records that the overlay is deliberately not ours to mirror. Dogfooded against build .278: it surfaced that Get-ChildItem -Exclude silently copies nothing on a bare directory path, which the runbook now calls out. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Triaging the 2809d9ba..ab83d4cd window turned up a commit that edits DevToolsProtocolSchema.inc while the bundled schema hash stays identical, which reads like the drift gate missing a change. It is not: methods marked DevToolsVisibility::Internal are never exported, and the JSON we check carries 50 public methods and no Internal ones. Say so, so the next sync does not go hunting. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The schema check only ever compared method and event *names*, and only against a schema staged under bin/. CI downloads a released CLI, which ships no DevTools schema, so the step warned and exited 0 on every run: the gate existed but had never guarded anything. Commit the schema we are built against, plus its provenance, and check against that. The gate now runs in CI, compares full schema *shape* so a renamed or retyped field is caught rather than only a renamed method, and records which CLI build we were last validated against - something bin/ being gitignored previously left unrecorded anywhere in git. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
overlay.ts claims that highlighting handle "0" clears the adorner and leaves the toolbar alone, which is the whole reason the panel never calls Overlay.hide. Nothing tested that, and getting it wrong would take the user's toolbar down with no event to explain why. Drive the panel through hover and un-hover, then read the result from the engine via the CLI rather than from the panel - the panel is the thing under test, so asking it to confirm its own effect would prove nothing. Verified the test fails when the clear path is broken. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
DevTools lives on an unmerged branch in another repository, so there is no package version to watch and nothing says when it moves. Until now the only way to find out was to go looking, which meant we found out late. Compare the pinned build against the live branch tip and the newest successful branch build, and report the gap. Non-failing: falling behind upstream is information, not a defect in this tree. Local-only, because CI's GITHUB_TOKEN cannot read the other repository. Fold it into the sync runbook as the first thing to run, and close out the two open items this work resolved. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Two gaps found while assessing readiness. The README never mentioned DevTools, even though useDevTools defaults to true and so every F5 on a WinUI app already starts it. Adds a feature section, the three missing launch.json properties, a scenario, and troubleshooting rows. Also says plainly that the panel opens for any app type and will fail to connect on a non-XAML one, which is what actually happens - we gate on useDevTools alone, never on the framework. The webview's failure reporting had almost no coverage: the error state was untested entirely, and the one disconnect test ignored severity, so nothing would have caught a disconnect being styled as an engine fault. Adds eight tests over the status banner and the compose error - severity, both fallback strings, the connecting state, the stale-banner clear, and that engine text never becomes markup. Each was checked by breaking the production path it covers. Client-level failures are already covered in devtools-client.test.ts and are not duplicated here. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ct tests Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Surface run JSON errors as a warning instead of failing silently - Keep committed edits from being reverted on blur; drop rejected edits - Show precedence chains; poll selected element for app-driven changes - Make binding and resource editors read-only (no RPC support) - Make brush sub-rows read-only; warn when literals break links - Load full tree when filtering; handle removed selection - Pin comment drafts to their element; replace stale panels on relaunch Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Matches winapp run: cancelling the waiting command stops the app it launched. A run that exits on its own still leaves the app open. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Keep a KIND applied to a bound property until a write actually lands - Hold property refreshes while a menu is open; keep diagnoses and the Restore binding confirmation for properties that did not change - On Stop, let winapp run finish its exit work (--unregister-on-exit) before falling back to killing it Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Keep keyboard focus in the tree: ignore the engine echoing the panel's own selection instead of revealing (and refocusing) the panel - Value dropdowns are select-only comboboxes with aria-activedescendant - View tabs follow the ARIA tab pattern (arrow keys, roving tabindex, aria-controls/tabpanel); add a main landmark - Fix text contrast in light themes and dimmed secondary text - Copy path button name now starts with its visible text Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Comments are a list; each action names the comment it acts on - Keep focus in the comments view after Resolve/Delete rebuilds it - Bound properties announce their binding with the value - Pick shortcut is now Ctrl+Shift+C as a panel-scoped keybinding; Ctrl+Shift+P toggled pick and opened the Command Palette at once Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Type names use the theme's blue symbol color; text previews are muted italic instead of the debug string orange. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The tree used text characters whose baselines differ (the open caret sat low) and the property chevron rotated a non-square box. All carets now use one icon glyph in a square, flex-centred box rotated in place. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Chiara Mooney (chiaramooney)
force-pushed
the
chiaramooney-devtools-launch-poc
branch
from
November 6, 2026 23:39
aaef084 to
1e5f75f
Compare
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
VSIX Build
Updated 2026-11-13 18:53:28 UTC · commit |
2 of 3 tasks
Jaylyn Barbee (Jaylyn-Barbee)
pushed a commit
to microsoft/winappCli
that referenced
this pull request
Nov 9, 2026
## What and why
Today, clicking **Inspect** in the in-app DevTools toolbar always opens
winapp's native inspector window. Our VS Code extension already talks to
the same DevTools engine over its named pipe, but it can't take over
that button. So users end up with two inspectors.
This PR adds an opt-in protocol so one connected client can present the
inspector instead:
- `Inspector.registerExternal {owner, displayName}` registers the
client. `owner` is the token it negotiated on the same connection.
- While a client is registered, toolbar **Inspect**, element **Open in
DevTools**, **Open comments list**, and a committed inspect-mode pick
send `Inspector.openRequested {view, handle?, origin}` to that client
only. The native window doesn't open.
- The engine still owns the toolbar, picking, highlights and comments.
- `Window.open` is refused with `inspector-external` while a client is
registered.
- `Inspector.unregisterExternal`, `DevTools.releaseOwnedState`, or a
disconnect clears the registration. The next click opens the native
inspector again; nothing opens on its own.
- Only one client can register. Others get `inspector-owned`.
Registration is refused with `native-inspector-active` while the native
window is open.
If no client registers, behavior is unchanged. There are no new CLI
commands, flags or config.
This is a prototype for team feedback. The VS Code side is in draft
microsoft/WinAppVSCE#295.
## Before / after
Nothing changes for a user unless a client registers, so there's no CLI
before/after. Protocol example (illustrative):
```json
-> {"jsonrpc":"2.0","id":3,"method":"Inspector.registerExternal","params":{"owner":"<ownerToken>","displayName":"My Editor"}}
<- {"jsonrpc":"2.0","id":3,"result":null}
// user clicks Inspect in the app
<- {"jsonrpc":"2.0","method":"Inspector.openRequested","params":{"view":"inspect","handle":"273","origin":null}}
```
Tested end to end on ARM64 with head `e1bde16d` (built as
`0.7.2-pr1296-e1bde16d`) bundled into the VS Code extension from
microsoft/WinAppVSCE#295, using a WinUI sample app and real mouse input:
- The panel registered. `winapp devtools call Window.open` was refused,
and no native window opened.
- Toolbar Pick then a click on a button: the panel selected that button.
The click didn't reach the app.
- Toolbar Inspect, **Open comments list**, and a comment box's **Open in
DevTools**: the panel showed the inspect or comments view with the right
element.
- Closing the panel: the app kept running, and the next toolbar Inspect
opened the native inspector.
## Not tested / risks
- If a registered client stays connected but stops responding (for
example, its debugger is paused), Inspect clicks do nothing until it
recovers or disconnects. This is an accepted trade-off to keep engine
changes small.
- `winapp devtools call` can't register, because each call opens a new
connection. A real client must keep its own pipe connection open.
- x64 was not tested end to end. The `native-inspector-active` error is
covered by native tests only.
## Checklist
- [x] Tests added or updated
- [x] Tested locally on Windows
- [ ] Docs, samples, and `plugins/winapp/skills/` updated if user-facing
behavior changed (N/A: the protocol is for our own clients, so it is
intentionally not in the public guides; it is described in the protocol
schema)
<details><summary>Notes for reviewers</summary>
- Routing is a single early return in `InprocInspect`, so every Inspect
entry point is covered in one place.
- Registration reuses the existing owner token, connection liveness
check and `releaseOwnedState` cleanup. A late disconnect cleanup can't
clear a newer owner.
- An earlier version waited 2 seconds for the client to acknowledge and
then fell back to the native inspector. It was removed to keep changes
to the DevTools engine small.
- Validation on ARM64: `build-devtools.ps1 -Arch arm64 -Configuration
Debug` passed. External inspector 27/27, native dispatcher 696/696,
native window 14327/14327, overlay geometry 762/762.
</details>
---------
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1bb10af2-69c5-4f5c-b5bb-70d8b69f864c
Defer DevTools mode to the CLI by default, pin the cf21887 CI build, ship full CLI payload sidecars, and harden staged edits and async replies. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep headless toolbar hidden, surface CLI launch and comment store errors, fix attach source roots, refresh windows, captions, comments and layout, add raw-tree fallback, color presets, Show DevTools Panel, and a11y fixes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Ignore the panel's own selection echo by connection id, keep live comments when the CLI detail read fails, stop polling the CLI offline, and relaunch WPF or Windows Forms apps without DevTools (with a warning) when DevTools is requested. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Main now has winapp v0.8.0 C++ project support (#378), so the branch's own .vcxproj run changes are dropped in favor of main's. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ixture - Replace useDevTools/noOverlay with one devTools property (on, headless, off), matching winapp run --devtools. - Remove the winapp.devTools.inspector setting and devToolsInspector; the VS Code panel is always the inspector. - Check the app type before launch: an explicit DevTools request for a WPF, Windows Forms, or other non-WinUI 3 app launches without DevTools and warns. - Gate DevTools commands on workspace trust like the other CLI commands. - Run the DevTools E2E specs on the shared XAML fixture (new DevToolsPage) and drop the duplicate devtools-app fixture. - README: define which apps DevTools supports and drop the CI note. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Solutions and folders are judged by the app the CLI will run, and a .csproj without UseWinUI is evaluated with MSBuild, so anything not shown to be WinUI 3 launches without DevTools and warns. The relaunch after a CLI refusal is removed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Resolves #59
Adds WinUI DevTools support to the extension's launch/debug flow. Launching a WinApp configuration now starts the app with the native DevTools overlay and opens a DevTools panel inside VS Code — replacing the separate native DevTools window, not the overlay toolbar that floats over the app.
The panel speaks the DevTools JSON-RPC protocol over a named pipe and renders the visual tree, property grid, comments and layout adorners. It reuses the manifest editor's controls so both surfaces look the same.
Also adds
noDebugsupport. With it set, the app launches and the DevTools panel opens without starting a language debugger, so no debugger extension (C# Dev Kit) needs to be installed. This covers both "Run Without Debugging" and an explicitlaunch.jsonattribute — and it is what makes the E2E tests runnable on a clean machine.Requires a
winappCLI build that includes the DevTools engine (microsoft/winappCli#943), currently0.7.2-nmetulev-devtools.247. There is no fallback and deliberately so: the feature has not shipped, so it owes no compatibility to an older CLI. An older build fails the launch outright rather than quietly starting without DevTools.Seven commits, reviewable independently:
Ship CLI sidecar binaries in the VSIXExtract shared webview controls from the manifest editorAdd WinUI DevTools support to launch and debugSkip DevTools E2E when the CLI lacks --devtoolsGive webview frame lookup and render their own timeoutsPass a --devtools mode, as the CLI now requiresRequire the CLI mode syntax in the DevTools probeUsage Example
{ "type": "winapp", "request": "launch", "name": "WinApp: Launch with DevTools", "inputFolder": "${workspaceFolder}/bin/Debug/net10.0-windows10.0.26100.0/win-x64", // Defaults to true - set false to launch without DevTools. "useDevTools": true, // Optional: launch and open the DevTools panel without attaching a debugger, // so no debugger extension is required. "noDebug": true }Related Issue
Depends on microsoft/winappCli#943. Protocol gaps that would let us delete adapter code are tracked in the DevTools gaps issue filed on that repo.
Type of Change
Checklist
.\scripts\build-vsce.ps1locallypackage.jsoncontribution points / command/debugger/custom-editor docs updated (if extension surface changed)Screenshots / Demo
The DevTools panel opens in the editor area alongside the running app, with the visual tree on the left and the property grid on the right.
Additional Notes
Validation
npx tsc -p ./ --noEmitnpm run lintnpm run check-devtools-schemawin-arm64andwin-x64npm run test:unitnpm run test:e2e -- --grep "@winui-app"Also live-driven end to end: F5 in a real VS Code with only the WinApp extension installed launched the app and populated the panel with no C# Dev Kit present, confirming the
noDebugpath.What CI actually showed
The pipeline answered the question, and the answer was useful. Two runs on
windows-latest:actions/setup-dotnetworks andwindows-latestcan build anet10.0-windowsWinUI appDebug: DevTools E2E.The DevTools specs failed on the first run with:
CI's
download-cli.ps1fetches the latest stable release (v0.7.1), which has no DevTools; locally I'm on0.7.1-nmetulev-devtools.80from microsoft/winappCli#943. So this is the known CLI dependency, not a runner limitation — but it looked like a product failure in the log, which is bad for anyone else reading a red build.Fixed by probing
winapp run --helpfor--devtoolsand skipping when it's absent, matching how thewinapp.newspecs skip without a template pack. The probe runs before the fixture build, so a CI that can't use these specs doesn't spend minutes compiling for them. They start running on their own once a CLI with DevTools ships — no follow-up change needed. Verified both paths locally: skip path 6 skipped / 1 passed in 1.9s, real path 7/7.Because CI never got past the CLI argument, the Windows App SDK runtime question is still open. If a hosted runner turns out not to have it, the fix is self-contained deployment or installing the runtime in CI.
Two things worth flagging to reviewers
Check DevTools protocol schemastep was reporting green while checking nothing. On a stable CLI there's no bundled schema, so it logged a quiet "skipping" and exited 0. It now says plainly that no drift check ran. It looked like coverage and wasn't.helpers.tsto its pre-branch version reproduces the same flakes locally (semantic-diagnostics3 flaky). So it's pre-existing and environmental, not a regression here. One real contributing bug was mine and is fixed — the refactor had frame discovery and the ready-selector wait sharing a single deadline, so a slow frame silently ate the rendering budget those specs used to get in full. Each phase now has its own. The underlying flakiness is worth a separate issue.Two bugs found by running the tests, not writing them
The CLI contract changed under us
Re-synced the bundled CLI from
0.7.1-nmetulev-devtools.80(Oct 1) to0.7.2-nmetulev-devtools.247(Oct 9), about a hundred commits. Two things broke:--devtoolsbecame a valued option takingon|off|headless, and--no-overlaywas removed. The failure is nastier than a parse error: the option swallows the next argument as its mode, so a bare--devtoolsfails with a message naming an unrelated flag.noOverlaynow maps toheadless.useDevTools: falsenow has to pass--devtools offexplicitly. Omitting the flag would silently turn it back on, which would only ever surface as "I disabled it and it is still there."Two smaller findings from the re-sync, both worth knowing before anyone else syncs:
bin/holds a DevTools build. The CLI branch'snpm-packageartifact omitswinapp-devtools-schema.json; only thenuget-packagesartifact carries it. Syncing from the npm tarball makes the gate silently inert again.Deliberately deferred
winapp.devTools.autoOpenPanel/panelLocationsettings — waiting for user feedback before adding configuration surface.devtools-panel.tshad no unit coverage because no unit test in this repo importsvscode(there's no module-mocking setup). The E2E specs are what cover it.