Add winapp-maui skill for the MAUI resizetizer manifest dependency - #610
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a new dedicated Copilot/Claude agent skill, winapp-maui, documenting how to package and sign .NET MAUI Windows apps with winapp. Its central purpose is to explain the "resizetizer manifest dependency": MAUI's source Platforms/Windows/Package.appxmanifest is full of $placeholder$ tokens that winapp package does not resolve, so users must point --manifest at the resizetizer-generated manifest instead. The skill fits into the repo's auto-generated docs pipeline (fragment → plugin SKILL.md → .claude mirror) and cross-links into the existing winapp-frameworks and winapp-troubleshoot skills.
Changes:
- Adds the
maui.mdskill fragment plus its generatedSKILL.mdin.github/plugin/skills/winapp-cli/maui/and.claude/skills/winapp-maui/. - Registers
mauiin the doc-generation and validation scripts (generate-llm-docs.ps1,validate-llm-docs.ps1). - Adds cross-links (frameworks table row +
.NET MAUIsection, troubleshoot error-table row, related-skills bullets) across the frameworks/troubleshoot fragments and their generated mirrors.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| docs/fragments/skills/winapp-cli/maui.md | New hand-written skill fragment: root cause, manifest locations, publish→pack→sign workflow, CI example, troubleshooting. |
| .github/plugin/skills/winapp-cli/maui/SKILL.md | Generated Copilot plugin skill (frontmatter + fragment body); verified identical to fragment. |
| .claude/skills/winapp-maui/SKILL.md | Claude mirror of the plugin skill; verified byte-identical to the plugin SKILL.md. |
| scripts/generate-llm-docs.ps1 | Registers maui in $SkillNames, $SkillDescriptions, and $SkillCommandMap (empty, like frameworks). |
| scripts/validate-llm-docs.ps1 | Adds maui to the skill-drift validation list. |
| docs/fragments/skills/winapp-cli/frameworks.md | Adds a .NET MAUI table row/section and a related-skills link to winapp-maui. |
| .github/plugin/skills/winapp-cli/frameworks/SKILL.md | Generated mirror of the frameworks fragment changes. |
| .claude/skills/winapp-frameworks/SKILL.md | Claude mirror of the frameworks changes. |
| docs/fragments/skills/winapp-cli/troubleshoot.md | Adds a MAUI placeholder-error row and related-skills link. |
| .github/plugin/skills/winapp-cli/troubleshoot/SKILL.md | Generated mirror of the troubleshoot changes. |
| .claude/skills/winapp-troubleshoot/SKILL.md | Claude mirror of the troubleshoot changes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Nikola Metulev (nmetulev)
left a comment
There was a problem hiding this comment.
🤖 AI-generated PR review
This review was produced by an automated multi-dimensional review agent (GitHub Copilot CLI) with a second-model cross-check. Everything below is a suggestion, not a mandate — the author decides what to implement, defer, or dismiss. Nothing here blocks merge, and any individual item may be wrong or simply not worth the churn. Specific items are attached as inline comments.
Verdict
Solid, well-written skill. I built the CLI and ran scripts/validate-llm-docs.ps1 → exit 0: the maui skill regenerates with zero drift, and the .github/plugin and .claude mirrors are byte-identical to the fragment. 0 critical · 0 high · 4 medium · 2 low.
Finding not tied to a diff line
M2 · llms.txt (lines 16-24) · docs sync — medium. The hand-maintained "Copilot Plugin Skills" list enumerates every skill but omits the new maui/SKILL.md, and no script regenerates llms.txt, so it won't self-heal. Suggestion: add a maui/SKILL.md entry between the frameworks and ui-automation lines.
Inline comments (author's discretion)
- M1
maui.md— the "preferred"bin\…\AppxManifest.xml+ the no---manifestshortcut don't hold for theWindowsPackageType=Noneflow the skill documents (medium; originally high, downgraded on cross-check). - M3
frameworks.md— standalonewinapp-mauiskill vs the frameworks+guide convention (medium, design call). - M4
validate-llm-docs.ps1— pre-existing: validate list omitsui-automation(medium). - L1 / L2
maui.md— CI cert-cleanup and password-handling nits (low).
Verified clean
CLI UX — every command/flag in the skill matches cli-schema.json (package → --cert/--cert-password; sign → positional cert + --password; cert generate --manifest). Plugin generation pipeline — both mirrors generate, description + version match the script.
🤖 Generated by an AI review agent — advisory only. Feel free to close anything that isn't worth it.
Nikola Metulev (nmetulev)
left a comment
There was a problem hiding this comment.
🤖 AI-generated review — GitHub Copilot CLI (Claude Opus 4.8), requested by Nikola Metulev (@nmetulev). Everything here is a suggestion for the author to accept or dismiss — nothing is blocking.
Unlike a static skim, I validated by actually running the workflow: built the winapp CLI from this branch and ran the full publish → cert generate → package → sign flow end-to-end, on both a fresh dotnet new maui project and this PR's checked-in sample.
✅ The approach is sound and works. A fresh dotnet new maui → dotnet publish -p:WindowsPackageType=None -p:SelfContained=true → winapp package --manifest obj\...\resizetizer\m\Package.appxmanifest --executable <app>.exe produced a correctly signed MSIX. The resizetizer resolved every $placeholder$ including <Identity>. So the guide/skill guidance is correct. 👍
- H1 — the checked-in sample is missing the Windows head, so it won't compile (
CS5001). - H2 — the sample's committed
Package.appxmanifestis a hand-authored / older-style manifest whose<Identity>and logo$placeholder$tokens the resizetizer does not resolve, so packaging the sample fails even after H1. A currentdotnet new mauimanifest doesn't have this problem. - CI reproducibility — Phase 1 scaffolds a multi-TFM project but the
maui-appCI job installs onlymaui-windows; restore may fail. - Doc accuracy — the skill's description of what resolves the Identity tokens is slightly off (the conclusion is fine).
Simplest fix for H1 + H2: regenerate samples/maui-app with dotnet new maui (keep the Windows head + a current-template manifest) instead of the hand-authored files.
Non-blocking doc-sync nits (not inline — these lines are outside the PR diff):
llms.txt— the Skills list doesn't includemaui/SKILL.md, and the Guides list doesn't includedocs/guides/maui.md.README.md— the samples table (~L254-263) has nomaui-approw (the badge + Additional-guides link were added).
Nice work overall — the skill/guide content is genuinely useful and the core workflow checks out. The fixes above are mostly about making the shipped sample actually build and package.
Reviewed at 622c596.
| Context "Phase 2: Sample Sanity Check" -Skip:$script:skip { | ||
| It "Should publish the checked-in MAUI sample project" { | ||
| Set-Location $script:sampleDir | ||
| dotnet publish ".\maui-app.csproj" ` |
There was a problem hiding this comment.
H1 · Sample won''t build — reproduced (CS5001). samples/maui-app/Platforms/Windows/ contains only Package.appxmanifest; the MauiWinUIApplication entry point (App.xaml, App.xaml.cs, app.manifest) is missing, so this publish fails with CSC error CS5001: Program does not contain a static 'Main' method. I verified that adding those 3 files (from dotnet new maui, namespace MauiSample.WinUI) makes the publish succeed. Simplest fix: regenerate the sample with dotnet new maui and keep the Windows head. (AI-generated; author decides.)
| xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" | ||
| IgnorableNamespaces="uap uap3 rescap"> | ||
|
|
||
| <Identity Name="$placeholder$" Publisher="$placeholder$" Version="$placeholder$" /> |
There was a problem hiding this comment.
H2 · This manifest doesn''t resolve → winapp package fails — reproduced. These <Identity> $placeholder$ tokens are not resolved by Microsoft.Maui.Resizetizer. After a clean publish, the generated obj\...\resizetizer\m\Package.appxmanifest still contains $placeholder$ for <Identity>, <PublisherDisplayName>, <Logo>, and the tile/splash logos, and winapp package exits 1: "manifest contains unresolved placeholders: $placeholder$".
A current dotnet new maui manifest differs and does resolve fully:
<Identity>uses literal defaults (Name="maui-package-name-placeholder",Publisher="CN=User Name",Version="0.0.0.0") which MAUI's single-project step overwrites fromApplicationId/ApplicationPublisher/ApplicationDisplayVersion.- logo attributes end in
.png($placeholder$.png), which the resizetizer matches and rewrites.
This sample's manifest is hand-authored / older-style, so nothing fills those tokens. I confirmed a fresh template packages to a signed MSIX, while this sample fails even after H1 is fixed. Fix: regenerate the manifest from a current dotnet new maui. (AI-generated; author decides.)
| Context "Phase 1: MAUI Guide Workflow (from scratch)" -Skip:$script:skip { | ||
| It "Should create a new MAUI project" { | ||
| Set-Location $script:tempDir | ||
| dotnet new maui -n $script:projectName |
There was a problem hiding this comment.
CI reproducibility (medium confidence). dotnet new maui scaffolds a multi-TFM project (net10.0-android;net10.0-ios;net10.0-maccatalyst;net10.0-windows...), but the maui-app job in test-samples.yml installs only maui-windows. Locally, publishing a multi-TFM project with just that workload failed to restore mobile runtime packs (NU1102 ... Microsoft.NETCore.App.Runtime.Mono.win-x64). Phase 1 may hit the same restore failure in CI. Worth verifying — either install the full maui workload, or strip the scaffolded project to the Windows TFM before publishing (as the checked-in maui-app.csproj already does). (AI-generated; author decides.)
| <uap:VisualElements DisplayName="$placeholder$" ... Square150x150Logo="$placeholder$" Square44x44Logo="$placeholder$"> | ||
| ``` | ||
|
|
||
| These are resolved at **build/publish time** by **`Microsoft.Maui.Resizetizer`** (bundled with the MAUI workload), which reads MSBuild properties (`ApplicationTitle`, `ApplicationId`, `ApplicationDisplayVersion`, `ApplicationPublisher`, the `MauiIcon`/`MauiSplashScreen` items, etc.), generates the app icon/tile/splash assets, and writes a **resolved** manifest into the intermediate output. |
There was a problem hiding this comment.
Root-cause description is slightly off (optional). This says the source <Identity Name="$placeholder$" ...> tokens are "resolved at build/publish time by Microsoft.Maui.Resizetizer." Empirically the resizetizer does not resolve <Identity> $placeholder$. Real MAUI projects work because their source <Identity> uses literal defaults (maui-package-name-placeholder, CN=User Name, 0.0.0.0) that MAUI's single-project step overwrites from MSBuild props — the resizetizer handles the DisplayName / logo / splash-image placeholders. The practical guidance (point winapp at the generated manifest) is correct; only the mechanism description could be tightened. (AI-generated; author decides.)
622c596 to
13a635a
Compare
|
|
||
| | Manifest | Path (relative to project) | State | | ||
| |----------|----------------------------|-------| | ||
| | **Resizetizer manifest** | `obj\<Config>\<TFM>\<RID>\resizetizer\m\Package.appxmanifest` | MAUI `$placeholder$` tokens resolved; `$targetnametoken$`/`$targetentrypoint$` remain (winapp resolves these via `--executable`) | |
| $manifest = ".\obj\Release\net10.0-windows10.0.19041.0\win-x64\resizetizer\m\Package.appxmanifest" | ||
| if (-not (Test-Path $manifest)) { throw "Resolved manifest not found: $manifest" } |
|
|
||
| It "Should package MAUI publish output with explicit manifest and executable" { | ||
| Set-Location $script:projectDir | ||
| Invoke-WinappCommand -Arguments "package .\publish\$($script:rid) --manifest `"$($script:manifestPath)`" --executable $($script:projectName).exe --cert .\devcert.pfx" |
| MAUI has one important quirk: its checked-in `Platforms/Windows/Package.appxmanifest` is full of `$placeholder$` tokens that **`winapp package` does not resolve**. MAUI's **resizetizer** fills them at build/publish time into a generated manifest: | ||
| - Resizetizer manifest: `obj\<Config>\<TFM>\<RID>\resizetizer\m\Package.appxmanifest` | ||
| - Fully-resolved output manifest: `bin\<Config>\<TFM>\<RID>\AppxManifest.xml` |
| @@ -19,6 +19,7 @@ Use this skill when: | |||
| | "Failed to add package identity" | Stale debug identity or untrusted cert | `Get-AppxPackage *yourapp* \| Remove-AppxPackage` to clean up, then `winapp cert install` and retry | | |||
| | "Certificate file already exists" | `devcert.pfx` already present | Use `winapp cert generate --if-exists overwrite` or `--if-exists skip` | | |||
| | "Manifest already exists" | `Package.appxmanifest` already present | Use `winapp manifest generate --if-exists overwrite` or edit manifest directly | | |||
| | "manifest contains unresolved placeholders: `$placeholder$`" (.NET MAUI) | Passed winapp the source `Platforms/Windows/Package.appxmanifest` | Point `--manifest` at the resizetizer-resolved manifest (`obj\...\resizetizer\m\Package.appxmanifest`) — see `winapp-maui` | | |||
| A .NET MAUI project has a **source** manifest at `Platforms/Windows/Package.appxmanifest` that is full of MAUI-specific `$placeholder$` tokens: | ||
|
|
||
| ```xml | ||
| <Identity Name="$placeholder$" Publisher="$placeholder$" Version="$placeholder$" /> |
| A .NET MAUI project has a **source** manifest at `Platforms/Windows/Package.appxmanifest` that is full of MAUI-specific `$placeholder$` tokens: | ||
|
|
||
| ```xml | ||
| <Identity Name="$placeholder$" Publisher="$placeholder$" Version="$placeholder$" /> |
| { | ||
| "name": "winapp", | ||
| "version": "0.5.1", | ||
| "version": "1.0.0", |
| The resolved manifest's `Identity.Publisher` comes from MSBuild (`$(ApplicationPublisher)`, defaulting to something like `CN=User Name`). Your signing certificate subject **must equal** that value exactly, or signing fails with a publisher mismatch. | ||
|
|
||
| ```powershell | ||
| # Read the publisher the resizetizer actually wrote, then generate a matching dev cert | ||
| winapp cert generate --manifest $manifest |
| # Strip to Windows-only TFM to avoid needing android/ios workloads | ||
| $csprojPath = Join-Path $script:projectDir "$($script:projectName).csproj" | ||
| $csprojContent = Get-Content $csprojPath -Raw | ||
| $csprojContent = $csprojContent -replace '<TargetFrameworks>[^<]+</TargetFrameworks>', "<TargetFrameworks>$($script:tfm)</TargetFrameworks>" | ||
| Set-Content -Path $csprojPath -Value $csprojContent |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 47 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (3)
docs/cli-schema.json:3
version.jsonstill declares 0.5.1, but this change stamps 1.0.0 into the schema, plugin metadata, and generated skills.validate-llm-docs.ps1explicitly normalizes fresh output to theversion.jsonvalue before comparing, so this branch will report schema/skill drift. Regenerate with the repository build so these files carry 0.5.1, or include the intentionalversion.jsonrelease bump.
"version": "1.0.0",
samples/maui-app/test.Tests.ps1:43
- Default cleanup only removes the Phase 1 temp directory, but Phase 2 writes
bin,obj,publish,devcert.pfx, and an MSIX into the checked-in sample. A normal local test therefore leaves all of those artifacts behind, making-SkipCleanupineffective for Phase 2 and allowing stale cert/package output to affect later runs. Remove the sample outputs here when cleanup is enabled, as the WPF and Flutter sample tests do.
.github/plugin/skills/winapp-cli/maui/SKILL.md:18 - This generated skill is not derived from the committed
docs/fragments/skills/winapp-cli/maui.md: the fragment saysPublisherDisplayNameisUser Nameand attributes all substitutions to Resizetizer, while this file uses$placeholder$and distinguishes the MAUI single-project targets. Because the generator appends the fragment verbatim and validation performs an exact comparison, CI will markmauiout of sync. Move the intended wording into the fragment, then regenerate both plugin mirrors.
A .NET MAUI project has a **source** manifest at `Platforms/Windows/Package.appxmanifest` that contains literal placeholder defaults for identity and MAUI-specific `$placeholder$` tokens for logos and display names:
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 53 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
docs/cli-schema.json:3
- The committed schema is stamped
1.0.0, butversion.jsonis still0.5.1.validate-llm-docs.ps1explicitly replaces the fresh schema version with theversion.jsonvalue before comparison, so this guarantees schema drift; the same accidental1.0.0stamp appears across the generated skills and plugin metadata. Regenerate or restamp all generated artifacts with the repository version.
"version": "1.0.0",
.github/plugin/skills/winapp-cli/maui/SKILL.md:24
- This generated skill is not byte-identical to its source fragment: the fragment has
PublisherDisplayNameset toUser Name, and the surrounding explanation also differs. Sincevalidate-llm-docs.ps1regenerates from the fragment and compares the result byte-for-byte, the newmauivalidation will fail. Regenerate the plugin skill from the finalized fragment and resync the Claude mirror.
<PublisherDisplayName>$placeholder$</PublisherDisplayName>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 53 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
docs/cli-schema.json:3
- This stamps the generated schema (and every generated skill/plugin file in this PR) as
1.0.0, butversion.jsonis still0.5.1.validate-llm-docs.ps1deliberately replaces the fresh schema version with theversion.jsonvalue before comparing (lines 42-45 and 84-93), so the docs validation will report drift. Regenerate these artifacts with the repository build/versioning flow so all committed versions remain0.5.1, or update the actual release version in the same release change.
"version": "1.0.0",
.github/plugin/skills/winapp-cli/maui/SKILL.md:24
- This generated skill is not generated from the committed
docs/fragments/skills/winapp-cli/maui.md: the fragment hasPublisherDisplayNameasUser Nameand a different root-cause paragraph, while this file contains$placeholder$and different prose. Sincevalidate-llm-docs.ps1compares the full generated output at lines 189-205, validation will fail even after version normalization. Update the source fragment as intended and regenerate both plugin and Claude skill outputs rather than committing divergent generated content.
A .NET MAUI project has a **source** manifest at `Platforms/Windows/Package.appxmanifest` that contains literal placeholder defaults for identity and MAUI-specific `$placeholder$` tokens for logos and display names:
```xml
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
<Properties>
<DisplayName>$placeholder$</DisplayName>
<PublisherDisplayName>$placeholder$</PublisherDisplayName>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 44 out of 53 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (3)
docs/cli-schema.json:3
- The committed generated version is
1.0.0, but the repository's canonicalversion.jsonis still0.5.1.validate-llm-docs.ps1explicitly normalizes fresh output to that canonical version, so this schema—and the regenerated plugin/skill version fields—will fail drift validation. Regenerate with the repository-stamped version or revert the accidental version changes.
"version": "1.0.0",
.github/plugin/skills/winapp-cli/maui/SKILL.md:24
- This generated content is out of sync with its source fragment:
docs/fragments/skills/winapp-cli/maui.md:19has<PublisherDisplayName>User Name</PublisherDisplayName>, while this output uses$placeholder$; several surrounding paragraphs also differ. Sincegenerate-llm-docs.ps1copies the fragment verbatim,validate-llm-docs.ps1will report drift. Regenerate the skill from the fragment rather than editing generated output.
<PublisherDisplayName>$placeholder$</PublisherDisplayName>
.claude/skills/winapp-maui/SKILL.md:24
- This Claude mirror contains the same content drift as the plugin skill: the source fragment uses
User Namehere, while this generated copy uses$placeholder$.sync-claude-plugin.ps1should produce this file from the regenerated plugin skill; rerun the generation/sync pipeline so both mirrors match the fragment.
<PublisherDisplayName>$placeholder$</PublisherDisplayName>
| --cert .\devcert.pfx ` | ||
| --cert-password $env:SIGN_PFX_PASSWORD ` |
| fail-fast: false | ||
| matrix: | ||
| sample: [cpp-app, dotnet-app, electron, flutter-app, packaging-cli, rust-app, tauri-app, wpf-app] | ||
| sample: [cpp-app, dotnet-app, electron, flutter-app, maui-app, packaging-cli, rust-app, tauri-app, wpf-app] |
| <MauiImage Update="Resources\Images\dotnet_bot.png" Resize="True" BaseSize="300,185" /> | ||
| <MauiFont Include="Resources\Fonts\*" /> |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 39 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
docs/fragments/skills/winapp-cli/maui.md:84
- The primary usage flow references
devcert.pfxbefore creating it, so a user following these numbered steps in a fresh project fails at packaging. Generate the matching certificate (with the same password) before invokingwinapp package; the publisher section currently introduces certificate generation only after this step.
winapp package .\publish\win-x64 `
--manifest $manifest `
--executable MyApp.exe `
--cert .\devcert.pfx `
--cert-password $env:SIGN_PFX_PASSWORD `
--output .\artifacts\MyApp-win-x64.msix
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 31 out of 39 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
docs/fragments/skills/winapp-cli/maui.md:83
- This local workflow reaches
winapp packagebefore the certificate is created in step 4, and it never definesSIGN_PFX_PASSWORD. On a fresh project the exact snippet exits withFile does not exist: '.\devcert.pfx'; after generating the default dev cert, passing an empty password argument is also invalid. Generate the matching certificate before packaging and either use its default password or explicitly initialize the password variable.
winapp package .\publish\win-x64 `
--manifest $manifest `
--executable MyApp.exe `
--cert .\devcert.pfx `
--cert-password $env:SIGN_PFX_PASSWORD `
| $script:tfm = "net10.0-windows10.0.19041.0" | ||
| $script:manifestPath = $null | ||
|
|
||
| if ($script:skip) { return } |
- Move certificate generation to step 2 (immediately after publish) - Step 2 now generates cert matching manifest publisher identity - Step 3 packages using the generated cert - Remove undefined $env:SIGN_PFX_PASSWORD and use default cert password - Fixes review comment: workflow now has correct logical ordering Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 31 out of 39 changed files in this pull request and generated no new comments.
Suppressed comments (2)
docs/fragments/skills/winapp-cli/maui.md:71
- MAUI's manifest generator does not consume
ApplicationPublisher; it preservesIdentity/@PublisherfromPlatforms/Windows/Package.appxmanifest. A clean publish with-p:ApplicationPublisher='CN=Review Probe'still producedCN=User Name, while editing the source manifest'sIdentity Publisherproduced the requested value. The later instructions to setApplicationPublishertherefore leave users with the same MSIX publisher mismatch. Document editing that non-placeholder attribute in the source manifest instead, and clarify that this equality is required for MSIX signing, not standalone EXE signing.
The resolved manifest's `Identity.Publisher` comes from MSBuild (`$(ApplicationPublisher)`, defaulting to something like `CN=User Name`). Your signing certificate subject **must equal** that value exactly, or signing fails with a publisher mismatch.
docs/fragments/skills/winapp-cli/maui.md:40
WindowsPackageType=MSIXis not the default for the current .NET 10 MAUI app template; newly scaffolded projects explicitly setWindowsPackageTypetoNone. Calling MSIX the default misleads users about whyAppxManifest.xmlis absent.
This issue also appears on line 71 of the same file.
> **Note:** When building with `WindowsPackageType=MSIX` (the default), MAUI also produces `bin\<Config>\<TFM>\<RID>\AppxManifest.xml` — a fully resolved manifest. This file is **not produced** in `WindowsPackageType=None` workflows. The resizetizer manifest above works in both cases.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 33 out of 39 changed files in this pull request and generated no new comments.
Suppressed comments (2)
docs/fragments/skills/winapp-cli/maui.md:83
--if-exists skipkeeps any existing PFX without checking that its subject matches this manifest. In the publisher-mismatch workflow described here, rerunning this command after changing the publisher therefore preserves the mismatched certificate and the subsequent package signing still fails. Useoverwritewhen generating the matching certificate (or explicitly tell users to remove/use a different output file), then regenerate the derived skills.
winapp cert generate --manifest $manifest --if-exists skip
docs/fragments/skills/winapp-cli/maui.md:86
ApplicationPublisheris not consumed by MAUI's resizetizer, so setting it in the project will not changeIdentity.Publisher; the generated manifest keeps the publisher fromPlatforms/Windows/Package.appxmanifest. Users following this instruction can still get the same publisher mismatch. Please direct them to updateIdentity/@Publisher(andPublisherDisplayName) in the source manifest, correct the earlier property list, and regenerate the derived skill files.
Set `<ApplicationPublisher>CN=Your Company</ApplicationPublisher>` (or the `ApplicationPublisher` MSBuild property) in the `.csproj` to control it, then regenerate the cert to match.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 33 out of 39 changed files in this pull request and generated no new comments.
Suppressed comments (3)
docs/fragments/skills/winapp-cli/frameworks.md:79
- This summary presents the
binmanifest as generally available, but this PR'sWindowsPackageType=Noneworkflow—and the current MAUI template default—does not produce it. Mark it as MSIX-only so users do not select a path that is absent after following the guide.
- Fully-resolved output manifest: `bin\<Config>\<TFM>\<RID>\AppxManifest.xml`
docs/fragments/skills/winapp-cli/maui.md:208
- Resizetizer does not overwrite
Platforms/Windows/Package.appxmanifest; it overwrites manifests underobj/bin. As written, this row incorrectly tells users that source-manifest edits are discarded, contradicting the publisher instructions above that require editing the source manifest.
| Placeholders reappear after editing the source manifest | Resizetizer overwrites its generated copy each build | Don't hand-edit the source manifest — change the MSBuild properties / `MauiIcon` instead |
docs/fragments/skills/winapp-cli/maui.md:40
- The current .NET 10 MAUI template sets
WindowsPackageTypetoNone(as does this PR's sample atsamples/maui-app/maui-app.csproj:16), so calling MSIX the default is incorrect. This can make users expect thebin/.../AppxManifest.xmlpath to exist after a normal publish when it does not.
This issue also appears on line 208 of the same file.
> **Note:** When building with `WindowsPackageType=MSIX` (the default), MAUI also produces `bin\<Config>\<TFM>\<RID>\AppxManifest.xml` — a fully resolved manifest. This file is **not produced** in `WindowsPackageType=None` workflows. The resizetizer manifest above works in both cases.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a3bda358-74df-4ddd-b5f9-9ceb597b0d06
This merge brings in the unified plugin structure from main while preserving our MAUI skill changes (fragment and sample). The old .github/plugin and .claude/skills directories are now migrated to plugins/winapp/. Next: regenerate skills in new structure.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a3bda358-74df-4ddd-b5f9-9ceb597b0d06
- Moved MAUI skill fragment to plugins/winapp/skills/winapp-maui/SKILL.md - Regenerated CLI schema and manifest versions (0.5.1) - Merged main's plugin structure changes (PR microsoft#631) - All MAUI changes (sample test, docs, CI example) preserved and verified The branch now aligns with main's unified plugin structure while retaining all prior MAUI skill improvements (cert generation ordering fix, test robustness, CI documentation updates). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
a289a6c to
98925d6
Compare
|
Nikola Metulev (@nmetulev) I ask copilot to fix the conflicts, can you review again? |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a3bda358-74df-4ddd-b5f9-9ceb597b0d06
| Get-ChildItem .\publish\win-x64 -Filter *.exe | | ||
| ForEach-Object { winapp sign $_.FullName $env:SIGN_PFX_PATH --password $env:SIGN_PFX_PASSWORD --quiet } |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 26 out of 32 changed files in this pull request and generated no new comments.
Suppressed comments (1)
plugins/winapp/skills/winapp-maui/SKILL.md:212
- This troubleshooting row mixes up the source and generated manifests. Resizetizer overwrites files under
obj/bin, notPlatforms/Windows/Package.appxmanifest; the current wording also conflicts with the earlier instruction to edit the source manifest when changingIdentity.Publisher. Describe edits to the generated manifest as the failure mode, and direct users to change the source manifest or its MSBuild/resource inputs before republishing.
| Placeholders reappear after editing the source manifest | Resizetizer overwrites its generated copy each build | Don't hand-edit the source manifest — change the MSBuild properties / `MauiIcon` instead |
Summary
Adds a dedicated
winapp-mauiskill that documents how to package and sign .NET MAUI Windows apps with winapp, focused on solving the resizetizer manifest dependency.The problem it solves
A .NET MAUI project ships a source manifest at
Platforms/Windows/Package.appxmanifestfull of MAUI-specific$placeholder$tokens (DisplayName, Logo, Identity Name/Publisher/Version, tile/splash logos).winapp packageonly auto-resolves its own$targetnametoken$/$targetentrypoint$tokens — it does not understand MAUI's$placeholder$tokens, so pointing it at the source manifest fails with:MAUI's resizetizer (bundled with the MAUI workload) fills those tokens at build/publish time into generated manifests:
obj\<Config>\<TFM>\<RID>\resizetizer\m\Package.appxmanifest(MAUI tokens resolved; entry-point tokens remain, resolved by--executable)bin\<Config>\<TFM>\<RID>\AppxManifest.xml(fully resolved)The fix is to point
winapp package --manifestat the generated manifest, never the source one — and never hand-edit the source manifest (the resizetizer overwrites its generated copy each build).What's included
docs/fragments/skills/winapp-cli/maui.mdand generatedSKILL.mdin.github/plugin/skills/winapp-cli/maui/and.claude/skills/winapp-maui/. Covers: root cause, where the resolved manifest lives, publish→pack→sign workflow, publisher/cert matching, a GitHub Actions CI example (x64, with guidance for adding arm64), tips, and a troubleshooting table.mauiinscripts/generate-llm-docs.ps1($SkillNames,$SkillDescriptions,$SkillCommandMap= empty — links to guidance, likeframeworks) and inscripts/validate-llm-docs.ps1.winapp-frameworks(guides table row +### .NET MAUInote + related-skills bullet) andwinapp-troubleshoot(error-table row + related-skills bullet).samples/maui-app/— a Windows-only MAUI app (from the latestdotnet new mauitemplate) with a Pester test that validates the full publish→cert→package→sign workflow.Validation
SKILL.mdfiles verified byte-identical togenerate-llm-docs.ps1output (ignoring the version line, which the release build stamps)..claude/skills/winapp-maui/SKILL.mdverified byte-identical to the plugin source (whatsync-claude-plugin.ps1produces).--manifestat the resizetizer manifest.