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: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
"url": "https://github.com/microsoft/win-dev-skills"
},
"description": "Agents and skills for native Windows app development with WinUI 3 and the Windows App SDK.",
"version": "0.3.0",
"version": "0.3.1",
"plugins": [
{
"name": "winui",
"description": "Agents and skills for WinUI 3 app development. Create new WinUI 3 desktop apps, convert from other frameworks to WinUI 3, or add features to existing WinUI 3 applications.",
"version": "0.3.0",
"version": "0.3.1",
"source": "./plugins/winui",
"category": "windows-development",
"tags": [
Expand Down
4 changes: 2 additions & 2 deletions .github/plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
},
"metadata": {
"description": "Agents and skills for native Windows app development with WinUI 3 and the Windows App SDK.",
"version": "0.3.0"
"version": "0.3.1"
},
"plugins": [
{
"name": "winui",
"description": "Agents and skills for WinUI 3 app development. Create new WinUI 3 desktop apps, convert from other frameworks to WinUI 3, or add features to existing WinUI 3 applications.",
"version": "0.3.0",
"version": "0.3.1",
"source": "./plugins/winui"
}
]
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: PR validation

on:
push:
branches: [ "main" ]
branches: [ "main", "staging" ]
pull_request:
branches: [ "main" ]
branches: [ "main", "staging" ]
workflow_dispatch:

permissions:
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ The `version-bump` and `changelog-entry` CI jobs enforce this.

### Deprecated

## [0.3.1] — 2026-05-19

### Added

- `winui-dev` agent: window sizing rubric, screenshot validation step, and
anti-self-delegation guardrails (#84).
- `winui-search`: batched CLI mode, background cache refresh, BM25-based
ranking, and upgraded WinUI Gallery + Community Toolkit data fetchers (#83).

### Changed

- CI: `pr-validation` workflow now also runs on PRs targeting `staging`.
- Bumped `coverlet.collector` from 10.0.0 to 10.0.1 (#87).

## [0.3.0] — 2026-05-13

Baseline entry covering everything currently shipped on `main` at the time the
Expand Down
4 changes: 4 additions & 0 deletions plugins/winui/agents/winui-dev.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ description: "Builds WinUI 3 desktop applications using Windows App SDK, XAML, a
user-invocable: true
---

## You Are The WinUI Developer — Do The Work Yourself

You are `winui-dev` — don't call `task` with `agent_type: "winui:winui-dev"` (self-hop). `task` is fine for scoped helpers (`explore` for parallel codebase mapping, `general-purpose` for rubber-duck critique), not for the build itself.

## Process

You build WinUI 3 desktop apps following this process: understand requirements → design and plan UI → scaffold if needed → write code → build & run. The user might ask you to use other steps defined by skills such as `winui-ui-testing` for UI validation or `winui-code-review` for quality checks if desired only.
Expand Down
2 changes: 1 addition & 1 deletion plugins/winui/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "winui",
"description": "Agents and skills for WinUI 3 app development. Create new WinUI 3 desktop apps, convert from other frameworks to WinUI 3, or add features to existing WinUI 3 applications.",
"version": "0.3.0",
"version": "0.3.1",
"author": {
"name": "Microsoft",
"url": "https://github.com/microsoft/win-dev-skills"
Expand Down
53 changes: 47 additions & 6 deletions plugins/winui/skills/winui-design/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ description: "WinUI 3 UI design and XAML correctness — layout planning, contro
> **Before picking controls, search the catalogue.** This skill ships `winui-search.exe` alongside this `SKILL.md`. It indexes 100+ WinUI Gallery controls, every Windows Community Toolkit scenario, and a curated set of platform integration patterns (JumpList, Share, file pickers, drag-drop). Use it to ground every control choice in a real shipping sample **before writing any XAML** — this is the difference between guessing property names and copying canonical code.
>
> ```powershell
> .\winui-search.exe search "<feature description>" # shortlist of matching scenarios
> .\winui-search.exe get <id> # full XAML + C# + pitfall notes
> .\winui-search.exe list # browse everything
> .\winui-search.exe update # refresh embedded snapshots from GitHub
> .\winui-search.exe search "<feature 1>" "<feature 2>" ... # batch one focused query per feature
> .\winui-search.exe get <id 1> <id 2> ... # batch up to 3 IDs — full XAML + C# + pitfall notes
> .\winui-search.exe list # browse all patterns (heavy — prefer search)
> .\winui-search.exe update # force refresh now
> ```
>
> **Workflow:** batch every search you need for the current page or featurepick the best ID from each shortlist → `get` the full code for each → then write XAML using those samples as reference. **Do NOT interleave searching with coding.** Search **one feature per query** — the BM25 scoring rewards focused queries.
> **Workflow:** in **one** `search` call, list every feature you need for the current page (one focused query per feature, not a bag of keywords) → from each shortlist pick the best ID → grab full code with `get` (batch up to 3 IDs per call) → then write XAML using those samples as reference. **Do NOT interleave searching with coding** — front-load all lookups, then code. BM25 rewards focused per-query phrasing, so keep each query about one control or pattern.

#### Step 1: Identify App Type and Anchor Control
| App Type | Anchor Control | Reference App |
Expand All @@ -40,7 +40,48 @@ description: "WinUI 3 UI design and XAML correctness — layout planning, contro
- Sidebar: fixed 300-360px width; main content: `Width="*"` with 24px padding
- Status bar: `Grid` row at bottom; toolbar: `CommandBar` or title bar buttons

#### Step 4: Design Anti-Patterns
#### Step 4: Size the Window to the App

> **WinUI 3 has no `SizeToContent`.** Without an explicit size, Windows defaults the main window to ~1024×768 — oversized for most utilities. **Size the window in `MainWindow`'s constructor; derive from the layout, not a generic.**

**Rubric.** Width = widest row + 48 padding (24 each side), rounded **up** to nearest 20. Height = 32 (titlebar) + Σ(row heights) + Σ(spacing) + 48 padding, rounded up to 20. Round up — clipped content is a worse failure than a slightly-wide window.

**Sanity check** (ranges, not targets — derive yours from the rubric):
- Single-purpose utility → ~440–560 wide
- Form / single-page tool → ~600–800 wide, ~640–800 tall
- Multi-pane (nav + content) → ~1100–1300 wide, ~720–840 tall
- Document / canvas / media editor → 1280+ wide

If your derived number is well below its range, you missed a row — re-check.

`AppWindow.Resize` takes **physical pixels**, not DIPs — multiply by the monitor's DPI scale:

```csharp
using Microsoft.UI;
using Microsoft.UI.Windowing;
using System.Runtime.InteropServices;
using Windows.Graphics;

public sealed partial class MainWindow : Window
{
[DllImport("user32.dll")]
private static extern uint GetDpiForWindow(IntPtr hWnd);

public MainWindow()
{
InitializeComponent();
var hwnd = Win32Interop.GetWindowFromWindowId(AppWindow.Id);
var scale = GetDpiForWindow(hwnd) / 96.0;
AppWindow.Resize(new SizeInt32((int)(460 * scale), (int)(860 * scale)));
}
}
```

`XamlRoot.RasterizationScale` is null in the ctor and stale after `AppWindow.Move`, so `[DllImport]` is the cleanest path. Don't try to size the window by setting `Width`/`Height` on the root `Grid` — that clips content, not the window.

If the user asks for UI validation, see `winui-ui-testing` Step 3.5 to verify the rubric against the visual checklist.

#### Step 5: Design Anti-Patterns
| ❌ Don't | ✅ Do Instead |
|----------|--------------|
| Centered floating card on background | Content fills window with padding |
Expand Down
Binary file modified plugins/winui/skills/winui-design/winui-search.exe
Binary file not shown.
24 changes: 24 additions & 0 deletions plugins/winui/skills/winui-ui-testing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ if ($missingId.Count -eq 0) {
$results += @{ name = "AutomationId coverage"; status = "FAIL"; detail = "Missing: $names" }
}

# ─── State Screenshots (capture each meaningful state for visual review) ───
New-Item -ItemType Directory -Force -Path "screenshots" | Out-Null
winapp ui screenshot -a $AppPid -o "screenshots/01-initial.png" 2>$null
# ...take more screenshots after key interactions above (mode switches, dialogs opened, etc.)

# ─── Final Screenshot ───
winapp ui screenshot -a $AppPid -o "test-screenshot.png" 2>$null

Expand Down Expand Up @@ -140,6 +145,25 @@ Write tests for **every requirement** from the user's prompt:

Read `test-results.json` for structured pass/fail. Only fix code if tests fail.

### Step 3.5: Look at the Screenshots

UIA assertions don't see clipping, overlap, wrong theming, or controls bleeding past their container — UIA returns `PASS` while the app is visually broken. **Capture screenshots with `winapp ui screenshot` and view each PNG.**

Capture the initial state and any state after a major interaction (the State Screenshots block in the script template above handles this).

**Visual checklist — fail the run if any item is `no`:**
- [ ] No unintended scrollbars
- [ ] No text ending in `…` that shouldn't be
- [ ] Hero elements fully visible (not sliced)
- [ ] Right-edge controls fully visible
- [ ] No overlapping rows
- [ ] Content uses the available width — no asymmetric dead zones (e.g. content pinned to one edge leaving empty space on the other)
- [ ] Spacing intentional — not cramped, not unintentionally vast
- [ ] Theming matches the user's ask (Light/Dark/HighContrast if relevant)
- [ ] Focus/hover/error states render if tested

If the checklist fails, it's a bug — fix before declaring done. Window too small → grow per `winui-design` Step 4.

### Step 4: Fix and Rerun (if the user asked for it)

If tests fail:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
<PackageReference Include="coverlet.collector" Version="10.0.0" />
<PackageReference Include="coverlet.collector" Version="10.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
17 changes: 16 additions & 1 deletion src/tools/winui-search/BM25.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static string[] Tokenize(string text)
{
return NonAlphaRegex().Replace(text.ToLowerInvariant(), " ")
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Where(w => w.Length > 1)
.Where(w => w.Length > 1 && !global::StopWords.Common.Contains(w))
.ToArray();
}

Expand Down Expand Up @@ -77,4 +77,19 @@ public static double Score(Doc doc, string[] queryWords, Corpus corpus)
}
return score;
}

/// <summary>
/// Count how many of the given query tokens appear at least once in the doc.
/// Used by SearchEngine for the coverage gate (rejects results where most
/// query terms are OOV — e.g. "find replace text" matching only "text").
/// </summary>
public static int CountHits(Doc doc, string[] queryTokens)
{
int hits = 0;
foreach (var word in queryTokens)
{
if (doc.Tf.TryGetValue(word, out var tf) && tf > 0) hits++;
}
return hits;
}
}
Loading
Loading