Repository navigation
Add Reactor (Microsoft.UI.Reactor) dotnet new templates - #6620
Merged
Alexandre Zollinger Chohfi (azchohfi) merged 35 commits intoAug 28, 2026
Merged
Alexandre Zollinger Chohfi (azchohfi) merged 35 commits into
Alexandre Zollinger Chohfi (azchohfi) merged 35 commits into
Conversation
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: There may be pipelines that require an authorized user to comment /azp run to run. |
Alexandre Zollinger Chohfi (azchohfi)
marked this pull request as ready for review
July 15, 2026 05:01
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Beth Pan (beth-panx)
requested review from
Dinah Xiaoman G (DinahK-2SO) and
Scott Jones (Scottj1s)
July 23, 2026 20:46
Contributor
Author
|
/azp run |
|
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>
Contributor
Author
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |
Dinah Xiaoman G (DinahK-2SO)
requested changes
Jul 24, 2026
Dinah Xiaoman G (DinahK-2SO)
requested changes
Jul 24, 2026
Dinah Xiaoman G (DinahK-2SO)
requested changes
Jul 24, 2026
Dinah Xiaoman G (DinahK-2SO)
requested changes
Jul 24, 2026
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>
Contributor
Author
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |
Alexandre Zollinger Chohfi (azchohfi)
enabled auto-merge (squash)
August 25, 2026 22:14
Contributor
|
LGTM |
Dinah Xiaoman G (DinahK-2SO)
approved these changes
Aug 27, 2026
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
This was referenced Aug 27, 2026
Contributor
Author
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |
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
Merged
8 tasks done
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
This was referenced Sep 25, 2026
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
This was referenced Oct 6, 2026
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds four Reactor (
Microsoft.UI.Reactor) project templates to the existingMicrosoft.WindowsAppSDK.WinUI.CSharp.Templatesdotnet newpack, mirroring the WinUI templates from #6407 but for Reactor's declarative, pure-C# (no XAML) model.reactor,reactor-blankreactor-mvuUseReducerreactor-navviewNavigationViewshell with multiple pagesreactor-tabviewTabViewshell with multiple tabsWhat changed
dev/Templates/templates.props— four new rows in theDotnetNewOnlyProjectTemplateslot (dotnet-new only, no VSIX). Reactor apps run unpackaged, so there is noPackage.appxmanifest(RenameManifestFromleft unset). This reuses the repo's existing single-source-of-truth pack pipeline.dev/Templates/Source/ProjectTemplates/Desktop/CSharp/Reactor*— the app sources: a sharedProjectTemplate.csproj(referencesMicrosoft.UI.Reactor+Microsoft.WindowsAppSDK,WindowsAppSDKSelfContained, Debug-only Reactor devtools), a single-fileApp.csper pattern, andProperties/launchSettings.json(default + Devtools F5 profiles).dev/Templates/Dotnet/templates/reactor-*— the.template.configfor each (template.json,dotnetcli.host.json,ide.host.json,icon.png). Defaults: Reactor0.1.0-preview.12, Windows App SDK2.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 theIconResolverfix from microsoft/microsoft-ui-reactor#855, shipped in preview.12).A Microsoft employee must use
/azp runto validate using the PR pipelines.