Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# Auto detect text files and perform LF normalization
* text=auto

# Generated files - always use LF to match what generate-llm-docs.ps1 writes
# Generated LLM documentation - always use LF to match what generate-llm-docs.ps1 writes
docs/cli-schema.json text eol=lf
.github/plugin/plugin.json text eol=lf
.github/plugin/skills/** text eol=lf
docs/npm-usage.md text eol=lf
src/winapp-npm/src/winapp-commands.ts text eol=lf

# Shell scripts should use LF
*.sh text eol=lf
Expand Down
11 changes: 4 additions & 7 deletions .github/actions/collect-metrics/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,17 @@ runs:
$artifacts = "${{ inputs.artifacts-path }}"
$sizes = @{}

# Sum all files excluding PDBs to get total CLI distribution size
$x64Files = Get-ChildItem "$artifacts/cli/win-x64" -File -ErrorAction SilentlyContinue | Where-Object { $_.Extension -ne '.pdb' }
$arm64Files = Get-ChildItem "$artifacts/cli/win-arm64" -File -ErrorAction SilentlyContinue | Where-Object { $_.Extension -ne '.pdb' }
$x64Exe = Get-Item "$artifacts/cli/win-x64/winapp.exe" -ErrorAction SilentlyContinue
$arm64Exe = Get-Item "$artifacts/cli/win-arm64/winapp.exe" -ErrorAction SilentlyContinue
$npmPkg = Get-ChildItem "$artifacts/*.tgz" -ErrorAction SilentlyContinue | Select-Object -First 1
$msixX64 = Get-ChildItem "$artifacts/msix-packages/*x64*.msix" -ErrorAction SilentlyContinue | Select-Object -First 1
$msixArm64 = Get-ChildItem "$artifacts/msix-packages/*arm64*.msix" -ErrorAction SilentlyContinue | Select-Object -First 1
$nugetPkg = Get-ChildItem "$artifacts/nuget/*.nupkg" -ErrorAction SilentlyContinue | Select-Object -First 1

if ($x64Files) { $sizes["cli-win-x64"] = ($x64Files | Measure-Object -Property Length -Sum).Sum }
if ($arm64Files) { $sizes["cli-win-arm64"] = ($arm64Files | Measure-Object -Property Length -Sum).Sum }
if ($x64Exe) { $sizes["cli-win-x64"] = $x64Exe.Length }
if ($arm64Exe) { $sizes["cli-win-arm64"] = $arm64Exe.Length }
if ($npmPkg) { $sizes["npm-package"] = $npmPkg.Length }
if ($msixX64) { $sizes["msix-x64"] = $msixX64.Length }
if ($msixArm64) { $sizes["msix-arm64"] = $msixArm64.Length }
if ($nugetPkg) { $sizes["nuget-package"] = $nugetPkg.Length }

$sizes | ConvertTo-Json | Set-Content "$artifacts/binary-sizes.json"

Expand Down
24 changes: 3 additions & 21 deletions .github/actions/report-metrics/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ runs:
uses: actions/cache/restore@v4
with:
path: metrics-baseline
key: build-metrics-baseline
restore-keys: |
build-metrics-main-
key: build-metrics-baseline-no-exact-match
restore-keys: build-metrics-main-

# On main, save current metrics as the baseline for future PRs
- name: Save metrics baseline
Expand All @@ -34,27 +33,12 @@ runs:
Copy-Item "${{ inputs.artifacts-path }}/startup-time.json" "metrics-baseline/startup.json" -ErrorAction SilentlyContinue
Copy-Item "${{ inputs.artifacts-path }}/coverage-summary.json" "metrics-baseline/coverage.json" -ErrorAction SilentlyContinue

# GitHub Actions caches are immutable — delete the old entry so we can save an updated one
- name: Delete old metrics baseline cache
if: github.ref == 'refs/heads/main'
shell: pwsh
env:
GH_TOKEN: ${{ inputs.github-token }}
run: |
$result = gh cache delete "build-metrics-baseline" --repo $env:GITHUB_REPOSITORY 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "Old baseline cache deleted"
} else {
Write-Host "No existing baseline cache to delete (expected on first run)"
}
exit 0

- name: Cache metrics baseline
if: github.ref == 'refs/heads/main'
uses: actions/cache/save@v4
with:
path: metrics-baseline
key: build-metrics-baseline
key: build-metrics-main-${{ github.sha }}

# On PRs, compare against baseline and post a comment
- name: Post PR metrics comment
Expand Down Expand Up @@ -108,7 +92,6 @@ runs:
'npm-package': 'npm-package',
'msix-x64': 'msix-packages',
'msix-arm64': 'msix-packages',
'nuget-package': 'nuget-packages',
};
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
for (const [sizeKey, artifactName] of Object.entries(artifactNameMap)) {
Expand Down Expand Up @@ -170,7 +153,6 @@ runs:
'npm-package': 'NPM Package',
'msix-x64': 'MSIX (x64)',
'msix-arm64': 'MSIX (ARM64)',
'nuget-package': 'NuGet Package',
};

let body = '## Build Metrics Report\n\n';
Expand Down
4 changes: 2 additions & 2 deletions .github/plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "winappcli",
"name": "winapp-cli",
"description": "Windows app development, packaging, and distribution. Helps with creating Windows installers (MSIX), code signing, certificates, Windows SDK and Windows App SDK setup, package identity for Windows APIs (push notifications, background tasks, share target), appxmanifest authoring, and Microsoft Store distribution. Supports Electron, .NET, C++, Rust, Flutter, and Tauri apps.",
"version": "0.2.2",
"version": "0.2.1",
"author": {
"name": "Microsoft",
"url": "https://github.com/microsoft/WinAppCli"
Expand Down
2 changes: 1 addition & 1 deletion .github/plugin/skills/winapp-cli/frameworks/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: winapp-frameworks
description: Framework-specific Windows development guidance for Electron, .NET (WPF, WinForms), C++, Rust, Flutter, and Tauri. Use when packaging or adding Windows features to an Electron app, .NET desktop app, Flutter app, Tauri app, Rust app, or C++ app.
version: 0.2.2
version: 0.2.1
---
## When to use

Expand Down
51 changes: 2 additions & 49 deletions .github/plugin/skills/winapp-cli/identity/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: winapp-identity
description: Enable Windows package identity for desktop apps to access Windows APIs like push notifications, background tasks, share target, and startup tasks. Use when adding Windows notifications, background tasks, or other identity-requiring Windows features to a desktop app.
version: 0.2.2
version: 0.2.1
---
## When to use

Expand Down Expand Up @@ -83,53 +83,6 @@ After running, launch your exe normally — Windows will recognize it as having
- If you have both a debug identity and an installed MSIX, they may conflict — use `--keep-identity` carefully
- For Electron apps, use `npx winapp node add-electron-debug-identity` instead (handles Electron-specific paths)

## Debugging: `winapp run` vs `create-debug-identity`

| | `winapp run` | `create-debug-identity` |
|---|---|---|
| **What it registers** | Full loose layout package (entire folder) | Sparse package (single exe) |
| **How the app launches** | Launched by winapp (AUMID activation or execution alias) | You launch the exe yourself (command line, IDE, etc.) |
| **Simulates MSIX install** | Yes — closest to production behavior | No — sparse identity only |
| **Files stay in place** | Copied to an AppX layout directory | Yes — exe stays at its original path |
| **Debugger-friendly** | Attach to PID after launch, or use `--no-launch` then launch via alias | Launch directly from your IDE's debugger — the exe has identity regardless |
| **Console app support** | `--with-alias` keeps stdin/stdout in terminal | Run exe directly in terminal |
| **Best for** | Most frameworks (.NET, C++, Rust, Flutter, Tauri) | Electron, or when you need full IDE debugger control (F5 startup debugging) |

### When to use which

**Default to `winapp run`** for most development — it simulates a real MSIX install with full identity, capabilities, and file associations:

```powershell
winapp run .\build\output # GUI apps
winapp run .\build\output --with-alias # console apps (preserves stdin/stdout)
```

**Use `create-debug-identity` when:**
- **Debugging startup code** — your IDE launches + debugs the exe directly; identity is attached from the first instruction
- **Exe is separate from build output** — e.g., Electron where `electron.exe` is in `node_modules/`
- **Testing sparse package behavior** — `AllowExternalContent`, `TrustedLaunch`

```powershell
winapp create-debug-identity .\bin\Debug\myapp.exe
# Now launch any way you like — F5, terminal, script — the exe has identity
```

### Common debugging scenarios

| Scenario | Command | Notes |
|----------|---------|-------|
| **Just run with identity** | `winapp run .\build\Debug` | Simplest workflow; add `--with-alias` for console apps |
| **Attach debugger to running app** | `winapp run .\build\Debug`, then attach to PID | Misses startup code |
| **Register identity, launch via AUMID** | `winapp run .\build\Debug --no-launch` | Launch with `start shell:AppsFolder\<AUMID>` or the execution alias (not the exe directly) |
| **F5 startup debugging** | `winapp create-debug-identity .\bin\myapp.exe` | IDE controls process from first instruction; best for debugging activation/startup code |
| **Capture debug output** | `winapp run .\build\Debug --debug-output` | Captures `OutputDebugString`; **blocks other debuggers** (one debugger per process) |
| **Run and auto-clean** | `winapp run .\build\Debug --unregister-on-exit` | Unregisters the dev package after the app exits |
| **Clean up stale registration** | `winapp unregister` | Removes dev packages for the current project (auto-detects from manifest) |

> **Using Visual Studio with a packaging project?** VS already handles identity, AUMID activation, and debugger attachment from F5. These workflows are most useful for VS Code, terminal-based development, and frameworks VS doesn't natively package (Rust, Flutter, Tauri, Electron, C++).

For full details including IDE setup examples, see the [Debugging Guide](https://github.com/microsoft/WinAppCli/blob/main/docs/debugging.md).

## Related skills
- Need a manifest? See `winapp-manifest` to generate `appxmanifest.xml`
- Need a certificate? See `winapp-signing` — a trusted cert is required for identity registration
Expand All @@ -140,7 +93,7 @@ For full details including IDE setup examples, see the [Debugging Guide](https:/
| Error | Cause | Solution |
|-------|-------|----------|
| "appxmanifest.xml not found" | No manifest in current directory | Run `winapp init` or `winapp manifest generate`, or pass `--manifest` |
| "Failed to add package identity" | Previous registration stale or cert untrusted | Run `winapp unregister` to remove stale packages, then `winapp cert install ./devcert.pfx` (admin) |
| "Failed to add package identity" | Previous registration stale or cert untrusted | `Get-AppxPackage *yourapp* \| Remove-AppxPackage`, then `winapp cert install ./devcert.pfx` (admin) |
| "Access denied" | Cert not trusted or permission issue | Run `winapp cert install ./devcert.pfx` as admin |
| APIs still fail after registration | App launched before registration completed | Close app, re-run `create-debug-identity`, then relaunch |

Expand Down
28 changes: 7 additions & 21 deletions .github/plugin/skills/winapp-cli/manifest/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: winapp-manifest
description: Create and edit Windows app manifest files (appxmanifest.xml) that define app identity, capabilities, and visual assets, or generate new assets from existing images. Use when creating a Windows app manifest for any app type (GUI, console, CLI tool, service), adding Windows capabilities, generating new app icons and assets, or adding execution aliases, file associations, protocol handlers, or other app extensions.
version: 0.2.2
description: Create and edit Windows app manifest files (appxmanifest.xml) that define app identity, capabilities, and visual assets. Use when creating a Windows app manifest for any app type (GUI, console, CLI tool, service), adding Windows capabilities, updating app icons and assets, or adding execution aliases, file associations, protocol handlers, or other app extensions.
version: 0.2.1
---
## When to use

Expand All @@ -13,7 +13,7 @@ Use this skill when:
## Prerequisites

- winapp CLI installed
- Optional: a source image (PNG or SVG, at least 400x400 pixels) for custom app icons
- Optional: a source image (PNG, at least 400x400 pixels) for custom app icons

## Key concepts

Expand Down Expand Up @@ -64,24 +64,11 @@ Output:
# Generate all required icon sizes from one source image
winapp manifest update-assets ./my-logo.png

# SVG source images produce the best quality at all sizes
winapp manifest update-assets ./my-logo.svg

# Specify manifest location (if not in current directory)
winapp manifest update-assets ./my-logo.png --manifest ./path/to/appxmanifest.xml

# Generate light theme variants from a separate image
winapp manifest update-assets ./my-logo.png --light-image ./my-logo-light.png

# Use the same image for both (generates all MRT light theme qualifiers)
winapp manifest update-assets ./my-logo.png --light-image ./my-logo.png
```

The source image should be at least 400x400 pixels (PNG or SVG recommended). The command reads the manifest to determine which asset sizes are needed and generates:
- **5 scale variants** per asset (100%, 125%, 150%, 200%, 400%)
- **14 plated + 14 unplated targetsize variants** for the app icon (44x44)
- **app.ico** — multi-resolution ICO file for shell integration. If an existing `.ico` file is present in the assets directory, it is replaced in-place (preserving the original filename)
- With `--light-image`: light theme variants using the correct MRT qualifiers per asset type
The source image should be at least 400x400 pixels (PNG recommended). The command reads the manifest to determine which asset sizes are needed and generates them all.

### Add an execution alias

Expand Down Expand Up @@ -164,7 +151,7 @@ Key fields to edit:
- The `sparse` template adds `uap10:AllowExternalContent="true"` for apps that need identity but run outside the MSIX container
- You can manually edit `appxmanifest.xml` after generation — it's a standard XML file
- Image assets must match the paths referenced in the manifest — `update-assets` handles this automatically
- For logos, transparent PNGs or SVGs work best. SVG source images are rendered as vectors directly at each target size, producing pixel-perfect results. Use a square image for best results across all sizes.
- For logos, transparent PNGs work best. Use a square image for best results across all sizes.
- **`$targetnametoken$` placeholder:** When `winapp manifest generate` creates `appxmanifest.xml`, it sets `Application.Executable` to `$targetnametoken$.exe` by default. This is a valid placeholder that gets automatically resolved by `winapp package --executable <name>` at packaging time — you rarely need to override it during manifest generation. If `--executable` is provided to `winapp manifest generate`, winapp reads `FileVersionInfo` from the actual exe to auto-fill package name, description, publisher, and extract an icon, so the exe must already exist on disk.

## Related skills
Expand All @@ -176,7 +163,7 @@ Key fields to edit:
| Error | Cause | Solution |
|-------|-------|----------|
| "Manifest already exists" | `appxmanifest.xml` present | Use `--if-exists overwrite` to replace, or edit existing file directly |
| "Invalid source image" | Image too small or wrong format | Use PNG or SVG, at least 400x400 pixels |
| "Invalid source image" | Image too small or wrong format | Use PNG, at least 400x400 pixels |
| "Publisher mismatch" during packaging | Manifest publisher ≠ cert publisher | Edit `Identity.Publisher` in manifest, or regenerate cert with `--manifest` |


Expand Down Expand Up @@ -213,13 +200,12 @@ Generate new assets for images referenced in an appxmanifest.xml from a single s
<!-- auto-generated from cli-schema.json -->
| Argument | Required | Description |
|----------|----------|-------------|
| `<image-path>` | Yes | Path to source image file (SVG, PNG, ICO, JPG, BMP, GIF) |
| `<image-path>` | Yes | Path to source image file |

#### Options
<!-- auto-generated from cli-schema.json -->
| Option | Description | Default |
|--------|-------------|---------|
| `--light-image` | Path to source image for light theme variants (SVG, PNG, ICO, JPG, BMP, GIF) | (none) |
| `--manifest` | Path to AppxManifest.xml or Package.appxmanifest file (default: search current directory) | (none) |

### `winapp manifest add-alias`
Expand Down
2 changes: 1 addition & 1 deletion .github/plugin/skills/winapp-cli/package/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: winapp-package
description: Package a Windows app as an MSIX installer for distribution or testing. Use when creating a Windows installer, packaging an Electron/Flutter/.NET/Rust/C++/Tauri app for Windows, building an MSIX, distributing a desktop app, packaging a console app or CLI tool, or adding MSIX packaging to a build script or CI/CD pipeline.
version: 0.2.2
version: 0.2.1
---
## When to use

Expand Down
10 changes: 2 additions & 8 deletions .github/plugin/skills/winapp-cli/setup/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: winapp-setup
description: Set up a Windows app project for MSIX packaging, Windows SDK access, or Windows API usage. Use when adding Windows support to an Electron, .NET, C++, Rust, Flutter, or Tauri project, or restoring SDK packages after cloning.
version: 0.2.2
version: 0.2.1
---
## When to use

Expand All @@ -24,8 +24,6 @@ npm install --save-dev @microsoft/winappcli

You need an **existing app project** — `winapp init` does **not** create new projects, it adds Windows platform files to your existing codebase.

> **Already have a `Package.appxmanifest`?** .NET projects that already have a packaging manifest (e.g., WinUI 3 apps or projects with an existing MSIX packaging setup) likely **don't need `winapp init`**. Ensure your `.csproj` references the `Microsoft.WindowsAppSDK` NuGet package and has the right properties for packaged builds (e.g., `<WindowsPackageType>MSIX</WindowsPackageType>`). WinUI 3 apps created from Visual Studio templates are typically already fully configured — you can go straight to building and using `winapp run` or `winapp package`.

## Key concepts

**`appxmanifest.xml`** is the most important file winapp creates — it declares your app's identity, capabilities, and visual assets. Most winapp commands require it (`package`, `run`, `cert generate --manifest`).
Expand Down Expand Up @@ -94,10 +92,6 @@ winapp run ./dist --manifest ./out/AppxManifest.xml --args "--my-flag value"

# Register identity without launching (useful for attaching a debugger manually)
winapp run ./bin/Debug --no-launch

# Launch and capture OutputDebugString messages and first-chance exceptions
# Note: prevents other debuggers (VS, VS Code) from attaching — use --no-launch if you need those instead
winapp run ./bin/Debug --debug-output
```

Use `winapp run` during iterative development — it creates a loose layout package, registers a debug identity, and launches the app in one step. For identity-only registration without loose layout, use `winapp create-debug-identity` instead.
Expand All @@ -121,7 +115,6 @@ For console apps, add `--with-alias` to preserve stdin/stdout in the current ter

For full debugging scenarios and IDE setup, see the [Debugging Guide](https://github.com/microsoft/WinAppCli/blob/main/docs/debugging.md).


## Recommended workflow

1. **Initialize** — `winapp init --use-defaults` in your existing project
Expand Down Expand Up @@ -216,6 +209,7 @@ Creates packaged layout, registers the Application, and launches the packaged ap
| Option | Description | Default |
|--------|-------------|---------|
| `--args` | Command-line arguments to pass to the application | (none) |
| `--clean` | Remove the existing package's application data (LocalState, settings, etc.) before re-deploying. By default, application data is preserved across re-deployments. | (none) |
| `--debug-output` | Capture OutputDebugString messages and first-chance exceptions from the launched application. Only one debugger can attach to a process at a time, so other debuggers (Visual Studio, VS Code) cannot be used simultaneously. Use --no-launch instead if you need to attach a different debugger. Cannot be combined with --no-launch or --json. | (none) |
| `--json` | Format output as JSON | (none) |
| `--manifest` | Path to the appxmanifest.xml (default: auto-detect from input folder or current directory) | (none) |
Expand Down
2 changes: 1 addition & 1 deletion .github/plugin/skills/winapp-cli/signing/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: winapp-signing
description: Create and manage code signing certificates for Windows apps and MSIX packages. Use when generating a certificate, signing a Windows app or installer, or fixing certificate trust issues.
version: 0.2.2
version: 0.2.1
---
## When to use

Expand Down
Loading