Integrate the WinUI 3 XAML language service into the winapp extension - #50
Open
Nikola Metulev (nmetulev) wants to merge 75 commits into
Open
Integrate the WinUI 3 XAML language service into the winapp extension#50Nikola Metulev (nmetulev) wants to merge 75 commits into
Nikola Metulev (nmetulev) wants to merge 75 commits into
Conversation
Nikola Metulev (nmetulev)
added a commit
that referenced
this pull request
Jul 14, 2026
- test:xaml-smoke now runs restore:fixture before the smoke harness so element completion has WinUI SDK metadata in CI. The fixture's obj/ is gitignored and was previously only restored by the integration pretest, so the standalone smoke step failed in CI with 0 completion items. This unblocks build-and-test and the packaged VSIX artifact. - redteam-gap4.test.js: use replaceAll for the caret-marker strip (CodeQL "incomplete string escaping or encoding"). - redteam19.test.js: drop the no-op self-replacement (CodeQL "replacement of a substring with itself"). - pr-description.yml: tolerate the REST diff API's 20k-line cap (HTTP 406) on very large PRs instead of failing; fall back to the changed-file list. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
This was referenced Aug 5, 2026
Chiara Mooney (chiaramooney)
marked this pull request as ready for review
August 5, 2026 03:02
VSIX Build
Updated 2026-08-19 18:36:09 UTC · commit |
Chiara Mooney (chiaramooney)
pushed a commit
that referenced
this pull request
Aug 5, 2026
- test:xaml-smoke now runs restore:fixture before the smoke harness so element completion has WinUI SDK metadata in CI. The fixture's obj/ is gitignored and was previously only restored by the integration pretest, so the standalone smoke step failed in CI with 0 completion items. This unblocks build-and-test and the packaged VSIX artifact. - redteam-gap4.test.js: use replaceAll for the caret-marker strip (CodeQL "incomplete string escaping or encoding"). - redteam19.test.js: drop the no-op self-replacement (CodeQL "replacement of a substring with itself"). - pr-description.yml: tolerate the REST diff API's 20k-line cap (HTTP 406) on very large PRs instead of failing; fall back to the changed-file list. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
Chiara Mooney (chiaramooney)
force-pushed
the
nmetulev/winui
branch
from
August 5, 2026 22:16
357cbf5 to
95f9ee0
Compare
Chiara Mooney (chiaramooney)
marked this pull request as draft
August 6, 2026 17:05
Folds the hardened XAML language service prototype (nmetulev/winui-vsc) into the shipping winapp VS Code extension as a single unified extension. Additive and non-breaking to the existing winapp CLI / debug / manifest features. Server: copy the .NET 10 LSP server (WinUiXaml.LanguageServer/Workspace/Xaml + 3 xUnit test projects + WinUiXaml.slnx + lsp-smoke) under server/. Builds 0/0; 489/489 unit tests pass. Client: add src/xaml/xamlLanguageService.ts (activateXaml/deactivateXaml, resolveServerDll bundled->dev fallback) wired additively from src/extension.ts; degrades to syntax-only on server-start failure. Contribute the xaml language, TextMate grammar, language-configuration, winui-xaml.showInfo|restartServer commands, winui-xaml.server.* config, onLanguage:xaml activation, and the vscode-languageclient ^9 dependency in package.json. Tests: port the 81-file integration harness to test/xaml-integration/ (kept as source of truth) with a clean committed WinAppSDK fixture at test/fixtures/xaml/fixture/ and a root .vscode-test.mjs. Full suite: 1596 passing / 28 pending / 0 failing. smoke.mjs and features.test.js (218) green. Packaging/CI: esbuild + package-vsc.ps1 publish the server into dist/server (bundled in the VSIX); .vscodeignore excludes C# sources/tests; release-vsc.yml adds UseDotNet@2, a server publish step, and a conditional ESRP DLL-signing step for our own WinUiXaml.*.dll. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
Automated fix->review loop iteration 1 — resolves all 17 findings from the post-migration PR review (2 High, 9 Medium, 6 Low): - H1 security: machine-scope winui-xaml.server.path/dotnetPath + workspace-trust gate (isTrusted + onDidGrantWorkspaceTrust) + capabilities.untrustedWorkspaces - H2: deterministic fixture NuGet restore (restore:fixture in pretest) - M1: run XAML/server/smoke suites in CI with .NET 10 (setup-dotnet) - M2: document .NET-dependent suites; unit tests stay dotnet-free - M3/M4: README Features + Requirements for the XAML language service - M5: serialize client start/stop lifecycle (no torn-down pending start) - M6: handle workspace/didChangeWatchedFiles (invalidate stale Roslyn cache) - M7: user-facing "degraded to syntax-only" notification with actions - M8: client command/lifecycle/degradation integration tests - M9: fold server bundling into vscode:prepublish (ensure-server-bundle.mjs) - L1: share bundled-asset path resolver (firstExistingPath) - L2: tighten .vscodeignore + VSIX-contents assertion - L3/L4: README command table + CONTRIBUTING .NET 10 SDK prereq - L5/L6: docs/RELEASE.md signing checklist + server/nuget.config feed pin Verified: tsc clean, eslint 0 errors, server build 0/0, 489/489 server tests, smoke PASS, integration 1601 passing / 0 failing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
Automated fix->review loop iteration 2 — resolves the 5 residual/new findings the independent GPT-5.6 review raised on iteration 1: - N1 (CRITICAL security): do not start the semantic server while the workspace is untrusted (Roslyn/MSBuild would evaluate an attacker-controlled .csproj and could execute code). Stay syntax-only until trust is granted; test host runs with --disable-workspace-trust so the feature suite still exercises the server. - N2 (correctness): replace the partial start-guard with a single lifecycle queue (runExclusive) so stop fully completes before any start — two servers can never coexist across concurrent restarts. - N3 (correctness): null-guard workspace/didChangeWatchedFiles (changes:null). - N4 (test-coverage): WINUI_XAML_FORCE_NO_SERVER test seam + a real absent-DLL degradation test (syntax-only, no throw). - N5 (packaging): ensure-server-bundle publishes fresh by default; reuse only under WINUI_REUSE_SIGNED_SERVER=1 (set by CI -SkipServerBuild) to preserve signed DLLs, so a bare vsce package can never ship a stale server. Verified: tsc clean, eslint 0 errors, server build 0/0, 489/489 server tests, smoke PASS, integration 1602 passing / 0 failing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
…(P1-P3) P1 (M5 residual): guard against server resurrection when restart races deactivate. Add module-level `disposing` flag set synchronously at the top of deactivateXaml and reset in activateXaml; doStart early-returns when disposing. Replace the separate stop+start in the restartServer command and onDidGrantWorkspaceTrust with a single restartClient() that runs stop-then-start inside one runExclusive op (atomic; skips start if disposing). P2: rewrite package.json untrustedWorkspaces capability description to match actual behavior (syntax highlighting only until the workspace is trusted). P3 (M9 residual): package-vsc.ps1 -SkipServerBuild set WINUI_REUSE_SIGNED_SERVER into the caller's environment and never cleaned it up. Capture the prior value before the try and restore/remove it in the finally block. Full integration suite: 1602 passing / 0 failing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
…packaging) Final 8-dimension PR-review gate over the whole branch surfaced 10 findings the per-iteration reviews (scoped to their own residuals) never looked at. Fix all. G1 (HIGH security): the isTrusted gate is necessary but not sufficient — an empty window is trusted, so opening a loose XAML file outside any workspace folder made the server warm up and MSBuild-evaluate its nearest .csproj (code-exec vector). Client now passes workspaceFolders as initializationOptions.allowedRoots; the server (ResolveAllowedRoots/IsPathUnderAllowedRoot/ResolveIfAllowedAsync) only runs project discovery + OpenProjectAsync for documents under a trusted root. Empty allow-list => no project evaluation; out-of-root/untitled files are served project-less (tolerant parser only). Boundary-aware, case-insensitive path check. allowedRoots is authoritative when present; legacy clients fall back to rootUri. G3 (HIGH test-coverage): add WINUI_XAML_FORCE_UNTRUSTED seam (mirrors WINUI_XAML_FORCE_NO_SERVER) so the trust gate + onDidGrantWorkspaceTrust recovery are exercised under the trusted harness. New client tests cover degrade+recover. G4 (docs): document winui-xaml.server.path in README. G5 (correctness): retain the synchronize.fileEvents FileSystemWatcher and dispose it in doStop / failed-start catch (was leaking one per start/restart/trust cycle). G6 (UX): untrusted degradation now shows a once-per-transition warning with a Manage Workspace Trust action (was log-only). G7 (test-coverage): extract pure buildDegradedNotification() + unit test message and action mapping. G8 (test-coverage): client tests for explicit server.path (valid -> semantic completion; invalid -> syntax-only, no throw). G9 (test-coverage): lsp-smoke sends didChangeWatchedFiles with omitted/null/empty changes and asserts the server stays responsive. G10 (packaging): drop the redundant bundle:server in package-vsc.ps1 (vscode: prepublish/ensure-server-bundle.mjs is the single publish path). G2 (packaging): narrow .vscodeignore to exclude only the apphost exe so Roslyn's net472 MSBuild BuildHost.exe ships; assert a BuildHost is present in the VSIX. Full integration 1605 passing / 0 failing; server 489, unit 595, smoke green. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
…indings) The final 8-dimension confirmation gate (incl. a cross-model check) found 5 issues the per-iteration reviews never scoped. Fix all 5. G15 (HIGH security): the allow-list was purely lexical — Path.GetFullPath does not resolve reparse points, so a junction/symlink placed inside a trusted workspace root that targets an external directory passed the containment check, and the resolver (FindOwningProject -> MSBuild GetOrLoadAsync) then evaluated the external .csproj. Fix: CanonicalizePath resolves the final physical path (GetFinalPathNameByHandle) for both the workspace roots (NormalizeRoots) and the document (IsPathUnderAllowedRoot) before containment; falls back to the lexical full path for non-existent/untitled docs or on any OS-call failure. A junction escaping the root now canonicalizes outside it and is served project-less. G11 (MEDIUM correctness): a workspace opened at a bare drive root (C:\) rejected all its children — NormalizeRoots keeps C:\ with its trailing separator, but PathIsWithin required path[root.Length] to be a separator (it was the first path-segment letter). Fix: when the root already ends in a separator (bare drive/UNC root) the prefix match is itself the boundary. The boundary-char check still guards C:\root vs C:\rootEvil. G12 (HIGH test-coverage): the security-critical boundary had no direct test. Made NormalizeRoots/PathIsWithin/CanonicalizePath internal (test project already has InternalsVisibleTo) and added AllowedRootBoundaryTests (exact/child/out-of-root/ sibling-prefix/drive-root/cross-drive/case/trailing-sep/normalize-trim + a non-admin mklink /J junction regression). Added a behavioral lsp-smoke case: a document under os.tmpdir (outside the sole allowedRoot) gets no project-backed resolution while the in-root fixture still resolves. G13 (MEDIUM UX): the degraded-notification guard was a single boolean reset only on a successful start, so after a user granted trust but the server still could not start (e.g. no dotnet) the server-missing guidance was suppressed. Fix: track the last degraded cause and notify once per distinct cause (untrusted vs server), still non-nagging; reset on successful start. G14 (LOW docs): README used the abbreviated server.dotnetPath; use the full winui-xaml.server.dotnetPath. Full integration 1605 passing / 0 failing; server 505, unit 595, smoke green; server debug build 0 warnings. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
…trust boundary
reviewer-iter5 (independent cross-model) found two HIGH residuals in the iter5
allow-list hardening. Both are closed here.
G15 (security) — the canonicalizer only resolved reparse points for an EXISTING
leaf (CreateFileW/OPEN_EXISTING). A not-yet-created XAML leaf under an in-root
junction (e.g. C:\trusted\link\Page.xaml, no file) failed that call and fell back
to the lexical path, which still passed lexical containment. XamlProjectResolver
.FindOwningProject only needs the DIRECTORY (new FileInfo(path).Directory +
dir.GetFiles("*.csproj")), so the external junction target's .csproj was still
MSBuild-evaluated — a code-exec bypass. CanonicalizePath now walks up to the
deepest EXISTING ancestor (which follows any junction/symlink in the ancestry),
resolves it via GetFinalPathNameByHandle, and re-appends the missing tail; lexical
fallback is used only when no ancestor exists or the OS call fails. Legit
not-yet-saved files under a real (non-junction) dir still resolve in-root, so
IntelliSense for new files is preserved.
G12 (test-coverage) — the junction regression test never created the linked file,
so it exercised the same missing-leaf fallback, and its Assert.False threw inside a
broad catch(Exception) that swallowed the failure: a green test over a live hole.
The test now creates the linked file and asserts BOTH the existing-leaf and the
missing-leaf paths canonicalize OUTSIDE the trusted root, with the assertions moved
out of the swallowing catch (it skips only on genuine junction-creation failure).
The out-of-root lsp-smoke case gains a sibling .csproj + code-behind so the null F12
result is attributable to the trust gate rather than to an absent project.
Verification: build:server:debug 0 warnings/0 errors; test:server 505/505 (junction
test genuinely exercised — junctions confirmed creatable in this env);
test:xaml-smoke PASS incl. the strengthened out-of-root case; full integration
1605 passing / 0 failing / 28 pending.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
- test:xaml-smoke now runs restore:fixture before the smoke harness so element completion has WinUI SDK metadata in CI. The fixture's obj/ is gitignored and was previously only restored by the integration pretest, so the standalone smoke step failed in CI with 0 completion items. This unblocks build-and-test and the packaged VSIX artifact. - redteam-gap4.test.js: use replaceAll for the caret-marker strip (CodeQL "incomplete string escaping or encoding"). - redteam19.test.js: drop the no-op self-replacement (CodeQL "replacement of a substring with itself"). - pr-description.yml: tolerate the REST diff API's 20k-line cap (HTTP 406) on very large PRs instead of failing; fall back to the changed-file list. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
CodeQL's full scan of the migrated test files (features.test.js, smoke.mjs)
flagged sanitization patterns in test helpers. All fixes are behavior
preserving (smoke PASS; integration 1605 passing / 0 failing):
- caret-marker strip: .replace("|", "") -> .replaceAll("|", "")
(js/incomplete-sanitization).
- exact completion-label membership: array.includes(<uri>) ->
array.some((l) => l === <uri>) — these were array-membership checks that
CodeQL misread as URL substring checks (js/incomplete-url-substring-sanitization).
- diagnostic display string: drop the nested template literal in favor of
string concatenation (js/bad-code-sanitization).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 03c713cc-41ae-4c28-ab49-3c851aa8e2bd
Build local native bundles, consume signed release artifacts, harden workspace boundaries and lifecycle behavior, and validate both packaged architectures. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d48e3dcd-70ba-416d-b66e-e5f046facd10
Keep bundled mode fail-closed for fallback resolution while allowing authoritative custom path settings to exercise degradation and recovery. Avoid secondary artifact-upload failures when an earlier CI gate fails. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d48e3dcd-70ba-416d-b66e-e5f046facd10
Keep the canonical x:Bind diagnostics in redteam15 and clarify that the prefix-sharing resource tests exercise references and document highlights separately. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d48e3dcd-70ba-416d-b66e-e5f046facd10
Add merged resource traversal, semantic binding diagnostics, namespace cleanup, on-type formatting, snippets, and surround-with refactors with full server and live VS Code coverage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d48e3dcd-70ba-416d-b66e-e5f046facd10
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d48e3dcd-70ba-416d-b66e-e5f046facd10
Distinguish language-server completions from VS Code word suggestions and align resource and attached-property assertions with current behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d48e3dcd-70ba-416d-b66e-e5f046facd10
Chiara Mooney (chiaramooney)
force-pushed
the
nmetulev/winui
branch
from
August 6, 2026 22:01
95f9ee0 to
182aba2
Compare
Shorten comments, split oversized server and test files, remove unrelated release and CLI downloader changes, and rename red-team tests by scenario. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d48e3dcd-70ba-416d-b66e-e5f046facd10
Remove static color, font-weight, and theme-resource tables; source completion data from project metadata and generic.xaml. Also remove standalone snippets, Surround With, and user-facing server path overrides. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d48e3dcd-70ba-416d-b66e-e5f046facd10
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d48e3dcd-70ba-416d-b66e-e5f046facd10
Build graph keys and source edges from ResourceScopeIndex root visibility so keyed nested dictionaries and child resource owners cannot leak globally. Preserve merged and theme dictionary traversal and runtime precedence, with cross-document completion and diagnostic coverage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: e68b9365-64fc-4da1-8c62-c9a2c0c10329
Treat a resource file's root ResourceDictionary Source as a visible graph edge without reopening traversal through keyed or child scopes. Add focused and live App.xaml proxy-chain coverage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: e68b9365-64fc-4da1-8c62-c9a2c0c10329
Derive resource definition locations from the fixture and align smoke expectations with authoritative diagnostics and DependencyObject-only TargetType completion. Keep watcher invalidation targeted at SmokePage after additional fixture types. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4e9f981c-7b33-4ddf-926e-45668fc6b0a2
Update live tests for referenced namespace discovery, scoped StaticResource ordering, prefixed property elements, DependencyObject-only TargetType completion, and fixture-derived resource locations. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4e9f981c-7b33-4ddf-926e-45668fc6b0a2
Address the remaining battle-test and PR-review findings across binding accessibility, static paths, diagnostics, code actions, reload resilience, generated-handler safety, and isolated live testing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4e9f981c-7b33-4ddf-926e-45668fc6b0a2
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4e9f981c-7b33-4ddf-926e-45668fc6b0a2
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4e9f981c-7b33-4ddf-926e-45668fc6b0a2
This was referenced Sep 1, 2026
Fixes from the pr-review skill loop: - Resolve the .NET host explicitly before running package restore instead of spawning a bare `dotnet`, and surface an actionable error when no compatible runtime is found (xamlLanguageService.ts). - Evict in-flight project loads on Invalidate so a restore that completes while a load is pending no longer leaves a stale workspace cached (XamlProjectResolver.cs). - Drop the pinned --configfile from restore:fixture so the fixture restore honors the machine NuGet configuration. - Ignore .drive-extensions/ test-harness output. - Mention the XAML language service in the extension description. - Comment the pre-apply document re-check in promptedTextEdit so it is not mistaken for a duplicated guard. Remaining review findings are tracked as issues #210-#214. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Follow-up self-review of 6de338c caught three problems it introduced: - Revert the unscoped `!IsCompleted` clause in XamlProjectResolver.Invalidate. It was not scoped to the invalidated key, so it evicted every in-flight load across all roots and disposed workspaces that active ResolveAsync callers were still awaiting. The narrow staleness gap it aimed at is tracked in #215. - Only set DOTNET_HOST_PATH when the resolved dotnet path is absolute. findCompatibleDotnet can return the bare "dotnet" PATH fallback, and DOTNET_HOST_PATH must be an absolute path to the host executable. - Restore the --configfile pin on restore:fixture. The fixture lives outside server/, so NuGet hierarchy discovery never finds server/nuget.config; the pin is the only thing keeping that restore deterministic in CI. Also corrects the comment on the pre-apply re-check in promptedTextEdit: there is no await between it and the preceding guard, so the live re-read that actually protects the file is the one in the applyEdit dependency. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
findCompatibleDotnet can return the bare dotnet PATH fallback. The restore path was already guarded; apply the same check when launching the server so the Roslyn build host never receives a non-absolute DOTNET_HOST_PATH. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Any workspace containing a .xaml.cs also contains the .xaml it is code-behind for, so workspaceContains:**/*.xaml already activates the extension everywhere the C# Dev Kit recommendation can pass its .xaml.cs gate. onLanguage:csharp only added activation in C# workspaces where the gate always returns false, loading the whole extension to test a filename suffix and do nothing. Replace the package.json string assertion in xaml-workspace-activation.test.ts with tests that state the invariant: activate for XAML-containing workspaces, do not activate on plain C#. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0a32116a-78ec-415a-aa5e-f98a06c74e9d
VS Code cannot activate on an individual file open, so the C# Dev Kit recommendation needs a workspaceContains glob to register its handler. Scope that glob to **/*.xaml.cs, which is the reason it exists, instead of **/*.xaml. Narrows startup activation: C++/WinRT WinUI and XAML-only workspaces no longer activate the extension, and onLanguage:xaml still covers opening XAML there. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0a32116a-78ec-415a-aa5e-f98a06c74e9d
DOTNET_HOST_PATH is the first candidate findCompatibleDotnet probes, so falling through to the bare 'dotnet' PATH fallback means the inherited value was absent or failed the .NET 10 check. Forwarding it unchanged let MSBuild and Roslyn's build host resolve a host we had already rejected -- e.g. DOTNET_HOST_PATH pointing at a .NET 8 host while .NET 10 is on PATH. Move the rule into createDotnetChildEnvironment so the server-start and restore paths share one implementation, and cover both branches with tests. The guard previously existed only as duplicated inline expressions, which is how the server-start path kept an unguarded assignment after restore was fixed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0a32116a-78ec-415a-aa5e-f98a06c74e9d
The extension hand-rolled .NET host discovery: probe an ordered candidate list with 'dotnet --list-runtimes' and take the first reporting Microsoft.NETCore.App 10.x. That never validated host architecture and never read the Windows registry install records, so it could hand back an x64 host on arm64 Windows and could not see a host installed off PATH. Delegate to the .NET Install Tool's dotnet.findPath instead, as the C# extension and C# Dev Kit do. The probe is deleted rather than kept as a fallback, so there is one behaviour to reason about. The request pins 10.0 with versionSpecRequirement 'equal' rather than the 'greater_than_or_equal' the C# extension uses: the Install Tool compares major.minor, so greater_than_or_equal on 10.0 also accepts a .NET 11 host, which cannot run a net10.0 app without cross-major roll-forward. rejectPreviews excludes prerelease runtimes for the same reason. The tool is installed silently on demand rather than declared in extensionDependencies, which is static and would install it for every WinApp user. Resolution stays behind the trust check, so an untrusted workspace never triggers an install. The resolved host is cached for the session and invalidated by Restart Language Server. A distinct degraded state covers a blocked marketplace, so a user who already has .NET 10 is not told to install it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0a32116a-78ec-415a-aa5e-f98a06c74e9d
The harness launches VS Code with --disable-extensions, so the .NET Install Tool cannot be installed or queried there. With host discovery now delegated to that tool, all 85 integration tests would have failed to start the server. Add a WINUI_XAML_DOTNET_PATH override that bypasses the Install Tool, alongside the existing WINUI_XAML_SERVER_PATH dev/test hook, and resolve a host in .vscode-test.mjs. The probing stays in test infrastructure rather than shipped code, so users still have a single discovery path. Verified: test/xaml-integration/smoke.test.js passes end to end against the real server. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0a32116a-78ec-415a-aa5e-f98a06c74e9d
The isolated .drive-extensions changes and the diagnostic code field are harness fixes with no relationship to the XAML language service, and they landed on this branch by accident. They now have their own pull request against main, so revert them here to keep this branch's diff limited to the language service integration. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0a32116a-78ec-415a-aa5e-f98a06c74e9d
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
Integrates the WinUI 3 XAML language service into the shipping
winappVS Code extension as a single additive extension experience. Existing CLI commands, debugging, AppxManifest editing, and the new manifest IntelliSense frommainremain intact.What lands:
src/xaml/) with lazy XAML activation, serialized start/stop/restart lifecycle, workspace-trust gating, automatic settings restarts, and actionable degraded-mode notifications.server/) providing completion, hover, definition, diagnostics, references, rename, code actions, formatting, semantic tokens, folding, links, and project-aware Roslyn/MSBuild features.BuildHost-netcore, but no .NET runtime and no apphost —scripts/validate-vsix-server.ps1fails the build if either appears.dotnet.findPathonms-dotnettools.vscode-dotnet-runtime— the same component the C# extension and C# Dev Kit use — pinned to10.0withversionSpecRequirement: "equal"so any10.0.xis accepted. The Install Tool is deliberately not anextensionDependenciesentry (that would install it for every WinApp user); it is installed silently on demand the first time a XAML file is opened in a trusted workspace.dotnet publish; CI/release builds the server once, signs it, downloads the signed artifact, and packages without unsigned fallback.Usage Example
Opening any
.xamlfile in a trusted workspace activates the language service. There is nothing to configure: thewinui-xaml.server.pathandwinui-xaml.server.dotnetPathsettings were removed in this PR, and the .NET runtime is resolved through the Install Tool. TheWINUI_XAML_SERVER_PATHenvironment variable remains, for development and integration testing only.Commands: WinUI XAML: Show Info and WinUI XAML: Restart Language Server.
Prerequisites
Type of Change
Checklist
.\scripts\package-vsc.ps1packaging flow run locallyREADME.md,CONTRIBUTING.md, and release documentation updatedpackage.jsonlanguage, grammar, commands, configuration, activation, and dependency surfaces updatedmainmerged and conflicts resolvedVerification
BuildHost-netcorepresent; apphost and bundled runtime files rejectedSecurity and runtime notes
The server only evaluates projects under trusted workspace-folder roots. Paths are canonicalized across reparse points before containment checks, preventing junction/symlink escapes. Untrusted and empty windows remain syntax-only.
Project-independent features remain available when no MSBuild toolset is present; project-aware features surface an actionable prerequisite warning rather than failing silently.
Review history
The implementation went through iterative multi-dimension review and an independent different-model cross-check. The final pass found no critical/high/medium defects. Non-blocking deduplication refactors were filed as follow-up issues rather than expanding this release-critical PR.
Scope note
Three VS Code test-harness fixes under
.github/skills/vsce-testing/were committed to this branch by accident and have been extracted to #218 (Isolate the VS Code test harness from the user's extension install). They were unrelated to the language service, so this PR no longer touches.github/skills/and its diff dropped from 273 to 270 files.