Skip to content

Add Reactor (Microsoft.UI.Reactor) dotnet new templates - #6620

Merged
Alexandre Zollinger Chohfi (azchohfi) merged 35 commits into
mainfrom
azchohfi-reactor-dotnet-new-templates
Aug 28, 2026
Merged

Alexandre Zollinger Chohfi (azchohfi) merged 35 commits into
mainfrom
azchohfi-reactor-dotnet-new-templates

Conversation

@azchohfi

@azchohfi Alexandre Zollinger Chohfi (azchohfi) commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds four Reactor (Microsoft.UI.Reactor) project templates to the existing Microsoft.WindowsAppSDK.WinUI.CSharp.Templates dotnet new pack, mirroring the WinUI templates from #6407 but for Reactor's declarative, pure-C# (no XAML) model.

Template Short names What it scaffolds
Reactor Blank App reactor, reactor-blank Minimal Hello-World Reactor app
Reactor MVU App reactor-mvu Model-View-Update counter using UseReducer
Reactor NavigationView App reactor-navview NavigationView shell with multiple pages
Reactor TabView App reactor-tabview TabView shell with multiple tabs

What changed

  • dev/Templates/templates.props — four new rows in the DotnetNewOnlyProjectTemplate slot (dotnet-new only, no VSIX). Reactor apps run unpackaged, so there is no Package.appxmanifest (RenameManifestFrom left unset). This reuses the repo's existing single-source-of-truth pack pipeline.
  • dev/Templates/Source/ProjectTemplates/Desktop/CSharp/Reactor* — the app sources: a shared ProjectTemplate.csproj (references Microsoft.UI.Reactor + Microsoft.WindowsAppSDK, WindowsAppSDKSelfContained, Debug-only Reactor devtools), a single-file App.cs per pattern, and Properties/launchSettings.json (default + Devtools F5 profiles).
  • dev/Templates/Dotnet/templates/reactor-* — the .template.config for each (template.json, dotnetcli.host.json, ide.host.json, icon.png). Defaults: Reactor 0.1.0-preview.12, Windows App SDK 2.1.3, net10.0; overridable via --reactor-version / --wasdk-version.
  • dev/Templates/Dotnet/README.md — documents the new Reactor templates.
  • dev/Templates/Dotnet/Test-DotnetNewTemplates.ps1 — adds the four to the scaffold/build validation loop.

Validation

Validated end-to-end against the live Microsoft.UI.Reactor 0.1.0-preview.12: dotnet pack → dotnet new install → all four register → dotnet new → dotnet build (Debug + Release) → dotnet run. All four launch cleanly, including the title-bar app-mark icon (which relies on the IconResolver fix from microsoft/microsoft-ui-reactor#855, shipped in preview.12).


A Microsoft employee must use /azp run to validate using the PR pipelines.

Adds four Reactor project templates to the Microsoft.WindowsAppSDK.WinUI.CSharp.Templates dotnet-new pack, mirroring the WinUI templates but for Microsoft.UI.Reactor (pure C#, no XAML):

- Reactor Blank App        (reactor, reactor-blank)
- Reactor MVU App          (reactor-mvu)
- Reactor NavigationView   (reactor-navview)
- Reactor TabView App      (reactor-tabview)

Wired into dev/Templates/templates.props via the DotnetNewOnlyProjectTemplate
slot (dotnet-new only, no VSIX, no manifest; Reactor apps run unpackaged).
Each shares a common csproj referencing Microsoft.UI.Reactor +
Microsoft.WindowsAppSDK, bundles the WinAppSDK runtime self-contained, and
enables the Debug-only Reactor devtools surface. README and
Test-DotnetNewTemplates.ps1 updated to document and validate the new templates.

Validated end-to-end: pack -> install -> dotnet new -> build (Debug + Release)
for all four templates.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
TitleBar(...).Icon(FontIcon(...)) threw System.ArgumentException (E_INVALIDARG)
at runtime when Reactor set TitleBar.IconSource on Windows App SDK 2.1.3, so
the scaffolded Blank, MVU, and TabView apps crashed on launch. The glyph was
only a placeholder, so drop the icon; the title bar still shows the title text
and all four templates now launch cleanly (validated with dotnet run).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
microsoft/microsoft-ui-reactor#855 fixes the IconResolver FontSize=NaN crash
(FontIcon in an IconSource slot without an explicit size threw
ArgumentException from TitleBar.set_IconSource). That fix ships in
Microsoft.UI.Reactor 0.1.0-preview.12, so restore the placeholder title-bar
app-mark icon in the Blank, MVU, and TabView templates and bump the default
reactorVersion 0.1.0-preview.11 -> 0.1.0-preview.12 across all four templates.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@azchohfi
Alexandre Zollinger Chohfi (azchohfi) marked this pull request as ready for review July 15, 2026 05:01
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@azchohfi

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.

The template smoke-test stage installed only .NET SDK 8.0.x, so scaffolding
and building the Reactor templates failed with NETSDK1045 (Reactor targets
net10.0 and declares a [10.0,) sdk-version constraint). The WinUI templates
auto-detect their TFM from the active SDK, so they built net8.0 and passed,
masking the gap.

Add a second UseDotNet@2 step (param reactorDotnetSdkVersion, default 10.0.x)
to the shared Test-Stage template so the agent has the .NET 10 SDK. Verified
locally that the WinUI templates still build cleanly on the .NET 10 SDK, so
existing coverage is unaffected. Both the official and PR pipelines consume
this shared stage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azchohfi

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.

Review feedback from @DinahK-2SO on #6620:
- Remove the explanatory comment block from the Reactor launchSettings.json
  files (the content overlapped the package README).
- Give the MVU, NavigationView, and TabView templates their own icon.png
  (reusing the existing WinUI mvvm/navigation/tabview template icons) instead
  of all reusing the blank-app icon.

The packaging/taskbar-icon, tabs-in-title-bar, and winui-* short-name comments
are still open pending a check with the Reactor team.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Review feedback from @DinahK-2SO on #6620: give each Reactor template a
winui-reactor* alias (winui-reactor, winui-reactor-mvu, winui-reactor-navview,
winui-reactor-tabview) so they also surface under 'dotnet new list winui'
alongside the other WinUI templates. README updated to note the aliases.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Review feedback from @DinahK-2SO on #6620: instead of stacking a separate
TitleBar row above the TabView, put the tabs up in the title bar (Edge/Terminal
style) to look cleaner and save vertical space.

Uses supported Reactor APIs: UseWindow().NativeWindow with
ExtendsContentIntoTitleBar + SetTitleBar, the TabView TabStripHeader (app name
at the leading edge) and TabStripFooter (draggable region), and UseDpi +
UseWindowSize to reserve the caption-button inset (RightInset) across DPI and
resize. Verified by scaffolding the template, building, running, and
screenshotting the window: the tabs render inline in the title bar with the
caption buttons clear.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Per review direction, the four Reactor templates now:

1. Are single-project MSIX packaged (like the WinUI templates) instead of
   unpackaged. Each gains app.manifest, Package.appxmanifest (EntryPoint
   Windows.FullTrustApplication since Reactor has no XAML App class), the shared
   Assets, and PublishProfiles. The csproj switches to EnableMsixTooling +
   Microsoft.Windows.SDK.BuildTools + Microsoft.Windows.SDK.BuildTools.WinApp so
   'dotnet run' registers a loose package and launches with MSIX identity.
   templates.props sets RenameManifestFrom and the template.json files gain the
   publisher / guid / build-tools-version symbols and the \\$
   modifier.

2. Visually match their WinUI counterparts:
   - reactor      -> title bar (app icon) + empty content (blank canvas).
   - reactor-mvu  -> centered 'Hello, WinUI!' + [+]/[-] icon counter (keeps the
     UseReducer MVU pattern under the same UI).
   - reactor-navview -> title bar + NavigationView Home/About + built-in Settings;
     pages render 'Title' + 'This is the X page'.
   - reactor-tabview -> MicaAlt, app-icon TabStripHeader, closable Home/About tabs
     with a '+' add button, tabs in the title bar.

Validated end-to-end for all four: pack -> install -> scaffold -> build ->
dotnet run (launches packaged with identity) -> screenshot matches the WinUI
counterpart. README updated (templates are now packaged).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…font parity

- MVU greeting is now 'Hello, Reactor!' (was 'Hello, WinUI!').
- Switch the Reactor text from Heading()/.SemiBold() (raw 28px Bold-700) to the
  type-ramp factories Title()/BodyStrong()/Body(), which apply the actual WinUI
  styles (TitleTextBlockStyle 28px Semibold-600, BodyStrongTextBlockStyle,
  BodyTextBlockStyle). This makes the Reactor headings/body render with the same
  weight and Segoe UI Variable optical size as the WinUI templates instead of a
  heavier bold. Applied to the mvu, navview, and tabview page text.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azchohfi

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.

@DinahK-2SO

Copy link
Copy Markdown
Contributor

LGTM

Alexandre Zollinger Chohfi (azchohfi) added a commit to azchohfi/microsoft-ui-reactor that referenced this pull request Aug 27, 2026
Review follow-up. The packaging-neutral rewrite named `EnableMsixTooling` as
the packaged marker and told the agent never to set `WindowsPackageType`.
Both were wrong in ways that matter:

- `EnableMsixTooling` only enables the single-project MSIX tooling. A project
  with `WindowsPackageType=None` *and* `EnableMsixTooling=true` builds
  unpackaged -- `None` wins. Verified live: that combination emits no
  `AppxManifest.xml` / `resources.pri` / `.build.appxrecipe`, while the same
  csproj with the property absent emits all three.
- Packaged does not require `WindowsPackageType=MSIX`. Omitting the property
  entirely also yields a packaged app off the default, which is what the
  templates in microsoft/WindowsAppSDK#6620 do. Mandating `MSIX` would have
  described that scaffold as broken.
- "Don't set `WindowsPackageType` yourself" contradicted
  `docs/guide/packaging.md`, which tells you to set it to `MSIX` -- and this
  skill routes readers to that guide two paragraphs later.

Both shapes are now described with the property precedence stated, and the
rule is scoped to the actual hazard (don't flip the mode of a project you
didn't scaffold) rather than to the property. `Package.appxmanifest` stays
the discriminator; it is true today and after #6620, so neither change waits
on the other.

Also drops `app.manifest` as a packaged marker -- the repo's only one belongs
to an unpackaged project (`tests/startup_perf/BlankWinUI3`) -- and the
present-tense claim about a packaged template's file list.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 784c77a5-bfd2-40f4-96a5-ce447df7c3e2
Alexandre Zollinger Chohfi (azchohfi) added a commit to azchohfi/microsoft-ui-reactor that referenced this pull request Aug 27, 2026
Companion to the packaging fix in 525efc2, same defect class: a property of
`dotnet new reactorapp` stated as a property of Reactor.

The skill claimed the `.csproj` does **not** enable implicit usings. That is
true of the shipped template, which sets no `ImplicitUsings` property, and
false of the templates in microsoft/WindowsAppSDK#6620 --
`ReactorBlankApp/ProjectTemplate.csproj` sets `<ImplicitUsings>enable</ImplicitUsings>`.

The divergence is observable in the scaffolded source: #6620's `App.cs` opens
with six usings and no `using System;`, against the seven in
`tools/Templates/templates/WinUIApp-CSharp/App.cs:1-7`, which leads with it.
That also made the sentence's own worked example misfire, since `System.Linq`
is in the implicit set -- an agent told to add `using System.Linq;` before
`.Select(...)` finds it already in scope.

Reworded so it holds for both: `App.cs` keeps its `using` block and that is
still where you add namespaces, with a note that some templates enable
implicit usings. The "seven-line using block" count in "Starting a new app"
goes with it, for the same reason.

The *Required imports* list is left as-is -- spelling `using System;` out
explicitly is redundant under implicit usings, not wrong.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 784c77a5-bfd2-40f4-96a5-ce447df7c3e2
Alexandre Zollinger Chohfi (azchohfi) added a commit to microsoft/microsoft-ui-reactor that referenced this pull request Aug 27, 2026
* Make reactor-getting-started packaging-neutral

The skill states 'WindowsPackageType MUST be None' as if it were an invariant of
Reactor, but it is a property of the current dotnet new reactorapp template. An
agent handed a packaged Reactor project therefore edits it back to unpackaged;
adding WindowsPackageType=None to a project with a Package.appxmanifest silently
drops its package identity while the build still succeeds, so nothing surfaces
the mistake.

Stop mandating a packaging mode. Describe both shapes, tell the agent to keep
whatever the scaffold produced, and warn about the downgrade. This is correct
against the current unpackaged template and against a packaged one, so it does
not have to land in lockstep with a template change.

Also drops the adjacent 'exactly two source files' claim, which is false for a
packaged scaffold and would contradict the same change.

* Describe both packaged shapes, don't forbid WindowsPackageType

Review follow-up. The packaging-neutral rewrite named `EnableMsixTooling` as
the packaged marker and told the agent never to set `WindowsPackageType`.
Both were wrong in ways that matter:

- `EnableMsixTooling` only enables the single-project MSIX tooling. A project
  with `WindowsPackageType=None` *and* `EnableMsixTooling=true` builds
  unpackaged -- `None` wins. Verified live: that combination emits no
  `AppxManifest.xml` / `resources.pri` / `.build.appxrecipe`, while the same
  csproj with the property absent emits all three.
- Packaged does not require `WindowsPackageType=MSIX`. Omitting the property
  entirely also yields a packaged app off the default, which is what the
  templates in microsoft/WindowsAppSDK#6620 do. Mandating `MSIX` would have
  described that scaffold as broken.
- "Don't set `WindowsPackageType` yourself" contradicted
  `docs/guide/packaging.md`, which tells you to set it to `MSIX` -- and this
  skill routes readers to that guide two paragraphs later.

Both shapes are now described with the property precedence stated, and the
rule is scoped to the actual hazard (don't flip the mode of a project you
didn't scaffold) rather than to the property. `Package.appxmanifest` stays
the discriminator; it is true today and after #6620, so neither change waits
on the other.

Also drops `app.manifest` as a packaged marker -- the repo's only one belongs
to an unpackaged project (`tests/startup_perf/BlankWinUI3`) -- and the
present-tense claim about a packaged template's file list.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 784c77a5-bfd2-40f4-96a5-ce447df7c3e2

* Stop asserting the template's using block is implicit-usings-free

Companion to the packaging fix in 525efc2, same defect class: a property of
`dotnet new reactorapp` stated as a property of Reactor.

The skill claimed the `.csproj` does **not** enable implicit usings. That is
true of the shipped template, which sets no `ImplicitUsings` property, and
false of the templates in microsoft/WindowsAppSDK#6620 --
`ReactorBlankApp/ProjectTemplate.csproj` sets `<ImplicitUsings>enable</ImplicitUsings>`.

The divergence is observable in the scaffolded source: #6620's `App.cs` opens
with six usings and no `using System;`, against the seven in
`tools/Templates/templates/WinUIApp-CSharp/App.cs:1-7`, which leads with it.
That also made the sentence's own worked example misfire, since `System.Linq`
is in the implicit set -- an agent told to add `using System.Linq;` before
`.Select(...)` finds it already in scope.

Reworded so it holds for both: `App.cs` keeps its `using` block and that is
still where you add namespaces, with a note that some templates enable
implicit usings. The "seven-line using block" count in "Starting a new app"
goes with it, for the same reason.

The *Required imports* list is left as-is -- spelling `using System;` out
explicitly is redundant under implicit usings, not wrong.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 784c77a5-bfd2-40f4-96a5-ce447df7c3e2

---------

Co-authored-by: azchohfi <527713+azchohfi@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 784c77a5-bfd2-40f4-96a5-ce447df7c3e2
@azchohfi

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.

@azchohfi
Alexandre Zollinger Chohfi (azchohfi) merged commit 2fd7355 into main Aug 28, 2026
56 checks passed
@azchohfi
Alexandre Zollinger Chohfi (azchohfi) deleted the azchohfi-reactor-dotnet-new-templates branch August 28, 2026 05:11
Alexandre Zollinger Chohfi (azchohfi) pushed a commit to microsoft/microsoft-ui-reactor that referenced this pull request Sep 24, 2026
Deletes `Microsoft.UI.Reactor.ProjectTemplates` (`tools/Templates/`, short name
`dotnet new reactorapp`). Reactor's project templates now ship in the official
Windows App SDK pack, `Microsoft.WindowsAppSDK.WinUI.CSharp.Templates`, which
published 0.0.7-alpha today carrying `reactor`, `reactor-mvu`, `reactor-navview`
and `reactor-tabview` (microsoft/WindowsAppSDK#6620 + #6786). Verified against
the published pack: a scaffold emits Microsoft.UI.Reactor 0.1.0-preview.16 and a
Package.appxmanifest.

Behaviour change worth calling out: no template produces the **unpackaged**
shape any more. The Windows App SDK templates scaffold packaged single-project
MSIX apps, so `dotnet run` launches with package identity and needs Developer
Mode. For an unpackaged app, scaffold and set WindowsPackageType=None by hand --
the packaging guide documents both shapes.

Published versions on NuGet.org are unaffected (NuGet does not allow deletion);
they are to be deprecated with a pointer to `dotnet new reactor`. That is a
portal action, not something this commit can do.

Removed:
  - tools/Templates/ and its solution + Directory.Build.props references
  - the `Pack Templates` step in release.yml and the internal ADO pipeline
  - `mur pack-local`'s templates pack and its `--framework-version` flag
    (plus the now-dead ResolveTemplateFrameworkVersion helper); the SemVer
    helpers it shared with `mur templates` are kept and still used
  - `mur doctor`'s local-template-nupkg check
  - TemplateMetadataTests and CreateTemplateTests

`mur clean-local` deliberately still knows the old package id: dev machines
bootstrapped before this change have a stale nupkg and template registration,
and cleaning those up is exactly what that command is for.

CreateTemplateTests also *contained* TemplatePackageTestFixture, which
SourceMapPackageConsumerTests depends on via LocalPackageFeedCollection.
Extracted it to LocalPackageFeedFixture (renamed, template plumbing dropped)
rather than losing unrelated coverage.

Tests: three guards -- bootstrap installs the Windows App SDK pack, bootstrap
never installs the removed id, and the repo no longer ships the package. The
last asserts on tracked source rather than Directory.Exists, because bin/obj
under tools/Templates are gitignored and survive a pull; an existence check
would fail for any contributor who had built it. Mutation-verified by
resurrecting the csproj. Suite 14,151 passed / 0 failed; Release build clean.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563
Alexandre Zollinger Chohfi (azchohfi) added a commit to microsoft/microsoft-ui-reactor that referenced this pull request Sep 25, 2026
* Use the Windows App SDK dotnet new templates instead of ours

The Windows App SDK template pack now ships first-class Reactor templates
(microsoft/WindowsAppSDK#6620): `reactor`, `reactor-mvu`, `reactor-navview`,
and `reactor-tabview`. Switch to those as the supported scaffolding path.

The in-repo `Microsoft.UI.Reactor.ProjectTemplates` pack (`dotnet new
reactorapp`, unpackaged) is kept — `mur pack-local` still builds it and the
release workflow still publishes it — but nothing installs it automatically
any more.

The big user-visible change is that scaffolded apps are now **packaged**
(single-project MSIX) rather than unpackaged, so `dotnet run` launches with
package identity and needs Developer Mode. Docs are updated accordingly.

- bootstrap.ps1: step 5 installs the Windows App SDK pack via `mur templates
  install`. New `-WinAppSdkTemplatesSource` (local feed, for testing an
  unpublished build), `-WinAppSdkTemplatesVersion`, and `-SkipTemplates`.
- New `mur templates install|status`, shared by bootstrap and `mur upgrade`.
- `mur doctor` now checks for the Windows App SDK pack; the legacy local
  template nupkg drops from FAIL to WARN.

Two hazards found and handled while validating:

- `dotnet new install <id>` has no `--prerelease` switch and resolves
  stable-only, so installing the bare package id fails outright while the
  pack is prerelease-only (it is today, at 0.0.6-alpha). We resolve the
  newest published version ourselves — newest stable, else newest
  prerelease — and install an explicit `<id>::<version>`.
- `dotnet new install --force` uninstalls the existing package *before*
  downloading the replacement, so a failed install leaves the machine with
  no templates at all. Observed for real: bare id + `--force` + no stable
  version uninstalled a working prerelease and then failed with exit 103.
  `--force` is now only used to replace an install with a version already
  known to exist, and `Install` leaves an existing install untouched when
  it cannot resolve a target.

Tests: version-selection rules (prefer stable, else newest prerelease
ordered numerically), local-folder version discovery, a source-level guard
against re-pairing `--force` with an unresolved spec, and bootstrap guards
that it installs the new pack and does not install the legacy one. All
mutation-checked. Full suite green (13,380).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* fix(cli): report what `mur templates install` actually did

Found by running the command against the real published template pack
(0.0.7-alpha) with NuGet unreachable. The non-destructive guard worked
correctly -- it kept the installed pack and uninstalled nothing -- but the
command still printed "Installed.", telling the user an install had happened
when none had.

A bare exit code cannot express the difference: "kept the existing install
because nothing could be resolved" is a success for exit-code purposes but is
not an install. `Install` now returns an `InstallOutcome`
(Installed / Updated / AlreadyCurrent / KeptExisting / Failed) and the callers
report the real outcome.

Also adds the credential-provider hint to the failure path: `dotnet new
install` does not use the NuGet credential provider, so an authenticated feed
reports "the package does not exist" -- indistinguishable from the package
genuinely not being published. That cost real time today.

Verified against the live pack, all three non-failure paths:
  no resolution + installed -> "Kept the existing install"
  --version 0.0.7-alpha     -> "Already up to date"
  (failure path unchanged)

Tests: outcome enum completeness, plus a source-level guard that the command
does not unconditionally print "Installed." -- the bug was in the reporting,
so asserting on Install() alone would have missed it.
Full suite 14,152 passed / 0 failed.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Remove the in-repo dotnet new template package

Deletes `Microsoft.UI.Reactor.ProjectTemplates` (`tools/Templates/`, short name
`dotnet new reactorapp`). Reactor's project templates now ship in the official
Windows App SDK pack, `Microsoft.WindowsAppSDK.WinUI.CSharp.Templates`, which
published 0.0.7-alpha today carrying `reactor`, `reactor-mvu`, `reactor-navview`
and `reactor-tabview` (microsoft/WindowsAppSDK#6620 + #6786). Verified against
the published pack: a scaffold emits Microsoft.UI.Reactor 0.1.0-preview.16 and a
Package.appxmanifest.

Behaviour change worth calling out: no template produces the **unpackaged**
shape any more. The Windows App SDK templates scaffold packaged single-project
MSIX apps, so `dotnet run` launches with package identity and needs Developer
Mode. For an unpackaged app, scaffold and set WindowsPackageType=None by hand --
the packaging guide documents both shapes.

Published versions on NuGet.org are unaffected (NuGet does not allow deletion);
they are to be deprecated with a pointer to `dotnet new reactor`. That is a
portal action, not something this commit can do.

Removed:
  - tools/Templates/ and its solution + Directory.Build.props references
  - the `Pack Templates` step in release.yml and the internal ADO pipeline
  - `mur pack-local`'s templates pack and its `--framework-version` flag
    (plus the now-dead ResolveTemplateFrameworkVersion helper); the SemVer
    helpers it shared with `mur templates` are kept and still used
  - `mur doctor`'s local-template-nupkg check
  - TemplateMetadataTests and CreateTemplateTests

`mur clean-local` deliberately still knows the old package id: dev machines
bootstrapped before this change have a stale nupkg and template registration,
and cleaning those up is exactly what that command is for.

CreateTemplateTests also *contained* TemplatePackageTestFixture, which
SourceMapPackageConsumerTests depends on via LocalPackageFeedCollection.
Extracted it to LocalPackageFeedFixture (renamed, template plumbing dropped)
rather than losing unrelated coverage.

Tests: three guards -- bootstrap installs the Windows App SDK pack, bootstrap
never installs the removed id, and the repo no longer ships the package. The
last asserts on tracked source rather than Directory.Exists, because bin/obj
under tools/Templates are gitignored and survive a pull; an existence check
would fail for any contributor who had built it. Mutation-verified by
resurrecting the csproj. Suite 14,151 passed / 0 failed; Release build clean.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Address PR-review findings on the template migration

Ran the repo `pr-review` skill (8 dimensions + multi-model cross-check, all 6
high findings confirmed by the second model). Fixes below.

CI BLOCKER (introduced by the package deletion):
  docs/_pipeline/templates/packaging.md.dt still resolved a snippet from the
  deleted tools/Templates/. SnippetExtractor raises REACTOR_DOC_SNIPPET_001 on a
  missing source file and CI runs `docs compile --ci`, so this branch would have
  failed the docs-build job. Replaced with an inline example.

Stale docs the deletion invalidated:
  getting-started.md.dt and packaging.md.dt still told users to install
  Microsoft.UI.Reactor.ProjectTemplates and run `dotnet new reactorapp`, and
  still described the scaffold as unpackaged. Both rewritten for
  `dotnet new reactor` + the packaged MSIX shape, and both guides recompiled.
  (These two templates are also being rewritten by a parallel workstream; this
  is the minimum factual correction, not a redesign.)

Destructive-install guard was incomplete (high):
  An explicit --version bypassed it entirely — the pin was trusted without any
  existence check and then paired with --force, which uninstalls before
  downloading. A typo'd pin would destroy a working install. The decision is now
  a pure `PlanInstall` table: --force is reachable only for a target confirmed
  present in the feed or folder; an unconfirmed pin is refused with the existing
  install left intact.

Credential leak (high):
  The echoed `dotnet new install ... --add-source <url>` line printed feed URLs
  verbatim, so a PAT in user-info or query landed in console and CI logs. Added
  RedactSource; local folder paths are still printed in full.

`install --help` performed an install (high):
  Help was only handled before the subcommand. Added install-level help and
  strict argv parsing — unknown options, stray positionals and flags missing a
  value are now rejected before any side effect.

Install outcomes were pinned by source-greps, not behaviour (high):
  Replaced the regex-on-source guards with a table test over `PlanInstall`
  (7 rows + an exhaustive property that ForcedReplace implies a confirmed
  target), and extracted `DescribeOutcome` so the reporting bug is tested
  directly rather than by grepping for a string literal.

Also:
  - --source URL was ignored during version resolution, so a custom feed
    silently resolved a version from nuget.org and installed a different
    package. URL sources now require an explicit --version.
  - Refuse plaintext http:// sources for a code-generating template package.
  - Extracted InterpretInstalledVersionOutput with tests for the present,
    absent and malformed listings (an adjacent package id must not be matched).
  - `mur upgrade` returned 0 when an explicitly requested --templates-source /
    --templates-version install failed; it now fails, while the routine
    no-argument refresh stays best-effort.

Mutation-verified: reintroducing the unconfirmed-pin force reddens both
PlanInstall guards. Exit codes checked directly (help 0; unknown flag, missing
value, http source and unpinned URL source all 1).
Suite 14,163 passed / 0 failed; Release build 0 errors; both guides recompile.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Address Copilot review round 1

Fixes all 11 findings. Two were real defects I had missed.

CI failure I would have shipped (high):
  Deleting tools/Templates/ broke
  Reactor.DocPipeline.Tests/MinimalCsprojDocTests.Documented_package_id_matches_the_scaffolded_template,
  which loads the deleted Company.ReactorApp1.csproj and asserts it exists. My
  earlier "suite passes" only covered tests/Reactor.Tests, so this never ran.
  Confirmed failing, then retargeted: the page's fast path is now a pack outside
  this repo, so there is no in-repo csproj to cross-check; the test now pins that
  the documented block names the real framework package id, keeping its positive
  control. Also emptied the now-stale WinAppSDKReferenceGuardTests allowlist,
  which existed solely for that template.

Credential exposure beyond the echo (high):
  Redacting the printed command line does not stop another process from reading
  this process's command line on Windows, where the feed URL is an argument. A
  --source URL carrying credentials in user-info or the query string is now
  refused outright, pointing at NuGet.config + a local folder instead. The
  Process.Start failure diagnostic also formatted the raw argument list; it now
  redacts like the normal echo.

Destructive --force via a pinned URL feed (medium):
  ResolveAvailableVersions does not query a URL source — it falls through to the
  public index. A version that exists publicly but is absent from the user's feed
  therefore set targetExists=true and authorized the --force path, uninstalling a
  working pack before failing to download. URL sources are now always treated as
  unverifiable, so a pin against one can never force.

Bootstrap reported success it had not verified (medium):
  `mur templates install` returns success for KeptExisting, which includes keeping
  a pack too old to contain any Reactor template (0.0.6-alpha shipped without
  them). Bootstrap printed "templates registered" regardless. It now confirms
  `dotnet new list reactor` actually resolves, and warns with a remediation
  otherwise.

Documented install commands could not work (low x5):
  README, the getting-started template, the release runbook and the agent
  fallback all told users to run a bare `dotnet new install <id>`. By this PR's
  own reasoning that cannot resolve a prerelease-only pack, and the pack is
  prerelease-only today. All pinned to ::0.0.7-alpha with the reason stated;
  CHANGELOG now points at `mur templates install` or the pinned spec.

Verified: tests/Reactor.Tests 14,163 passed; tests/Reactor.DocPipeline.Tests 462
passed (was 1 failed); Release build 0 errors; getting-started recompiled.
Reactor.IntegrationTests fails locally only on NU1301/TLS reaching nuget.org from
temp consumer projects — environmental, unrelated to the extracted fixture, which
constructs successfully.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Harden template detection and credential redaction

Copilot review round 2.

Short-name detection matched with Contains("reactor"), which also matches
`reactor-mvu` and `winui-reactor` — a pack that shipped the richer shells but
not the blank template would read as available, and `mur doctor` would report a
false PASS. A `\breactor\b` regex has the same hole, because '-' is a word
boundary. Match the short name as a whole token instead, delimited by
whitespace, a comma, or the edge of the text (short names appear
comma-separated within a whitespace-delimited column).

The match is deliberately case-sensitive: the Template Name column carries the
capitalised prose word ("Reactor MVU App"), which *is* a standalone token, so a
case-insensitive token match still passes when the blank template is absent.
The new test caught exactly that.

bootstrap.ps1 hand-rolled the same check as a `\breactor\b` regex over
`dotnet new list` output, so it carried both bugs. It now calls
`mur templates status`, which is the tested implementation, and keys off its
exit code.

Credential rejection and redaction covered user-info and the query string but
not the fragment, which UriBuilder preserves verbatim. A `--source` URL whose
fragment carries a PAT would have been echoed to the console and passed on the
child process command line, readable by any other process on Windows.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Require --source to be a local folder, and fix the CI template guard

Copilot review round 3.

`dotnet new install` has no feed-isolation switch — `--add-source` only *adds*
to the configured sources. So `mur templates install --source <feed-url>
--version X` could be satisfied from nuget.org instead of the requested feed,
installing a different package. The version pin cannot disambiguate them
either: an unpublished build and the published pack routinely carry the same
version string (a locally packed 0.0.7-alpha vs the published 0.0.7-alpha).

A local folder has neither problem — it is enumerable, so a pin is confirmable,
and `--add-source <folder>` with an exact version resolves the file that is
actually there. `dotnet new install` also ignores the NuGet credential
provider, so an authenticated feed URL fails anyway with a misleading "the
package does not exist". So require a folder and point at the
restore-then-install-from-cache workflow, which is what the help text and
bootstrap.ps1 already described.

That subsumes the previous URL-specific guards (insecure scheme, credentials in
user-info/query/fragment) and makes the property stronger: no URL now reaches
the child process command line at all.

PlanInstall gains the matching rule — with an explicit source, refuse anything
not confirmed to be in it, including the empty-folder case where no version
resolves and a bare package id would fall through to the configured feeds. The
previous table allowed that whenever nothing was installed.

The bootstrap CI guard verified each short name with a plain substring test, so
the `reactor` probe was satisfied by `reactor-mvu` — the same prefix-matching
hole just fixed in the CLI. It now uses the same delimited token match.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Address code-quality findings on the template migration

GitHub code-quality review, 10 findings.

Generic `catch` clauses narrowed to the exceptions the guarded operation can
actually raise, so a bug inside the try block surfaces instead of being
swallowed as "offline" or "best-effort cleanup":
  - the NuGet flat-container query to HttpRequestException /
    TaskCanceledException / JsonException,
  - local nupkg enumeration to IOException / UnauthorizedAccessException /
    ArgumentException,
  - both `dotnet` process launches to Win32Exception /
    InvalidOperationException / IOException,
  - the two temp-directory cleanups in the tests and the integration-test
    fixture to IOException / UnauthorizedAccessException.

EnumerateLocalVersions now maps with Select instead of an accumulate-only
foreach.

`Path.Combine(repoRoot, "local-nupkgs")` became `Path.Join`: Combine discards
everything before a rooted later argument, which is not what this call wants.

Dropped a null-coalesce on a value the compiler already knows is non-null on
that branch.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Restore packaging.md to the solid doc tier

Deleting the in-repo template package removed a `snippet=` reference from
packaging.md.dt, dropping it to 2 resolved snippets. The solid tier requires 3,
so REACTOR_DOC_TIER_003 failed both the "Docs build" and "Docs tier-drift" CI
jobs.

Rather than pad the count, add the snippet the MSIX section was missing: the
identity block of this repo's own packaged selftest host, which is a real
single-project MSIX app. The prose said "Package.appxmanifest declares the
package identity" and then showed no manifest at all.

Also corrects the publish-shape table, which still labelled the unpackaged row
"(template default)". The Windows App SDK `reactor` templates scaffold a
packaged app, so MSIX is the default now — the page's own opening paragraph
already said so.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Resolve template versions through the configured feed

Copilot review round 4.

The version resolver hard-coded api.nuget.org's flat container. On a machine
that reaches its configured mirror but not nuget.org, resolution returned null;
with nothing installed the install then fell back to a bare package id, which
cannot reach a prerelease-only pack — so bootstrap failed with a usable feed
sitting right there.

`mur templates install` now takes `--feed <service-index-url>` (also
`mur upgrade --templates-feed`), used for version lookup only and never passed
to `dotnet new install`. bootstrap.ps1 passes the source its feed resolver
already selected. Resolution reads PackageBaseAddress out of the service index
rather than guessing a /flatcontainer/ path — service-index hosts generally
have no such path and 404 for every package, including ones that exist. Falls
back to nuget.org when the feed cannot be read.

Verified against the real internal feed: the composed URL returns 122 versions
for the newtonsoft.json control and 5 for the template pack.

Also in this round:

- The bootstrap CI guard token-matched before checking the "No templates found"
  marker. That output repeats the search term and prints a `dotnet new search
  reactor` hint, both whole-token matches — so the probe reported success
  exactly when the template was absent. Confirmed against real not-found text.

- `mur upgrade --templates-source` / `--templates-version` were silently ignored
  as the final argument, running an unpinned upgrade instead of reporting the
  missing value. ParseFlag now scans the whole argv and reports it.

- The file header still described the legacy ProjectTemplates pack as built by
  `mur pack-local` and published from the release workflow; this PR deleted
  both. Help text, XML docs and the bootstrap.ps1 parameter docs still offered
  feed URLs as a `--source`, which is now rejected.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Use Path.Join in the touched test files

Code-quality review flagged every Path.Combine in the files this PR touches:
Combine silently discards everything before a rooted later argument, which is
never what these calls want. Path.Join concatenates unconditionally and is
identical for the relative segments used here.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Validate the version feed, and derive one from an explicit NuGet config

Copilot review round 5.

The `--feed` URL went straight to HttpClient without the feed-URL policy the
rest of the repo applies to `-NuGetSource` (tools/BootstrapFeedResolver.ps1).
Version metadata is what selects the package to install, so fetching it over
plaintext lets a network attacker choose the version, and credentials in the
URL would be sent to whatever endpoint it names. IsAllowedFeedUrl now mirrors
Test-ReactorPackageFeedUrl: HTTPS, or HTTP only for loopback, and no
user-info/query/fragment. A rejected feed warns and falls back to nuget.org
rather than failing the install.

bootstrap only supplied `--feed` for a *detected* source. An explicit
`-NuGetConfig` reaches restore as `--configfile` and yields no bare URL, so the
explicit-mirror path still resolved against nuget.org only — the exact case the
feed support was added for. Get-ReactorFeedSourceFromConfig reads the first
enabled feed URL out of that config (preferring packagefeedproxy, matching the
detector's order) and bootstrap passes it.

`mur templates install` printed four `dotnet new` scaffold lines unconditionally
on success. KeptExisting is a success that means resolution failed and an older
pack was left in place — and 0.0.6-alpha shipped without the Reactor templates,
so those lines would immediately fail. The command now verifies the short name
resolves before printing them, and exits non-zero with remediation when it
doesn't.

Docs: the MSIX row's "(template default)" label attached generic signed-MSIX
publish properties to the scaffold, which doesn't set them. The default is now
stated in prose — scaffolded apps are packaged via Package.appxmanifest and
EnableMsixTooling, while producing and signing a redistributable .msix is a
separate publish concern.

Also drops a stale `<see cref="CreateTemplateTests"/>` left by that class's
deletion.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Filter the service-index resources with Where

Code-quality review: the loop implicitly filtered to object elements in its
body. Behaviour and defensive checks are unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Revalidate the advertised base address, and test the config feed extraction

Copilot review round 6.

The service-index URL was validated, but the PackageBaseAddress it advertises
was then followed without any check. A compromised or misconfigured HTTPS index
could point it at plaintext HTTP, or at a URL carrying credentials — and that
second request is the one that fetches the version list, which is what selects
the package to install. The parsed base address now goes through the same
policy, and a rejected one falls back to nuget.org.

Get-ReactorFeedSourceFromConfig was only covered by source-text assertions
("the function exists", "it is called"), which would survive any XPath,
disabled-source, or preference bug — and the failure is silent, sending version
lookup back to nuget.org on a mirror-only machine. Added behavioural cases to
BootstrapFeedResolver.Tests.ps1: mirror preference with a local folder and a
trailing slash, a disabled preferred mirror falling through, a config whose
only URLs fail the policy, malformed XML, and a missing file. Mutation-checked
both filters — removing the disabled-source check or the URL policy reddens the
matching case and nothing else.

bootstrap's completion guidance advertised `dotnet new reactor` even under
-SkipTemplates, which deliberately leaves the pack uninstalled. It now points
at `mur templates install` in that case.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Express the service-index scan as a LINQ pipeline

Code-quality review: the remaining `continue` guards were implicit filters on
the enumerated resources. Extracting the per-resource projection into a local
function leaves a Where/Select/FirstOrDefault chain with no filtering hidden in
a loop body. Behaviour is unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Isolate the scaffolded TestApp from the repo's build rules

The Bootstrap job's "Build TestApp (packaged single-project MSIX)" step failed
with 36 IL2081 trim-analysis errors from CsWinRT's generated ABI code and
NETSDK1144.

Cause: the TestApp is scaffolded under the repo so NuGet's parent-dir walk
finds the root nuget.config (which is the point — it maps local-nupkgs/), but
MSBuild's walk then also finds the root Directory.Build.props/.targets, which
set IsAotCompatible=true and promote IL trim warnings to hard errors. A
packaged Release build runs ILLink, and CsWinRT's generated marshalling emits
IL2081 by design, so the app cannot build under repo rules. Outside the repo
those are warnings and the build succeeds — which is why this only appeared
once the templates started scaffolding packaged apps.

Shadow both files with `<Project />`, the same trick already used for
Directory.Packages.props, and for the same stated reason: faithfully mimic an
end-user scaffold, which has none of these above it.

Verified the mechanism rather than assuming it — a probe project under the same
directory reports IsAotCompatible=[true] without the shadow and [] with it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Enforce the feed policy across redirects, and stop reporting unusable templates as success

Copilot review round 7.

HttpClient follows redirects by default, which defeated IsAllowedFeedUrl
entirely: a validated HTTPS service index could 302 to plaintext HTTP, or to a
host with credentials in the URL, and the body would be accepted without the
policy ever seeing that address. Since the version list is what selects the
package to install, that is a real downgrade vector. Redirects are now handled
manually with the policy re-applied at every hop and a 5-hop ceiling.

Mutation-checked: removing the per-hop check reddens exactly the two downgrade
tests and nothing else. A compliant-redirect case is included so the negative
tests cannot pass vacuously against a method that always returns null.

Two remaining false-PASS paths, the same class already fixed in `mur templates
install`:

- bootstrap warned when step 5's verification failed but still printed
  `dotnet new reactor` in its closing guidance — the exact command it had just
  proved unavailable. `$templatesVerified` is hoisted and the guidance now
  branches on it.
- `mur upgrade` checked only the install outcome. An older pack (0.0.6-alpha
  predates the Reactor templates) installs cleanly and still cannot scaffold, so
  it reported "Upgrade complete." It now verifies availability, and fails when
  the user explicitly pinned a source or version.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Mask file-URI query/fragment, cover the install parser, and honour --templates-feed

Copilot review round 8.

RedactSource short-circuited on `uri.IsFile` as "a local path, nothing to hide".
A file URI can still carry a query or fragment, and either can hold a token, so
it now only short-circuits when there is demonstrably nothing to mask. (User-info
on the file scheme turns out not to be constructible at all — Uri rejects it —
so the test asserts the case that is actually reachable rather than one that
silently exercises the TryCreate-failure path.)

`mur upgrade`'s explicit-request checks listed --templates-source and
--templates-version but not the new --templates-feed, so a caller who named a
feed and got a failed or unusable install still saw exit 0.

`mur templates install`'s strict argv parser had no automated coverage, which is
the parser whose whole job is to stop `--sorce ./pkgs` from silently installing
from the configured feeds instead. Added TemplatesCommandArgvTests covering
help, unknown options, bare positionals, missing values, a following flag
misread as a value, and both no-subcommand and unknown-subcommand paths. Only
branches that return before touching the machine are exercised — a real install
is a global `dotnet new install` — and each case also asserts the install banner
never printed.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Dispose the stub handler's responses

Code-quality review: StubHandler allocated a fresh NotFound response on every
exhausted-queue request and never disposed it. One reusable instance, plus a
Dispose override that also drains any responses the test did not consume.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Resolve a relative --templates-source against the caller's CWD

Copilot review round 9.

`mur upgrade --templates-source ./pkgs` passed the path through unchanged while
Install() runs `dotnet new install --add-source` with repoRoot as the child
process working directory. The existence check therefore resolved against the
caller's CWD and the install against repoRoot — so a valid source could fail, or
silently name a different folder. `mur templates install` and bootstrap.ps1
already normalize for exactly this reason.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Drain both pipes concurrently in RunCapture

Copilot review round 10.

RunCapture read stdout to the end and only then read stderr. `dotnet new` can
fill the unread stderr pipe and block before it exits, so the CLI hangs — a
deadlock, not a slow path. Every `mur templates status`, `mur doctor` template
probe and bootstrap verification goes through this method.

Both streams are now started with ReadToEndAsync and awaited together, matching
the pattern CheckCommand already documents for the same hazard.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Mask credentials in URL-like sources that Uri refuses to parse

Copilot review round 11.

RedactSource returned its input unchanged when Uri.TryCreate failed, on the
assumption that anything unparsable is a local path. It isn't: Uri rejects
user-info on the file scheme outright, so `file://user:pat@host/share` lands in
exactly that branch — and that branch runs on every *rejected* --source, which
is precisely the set of values a user is most likely to have typed a PAT into.

URL-looking values (containing "://") are now masked best-effort: anything from
the first '?' or '#' is dropped, and the authority's user-info is replaced. Plain
paths — Windows, UNC and relative — still pass through untouched, since the error
messages that quote them are useless if mangled.

Mutation-checked, which also corrected the test's own comment: removing the new
masking reddens the file-URI row and only that row, so the bracketed-URL rows go
through the ordinary UriBuilder path rather than this one. The comment now says
that instead of implying all four exercise the new code.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* State the ShortNames contract, and ground the parser fixtures in the real listing

Copilot review round 12.

ShortNames was documented as "every Reactor short name the pack registers". It
isn't: the published 0.0.7-alpha pack registers nine names for four templates —
each has a `winui-` alias, and the blank one also answers to `reactor-blank`.
Verified against `dotnet new list reactor` rather than taken on faith.

Kept the four canonical names (listing nine under "scaffold an app with" would
be noise) and made the contract explicit instead, pointing callers that need to
recognise an arbitrary alias at the listing.

The same check turned up that my InterpretTemplateListOutput fixtures were
invented rather than measured, and were missing a trap the real output contains:
the Tags column carries a slash-delimited "Reactor". Both fixtures are now
verbatim from the shipped pack, so the parser is tested against what it will
actually see.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Distinguish "installed but unusable" from "install failed"

Copilot review round 13 — an interaction between two earlier fixes in this PR.

Round 5 made `mur templates install` exit non-zero when the pack installs but
`dotnet new reactor` still doesn't resolve. bootstrap treats any non-zero from
that command as fatal, so an old 0.0.6-alpha install hit Fail and exited before
reaching the verification step and the guidance gated on it — the two things
rounds 5 and 7 added for exactly that case. Both were unreachable.

The command now exits 2 for "installed, not usable", distinct from 1 for a real
install failure (or rejected arguments), and bootstrap lets 2 through. The
mapping is a pure ExitCodeForAvailability so the contract bootstrap depends on
is testable without touching the machine, and the help text documents all three
codes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Separate the three `mur templates status` failure modes

Copilot review round 14.

`mur templates status` returned 1 for three different situations — the template
engine could not be enumerated, the pack is installed without the Reactor
templates, and the pack is not installed — so bootstrap warned "is installed but
does not provide `dotnet new reactor`; that version predates the Reactor
templates" for all of them. For a machine with no pack at all, or a probe that
simply failed, that sends the user to re-pin a version that was never the
problem.

status now exits 0 / 1 (probe failed) / 2 (installed but unusable) / 3 (not
installed), and bootstrap emits the matching remediation for each. The mapping
is a pure StatusExitCode(bool?, bool?) so the distinction is covered by real
assertions, including the case where the *package list* is unreadable while the
short name is absent — that is a probe failure, not a stale pack.

Smoke-tested live: on a machine with 0.0.7-alpha installed, `mur templates
status` prints the available line and exits 0.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Pass the configured mirror to the install, not only to version resolution

Copilot review round 15.

`--feed` was resolution-only. `dotnet new install` runs its own restore and
ignores the MSBuild RestoreSources/RestoreConfigFile that
Invoke-ReactorWithRestoreEnvironment sets, so on a machine whose mirror is not
in the default NuGet configuration bootstrap could resolve a version from the
mirror and then fail to download it — or pull it from an unintended configured
feed.

The feed is now also added to the install as a supplementary `--add-source`,
but only when it passes IsAllowedFeedUrl — which forbids credentials, so nothing
secret reaches the child process command line. That is the distinction that
makes this safe where a URL `--source` is not: `--source` means "install *from*
here" and `--add-source` cannot guarantee it, whereas a mirror is "also look
here", which is exactly what the flag does.

The argument list is now built by a pure BuildInstallArgs so the wiring is
asserted directly rather than inferred. The echo also redacts by position — the
value after each `--add-source` — instead of comparing against one variable,
which would have left a second source unredacted.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Keep the mirror out of a local-source install, and match package ids exactly

Copilot review round 16.

Round 15 added the configured mirror as a second `--add-source`, including when
the caller supplied a local `--source`. That reintroduces precisely the
collision `--source` exists to prevent: NuGet treats identical id+version
candidates across sources as interchangeable, so an unpublished local
0.0.7-alpha can be served by the published 0.0.7-alpha instead. The mirror is
now used only when there is no folder source — and with a folder source it was
never needed for resolution either, since the folder listing is authoritative.

Separately, IsPackageInstalled substring-searched the whole `dotnet new
uninstall` transcript, so a longer package id that merely contains ours — or the
uninstall hint line that echoes it — reported this pack as installed and sent
`status`/`doctor` to the wrong remediation. It now matches the id line exactly,
as InterpretInstalledVersionOutput already did, behind a testable
InterpretPackageInstalledOutput.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Replace the constant-condition switch in StatusExitCode

Code-quality review: switching on a nullable after the non-null cases are
already ruled out gives the analyzer arms it can prove constant. An explicit
null guard says the same thing without them; semantics are unchanged and the
StatusExitCode theory still covers all five rows.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Install the nupkg itself when --source names a local folder

Copilot review round 17.

`dotnet new install id::version --add-source <folder>` leaves every configured
feed active, and NuGet queries sources in parallel, so a local unpublished nupkg
that reuses a published id+version can be silently served by the public package.
Enumerating the folder confirms the version exists; it says nothing about which
bytes get selected. That is the whole reason --source exists, so the previous
rounds' narrowing (rejecting URL sources, refusing unconfirmed pins, keeping the
mirror out) tightened everything around this hole without closing it.

With a folder source and a known version the install now targets the .nupkg file
directly, and passes no --add-source at all — there is no second candidate to
choose between. The mirror-feed path for the no-folder case is unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Retire `mur templates install` in favour of `winapp new`

The Windows App SDK CLI now installs the template pack on demand: `winapp new
-t reactor -n MyApp` installs and scaffolds in one step, `winapp new --list`
installs without scaffolding, and it offers to update a stale pack. That is
everything Reactor's own installer did, done by the tool that owns the pack.

Reactor carried an installer because `dotnet new install` has no --prerelease
switch and resolves stable-only, which fails outright while the pack is
prerelease-only. Working around that meant resolving versions off the NuGet
flat container, re-validating every redirect hop, redacting credentials out of
feed URLs, and tiptoeing around `dotnet new install --force` (which uninstalls
the existing pack *before* downloading the replacement). None of it is needed
now, so ~700 lines of it are gone along with its tests.

What changed:

- `mur templates install` is removed. The subcommand is still *recognised* and
  names its replacement, rather than falling into "unknown subcommand" — it
  existed, bootstrap and the docs called it, and anyone with it in muscle
  memory needs pointing at `winapp new`, not left hunting for a typo.
- `mur templates status` is unchanged, and still backs `mur doctor` and
  bootstrap's verification. `WinAppSdkTemplates` keeps only the probes.
- `bootstrap.ps1` §5 runs `winapp new --list --use-defaults`: installs when
  missing, keeps an already-installed pack, never prompts — the same
  self-healing semantics the old step documented. winapp is installed in §4;
  when it is absent (`-SkipWinAppCli`, or no winget) the step warns and lets
  the existing verification report the real state instead of failing.
- `mur upgrade` reports on the templates instead of installing them, so its
  `--templates-source/-version/-feed` flags are gone.
- `-WinAppSdkTemplatesSource` is removed — winapp has no local-folder
  equivalent. `-WinAppSdkTemplatesVersion` maps to `--template-version`.

Verified against the real CLI rather than its help text: `winapp new -t reactor`
emits a packaged Reactor app (App.cs, Package.appxmanifest, EnableMsixTooling,
Microsoft.UI.Reactor reference), `--list` shows all four templates, and
`--list --use-defaults` exits 0 leaving the installed pack untouched. `mur
templates status` / `install` / `--help` and `mur doctor` all smoke-tested.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Fix fallout from retiring the in-repo template installer

Copilot review on the winapp migration — six code/doc findings, all introduced
by that refactor.

Probe classification. `AreTemplatesAvailable` treated any readable output as an
answer, so an SDK/engine failure whose stderr happens not to contain "No
templates found" was reported as a definite *missing* template — making
`mur doctor` fail and bootstrap advise a reinstall on the strength of an error
it never parsed. The exit code now survives capture: 103 is the engine's
documented "no match" and is an answer, 0 is a listing, anything else is null
("couldn't tell"). The not-found marker still wins when present, since it is a
real answer regardless of exit code. Mutation-checked — dropping the exit-code
arm reddens the engine-failure case and nothing else.

bootstrap invoked a bare `winapp` while `Test-WinAppCli` deliberately also
accepts the app-execution alias, which exists on disk without always being
resolvable through the current PATH. So on exactly the machines the fallback
exists for, the step skipped its warning and then failed to launch anything.
`Get-WinAppCliPath` now returns the concrete path and bootstrap invokes that.

`mur doctor` compared `IsPackageInstalled()` to `true` only, so null ("could not
read the installed-package list") fell into the "not registered" FAIL — the same
ProbeFailed distinction `StatusExitCode` already draws. It now WARNs.

Docs and help that still described the old behaviour: `mur --help` advertised
`mur templates` as an installer, and both the dev-tooling table and the
getting-started "After git pull" block said `mur upgrade` refreshes the
templates. It only checks them now; bootstrap installs, `winapp` updates.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Restore packaged launch coverage, and fix three migration leftovers

Copilot review round 2 on the winapp migration.

Packaged launch coverage is back, and this one I had wrong. I had recorded the
gap in the PR description as "deliberately deferred — launching a packaged app
in CI needs Developer Mode plus identity", but the repo already solves exactly
that: ci.yml's Packaged Selftests job enables Developer Mode via AppModelUnlock,
because GitHub's windows runners are administrators. So the blocker I assumed
was not a blocker.

The deleted integration test really did scaffold → `dotnet run` → assert over
UIA; it covered the *unpackaged* `reactorapp` template, so it could not survive
this migration unchanged, but dropping it left build-only coverage of the change
this PR is actually about. The bootstrap job now enables Developer Mode and
launches the scaffolded app, asserting the two things a build cannot: the
loose-layout package registers (Get-AppxPackage) and the app activates. On
failure it dumps the `dotnet run` output rather than just timing out.

Also:

- `plugins/reactor/agents/reactor-dev.agent.md` is *shipped* in the agent kit
  and still told agents to `dotnet new install ...::0.0.7-alpha` — a hard-coded
  version in the one artifact most likely to be followed verbatim, and the one
  place a stale pin does the most damage. Now points at `winapp new`.
- CHANGELOG called `mur templates status` "unchanged". It has never shipped —
  `mur templates` is new in this release — so it now has an Added entry
  documenting the exit codes that bootstrap and `mur doctor` branch on.
- Restored a `<summary>` opening tag lost when I sliced WinAppSdkTemplates.cs
  down to the probes, which left the doc comment on a public member malformed.
  Checked the other two sliced files for the same damage; they are balanced.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Resolve the packaged app by its real identity, and bound the version scan

Copilot review round 3 — both findings are in code from the previous two
commits, and the first would have failed CI on its first run.

The packaged launch smoke resolved the registered package with
`Get-AppxPackage -Name 'TestApp'`. The Reactor manifest's Identity/@Name is a
generated GUID, not the project name, so that lookup returns nothing even on a
perfectly successful activation and the step throws every time. Verified by
scaffolding: the emitted manifest carries
`Name="4B99F56F-D9A7-4DDA-8850-ADE3D1D146DE"`. The step now reads the identity
out of the scaffolded Package.appxmanifest and looks that up, and prints it so
a future failure is diagnosable rather than mysterious.

`InterpretInstalledVersionOutput` scanned up to four lines past the package
header for a `Version:` line without stopping at the next package. A pack with
no version line therefore borrowed its neighbour's — reporting a version that
is not installed, which is worse than reporting none, because `mur doctor`
prints it in a PASS line. The scan now stops at the first line indented no
further than the header. Mutation-checked: removing that guard reddens the new
adjacent-package case and nothing else.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Assert the scaffolded app actually renders, and fix the packaging goal

Copilot review round 4.

The packaged launch smoke proved a process started and a package registered,
but not that the Reactor UI came up. A scaffold with a broken App.cs or package
reference can launch into Reactor's render-error fallback and satisfy both — so
the replacement was weaker than the `CreateTemplateTests` it replaced, which
asserted a real UIA element.

The step now asserts one. The blank template renders
`TitleBar("$projectname$")`, so an element named TestApp is in the tree exactly
when the scaffold rendered; `winapp ui search` (already a CI dependency, used by
the E2E job) queries it against the app's window, with a retry loop and a full
`ui inspect` dump on failure so a regression is diagnosable rather than a bare
timeout.

packaging.md.dt's frontmatter goal still described the unpackaged
WindowsPackageType=None shape as "what the project template produces". The body
had already been corrected; the goal now leads with the packaged single-project
MSIX default and names unpackaged as the alternative. It is authoring metadata
rather than rendered output, so no generated file changes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Match the template pack id by line in the bootstrap CI guard

Copilot review round 5.

The workflow's "pack is installed" assertion was a substring match over the
whole `dotnet new uninstall` transcript, so a longer id that merely contains
ours — `...CSharp.Templates.Extras` — satisfied it while the required pack was
absent. That is the same prefix false-positive
`WinAppSdkTemplates.InterpretPackageInstalledOutput` already guards against in
the CLI; the CI mirror had not been updated to match.

Both assertions now compare trimmed whole lines. Verified in both directions
rather than by inspection: against a transcript containing only the `.Extras`
pack the old check reports installed=True and the new one False, and against
this machine's real listing the new check still reports True.

Rewriting the positive assertion left `$packages` undefined at the negative
one, which would have made the "the removed ProjectTemplates pack must not be
installed" check silently vacuous — a guard that always passes. Both now read
from the same `$packageLines`.

Also reconciled the PR description, which still claimed the scaffold→launch
smoke was deliberately not replaced. It is replaced, and strengthened: the
description now documents the registration/activation/render assertions and
quotes the CI output.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Resolve winapp in the CI UI assertion too

Copilot review round 6 — the same alias-path bug it caught in bootstrap.ps1,
which I then reintroduced in the CI step added two commits later.

winget's MSIX install drops an app-execution alias that exists on disk without
always being resolvable through the current process's PATH; bootstrap's
Get-WinAppCliPath handles that, and the workflow does not add the alias
directory to PATH afterwards. So the rendered-UI assertion could fail on a
runner with exactly the installation state the fallback exists to support —
reported as "the Reactor UI did not render" rather than "winapp was not found",
which is the misdiagnosis that costs the most time.

The step now resolves the concrete path the same way and invokes it, and fails
with an explicit "winapp CLI not found" if neither location has it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

* Tear down the smoke app on every failure path

Copilot review round 7.

The launch smoke's cleanup sat on the success path, so any throw between
starting the job and the final assertion left a live packaged TestApp and a
blocked `dotnet run` job behind. That is worse than a leak: the steps that
follow are the `mur upgrade` and bootstrap idempotence checks, which a
still-registered, still-running smoke app can contaminate — and the orphaned
job can leave the runner waiting on it.

Process and job teardown moved into `finally`, guarded so it is safe when the
failure happened before either was created.

Verified rather than assumed, with a PID-specific oracle: a probe that throws
before the old cleanup point leaves no surviving process. (The first probe used
`notepad`, which was already running on this machine — an oracle that cannot
tell a leak from a pre-existing process, so it was replaced.)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b893b2b8-78f8-46c6-9227-515e1dc3a563
Kyaw Thant (kythant) added a commit that referenced this pull request Oct 2, 2026
* Remove github-artifacts mcp server (#6684)

* Remove github-artifacts mcp server

* Update review prompts for GitHub MCP migration (#6686)

Remove references to the retired github-artifacts helper and direct issue and PR review workflows to Copilot's standard web, file, and execution tools.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2b34993b-0dcf-4789-94c5-97fd92cce84d

---------

Co-authored-by: Gordon Lam <73506701+yeelam-gordon@users.noreply.github.com>
Copilot-Session: 2b34993b-0dcf-4789-94c5-97fd92cce84d

* MSIX: Always include PackageIntegrity/Content[Enforcement=on] in VS project templates (#6613)

* Bump VSIX build .NET SDK to 10.0.111 (security release) (#6699)

* Pin .NET SDK to patched 10.0.111 (CG DOTNET-Security-10.0)

Component Governance flags a vulnerable .NET SDK (10.0.101) against
/global.json. That version string is not in the repo -- global.json has
no "sdk" block at all, so builds resolve whatever SDK the agent image
happens to carry, and CG attributes what it detects to the nearest
manifest. Note "tools.dotnet" is a non-standard bootstrap field and does
not govern SDK resolution; only an "sdk" block does.

Pins sdk.version to 10.0.111 (runtime 10.0.11, 2026-08-11 security
release). Staying in the 1xx feature band already used here avoids
unrelated MSBuild/SDK/analyzer behavior changes.

Also bumps BuildVSIX 10.0.110 -> 10.0.111 so an SDK satisfying the pin is
actually installed -- rollForward only rolls forward, never backward.
That is independently a security improvement: 10.0.110 carries runtime
10.0.10 and is one security release behind. Follows up #6624.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5474160f-e555-4254-899b-783ad9211b71

* Remove root global.json SDK pin; scope PR to VSIX only

The root global.json `sdk` block is a repo-wide floor for every dotnet/MSBuild
invocation beneath it. Foundation/MRT/PREfast jobs install only .NET SDK 6.0.414
(matched to the shipping net6.0 / net6.0-windows10.0.19041.0 TFMs), and
rollForward never rolls backward across majors -- so Microsoft.NET.Sdk became
unresolvable and 10 CI jobs failed with MSB4236.

Scoping this PR to the BuildVSIX 10.0.110 -> 10.0.111 bump only. The CG
global.json remediation requires installing the pinned SDK in every job that
restores under the root global.json, and will be handled separately.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 484c9277-ea15-4f85-a4a0-0429347ade48

---------

Co-authored-by: Vineeth Thomas Alex <vithoma@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5474160f-e555-4254-899b-783ad9211b71
Copilot-Session: 484c9277-ea15-4f85-a4a0-0429347ade48

* [main] Update dependencies from microsoft/LiftedIXP/DCPP (#6636)

* Update dependencies from https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP build 20260717.1
On relative base path root
Microsoft.FrameworkUdk , Microsoft.ProjectReunion.InteractiveExperiences.TransportPackage From Version 3.0.0-experimental-27300.1896.260713-1015.0 -> To Version 3.0.0-experimental-27300.1897.260717-1605.0
Microsoft.WindowsAppSDK.InteractiveExperiences From Version 3.0.0-experimental-Rolling.20260713.2 -> To Version 3.0.0-experimental-Rolling.20260717.1

* Update dependencies from https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP build 20260719.1
On relative base path root
Microsoft.FrameworkUdk , Microsoft.ProjectReunion.InteractiveExperiences.TransportPackage From Version 3.0.0-experimental-27300.1896.260713-1015.0 -> To Version 3.0.0-experimental-27300.1898.260719-1733.0
Microsoft.WindowsAppSDK.InteractiveExperiences From Version 3.0.0-experimental-Rolling.20260713.2 -> To Version 3.0.0-experimental-Rolling.20260719.1

* Update dependencies from https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP build 20260723.1
On relative base path root
Microsoft.FrameworkUdk , Microsoft.ProjectReunion.InteractiveExperiences.TransportPackage From Version 3.0.0-experimental-27300.1896.260713-1015.0 -> To Version 3.0.0-experimental-27300.1899.260723-1213.0
Microsoft.WindowsAppSDK.InteractiveExperiences From Version 3.0.0-experimental-Rolling.20260713.2 -> To Version 3.0.0-experimental-Rolling.20260723.1

* Update dependencies from https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP build 20260727.2
On relative base path root
Microsoft.FrameworkUdk , Microsoft.ProjectReunion.InteractiveExperiences.TransportPackage From Version 3.0.0-experimental-27300.1896.260713-1015.0 -> To Version 3.0.0-experimental-27300.1900.260726-2015.1
Microsoft.WindowsAppSDK.InteractiveExperiences From Version 3.0.0-experimental-Rolling.20260713.2 -> To Version 3.0.0-experimental-Rolling.20260727.2

* Update dependencies from https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP build 20260729.1
On relative base path root
Microsoft.FrameworkUdk , Microsoft.ProjectReunion.InteractiveExperiences.TransportPackage From Version 3.0.0-experimental-27300.1896.260713-1015.0 -> To Version 3.0.0-experimental-27300.1901.260728-1900.0
Microsoft.WindowsAppSDK.InteractiveExperiences From Version 3.0.0-experimental-Rolling.20260713.2 -> To Version 3.0.0-experimental-Rolling.20260729.1

* Update dependencies from https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP build 20260806.3
On relative base path root
Microsoft.FrameworkUdk , Microsoft.ProjectReunion.InteractiveExperiences.TransportPackage From Version 3.0.0-experimental-27300.1896.260713-1015.0 -> To Version 3.0.0-experimental-27300.1902.260806-0506.0
Microsoft.WindowsAppSDK.InteractiveExperiences From Version 3.0.0-experimental-Rolling.20260713.2 -> To Version 3.0.0-experimental-Rolling.20260806.3

* Update dependencies from https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP build 20260814.1
On relative base path root
Microsoft.FrameworkUdk , Microsoft.ProjectReunion.InteractiveExperiences.TransportPackage From Version 3.0.0-experimental-27300.1896.260713-1015.0 -> To Version 3.0.0-experimental-27300.1903.260814-0918.0
Microsoft.WindowsAppSDK.InteractiveExperiences From Version 3.0.0-experimental-Rolling.20260713.2 -> To Version 3.0.0-experimental-Rolling.20260814.1

* Update dependencies from https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP build 20260818.1
On relative base path root
Microsoft.FrameworkUdk , Microsoft.ProjectReunion.InteractiveExperiences.TransportPackage From Version 3.0.0-experimental-27300.1896.260713-1015.0 -> To Version 3.0.0-experimental-27300.1904.260818-1237.0
Microsoft.WindowsAppSDK.InteractiveExperiences From Version 3.0.0-experimental-Rolling.20260713.2 -> To Version 3.0.0-experimental-Rolling.20260818.1

* Update dependencies from https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP build 20260823.1
On relative base path root
Microsoft.FrameworkUdk , Microsoft.ProjectReunion.InteractiveExperiences.TransportPackage From Version 3.0.0-experimental-27300.1896.260713-1015.0 -> To Version 3.0.0-experimental-27300.1905.260822-1925.0
Microsoft.WindowsAppSDK.InteractiveExperiences From Version 3.0.0-experimental-Rolling.20260713.2 -> To Version 3.0.0-experimental-Rolling.20260823.1

---------

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>

* [57514396] Use the central TSA area path in Foundation native builds

* Fix "Cancel" button in the C# and C++ wapproj templates so that it returns to the "Configure your new project" menu instead of creating a broken project (#6708)

* Add nuget cli alternative to Test-DotnetnNewTemplates for local execution

* Add check in Build-VSIX-Local to verify that the templates are included in the VSIX

* Add MsBuild parameter to build and install VSIX scripts

* Set WindowsAppSDkVersion, WindowsSdkBuildToolsVersion,and WindowsSdkBuildToolsWinAppVersion to {name}$ (parent template parameter) instead of project template parameter

* Move the Windows platform selection wizard from the Wapproj.vstemplate to the PackagedApp.vstemplate

* Move the Windows platform selection wizard from the C++ Wapproj.vstemplate to the PackagedApp.vstemplate

* Substitute publisher name from parent project in C++ wapproj Package.appxmanifest

* Rename VsVersion in help guide to MsBuildVersion

* Update missing MSBuild error message to include the MsBuildVersion selected in the script

* Remove duplicate problems.Count newline

* Remove extra excludedVersionPrefixes in Test-DotnetNewTemplates.ps1

* Add Reactor (Microsoft.UI.Reactor) dotnet new templates (#6620)

* Add Reactor (Microsoft.UI.Reactor) dotnet new templates

Adds four Reactor project templates to the Microsoft.WindowsAppSDK.WinUI.CSharp.Templates dotnet-new pack, mirroring the WinUI templates but for Microsoft.UI.Reactor (pure C#, no XAML):

- Reactor Blank App        (reactor, reactor-blank)
- Reactor MVU App          (reactor-mvu)
- Reactor NavigationView   (reactor-navview)
- Reactor TabView App      (reactor-tabview)

Wired into dev/Templates/templates.props via the DotnetNewOnlyProjectTemplate
slot (dotnet-new only, no VSIX, no manifest; Reactor apps run unpackaged).
Each shares a common csproj referencing Microsoft.UI.Reactor +
Microsoft.WindowsAppSDK, bundles the WinAppSDK runtime self-contained, and
enables the Debug-only Reactor devtools surface. README and
Test-DotnetNewTemplates.ps1 updated to document and validate the new templates.

Validated end-to-end: pack -> install -> dotnet new -> build (Debug + Release)
for all four templates.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Fix Reactor template runtime crash: remove TitleBar icon

TitleBar(...).Icon(FontIcon(...)) threw System.ArgumentException (E_INVALIDARG)
at runtime when Reactor set TitleBar.IconSource on Windows App SDK 2.1.3, so
the scaffolded Blank, MVU, and TabView apps crashed on launch. The glyph was
only a placeholder, so drop the icon; the title bar still shows the title text
and all four templates now launch cleanly (validated with dotnet run).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Bump Reactor templates to preview.12 and restore title-bar icon

microsoft/microsoft-ui-reactor#855 fixes the IconResolver FontSize=NaN crash
(FontIcon in an IconSource slot without an explicit size threw
ArgumentException from TitleBar.set_IconSource). That fix ships in
Microsoft.UI.Reactor 0.1.0-preview.12, so restore the placeholder title-bar
app-mark icon in the Blank, MVU, and TabView templates and bump the default
reactorVersion 0.1.0-preview.11 -> 0.1.0-preview.12 across all four templates.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Provision .NET 10 SDK in dotnet-new templates test stage

The template smoke-test stage installed only .NET SDK 8.0.x, so scaffolding
and building the Reactor templates failed with NETSDK1045 (Reactor targets
net10.0 and declares a [10.0,) sdk-version constraint). The WinUI templates
auto-detect their TFM from the active SDK, so they built net8.0 and passed,
masking the gap.

Add a second UseDotNet@2 step (param reactorDotnetSdkVersion, default 10.0.x)
to the shared Test-Stage template so the agent has the .NET 10 SDK. Verified
locally that the WinUI templates still build cleanly on the .NET 10 SDK, so
existing coverage is unaffected. Both the official and PR pipelines consume
this shared stage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Address PR review: trim launchSettings comments, use per-template icons

Review feedback from @DinahK-2SO on #6620:
- Remove the explanatory comment block from the Reactor launchSettings.json
  files (the content overlapped the package README).
- Give the MVU, NavigationView, and TabView templates their own icon.png
  (reusing the existing WinUI mvvm/navigation/tabview template icons) instead
  of all reusing the blank-app icon.

The packaging/taskbar-icon, tabs-in-title-bar, and winui-* short-name comments
are still open pending a check with the Reactor team.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Add winui-reactor* short-name aliases to Reactor templates

Review feedback from @DinahK-2SO on #6620: give each Reactor template a
winui-reactor* alias (winui-reactor, winui-reactor-mvu, winui-reactor-navview,
winui-reactor-tabview) so they also surface under 'dotnet new list winui'
alongside the other WinUI templates. README updated to note the aliases.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* reactor-tabview: integrate tabs into the title bar

Review feedback from @DinahK-2SO on #6620: instead of stacking a separate
TitleBar row above the TabView, put the tabs up in the title bar (Edge/Terminal
style) to look cleaner and save vertical space.

Uses supported Reactor APIs: UseWindow().NativeWindow with
ExtendsContentIntoTitleBar + SetTitleBar, the TabView TabStripHeader (app name
at the leading edge) and TabStripFooter (draggable region), and UseDpi +
UseWindowSize to reserve the caption-button inset (RightInset) across DPI and
resize. Verified by scaffolding the template, building, running, and
screenshotting the window: the tabs render inline in the title bar with the
caption buttons clear.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Make Reactor templates packaged (MSIX) and match the WinUI templates

Per review direction, the four Reactor templates now:

1. Are single-project MSIX packaged (like the WinUI templates) instead of
   unpackaged. Each gains app.manifest, Package.appxmanifest (EntryPoint
   Windows.FullTrustApplication since Reactor has no XAML App class), the shared
   Assets, and PublishProfiles. The csproj switches to EnableMsixTooling +
   Microsoft.Windows.SDK.BuildTools + Microsoft.Windows.SDK.BuildTools.WinApp so
   'dotnet run' registers a loose package and launches with MSIX identity.
   templates.props sets RenameManifestFrom and the template.json files gain the
   publisher / guid / build-tools-version symbols and the \\$
   modifier.

2. Visually match their WinUI counterparts:
   - reactor      -> title bar (app icon) + empty content (blank canvas).
   - reactor-mvu  -> centered 'Hello, WinUI!' + [+]/[-] icon counter (keeps the
     UseReducer MVU pattern under the same UI).
   - reactor-navview -> title bar + NavigationView Home/About + built-in Settings;
     pages render 'Title' + 'This is the X page'.
   - reactor-tabview -> MicaAlt, app-icon TabStripHeader, closable Home/About tabs
     with a '+' add button, tabs in the title bar.

Validated end-to-end for all four: pack -> install -> scaffold -> build ->
dotnet run (launches packaged with identity) -> screenshot matches the WinUI
counterpart. README updated (templates are now packaged).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* reactor-mvu: greet 'Hello, Reactor!'; use WinUI type-ramp styles for font parity

- MVU greeting is now 'Hello, Reactor!' (was 'Hello, WinUI!').
- Switch the Reactor text from Heading()/.SemiBold() (raw 28px Bold-700) to the
  type-ramp factories Title()/BodyStrong()/Body(), which apply the actual WinUI
  styles (TitleTextBlockStyle 28px Semibold-600, BodyStrongTextBlockStyle,
  BodyTextBlockStyle). This makes the Reactor headings/body render with the same
  weight and Segoe UI Variable optical size as the WinUI templates instead of a
  heavier bold. Applied to the mvu, navview, and tabview page text.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* reactor-tabview: give tab pages a solid background to match WinUI

The WinUI TabView template's pages set Background=SolidBackgroundFillColorTertiaryBrush,
which covers the window's Mica in the tab content area. The Reactor version left
the pages transparent, so MicaAlt showed through the content. Wrap the tab page
content in a Border painted with that same tertiary brush so the content is a
solid surface and only the tab strip / title bar show Mica, matching X_Tab.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* reactor-tabview: stretch the tab page surface to fill the content area

The solid tertiary page background only covered the text at the top because
Reactor sizes the tab content to the element's desired size. Force the page
Border to HorizontalAlignment/VerticalAlignment Stretch so the solid surface
fills the whole tab content region, matching the WinUI TabView template
(verified: the content is a uniform solid fill down to the window bottom).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Fill reactor-tabview page surface to window height

Match the WinUI TabView template's uniform tertiary content background by
sizing the shared page surface to the window height, so it fills the whole
tab content area instead of shrinking to its text (two-tone with Mica below).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Use Reactor's navigation system in reactor-navview

Match the WinUI NavigationView template's shell: the title bar owns the back
and pane toggle buttons, and NavigationView's own copies are hidden.

Switch from hand-rolled tag state to Reactor's navigation handle
(UseNavigation + NavigationHost), so the title bar back button is wired by
.WithNavigation(nav) and tracks the back stack instead of never appearing.
Also request the tall title bar layout the WinUI template uses.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Toggle the nav pane on the control instead of mirrored state

NavigationView opens and closes its pane on its own (light dismiss, display
mode changes), so a separate IsPaneOpen state copy drifted out of sync and
the title bar toggle needed two clicks to take effect.

Flip IsPaneOpen on the control directly, the same way the WinUI template's
code-behind does.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Match the WinUI page transition in reactor-navview

Reactor's NavigationHost slides pages in from the side, while WinUI's Frame
defaults to an entrance transition that rises the new page up into place.
Slide from the bottom so switching pages animates the same way.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Trim the Reactor templates to match the XAML templates' style

The Reactor templates carried long comments explaining Reactor concepts and
how they differ from XAML, which made them read like documentation rather
than a starting point. Keep only the brief, functional comments the XAML
templates use, and a single pointer to the Reactor project info.

Also drop the explicit navigation transition from reactor-navview: matching
the XAML Frame's entrance animation added verbosity and called out a
difference between the two, so use Reactor's default instead.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Mark the Reactor templates as experimental

Microsoft.UI.Reactor is prerelease and its API may still change, so label the
templates accordingly: add `(Experimental)` to each template name, an
`Experimental` classification so it shows in the dotnet new tags column, and
a note in each description and in the README.

Also correct the templates.props comment, which still described the Reactor
apps as unpackaged with RenameManifestFrom unset; they are packaged
(single-project MSIX) and do set it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Fix Reactor analyzer warnings in the MVU and TabView templates

The templates tripped four of Reactor's analyzers, so a freshly scaffolded
project did not build clean:

- REACTOR_A11Y_001 (x2): the MVU counter's icon-only buttons had no
  accessible name. Add .AutomationName().
- REACTOR_A11Y_002: the TabView tab strip icon is decorative. Mark it
  .AccessibilityHidden().
- REACTOR_HOOKS_013: the initial tab array was reallocated on every render
  though only read on the first. Wrap it in UseMemo.
- REACTOR_POOL_001: the page surface set MinHeight via .Set(...), which is
  reset when the element returns to the pool, so the tab content fill could
  be lost on re-render. Use the .MinHeight() modifier instead.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Use $targetentrypoint$ in the Reactor manifests, like the XAML templates

The Reactor manifests hardcoded EntryPoint=Windows.FullTrustApplication while
every XAML template uses the $targetentrypoint$ token. The token already
resolves to Windows.FullTrustApplication for these projects, so the generated
AppxManifest.xml is unchanged - this just removes an unexplained difference
between the two sets of templates.

The four Reactor manifests are now byte-identical to their XAML counterparts.

Verified: all four scaffold, build warning-free, generate the same
EntryPoint=Windows.FullTrustApplication, and launch with package identity.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Commit the Reactor templates' publish profiles

The root .gitignore has a blanket `*.pubxml` rule, so the three publish
profiles in each Reactor template were silently never added. They existed
only on the authoring machine; a clean clone got none of them. The WinUI
templates force-added theirs in #6407 for the same reason.

Without the profiles the csproj's
`<PublishProfile Condition="Exists(...)">` never resolves, so SelfContained
is never set to true. Combined with PublishTrimmed=true for non-Debug
configurations that fails a Release build outright:

  error NETSDK1102: Optimizing assemblies for size is not supported for the
  selected publish configuration. Please ensure that you are publishing a
  self-contained app.

Force-add all 12 files so Release builds and publish work from a fresh
clone, matching the WinUI templates.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Stop .gitignore from swallowing template publish profiles

The blanket `*.pubxml` rule silently ignored the Reactor templates' publish
profiles, so they were never committed and Release builds failed from a
clean clone (fixed in 8ea4586 by force-adding them).

`git add -f` fixed those 12 files but not the mechanism: the next template
added, or a new RID added to an existing one, hits the same trap and it is
again invisible to anyone whose working tree still has the files on disk.

Add a `!dev/Templates/**/*.pubxml` negation alongside the existing one for
dev/vsix, so template publish profiles are committable by default. Publish
profiles elsewhere in the repo stay ignored.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Match the XAML templates' icon font and size

The Reactor templates hardcoded `Segoe Fluent Icons` on their FontIcons and
left the size at WinUI's default. The XAML templates do neither: they use
`<FontIcon Glyph="..." />` with no FontFamily, inheriting SymbolThemeFontFamily,
which resolves the right icon font for the OS — worth keeping given the
templates support Windows 10 1809 and Segoe Fluent Icons is Windows 11 era.

The MVVM template also sets FontSize="14" on its counter icons, which ours
missed, so the buttons rendered larger than their XAML counterpart:

  XAML MVVM      58x41
  Reactor MVU    67x51  ->  58x42

Verified against Microsoft.UI.Reactor 0.1.0-preview.12: both templates build
warning-free and the glyphs render correctly (Icon(FontIcon(...)) resolves
through IconResolver, not the Button(string) content path).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Update Reactor dotnet new templates for 0.1.0-preview.13

Reactor preview.13 adds declarative APIs that let the Navigation and
TabView templates drop their imperative escape hatches:

- NavigationView: use IsBackButtonVisible / IsPaneToggleButtonVisible and
  .IsPaneOpen(value, handler) instead of UseRef + OnMount downcast, and
  select the built-in Settings item via NavigationViewElement.SettingsTag.
  OnSelectedTagChanged still reports null for Settings by design, so
  TagToRoute keeps handling both SettingsTag and null.
- TitleBar: use .Tall() instead of the UseEffect + DispatcherQueue hop and
  the redundant .Height(48).
- TabView: set FillContentArea, removing the MinHeight workaround.

Also bump the reactorVersion default to 0.1.0-preview.13 in all four
Reactor template.json files.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 38f0823a-2ee4-4c65-8f3f-7dde6a049509

* Let the OS size the window, like the XAML templates

Drop the hardcoded 1000x700 from all four Reactor templates. Reactor
PR #924 makes ReactorApp.Run's width/height optional, so omitting them
lets the OS pick the size, matching the XAML templates which set no
size at all. Verified identical to a freshly scaffolded XAML app.

This requires 0.1.0-preview.13; before #924, omitting width/height
meant a hardcoded 1024x768 rather than an OS-chosen size.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 38f0823a-2ee4-4c65-8f3f-7dde6a049509

* Add the MsixPackage launch profile to the Reactor templates

The Reactor templates were originally unpackaged and their launchSettings.json
only declared `commandName: Project` profiles. Making them single-project MSIX
updated the csproj and added Package.appxmanifest but left launchSettings
behind, so F5 from Visual Studio failed:

  ...launchSettings.json does not contain a profile with commandName
  'MsixPackage'. To debug a packaged single-project MSIX solution, a profile
  with command name MsixPackage in launchSettings.json is required.

`dotnet run` goes through Microsoft.Windows.SDK.BuildTools.WinApp instead, so
it worked throughout and the gap went unnoticed.

Declare the same Package / Unpackaged pair the WinUI XAML templates ship, with
Package first so it is the F5 default, and keep the Reactor devtools profile
alongside them.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Float the Windows App SDK version in the Reactor templates

The Reactor templates pinned Microsoft.WindowsAppSDK to 2.1.3 while the WinUI
XAML templates default to `*`. That pinned new projects to an older SDK than
the one Visual Studio offers everywhere else — 2.3.1 is current, so scaffolded
Reactor apps were two releases behind for no reason.

2.1.3 was the version Reactor happened to be built against, not a hard floor:
Microsoft.UI.Reactor 0.1.0-preview.13 depends on Microsoft.WindowsAppSDK.WinUI
>= 2.1.0. Keep the requirement in the parameter description rather than
encoding it as the pin, matching the WinUI templates.

Verified with the floated default: all four templates resolve
Microsoft.WindowsAppSDK 2.3.1, build warning-free, and launch with package
identity.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Accept MSB4181 for the invalid-version restore test on .NET SDK 10

The dotnet-new template test stage previously installed only the .NET 8 SDK.
Adding the .NET 10 SDK (needed because the Reactor templates target net10.0)
means the muxer now selects 10.0.400 for the pre-existing winui negative
tests as well, which changes the diagnostic NuGet emits for an unparseable
package version:

  SDK 8.0.424 / 9.0.317 : no error code; "'not-a-version' is not a valid
                          version string."
  SDK 10.0.400          : MSB4181 - RestoreTask returns false without
                          logging the descriptive error, so no NU code
                          surfaces at all.

The old assertion short-circuited on any error code being present and
demanded NU1105, so MSB4181 failed the run. (NU1105 never actually
surfaced on any tested SDK; the test passed via the descriptive-message
fallback.) Accept NU1105/MSB4181 or the descriptive message, and stop a
code's presence from bypassing the fallback.

Verified on 8.0.424 / 9.0.317 / 10.0.400. Unrelated failures (NU1101,
NU1301) still fail the assertion, so it is not weakened to "any failure".
Scenario 5's build check (NETSDK1004), scenario 6 (NU1102) and scenario 7
(NU1301) were confirmed unchanged on SDK 10.

Also corrects an adjacent comment that said NETSDK1005 where the check and
the observed behaviour are both NETSDK1004.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Pin the Reactor test-stage .NET SDK instead of floating 10.0.x

Every other UseDotNet@2 task in this repo pins an exact SDK (6.0.414,
6.0.427, 8.0.100, 9.0.200, 10.0.111); #6624 added the BuildVSIX pin so
Component Governance scans a patched toolchain, and #6699 bumped it
deliberately for a security release. reactorDotnetSdkVersion was the only
new floating pin.

Floating is what broke CI: '10.0.x' resolved to 10.0.302 when the task was
added on 2026-07-23, then silently jumped a whole feature band when 10.0.400
shipped on 2026-08-11. 10.0.400 changed the NuGet diagnostic for an
unparseable package version, so the pre-existing winui invalid-version smoke
test started failing with no corresponding source change.

Pinned to 10.0.400 rather than the 10.0.111 used by BuildVSIX. The Reactor
templates cannot use the 1xx servicing band: Microsoft.UI.Reactor's analyzers
and source generators (Reactor.Analyzers, Reactor.Wrappers.Generator,
Reactor.Localization.Generator) reference Roslyn 5.6.0.0, and 10.0.111 ships
Roslyn 5.0.0.0, so all three are silently disabled with CS9057 while the
build still reports success. Verified by building the same scaffolded project
on both SDKs: 10.0.111 -> 3x CS9057, 10.0.400 (Roslyn 5.9.0.0) -> 0 warnings.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Accept NETSDK1005 for the invalid-version build test on .NET SDK 10

Follow-up to 5ff625e, which fixed the restore assertion in the same
scenario. The build assertion immediately after it failed for the same
underlying reason.

On .NET SDK 10 NuGet's RestoreTask fails (MSB4181) but still writes a
partial obj/project.assets.json. The subsequent --no-restore build therefore
reports NETSDK1005 (assets file has no target for the project's TFM) rather
than NETSDK1004 (assets file missing). Accept either, since both mean restore
did not produce usable assets. Scenario 7's list gains NETSDK1005 for the
same reason; it currently resolves to NU1301, but NETSDK1004 is in that list
for the 'restore never succeeded' case whose SDK 10 equivalent is 1005.

This also reverts the NETSDK1005 -> NETSDK1004 comment change from 5ff625e.
That comment was correct as written; I changed it based on a repro that used
a bare net8.0 project with no obj directory, which produces NETSDK1004 and
does not reproduce the real template's behaviour. Re-verified with a faithful
repro (net10.0-windows10.0.26100.0, WinUI props, same build flags), which
reproduces CI exactly: assets file present after the failed restore, build
fails with NETSDK1005.

All four error-code assertions in this script are now backed by faithful
repros on the pinned SDK 10.0.400: restore MSB4181, build NETSDK1005,
scenario 6 NU1102, scenario 7 NU1301. Unrelated failures still throw.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
Copilot-Session: 38f0823a-2ee4-4c65-8f3f-7dde6a049509

* dotnet new WinUI3 templates 0.0.7-alpha (#6729)

* Propagate the PackageReference version into the C# wapproj template's BlankApp project file (#6705)

* Fix AppInstance process handle validation (#6733)

* Fix AppInstance process handle validation

Open non-current processes with SYNCHRONIZE once and transfer the
validated handle into AppInstance before registering the termination wait.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Set ApplicationIcon in the C# app templates (#6728)

* Set ApplicationIcon in the C# app templates

The eight C# app templates ship Assets\AppIcon.ico and reference it from the
window (AppWindow.SetIcon in the XAML templates, TitleBar.Icon in the Reactor
ones), but none of them set <ApplicationIcon>, so the icon was never embedded
into the built executable as a Win32 icon resource. Explorer, shortcuts, and
the taskbar for an unpackaged build therefore showed the default .NET icon.

Guarded with Condition=Exists so the property is simply skipped if a project
does not have the asset, matching the existing PublishProfile pattern in these
same templates.

Applied to all eight app templates that ship the asset -- the four WinUI XAML
ones and the four Reactor ones -- rather than only the Reactor set, so the
templates stay consistent with each other. ClassLibrary, PackagedApp, and
UnitTestApp do not ship an AppIcon.ico and are untouched.

Only ProjectTemplate.csproj is modified: that is the file scaffolded for the
user by both dotnet new and the VSIX. The WinUI.Desktop.Cs.*.csproj files are
VSSDK packaging projects for the VSIX itself, not scaffolded output.

Validated by scaffolding and building all eight templates (Debug, x64): all
build clean and the icon is embedded in the produced exe, confirmed by
ExtractAssociatedIcon returning a 32x32 icon for each. The two warnings from
winui-mvvm are pre-existing MVVMTK0045 diagnostics from the MVVM Toolkit and
are unrelated.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Bump Reactor to 0.1.0-preview.14 and drop the explicit title bar icon

Reactor 0.1.0-preview.14 makes TitleBar(...) inherit the window's icon
(microsoft/microsoft-ui-reactor#1153), so the explicit
.Icon("ms-appx:///Assets/AppIcon.ico") in the templates is now redundant.
Removing it keeps the scaffolded App.cs to the shape a starter template
should have, and the title bar still renders the app mark.

Applies to the three templates that use a TitleBar element: ReactorBlankApp,
ReactorMvuApp and ReactorNavigationApp. ReactorTabViewApp has no TitleBar --
it extends content into the title bar with a custom drag region and renders
its icon through TabStripHeader = Image(...), which is a different surface
that the inherit behaviour does not cover -- so it keeps its explicit
reference and is intentionally untouched.

Validated against the real 0.1.0-preview.14 package, four scaffolded apps,
with the icon line present and absent:

  control, .Icon present, preview.14    title bar mark shown
  line removed, preview.14              title bar mark shown  <- the change
  line removed + icon: arg, preview.14  title bar mark shown
  line removed, preview.13              NO mark

The last row is the negative control: identical source and capture method,
only the package version differs, so the mark on preview.14 is caused by the
inherit behaviour rather than by something incidental.

All four templates were then scaffolded from the built pack and built clean
on x64: Debug 0 warnings, Release 2 warnings. The Release warnings are
pre-existing IL2104 trim warnings from Microsoft.Windows.SDK.NET and
WinRT.Runtime, unrelated to this change and present without it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1

* Fix errors from missing resource dll with version info (#6725)

* [57514396] Use central TSA config for Foundation source analysis (#6738)

* Normalize line endings in AppInstance.cpp (#6752)

* AppNotificationManager::Show and AppInstance::GetInstances: refactor to noexcept workers (Bug 61688595) (#6714)

Refactor two hot-path WinRT projection entry points so a failed HRESULT does not trigger the deep C++/WinRT projection rethrow path that exhausted the stack via WIL's FormatMessage-based exception logging chain inside ResultFromCaughtException_CppWinRt::catch$8 (the Watson failure signature for this crash bucket).

AppNotificationManager::Show: move the throwing body into a private noexcept HRESULT worker (ShowImpl) using RETURN_HR_IF / RETURN_IF_FAILED / CATCH_RETURN. The public Show keeps the IsSupported() early-return and rethrows any failure HRESULT via THROW_IF_FAILED(ShowImpl(...)).

AppLifecycle::AppInstance::GetInstances: same pattern. The body becomes GetInstancesImpl(IVector<AppInstance>& out) noexcept; the public GetInstances() is a thin THROW_IF_FAILED(GetInstancesImpl(...)) wrapper. Internal callers (RedirectActivationToAsync at line 636) are unaffected because the public signature is unchanged.

These are the two entry points observed in the Watson cabs attached to this bucket: WinUI3 Controls Gallery cabs originate in Show, and the auto-filer cab originates in Photos -> AppInstance::GetInstances (frames 16-22 in the cab call stack). The catch handler one frame deeper is mis-attributed by Watson's PDB walker to SecurityDescriptorHelpers::NonDelegatingGetTrustLevel::catch$0 (lexically-nearest catch symbol).

AB#61688595

Co-authored-by: James Pike <jamespik@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Retire the standalone StoragePickersTestApp (#6779)

Remove the specialized UI harness, its assets, and solution mappings to simplify ongoing build maintenance. Keep the Storage Pickers implementation and automated tests unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Change WindowsAppSDK-DotnetNewTemplates template from Microsoft.NonOfficial to Microsoft.Official template (#6783)

* Add OneBranch.Official.CrossPlat.yml template to WindowsAppSDK-DotnetNewTemplates.yml

* Use Microsoft Official template for dotnet templates

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30bef3b6-3b91-4f20-96cd-7c242a8a370f

---------

Copilot-Session: 30bef3b6-3b91-4f20-96cd-7c242a8a370f

* Add network isolation to WindowsAppSDK-DotnetNewTemplates.yml (#6787)

* Use path filter for template PR validation (#6782)

* Skip OneBranch tool download when running template change validation on PRs from forks

* Use ADO path filter for template PR validation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6baeec26-f59b-466a-8eab-cd3b09b19380

---------

Copilot-Session: 6baeec26-f59b-466a-8eab-cd3b09b19380

* Reactor templates: bump to 0.1.0-preview.16 and raise WindowsAppSDK floor to 2.2.0 (#6786)

Updates the four Reactor dotnet-new templates for the 0.1.0-preview.16 release:

  reactorVersion       0.1.0-preview.14 -> 0.1.0-preview.16
  windowsAppSdkVersion documented floor 2.1.3 -> 2.2.0

microsoft/microsoft-ui-reactor#1259 adopts ApplicationData.GetForUnpackaged(),
a Windows App SDK 2.2.0 API, and raises Microsoft.UI.Reactor's dependency on
Microsoft.WindowsAppSDK.WinUI to 2.2.1. Verified that commit is contained in
the v0.1.0-preview.16 tag, and that Directory.Build.props at that tag declares
WindowsAppSDKVersion 2.2.0 / WindowsAppSDKWinUIVersion 2.2.1.

These templates reference the full Microsoft.WindowsAppSDK metapackage (not the
lean WinUI sub-package) and scaffold packaged single-project MSIX apps, so the
correct consumer floor is metapackage 2.2.0 - the first version whose WinUI
dependency is 2.2.1 (2.1.3 -> WinUI 2.1.0; 2.2.0 -> WinUI 2.2.1).

Both edits ship together because the mismatch they prevent is silent, not a
restore error. Measured with a stub package carrying the post-#1259 dependency
shape: pinning --wasdk-version 2.1.3 restores with exit code 0 and zero
warnings, resolving Microsoft.WindowsAppSDK.WinUI 2.2.1 while the metapackage
holds Microsoft.WindowsAppSDK.Runtime at exactly [2.1.3]. WinUI is only ever a
transitive reference, so NuGet takes the highest floor and never reports
NU1605; the result is 2.2.1 reference assemblies over a 2.1.3 runtime, which
builds clean and fails at runtime. The same probe at 2.2.0 resolves Runtime
2.2.0. Since the toolchain raises no error, the description text is the only
guardrail a user pinning explicitly will ever see.

Validated by scaffolding all four templates from a locally packed template
pack: each emits Microsoft.UI.Reactor and Microsoft.UI.Reactor.Devtools at
0.1.0-preview.16, Microsoft.WindowsAppSDK at the default '*', and a
Package.appxmanifest. Also verified the explicit pin path
(--wasdk-version 2.2.0 --reactor-version 0.1.0-preview.16).

Restore/build validation is deferred to CI: 0.1.0-preview.16 is on nuget.org
but has not yet mirrored to the internal package proxy reachable from this
machine.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Pin GitHub Actions to full-length commit SHAs (#6791)

Co-authored-by: Dan Fiedler <danfiedler@microsoft.com>

* Retry transient bootstrap initialization registration failures in tests (#6816)

* Retry transient bootstrap initialization failure

Retry MddBootstrapInitialize only when DDLM registration is temporarily unavailable, using a bounded exponential backoff.

AB#62489699

* Migrate TouchDownBuild-WinAppSDK  (#6814)

* Fix TouchDown variable group

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: e6b7e13d-59ce-4751-91f4-e8e589787837

* Fix TouchDown service connection

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: e6b7e13d-59ce-4751-91f4-e8e589787837

* Use TouchDown Azure resource connection

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: e6b7e13d-59ce-4751-91f4-e8e589787837

---------

Copilot-Session: e6b7e13d-59ce-4751-91f4-e8e589787837

---------

Co-authored-by: Roman Sivak (AKVELON INC) <v-romansivak@microsoft.com>
Co-authored-by: ssparach <128866445+ssparach@users.noreply.github.com>
Copilot-Session: e6b7e13d-59ce-4751-91f4-e8e589787837

---------

Co-authored-by: Lauren Ciha <laurenciha@microsoft.com>
Co-authored-by: Gordon Lam <73506701+yeelam-gordon@users.noreply.github.com>
Co-authored-by: Howard Kapustein <howardk@microsoft.com>
Co-authored-by: Vineeth Thomas Alex <vineeththomasalex@gmail.com>
Co-authored-by: Vineeth Thomas Alex <vithoma@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: v-goradojcic <v-goradojcic@microsoft.com>
Co-authored-by: Alexandre Zollinger Chohfi <alzollin@microsoft.com>
Co-authored-by: Dinah Xiaoman G <116714259+DinahK-2SO@users.noreply.github.com>
Co-authored-by: Scott Jones <sjones@microsoft.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Manodasan Wignarajah <mawign@microsoft.com>
Co-authored-by: Dreynor87 <wall_c.s@outlook.com>
Co-authored-by: James Pike <jamespik@microsoft.com>
Co-authored-by: Dan Fiedler <danfiedler@microsoft.com>
Co-authored-by: romsi1983 <41230962+romsi1983@users.noreply.github.com>
Co-authored-by: Roman Sivak (AKVELON INC) <v-romansivak@microsoft.com>
Co-authored-by: ssparach <128866445+ssparach@users.noreply.github.com>
Copilot-Session: 2b34993b-0dcf-4789-94c5-97fd92cce84d
Copilot-Session: 5474160f-e555-4254-899b-783ad9211b71
Copilot-Session: 484c9277-ea15-4f85-a4a0-0429347ade48
Copilot-Session: 16d7d2fc-3d7c-41e8-9999-0c2084ba9ea1
Copilot-Session: 38f0823a-2ee4-4c65-8f3f-7dde6a049509
Copilot-Session: 30bef3b6-3b91-4f20-96cd-7c242a8a370f
Copilot-Session: 6baeec26-f59b-466a-8eab-cd3b09b19380
Copilot-Session: e6b7e13d-59ce-4751-91f4-e8e589787837
Lauren Ciha (lauren-ciha) pushed a commit that referenced this pull request Oct 15, 2026
…plate coverage

Two comments in the template smoke test described behaviour the script does
not have, both in the same direction: they implied the packaged path and
`dotnet run` are covered when neither is.

.DESCRIPTION claimed app templates "are optionally launched via dotnet run
using the recommended WinAppSDK self-contained properties." Neither half is
true. Launch-AppExecutables (line 265) resolves the built .exe under bin/ and
Start-Process's it directly at line 277; `dotnet run` is never invoked. Builds
pass -p:WindowsPackageType=None, which is the opposite of the self-contained
packaged shape.

The comment above the Reactor entries called those templates "unpackaged" and
said "their .csproj already sets it" (WindowsPackageType). Both are wrong. The
Reactor templates are packaged single-project MSIX apps: templates.props gives
each one RenameManifestFrom=Package-managed.appxmanifest, and their
ProjectTemplate.csproj sets EnableMsixTooling=true and no WindowsPackageType
at all - the flag comes from the harness command line at line 372.

That comment was never accurate rather than having drifted: 2fd7355 (#6620)
introduced it in the same commit that added the templates, and at that commit
all four ProjectTemplate.csproj files already declared EnableMsixTooling and
no WindowsPackageType. It contradicted the templates it shipped with.

This matters beyond tidiness. All nine Kind='App' templates ship a manifest
and are built with packaging disabled, so Package.appxmanifest processing,
MSIX tooling and identity activation are unexercised. Anyone auditing that
coverage reads .DESCRIPTION, sees "launched via dotnet run", and stops. The
comments were hiding the gap from the repo that owns it.

No rationale for the flag is asserted here: none is recorded. It arrived with
the harness in 9b5d40a (#6407), which added the file, so it was present from
the first version rather than introduced later as a deliberate constraint.

Comment-only; no behaviour change. Script parses with 0 errors. Line numbers
above are as of this commit.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Separately, the comment-based help block opened with `<#+` instead of `<#`.
That is a valid block comment to the parser, so the script always ran fine,
but Get-Help could not recognise it as comment-based help: `Get-Help
.\Test-DotnetNewTemplates.ps1` returned the auto-generated syntax line and no
DESCRIPTION or PARAMETER text at all. Verified by copying the file to a
scratch directory and changing only that token: as-is Get-Help reports no
description, corrected it renders the full help including every .PARAMETER.

That matters here because it is the reason the inaccurate .DESCRIPTION went
unnoticed for so long - the corrected text would still have been invisible to
anyone running Get-Help, which is how a PowerShell script is normally
inspected.
Alexandre Zollinger Chohfi (azchohfi) added a commit that referenced this pull request Oct 21, 2026
…plate coverage (#6846)

Two comments in the template smoke test described behaviour the script does
not have, both in the same direction: they implied the packaged path and
`dotnet run` are covered when neither is.

.DESCRIPTION claimed app templates "are optionally launched via dotnet run
using the recommended WinAppSDK self-contained properties." Neither half is
true. Launch-AppExecutables (line 265) resolves the built .exe under bin/ and
Start-Process's it directly at line 277; `dotnet run` is never invoked. Builds
pass -p:WindowsPackageType=None, which is the opposite of the self-contained
packaged shape.

The comment above the Reactor entries called those templates "unpackaged" and
said "their .csproj already sets it" (WindowsPackageType). Both are wrong. The
Reactor templates are packaged single-project MSIX apps: templates.props gives
each one RenameManifestFrom=Package-managed.appxmanifest, and their
ProjectTemplate.csproj sets EnableMsixTooling=true and no WindowsPackageType
at all - the flag comes from the harness command line at line 372.

That comment was never accurate rather than having drifted: 2fd7355 (#6620)
introduced it in the same commit that added the templates, and at that commit
all four ProjectTemplate.csproj files already declared EnableMsixTooling and
no WindowsPackageType. It contradicted the templates it shipped with.

This matters beyond tidiness. All nine Kind='App' templates ship a manifest
and are built with packaging disabled, so Package.appxmanifest processing,
MSIX tooling and identity activation are unexercised. Anyone auditing that
coverage reads .DESCRIPTION, sees "launched via dotnet run", and stops. The
comments were hiding the gap from the repo that owns it.

No rationale for the flag is asserted here: none is recorded. It arrived with
the harness in 9b5d40a (#6407), which added the file, so it was present from
the first version rather than introduced later as a deliberate constraint.

Comment-only; no behaviour change. Script parses with 0 errors. Line numbers
above are as of this commit.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Separately, the comment-based help block opened with `<#+` instead of `<#`.
That is a valid block comment to the parser, so the script always ran fine,
but Get-Help could not recognise it as comment-based help: `Get-Help
.\Test-DotnetNewTemplates.ps1` returned the auto-generated syntax line and no
DESCRIPTION or PARAMETER text at all. Verified by copying the file to a
scratch directory and changing only that token: as-is Get-Help reports no
description, corrected it renders the full help including every .PARAMETER.

That matters here because it is the reason the inaccurate .DESCRIPTION went
unnoticed for so long - the corrected text would still have been invisible to
anyone running Get-Help, which is how a PowerShell script is normally
inspected.
Lauren Ciha (lauren-ciha) pushed a commit that referenced this pull request Oct 21, 2026
…plate coverage (#6846)

Two comments in the template smoke test described behaviour the script does
not have, both in the same direction: they implied the packaged path and
`dotnet run` are covered when neither is.

.DESCRIPTION claimed app templates "are optionally launched via dotnet run
using the recommended WinAppSDK self-contained properties." Neither half is
true. Launch-AppExecutables (line 265) resolves the built .exe under bin/ and
Start-Process's it directly at line 277; `dotnet run` is never invoked. Builds
pass -p:WindowsPackageType=None, which is the opposite of the self-contained
packaged shape.

The comment above the Reactor entries called those templates "unpackaged" and
said "their .csproj already sets it" (WindowsPackageType). Both are wrong. The
Reactor templates are packaged single-project MSIX apps: templates.props gives
each one RenameManifestFrom=Package-managed.appxmanifest, and their
ProjectTemplate.csproj sets EnableMsixTooling=true and no WindowsPackageType
at all - the flag comes from the harness command line at line 372.

That comment was never accurate rather than having drifted: 2fd7355 (#6620)
introduced it in the same commit that added the templates, and at that commit
all four ProjectTemplate.csproj files already declared EnableMsixTooling and
no WindowsPackageType. It contradicted the templates it shipped with.

This matters beyond tidiness. All nine Kind='App' templates ship a manifest
and are built with packaging disabled, so Package.appxmanifest processing,
MSIX tooling and identity activation are unexercised. Anyone auditing that
coverage reads .DESCRIPTION, sees "launched via dotnet run", and stops. The
comments were hiding the gap from the repo that owns it.

No rationale for the flag is asserted here: none is recorded. It arrived with
the harness in 9b5d40a (#6407), which added the file, so it was present from
the first version rather than introduced later as a deliberate constraint.

Comment-only; no behaviour change. Script parses with 0 errors. Line numbers
above are as of this commit.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Separately, the comment-based help block opened with `<#+` instead of `<#`.
That is a valid block comment to the parser, so the script always ran fine,
but Get-Help could not recognise it as comment-based help: `Get-Help
.\Test-DotnetNewTemplates.ps1` returned the auto-generated syntax line and no
DESCRIPTION or PARAMETER text at all. Verified by copying the file to a
scratch directory and changing only that token: as-is Get-Help reports no
description, corrected it renders the full help including every .PARAMETER.

That matters here because it is the reason the inaccurate .DESCRIPTION went
unnoticed for so long - the corrected text would still have been invisible to
anyone running Get-Help, which is how a PowerShell script is normally
inspected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants