Compare commits

...

232 Commits

Author SHA1 Message Date
Gordon Lam (SH)
a99a86b98b feat(runner): add shared task-runner library for parallel execution and retries 2026-03-02 19:00:16 +08:00
Gordon Lam
70d84fcb88 chore(claude): add symlinks for Claude Code support to GitHub configs (#45204)
## Summary of the Pull Request

Adds Claude Code support by creating symbolic links under `.claude/`
that point to existing GitHub Copilot configuration files in `.github/`.
This enables Claude Code to use the same AI contributor guidance,
agents, prompts, instructions, and skills without duplicating content.

## Detailed Description of the Pull Request / Additional comments

This PR creates a `.claude/` directory with symbolic links mapping
Claude Code's expected paths to existing GitHub Copilot configurations:

| Claude Code Path | → | GitHub Copilot Source |
|------------------|---|----------------------|
| `.claude/CLAUDE.md` | → | `.github/copilot-instructions.md` |
| `.claude/agents/` | → | `.github/agents/` |
| `.claude/commands/` | → | `.github/prompts/` |
| `.claude/rules/` | → | `.github/instructions/` |
| `.claude/skills/` | → | `.github/skills/` |

**Key benefits:**
- Single source of truth — edits to `.github/` files automatically apply
to Claude Code
- Directory symlinks ensure new files (agents, prompts, skills) are
picked up without updating the mapping
- `.gitattributes` updated with `symlink` hint for `.claude/**`

**Windows users cloning this repo need:**
- Developer Mode enabled, OR admin privileges
- `git config --global core.symlinks true` before cloning

## Validation Steps Performed

- [x] Verified symlinks resolve correctly on Windows (`Get-ChildItem
.claude` shows targets)
- [x] Confirmed content is readable through symlinks (`Get-Content
.claude\CLAUDE.md`)
- [x] Verified Git indexes files as symlinks (mode `120000` in `git
ls-files -s`)
- [x] Confirmed symlink targets stored with forward slashes for
cross-platform compatibility
- [x] No automated tests required — changes are config/symlinks only
with no runtime impact
2026-02-04 08:31:40 -08:00
Mario Hewardt
8d9de117b9 Adds a video trim dialog to ZoomIt (#45334)
## Summary of the Pull Request
Adds a video trim dialog to ZoomIt

## PR Checklist
Closes 45333

## Validation Steps Performed
Manual validation

---------

Co-authored-by: Mark Russinovich <markruss@ntdev.microsoft.com>
Co-authored-by: foxmsft <foxmsft@hotmail.com>
2026-02-03 13:05:31 -08:00
Jiří Polášek
42a7213644 CmdPal: Supress warning CsWinRT1028 for DeleteObjectSafeHandle (#45324)
<!-- 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 a local suppression for warning CsWinRT1028: Class should
be marked partial for source generated class `DeleteObjectSafeHandle`.

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

- [x] Related to: #42574
<!-- - [ ] 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-03 12:12:38 -06:00
Kai Tao
27ba536872 UT: Add ut to protect common utils codes (#45290)
<!-- 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
Tests should be picked up and run and pass
2026-02-03 15:12:45 +08:00
moooyo
18efa0559c Introduce new utility PowerDisplay to control your monitor settings (#42642)
<!-- 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
Introduce a new PowerToys' module PowerDisplay to let user can control
their monitor settings without touching monitor's button.

Support feature list:
Common:
1. Profiles support
2. Integration with LightSwitch (auto switch profile when theme change)
3. TrayIcon
4. Save and restore settings when startup
5. Shortcut
6. Rotation
7. GPO support
8. Auto re-discovery monitor when plugging and unplugging monitors.
9. Identify Monitors
10. Quick profile switch

Especially for DDC/CI monitor:
1. Brightness
2. Contrast
3. Volume
4. Color temperature (preset profile)
5. Input source
6. Power State (poweroff)


Design doc:
https://github.com/microsoft/PowerToys/blob/yuleng/display/pr/3/doc/devdocs/modules/powerdisplay/design.md

AOT compatibility:
I designed this module for AOT from the start, so I'm pretty sure at
least 95% of it is AOT compatible. But unfortunately, PowerToys still
have a AOT blocker to block this module publish with AOT.

Currently PowerToys will check the .net file version (file version not
lib version) to avoid crash. So, all modules should reference Common.UI
or add UseWPF to avoid overwrite the .net file with different version
(which may cause crash).

Todo:
- [ ] BugBash
- [ ] Icon
- [ ] IdentifyWindow UI improvement


Demo

Main UI:
<img width="546" height="671" alt="image"
src="https://github.com/user-attachments/assets/b0ad9ac5-8000-4365-a192-ab8c2d66d4f1"
/>

Input Source:
<img width="536" height="674" alt="image"
src="https://github.com/user-attachments/assets/80f9ccd7-4f8c-4201-b177-cc86c5bcc9e3"
/>


Settings UI:
<img width="1581" height="1191" alt="image"
src="https://github.com/user-attachments/assets/6a82e4bb-8f96-4f28-abf9-d7c45e1c8ef7"
/>

<img width="1525" height="1146" alt="image"
src="https://github.com/user-attachments/assets/aae81e65-08fd-453a-bf52-02a74f2fdea0"
/>



Closes: 
#42942
#42678
#41117
#38109
#35564
#34932
#28500
#1052
#18149

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

- [x] Closes: #1052
- [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
- [x] **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: Niels Laute <niels.laute@live.nl>
Co-authored-by: moooyo <lengyuchn@gmail.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 13:53:25 +08:00
Jaylyn Barbee
b3e7c9d227 [Light Switch] Fix Light Switch start up logic (#45304)
<!-- 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
Title

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

- [x] Closes: https://github.com/microsoft/PowerToys/issues/45291
<!-- - [ ] 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

<!-- 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
Before, there was a function that initialized some variables about the
current system state that were later used to check against if that state
needed to change in a different function. That caused from some issues
because I was reusing the function for a double purpose. Now the
`SyncInitialThemeState()` function in the State Manager will sync those
initial variables and apply the correct theme if needed.

I also removed an unnecessary parameter from `onTick`

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manual testing
2026-02-03 09:23:54 +08:00
Jiří Polášek
49cc504d94 CmdPal: Improve fuzzy matcher Unicode and emoji robustness (#45275)
## Summary of the Pull Request

Add comprehensive unit tests for emoji, ZWJ sequences, skin tone
modifiers, and UTF-16 edge cases (unpaired surrogates, combining marks,
random garbage). Update matcher logic to skip normalization of lone
surrogates, preventing errors with malformed Unicode. Expand comparison
test data to cover emoji scenarios. Adds regression guards for diacritic
handling and surrogate processing.

Fixes #45246 introduced in #44809.

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

- [x] Closes: #45246
<!-- - [ ] 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-02 12:30:00 -06:00
Jiří Polášek
18c6d6b0f3 CmdPal: Improve loading of application icons (uwp and jumbo icons) - part 2 (#44973)
<!-- 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 improves icons for app items:
- Refactors icon detection and selection from the AppX manifest out of
`UWPApplication`
- Prefer *unplated* UWP app logos so icons no longer appear smaller than
expected
- Adds an icon loader based on `IShellItemImageFactory` to correctly
load large icons
- Jumbo icons loaded from shortcuts are now crisp
- Jumbo icons loaded from shortcuts are no longer scaled down
- Refactors detail loading in `AppListItem` to prevent potential
deadlocks
- Makes PWA icons more crisp
- Fixes fallback item (now it gets used not only when the icon is null,
but also when it's empty).

<table>

<thead>
<tr>
<th></th>
<th>Old</th>
<th>New</th>
</tr>
</thead>

<tr>
<td>1</td>
<td>
<img width="830" height="495" alt="image"
src="https://github.com/user-attachments/assets/bc9875bd-6a8b-4a3d-88e1-07a655a5a5cd"
/>
</td>
<td>
<img width="750" height="533" alt="image"
src="https://github.com/user-attachments/assets/a82ed464-b925-4d0c-95c4-6c04859e886e"
/>
</td>
</tr>

<tr>
<td>2</td>
<td>
<img width="814" height="233" alt="image"
src="https://github.com/user-attachments/assets/d560d3c0-ffc5-4178-a610-4e3b3c7107c8"
/>
</td>
<td>
<img width="760" height="299" alt="image"
src="https://github.com/user-attachments/assets/f29c825e-324f-46f1-b6bb-6edcf286fc9a"
/>

</td>
</tr>


<tr>
<td>3</td>
<td>
<img width="813" height="262" alt="image"
src="https://github.com/user-attachments/assets/d94f724d-ec26-48c8-bb8a-1b10f6a0f7eb"
/>
</td>
<td>
<img width="762" height="260" alt="image"
src="https://github.com/user-attachments/assets/76c5debb-baac-417e-8aba-9cec198e742c"
/>
</td>
</tr>

<tr>
<td>4</td>
<td>
<img width="819" height="250" alt="image"
src="https://github.com/user-attachments/assets/5f16d714-56d8-42f2-ad8b-1c2be6570e5c"
/>
</td>
<td>
<img width="747" height="244" alt="image"
src="https://github.com/user-attachments/assets/485c72cf-ef39-4c05-afdd-877f0a47f51a"
/>
</td>
</tr>


<tr>
<td>5</td>
<td>
<img width="815" height="327" alt="image"
src="https://github.com/user-attachments/assets/4108e36a-5950-43c9-bdff-6a9f58dadcf6"
/>
</td>
<td>
<img width="762" height="272" alt="image"
src="https://github.com/user-attachments/assets/804a3159-a165-4a48-87f6-15849f5f4516"
/>
</td>
</tr>

<tr>
<td>6</td>
<td>
<img width="809" height="257" alt="image"
src="https://github.com/user-attachments/assets/93ad8241-1d75-415f-b08c-4161c0905e41"
/>
</td>
<td>
<img width="756" height="231" alt="image"
src="https://github.com/user-attachments/assets/a0c9bb44-7151-438d-a811-82d5e2080f44"
/>
</td>
</tr>

<tr>
<td></td>
<td>
</td>
<td>
</td>
</tr>

</table>

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

- [x] Closes: #44970
- [x] Closes: #43320
<!-- - [ ] 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-02 11:53:40 -06:00
Jiří Polášek
4d1f92199c CmdPal: Make Indexer great again - part 1 - hotfix (#44729)
## Summary of the Pull Request

This PR introduces a rough hotfix for several indexer-related issues.

- Premise: patch what we can in-place and fix the core later (reworking
`SeachEngine` and `SearchQuery` is slightly trickier). This patch also
removes some dead code for future refactor.
- Adds search cancellation to the File Search page and the indexer
fallback.
- Prevents older searches from overwriting newer model state and reduces
wasted work.
- Stops reusing the search engine; creates a new instance per search to
avoid synchronization issues.
- That `SeachEngine` and `SearchQuery` are not multi-threading friendly.
- Removes search priming to simplify the code and improve performance.
- Since `SearchQuery` cancels and re-primes on every search, priming
provides little benefit and can hide extra work (for example,
cancellation triggering re-priming).
- Fixes the indexer fallback subject line not updating when there is
more than one match.
  - It previously kept the old value, which was confusing.
- ~Shows the number of matched files in the fallback result.~
- Fetching total number of rows was reverted, performance was not stable
:(
- Optimizes the indexer fallback by reducing the number of items
processed but not used.
- Only fetches the item(s) needed for the fallback itself—no extra work
on the hot path.
- Stops reusing the fallback result when navigating to the File Search
page to show more results. This requires querying again, but it
simplifies the flow and keeps components isolated.
- Fixes the English mnemonic keyword `kind` being hardcoded in the
search page filter. Windows Search uses localized mnemonic keyword
names, so this PR replaces it with canonical keyword `System.Kind` that
is universaly recognized.
- Adds extra diagnostics to `SearchQuery` and makes logging more
precise.
- DataPackage for the IndexerListItem now defers including of storage
items - boost performance and we avoid touching the item until its
needed.
- IndexerPage with a prepopulated query will delay loading until the
items are actually enumerated (to avoid populating from fallback hot
path) and it no longer takes external SearchEngine. It just recreates
everything.

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

- [x] Related to: #44728
- [x] Closes: #44731
- [x] Closes: #44732
- [x] Closes: #44743
<!-- - [ ] 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-02 11:23:34 -06:00
Jiří Polášek
dca532cf4b CmdPal: Icon cache (#44538)
## Summary of the Pull Request

This PR implements actual cache in IconCacheService and adds some fixes
on top for free.

The good
- `IconCacheService` now caches decoded icons
- Ensures that UI thread is not starved by loading icons by limiting
number of threads that can load icons at any given time
- `IconCacheService` decodes bitmaps directly to the required size to
reduce memory usage
- `IconBox` now reacts to theme, DPI scale, and size changes immediately
- Introduced `AdaptiveCache` with time-based decay to improve icon reuse
- Updated `IconCacheProvider` and `IconCacheService` to handle multiple
icon sizes and scale-aware caching
- Added priority-based decoding in `IconCacheService` for more
responsive loading
- Extended `IconPathConverter` to support target icon sizes
- Switched hero images in `ShellPage` to use the jumbo icon cache
- Made `MainWindow` title bar logic resilient to a null `XamlRoot`
- Fixed Tag icon positioning
- Removes custom `TypedEventHandlerExtensions` in favor of
`CommunityToolkit.WinUI.Deferred`.

The bad
- Since IconData lacks a unique identity, when it includes a stream, it
relies on simple reference equality, acknowledging that it might not be
stable. We might cache some obsolete garbage because of this, but it is
fast and better than nothing at all. Yet another task for the future me.

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

- [ ] Closes: 
- [ ] Closes: #38284
- [ ] Related to: #44407
- [ ] Related to: https://github.com/zadjii-msft/PowerToys/issues/333
- [ ] **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-02 11:16:43 -06:00
Jiří Polášek
b5991642f8 CmdPal: Add trailing backslash to OutDir in Microsoft.Terminal.UI project file (#45250)
<!-- 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

Ensures the OutDir path in Microsoft.Terminal.UI.vcxproj ends with a
backslash, making it explicit as a directory, and fixes warning MSB8004.


<!-- 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-02 11:10:36 -06:00
Jaylyn Barbee
84b39a9edc [Light Switch] Changed the rules surrounding the max/min value of the Offset field (#45125)
<!-- 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 logic that dictates the max and min value for the
`Offset` field that the user can change when using Sunrise to Sunset
mode.

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

- [x] Closes: #44959
<!-- - [ ] 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

<!-- 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 new logic is as follows:
- The sunrise offset cannot go into the previous day and cannot overlap
the current sunset transition time
- The sunset offset cannot overlap the last sunrise time and cannot
overlap into the next day.

These values are dynamic and update when the VM updates with new times.
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
- Manual testing
2026-02-02 09:33:25 -05:00
Kai Tao
67d96b0a13 PowerToys extension: Bundle localization files into installer (#45194)
<!-- 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: #45171
<!-- - [ ] 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="925" height="612" alt="image"
src="https://github.com/user-attachments/assets/214ead95-504a-4e48-bc25-138323d973f9"
/>
2026-02-02 11:31:21 +08:00
Kai Tao
c5d4f992c1 Workspace: Fix an overlay issue for workspace snapshot draw (#45183)
<!-- 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
Root cause: Workspaces uses DPI-unaware coordinates (via
GetDpiUnawareScreens()
which runs in a temporary DPI-unaware thread) to store/match window
positions
across different DPI settings. However, WorkspacesEditor itself uses
PerMonitorV2
DPI awareness for UI clarity. When assigning these DPI-unaware
coordinates directly
to WPF window properties, WPF automatically scaled them again based on
current DPI,
causing incorrect overlay positioning.

Fix: Use SetWindowPositionDpiUnaware() to bypass WPF's automatic DPI
scaling
by temporarily switching to DPI-unaware context when calling Win32
SetWindowPos.

Fix #45174

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

- [ ] Closes: #45174
<!-- - [ ] 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 in local build vs production build, and the problem fixed in
local build.
2026-02-02 09:34:50 +08:00
Kai Tao
11b406feee Build: Fix release pipeline and local build failure (#45211)
## Summary of the Pull Request
Release pipeline is keeping failed, and local build failed at ut.

This pull request introduces changes to improve how test projects are
handled during release builds, ensuring that test code is not compiled
or analyzed when not needed - in doing release build, to - succeed the
execution and reduce built time.

And, to upgrade from VS17 to VS18 in cmdpal sdk build, this is to keep
consistency with all other build step


<!-- 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
Local build & release pipeline build should all pass:

Local build:
<img width="1815" height="281" alt="image"
src="https://github.com/user-attachments/assets/f350cf3f-b856-432d-97f3-e392d38ef7fa"
/>

Release pipeline is working too:
<img width="1195" height="163" alt="image"
src="https://github.com/user-attachments/assets/ce58de38-f0fb-45ad-9d70-2b8eb1c4db60"
/>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-02 09:15:53 +08:00
Jiří Polášek
256af8f6e0 Spellcheck: Add missing words and sort expect.txt (#45251)
## PR Checklist

This PR adds missing words to the spell checker dictionary.

- [ ] 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-01 20:14:37 +08:00
Gordon Lam
87c65f9eec docs(paste): add AI preview credit documentation (#45236)
docs(paste): add AI preview credit documentation

```markdown
## Summary of the Pull Request

Adds documentation clarifying that the "Show preview" setting for Paste with AI does not consume additional AI credits. The preview displays the same AI response that was already generated from a single API call, cached locally.

## PR Checklist

- [x] Closes: #32950
- [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 (documentation only)
- [ ] **Localization:** All end-user-facing strings can be localized - N/A (dev docs only)
- [x] **Dev docs:** Added/updated
- [ ] **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

This PR addresses the question raised in issue #32950 about whether enabling preview for Paste with AI costs extra AI quota.

Changes to `doc/devdocs/modules/advancedpaste.md`:
- Added new "Paste with AI Preview" section explaining:
  - The `ShowCustomPreview` setting behavior
  - Confirmation that preview does **not** consume additional AI credits
  - The implementation flow showing a single API call with local caching
  - Reference to `OptionsViewModel.cs` lines 702-717
- Added settings documentation table for `ShowCustomPreview`

Fixes #32950

## Validation Steps Performed

- Verified documentation renders correctly in Markdown preview
- Confirmed technical accuracy by referencing `OptionsViewModel.cs` implementation
```

---------

Co-authored-by: yeelam-gordon <yeelam-gordon@users.noreply.github.com>
2026-01-31 09:03:24 -08:00
Gordon Lam
971c7e9fba docs(settings-ui): update Advanced Paste OOBE description for AI features (#45233)
## Summary of the Pull Request

Updates the Advanced Paste OOBE (Out-of-Box Experience) description to
accurately reflect that AI features no longer require specifically an
OpenAI API key. The new text clarifies:
- Changed "markdown" to "Markdown" and "json" to "JSON" for proper
casing
- Replaced "100% opt-in and requires an Open AI key" with "opt-in AI
feature that can use an online or local language model endpoint"

This fixes the outdated description that still referenced OpenAI as the
only option.

## PR Checklist

- [x] Closes: #44044
- [x] **Communication:** Documentation/string fix, no core contributor
discussion needed
- [ ] **Tests:** N/A - string-only change
- [x] **Localization:** The updated string is in the localizable
Resources.resw file
- [ ] **Dev docs:** N/A
- [ ] **New binaries:** N/A
- [ ] **Documentation updated:** N/A

## Detailed Description of the Pull Request / Additional comments

The change updates
\src/settings-ui/Settings.UI/Strings/en-us/Resources.resw\ to fix the
\Oobe_AdvancedPaste.Description\ string that incorrectly stated AI
features require an OpenAI key.

## Validation Steps Performed

- Verified the string change is valid XML
- Confirmed the updated description accurately reflects current Advanced
Paste AI capabilities
2026-01-31 08:46:31 -08:00
Jaylyn Barbee
055c3011cc Documentation walking through important steps for writing a New PowerToy (#44242)
<!-- 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 new document serves as a handy guide, packed with key details and
helpful tips to keep in mind when creating a new PowerToy.
2026-01-30 14:45:35 +01:00
leileizhang
2f7fc91956 Fix OOBE pages Launch buttons remain clickable when modules are disabled (#44736)
<!-- 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 the issue where Launch/Open buttons on OOBE (Welcome to PowerToys)
pages remain clickable even when the corresponding module is disabled.

Added enabled state checks to the following OOBE pages:
- **OobeColorPicker** - checks `ModuleType.ColorPicker`
- **OobeEnvironmentVariables** - checks
`ModuleType.EnvironmentVariables`
- **OobeHosts** - checks `ModuleType.Hosts`
- **OobeRun** - checks `ModuleType.PowerLauncher`
- **OobeRegistryPreview** - checks `ModuleType.RegistryPreview`
- **OobeShortcutGuide** - checks `ModuleType.ShortcutGuide`

<img width="1538" height="239" alt="image"
src="https://github.com/user-attachments/assets/da20628e-9c82-4619-8a5c-4b75a22b6901"
/>

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

- [x] Closes: #44737
<!-- - [ ] 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-01-30 14:48:09 +08:00
Kai Tao
6d4f56cd83 Always on top: Add transparent support for on topped window (#44815)
<!-- 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
Transparency support (best-effort)
> Not every window can be made transparent. Transparency is applied on a
best-effort basis and depends on how the target app/window is built and
rendered.

## When it may not work
* Windows with special rendering pipelines (e.g., certain
hardware-accelerated / compositor-managed surfaces).
* Some tool/popup/owned windows where the foreground window isn’t the
actual surface being drawn.

## How it works (high-level)
* Resolve the best target window (preferring the top-level/root window
over transient children).
* Apply Windows’ standard layered-window alpha mechanism (per-window
opacity) to adjust transparency.
* When unpinned, Restore the original opacity/state when possible.

If transparency doesn’t change, it means the window doesn’t support this
mechanism in its current configuration.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: 
#43278 
#42929
#28773

<!-- - [ ] 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/c97a87f2-3126-4e19-990f-8c684dbeb631

<img width="1119" height="426" alt="image"
src="https://github.com/user-attachments/assets/547671ee-81d3-4c94-8199-bf0c4b1b7760"
/>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-29 13:48:27 +08:00
Jiří Polášek
4986915dae CmdPal: Batch ViewModel property change notifications (#44545)
<!-- 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 batching for property change notifications emitted by
Command Palette view models. It also adds a secondary notification path
that is guaranteed to execute on a background thread.

- Introduces **`BatchUpdateManager`**, which batches
`INotifyPropertyChanged` events from view models and replays them in a
coordinated way.
- Slightly reduces UI thread contention and allows related UI updates to
be applied together, reducing visual "tearing" in list items (when
title, subtitle and icon are updated separately with slight delay).
Batching won't mitigate all occurences, but its good enough and works
auto-magically.
- Adds a complementary background notification event that:
  - Is guaranteed to run on a background thread.
  - Fires before UI-thread notifications.
- Allows consumers to attach handlers without blocking COM out-of-proc
objects.

- Updates `TopLevelViewModel` to subscribe to the background property
change event instead of the UI-thread one.
- This avoids unintentionally shifting work onto the UI thread and
re-triggering expensive operations there.
- Previously, because `TopLevelViewModel` wraps another view model and
our view models raise `INPC` on the UI thread by default, its handler
was executing on the UI thread and re-raising the event as
`IListItem.PropertyChanged`, causing `FetchProperty` methods to run on
the UI thread again.
- Ideally, `TopLevelViewModel` should be reworked to address this more
cleanly, but that turned out to be a non-trivial change. This PR applies
a targeted mitigation in the meantime.








<!-- 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-01-28 21:56:11 -06:00
Jiří Polášek
cc2dce8816 CmdPal: replace custom fuzzy matching in Window Walker (#44807)
## Summary of the Pull Request

This PR replaces the custom search controller and fuzzy matching with
standard classes from the Extension SDK Toolkit.

<!-- 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-01-28 21:23:50 -06:00
Jiří Polášek
0de2af77ac CmdPal: Make Calculator Great Again (#44594)
## Summary of the Pull Request

This PR continues the tradition of alphabetical progress. After
[MBGA](#41961), we move on to **MCBA — Make Calculator Better Again!**

- Introduces limited automatic correction and completion of expressions.
- The goal is to allow uninterrupted typing and avoid disruptions when a
partially entered expression is temporarily invalid (which previously
caused the result to be replaced by an error message or hidden by the
fallback).
  - The implementation intentionally aims for a sweet spot:
    - Ignores trailing binary operators.
    - Automatically closes all opened parentheses.
- It is not exhaustive; for example, incomplete constants or functions
may still result in an invalid query.
- Copy current result to the search bar.
- Adds an option to copy the current result to the search bar when the
user types `=` at the end of the expression.
  - Adds a new menu item for the same action.
  - Fixes the **Save** command to also copy the result to the query.
- Adds support for the `factorial(x)` function and the `x!` expression.
- Factorial calculations are supported up to `170!` (limited by
`double`), but display is constrained by decimal conversion and allows
direct display of results up to `20!`.
- Adds support for the `sign(x)` function.
- Adds support for the `π` symbol as an alternative to the `pi`
constant.
- Adds a context menu item to the result list item and fallback that
displays the octal representation of the result.
- Implements beautification of the query:
- Converts technical symbols such as `*` or `/` to `×` or `÷`,
respectively.
- Not enabled for fallbacks for now, since the item text should match
the query to keep the score intact.
- Implements additional normalization of symbols in the query:
  - Percent: `%`, `%`, `﹪`
  - Minus: `−`, `-`, `–`, `—`
  - Factorial: `!`, `!`
- Multiplication: `*`, `×`, `∗`, `·`, `⋅`, `✕`, `✖`, `\u2062` (invisible
times)
  - Division: `/`, `÷`, ``, `:`
- Allows use of `²` and `³` as alternatives to `^2` and `^3`.
- Updates the unit test that was culture sensitive to force en-US output
(not an actual fix, but at least it clears false positive for now)
- Fixes pre-parsing of scientific notation to prevent capturing minus
sign as part of it.
- Fixes normalization/rounding of the result, so it can display small
values (the current solution turned it into a string with scientific
notation and couldn't parse it back).
- Updates test with new cases

## Pictures? Moving!

Previous behavior:


https://github.com/user-attachments/assets/ebcdcd85-797a-44f9-a8b1-a0f2f33c6b42

New behavior:


https://github.com/user-attachments/assets/5bd94663-a0d0-4d7d-8032-1030e79926c3





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

- [x] Closes: #43481
- [x] Closes: #43460
- [x] Closes: #42078
- [x] Closes: #41839
- [x] Closes: #39659
- [x] Closes: #40502
- [x] Related to: #41715
<!-- - [ ] 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
- [ ] **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-01-28 21:23:39 -06:00
Jiří Polášek
4694e99477 CmdPal: Upgrade FuzzyStringMatcher in the Command Palette Extensions SDK (#44809)
## Summary of the Pull Request

This PR upgrades the `FuzzyStringMatcher` used in the Command Palette
Extensions SDK with a focus on performance, memory efficiency, and
improved matching behavior, while preserving compatibility with the
existing API. This PR is a backwards compatible alternative to
precomputed fuzzy matcher introduces in another PR.

The new implementation is designed as a drop-in replacement. Any
behavioral differences are intentional and primarily related to improved
diacritic handling, scoring consistency, and correctness of highlight
positions.

Changes:
- Keeps the existing public API intact and preserves behavior in nearly
all cases.
- Enables diacritics-insensitive matching by default, improving results
across accented and non-English languages.
- Significantly improves performance, with measured speedups in the
range of ~5–20 times, depending on scenario and input size.
- Reduces heap allocations to near zero by using stack allocation and
pooled buffers instead of large per-match DP arrays.
- Simplifies and optimizes matching logic:
  - Folds the haystack only once per match.
  - Uses rolling DP buffers instead of `O(query × target)` tables.
- Replaces large match tables with a compact bitset when tracking
highlight positions.
- Improves consistency and correctness:
  - Normalizes path separators (`\` → `/`) during folding.
- Avoids returning highlight positions for PinYin-only matches where no
1:1 mapping exists.
- Introduces unit tests, including comparison tests against the legacy
implementation to validate compatibility.

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

- [x] Closes: #44066
<!-- - [ ] 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-01-28 21:23:12 -06:00
Jiří Polášek
64cabc8789 CmdPal: Fix window centering when moving to a display with different DPI (#45057)
## Summary of the Pull Request

This PR fixes centering of main window, when the window also moves
between move display with a different DPI.

- The centered position was calculated using the current window width
and height, but those values change after the window is moved to
accommodate the new display’s DPI.
- Calculations have been refactored out of main window to a helper
class.

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

- [x] Closes: #44932
<!-- - [ ] 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-01-28 21:21:11 -06:00
Jiří Polášek
989e005500 CmdPal: Run shutdown and restart commands in a hidden window (#45062)
<!-- 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: #40621 
<!-- - [ ] 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-01-28 21:20:52 -06:00
Jiří Polášek
5f124cec55 CmdPal: Cache and show information for disabled command providers (#44278)
## Summary of the Pull Request

This PR adds a cache of command provider information so we can show
providers even when the command provider isn’t loaded.

It also updates the description for disabled extensions on the
Extensions page to always include the extension name.

Finally, it adds a placeholder icon for cases where an extension icon
isn’t loaded. Note that this doesn’t address fully transparent icons
that some extensions may inherit from the default template.

Before:

<img width="1883" height="167" alt="image"
src="https://github.com/user-attachments/assets/7ccaa669-9516-4b57-9646-4e755d29d75c"
/>


After:

<img width="1873" height="190" alt="image"
src="https://github.com/user-attachments/assets/f29549c2-ddd5-4688-ba9c-d1abd4b523a0"
/>


<!-- 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-01-28 21:19:25 -06:00
Jiří Polášek
8ec530c65e CmdPal: GEH per partes; part 1: error report builder, sanitizer and internals tools setting page (#44140)
<!-- 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 three parts of the original big bad global error handler
(error report builder, sanitization and internal tools UI).

### Error Report Generation

- `ErrorReportBuilder`: Produces a detailed, technical report with
system context.
- Comprehensive data: OS version, architecture, culture, app version,
elevation status, etc.
- Exception analysis: Coalesces nested exception messages and HRESULT
details for clearer diagnostics.

<details><summary>Example</summary>
<pre>

This is an error report generated by Windows Command Palette.
If you are seeing this, it means something went a little sideways in the
app.
You can help us fix it by filing a report at
https://aka.ms/powerToysReportBug.

(While you’re at it, give the details below a quick skim — just to make
sure there’s nothing personal you’d prefer not to share. It’s rare, but
sometimes little surprises sneak in.)
============================================================
Summary:
  Message:               Test exception; thrown from the UI thread
  Type:                  System.NotImplementedException
  Source:                Microsoft.CmdPal.UI
  Time:                  2025-08-25 18:54:44.3854569
  HRESULT:               0x80004001 (-2147467263)
  Context:               MainThreadException

Application:
  App version:           0.0.1.0
  Is elevated:           no

Environment:
  OS version:            Microsoft Windows 10.0.26120
  OS architecture:       X64
  Runtime identifier:    win-x64
  Framework:             .NET 9.0.8
  Process architecture:  X64
  Culture:               cs-CZ
  UI culture:            en-US

Stack Trace:
at
Microsoft.CmdPal.UI.Settings.InternalPage.ThrowPlainMainThreadException_Click(Object
sender, RoutedEventArgs e)
at
WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object
sender, RoutedEventArgs e)
at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr
thisPtr, IntPtr sender, IntPtr e)

------------------ Full Exception Details ------------------
System.NotImplementedException: Test exception; thrown from the UI
thread
at
Microsoft.CmdPal.UI.Settings.InternalPage.ThrowPlainMainThreadException_Click(Object
sender, RoutedEventArgs e)
at
WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object
sender, RoutedEventArgs e)
at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr
thisPtr, IntPtr sender, IntPtr e)

============================================================

</pre>
</details> 

Real-world example: #41362

### PII Sanitization Framework

- `ErrorReportSanitizer`: Multi-layer sanitization pipeline for
sensitive data.
- Nine specialized rule providers:
- `PiiRuleProvider`: Personally identifiable information (emails, phone
numbers, SSNs).
- `ProfilePathAndUsernameRuleProvider`: Windows user profiles and
usernames.
- `NetworkRuleProvider`: IP addresses, MAC addresses, network
identifiers.
- `SecretKeyValueRulesProvider`: API keys, tokens, passwords in
key/value formats.
  - `FilenameMaskRuleProvider`: Sensitive file paths and extensions.
  - `UrlRuleProvider`: URLs and web addresses.
  - `TokenRuleProvider`: JWT and other auth tokens.
  - `ConnectionStringRuleProvider`: Database connection strings.
- `EnvironmentPropertiesRuleProvider`: Environment variables and system
properties.

### Internals Tools Page

A page in settings available in non-CI-builds:

<img width="1305" height="745" alt="image"
src="https://github.com/user-attachments/assets/3145ecfd-997f-491d-8c8a-6096634b6045"
/>


<!-- 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-01-28 21:09:37 -06:00
Jeremy Sinclair
f82afdf384 [Dev][Build] VS 2026 Support (#44304)
<!-- 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 the PowerToys solution to support **Visual Studio 2026
(PlatformToolset v145)**. It centralizes the build configuration,
updates the C++ language standards, and fixes an issue with a MouseJump
unit test that appears while using the VS 2026 supported build agent.

<!-- Please review the items on the PR checklist before submitting-->
## 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
- [x] **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

**Build System & Configuration:**
- Updated `Cpp.Build.props` to use `v145` (VS 2026) as the default
`PlatformToolset`, with fall back to `v143` for VS 2022.
- Configured C++ Language Standard:
  - `stdcpplatest` for production projects.
- Removed explicit `<PlatformToolset>` definitions from individual
project files (approx. 37 modules) to inherit correctly from the central
`Cpp.Build.props`.

**Code Refactoring & Fixes:**
- Updated `DrawingHelperTests.cs` in MouseJump Unit Test to ease the
pixel difference tolerance. This became an issue after switching to the
new VS2026 build agent.
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

- Validated successful compilation of the entire solution. Similar
updates have been made to the .NET 10 branch, but these are much cleaner
and will be merged into that branch once fully confirmed working.

---------

Co-authored-by: Kai Tao (from Dev Box) <kaitao@microsoft.com>
Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
2026-01-28 15:46:34 -08:00
Kai Tao
aa2ba0c325 0.97.1 change log (#45112)
<!-- 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

97.1 change log

<!-- 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-01-28 15:04:00 +08:00
Kai Tao
f534e5b8e5 [ZoomIt] Show users full hotkey list in settings (#43073)
<!-- 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 enhances the ZoomIt settings UI by refactoring some of the XAML
code and putting instructions as part of the settingsexpanders.
Additionally, the alternate hotkey combinations are now shown too and
will be updated based on the configured hotkey.
so that **Users will now be able to see all the hotkeys**.

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

- [x] Closes: #42236
- [ ] **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

### ZoomIt Extended (Derived) Hotkeys

Feature | Base Key Property | Default Base Key | Derived Key Property |
XOR Logic | Default Derived Key | Description
-- | -- | -- | -- | -- | -- | --
LiveZoom | LiveZoomToggleKey | Ctrl+4 | LiveZoomToggleKeyDraw | XOR
Shift | Ctrl+Shift+4 | Enter drawing mode in LiveZoom
Record | RecordToggleKey | Ctrl+5 | RecordToggleKeyCrop | XOR Shift |
Ctrl+Shift+5 | Record selected region (crop)
Record | RecordToggleKey | Ctrl+5 | RecordToggleKeyWindow | XOR Alt |
Ctrl+Alt+5 | Record specific window
Snip | SnipToggleKey | Ctrl+6 | SnipToggleKeySave | XOR Shift |
Ctrl+Shift+6 | Snip and save to file
DemoType | DemoTypeToggleKey | Ctrl+7 | DemoTypeToggleKeyReset | XOR
Shift | Ctrl+Shift+7 | Rewind to previous segment


<img width="832" height="3679" alt="Frame 2018778631"
src="https://github.com/user-attachments/assets/bebddcd8-d705-4582-ae8a-c847cb1c3e88"
/>

---------

Signed-off-by: check-spelling-bot <check-spelling-bot@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Kai Tao <vanzue@users.noreply.github.com>
2026-01-28 10:37:22 +08:00
Jiří Polášek
08715a6e46 CmdPal: Allow list item context menu (#45086)
## Summary of the Pull Request

This PR enables pointer-invoked context menus for list items when the
list contains at least one item, including the primary item.

The command bar "More" button or Ctrl+K hotkey remain unaffected - the
menu is not accessible through those.

<img width="453" height="210" alt="image"
src="https://github.com/user-attachments/assets/af0f38e3-e1e7-4968-9e2d-6d9293785ab1"
/>


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

- [x] Closes: #45083
<!-- - [ ] 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-01-27 13:52:12 -06:00
Mike Hall
d26d9f745a CursorWrap improvements (#44936)
## Summary of the Pull Request
- Updated engine for better multi-monitor support.
- Closing the laptop lid will now update the monitor topology
- New settings/dropdown to support wrapping on horizontal, vertical, or
both

<img width="1103" height="643" alt="image"
src="https://github.com/user-attachments/assets/ff4f0835-a8ca-4603-9441-123b71747d5c"
/>

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

- [x] Closes: #44820
- [x] Closes: #44864
- [x] Closes: #44952

- [ ] **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
Feedback for CursorWrap shows that users want the ability to constrain
wrapping for horizontal only, vertical only, or both (default behavior).
This PR adds a new dropdown to CursorWrap settings to enable a user to
select the appropriate wrapping model.

## Validation Steps Performed
Local build and running on Surface Laptop 7 Pro - will also validate on
a multi-monitor setup.

---------

Co-authored-by: vanzue <vanzue@outlook.com>
2026-01-27 13:27:11 +08:00
Gordon Lam
6661adbd5c chore(prompts): add fix active PR comments prompt with scoped changes (#44996)
## Summary of the Pull Request
Enhance the active PR comments prompt to allow for scoped changes while
removing outdated model references from various prompt files.

## 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
- [ ] **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 changes include the addition of a new prompt for fixing active PR
comments with scoped changes, ensuring that only simple fixes are
applied. Additionally, references to the model 'GPT-5.1-Codex-Max' have
been removed from several prompt files to streamline the prompts.

## Validation Steps Performed
Manual validation of the new prompt functionality was conducted to
ensure it correctly identifies and resolves active PR comments.
```
2026-01-26 20:34:11 -08:00
Heiko
5ecb97b4e0 [Enterprise; Policy] Add policy for CursorWrap to ADMX (#45028)
<!-- 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 missing policy definition.

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

- [x] Closes: #44897
<!-- - [ ] 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
- [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)
- [x] **Documentation updated:** See PR for issue #44484 

<!-- 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-01-27 11:24:02 +08:00
Jiří Polášek
13ce5db6b1 CmdPal: Add solution filter for Microsoft.CmdPal.Ext.PowerToys (#45096)
## Summary of the Pull Request

This PR adds a new solution filter (.slnf) for the
Microsoft.CmdPal.Ext.PowerToys extension project and its dependencies.

This is added as a separate solution filter alongside
CommandPalette.slnf, since the extension is not directly dependent on
Command Palette. Instead, it relies on the public SDK distributed via
NuGet. It also depends on other PowerToys projects, which would
unnecessarily clutter CommandPalette.slnf.

<!-- 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-01-26 21:14:05 -06:00
Jiří Polášek
f0831742d6 CmdPal: Remove deadlock bait from AppListItem (#45076)
## Summary of the Pull Request

This PR removes a Task.Wait() call from lazy-loading AppListItem details
that could be invoked on the UI thread and lead to a deadlock.

It now follows the same pattern previously used for loading icons in the
same class, which has proven to work well.

Prevents #44938 from stepping on this landmine.

Cherry-picked from #44973.

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

- [x] Closes: #45074 
<!-- - [ ] 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-01-27 09:51:16 +08:00
Shawn Yuan
ea43974287 [Settings] [Advanced Paste] Upgrade advanced paste settings safely to fix settings ui crash (#44862)
<!-- 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 makes a minor fix in the `AdvancedPasteViewModel`
constructor to ensure the correct settings repository is used for null
checking. The change improves code correctness by verifying
`advancedPasteSettingsRepository` instead of the generic
`settingsRepository`.

- Fixed null check to use `advancedPasteSettingsRepository` instead of
`settingsRepository` in the `AdvancedPasteViewModel` constructor for
more accurate validation.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44835
<!-- - [ ] 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-01-26 15:28:59 +08:00
Gordon Lam
0b3dc089ac [Peek] Fix Space key triggering during file rename (#44845) (#44995)
Don't show error window when CurrentItem is null - just return silently.
This restores the original behavior where CaretVisible() detection in
GetSelectedItems() would suppress Peek by returning null, and no window
would be shown.

PR #44703 added an error window for virtual folders (Home/Recent), but
this also triggered when user was typing (rename, search, address bar),
stealing focus and cancelling the operation.

Fixes #44845

<!-- 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
2026-01-26 15:20:07 +08:00
Shawn Yuan
4ba6fd2723 Add telemetry for tray icon (#44985)
<!-- 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 telemetry tracking for user interactions with the
application's tray icon. Specifically, it introduces new methods for
logging `left-click`, `right-click`, and `double-click` events, and
integrates these telemetry calls into the tray icon event handling
logic.

<!-- 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-01-26 09:44:10 +08:00
Shawn Yuan
086c63b6af [Settings] Fix right click menu display issue (#44982)
<!-- 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 the tray icon context menu logic to better
reflect the state of the "Quick Access" feature. The menu now
dynamically updates its items and labels based on whether Quick Access
is enabled or disabled, improving clarity for users.

**Menu behavior improvements:**

* The tray icon menu now reloads itself when the Quick Access setting
changes, ensuring the menu always matches the current state.
* The "Settings" menu item label changes to "Settings\tLeft-click" when
Quick Access is disabled, providing clearer instructions to users.
[[1]](diffhunk://#diff-e5efbda4c356e159a6ca82a425db84438ab4014d1d90377b98a2eb6d9632d32dR176-R179)
[[2]](diffhunk://#diff-7139ecb2cf76e472c574a155268c19e919e2cce05d9d345c50c1f1bffc939e1aR198-R248)
* The Quick Access menu item is removed from the context menu when the
feature is disabled, preventing confusion.

**Internal state tracking:**

* Added a new variable `last_quick_access_state` to track the previous
Quick Access state and trigger menu reloads only when necessary.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44810
<!-- - [ ] 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
- When Quick Access is disabled

<img width="1537" height="312" alt="image"
src="https://github.com/user-attachments/assets/5d51f24e-ccb4-4973-afaa-8b64cc35db87"
/>

- When Quick Access is enabled
<img width="1601" height="201" alt="image"
src="https://github.com/user-attachments/assets/56366d10-bcec-4892-b2d2-f8213ad726aa"
/>

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-23 14:47:35 +08:00
moooyo
d192672c74 fix: Improve Unicode normalization and add regex metachar tests (#44944)
Enhanced SanitizeAndNormalize to handle Unicode normalization more
robustly, ensuring correct buffer sizing and error handling. Added unit
tests for regex metacharacters `$` and `^` to verify correct replacement
behavior at string boundaries. Improves Unicode support and test
coverage for regex edge cases.

<!-- 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: #44942 #44892
<!-- - [ ] 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-01-23 14:43:21 +08:00
Kai Tao
60b8419366 Runner TrayIcon: Monochrome icon should adapt to windows theme instead of the app theme (#44931)
<!-- 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

- [X] Closes: #44891
<!-- - [ ] 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
============ System light + App Light
<img width="903" height="239" alt="image"
src="https://github.com/user-attachments/assets/581606fb-99b5-4df9-a520-545a0c04676c"
/>
============ System Light + App Dark
<img width="991" height="239" alt="image"
src="https://github.com/user-attachments/assets/822009e9-57cf-452b-b3aa-f1cbc25883f8"
/>
============ System Dark + App Light
<img width="932" height="236" alt="image"
src="https://github.com/user-attachments/assets/98a56d48-31f0-4f75-95a4-8c7dc83c3866"
/>
============ System Dark + App Dark
<img width="903" height="236" alt="image"
src="https://github.com/user-attachments/assets/2500a0d5-6b27-403e-89b4-69b7d3b91e79"
/>
============
2026-01-23 10:47:19 +08:00
Kai Tao
d46a996fcd Cmdpal: use latest msix to install (#44886)
<!-- 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 should install latest cmdpal msix
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #44860
<!-- - [ ] 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-01-23 09:58:53 +08:00
Jiří Polášek
395850389f CmdPal: Improve loading of application icons - part 1 (#44938)
## Summary of the Pull Request

This PR improves loading of application icons:

- Fixes loading of icons from internet shortcuts

## Pictures? Pictures!

<img width="683" height="399" alt="image"
src="https://github.com/user-attachments/assets/5e566648-7b1a-4254-8afd-557a321b19d6"
/>


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

- [x] Closes: #44819
<!-- - [ ] 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-01-22 19:25:24 +01:00
Jessica Dene Earley-Cha
fbabdffcfa Update DATA_AND_PRIVACY to reflect current status (#44844)
<!-- 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
Updates the telemetry events documentation in `DATA_AND_PRIVACY.md` to
ensure completeness and improve organization.
- Added missing & new events
- Removed obsolete events (deprecated or unused event)
- Alphabetized all modules for easier navigation and maintenance
- Made all tables uniform with `table-layout:fixed`



<!-- 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-01-21 11:07:12 -08:00
Mike Hall
7cfa4d443c add script parameters to add user, machine, and devices names, default is to not include. (#44880)
## Summary of the Pull Request
Update the screen capture/layout powershell script to NOT include user
name, machine name, and device names - these can be added into the
output JSON file using new command line parameters - also added '-help'.

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

- [ ] 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
Ran the script locally with each of the new command line parameters and
validated the json output.
2026-01-21 12:58:00 +00:00
Gordon Lam
5422bc31bb docs(prompts): Enhance release notes generation and implement GitHub issue tools (#44762)
<!-- 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 update improves the release notes generation process by
restructuring documentation for clarity and enhancing workflows. It
introduces new tools for handling GitHub issue images and attachments,
along with automated tests to ensure functionality.

<!-- 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
- [x] **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)
- [x] **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
The changes include updates to the release notes summarization process
and workflow documentation for better clarity. New scripts for managing
PR diffs, grouping, and milestone assignments have been added.
Additionally, tools for downloading images and attachments from GitHub
issues have been implemented, ensuring a more streamlined process.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Automated tests were added for the new GitHub issue tools, and all tests
passed successfully. Manual validation included testing the new
workflows and ensuring the documentation accurately reflects the changes
made.
```
2026-01-21 16:18:57 +08:00
Den Delimarsky
27dcd1e5bc Awake and DevEx improvements (#44795)
This PR contains a set of bug fixes and general improvements to
[Awake](https://awake.den.dev/) and developer experience tooling for
building the module.

### Awake Fixes

- **#32544** - Fixed an issue where Awake settings became non-functional
after the PC wakes from sleep. Added `WM_POWERBROADCAST` handling to
detect system resume events (`PBT_APMRESUMEAUTOMATIC`,
`PBT_APMRESUMESUSPEND`) and re-apply `SetThreadExecutionState` to
restore the awake state.

- **#36150** - Fixed an issue where Awake would not prevent sleep when
AC power is connected. Added `PBT_APMPOWERSTATUSCHANGE` handling to
re-apply `SetThreadExecutionState` when the power source changes
(AC/battery transitions).

- **#41674** - Fixed silent failure when `SetThreadExecutionState`
fails. The monitor thread now handles the return value, logs an error,
and reverts to passive mode with updated tray icon.

- **#41738** - Fixed `--display-on` CLI flag default from `true` to
`false` to align with documentation and PowerToys settings behavior.
This is a breaking change for scripts relying on the undocumented
default.

- **#41918** - Fixed `WM_COMMAND` message processing flaw in
`TrayHelper.WndProc` that incorrectly compared enum values against enum
count. Added proper bounds checking for custom tray time entries.

- **#44134** - Documented that `ES_DISPLAY_REQUIRED` (used when "Keep
display on" is enabled) blocks Task Scheduler idle detection, preventing
scheduled maintenance tasks like SSD TRIM. Workaround: disable "Keep
display on" or manually run `Optimize-Volume -DriveLetter C -ReTrim`.

- **#38770** - Fixed tray icon failing to appear after Windows updates.
Increased retry attempts and delays for icon Add operations (10
attempts, up to ~15.5 seconds total) while keeping existing fast retry
behavior for Update/Delete operations.

- **#40501** - Fixed tray icon not disappearing when Awake is disabled.
The `SetShellIcon` function was incorrectly requiring an icon for Delete
operations, causing the `NIM_DELETE` message to never be sent.

- Fixed an issue where toggling "Keep screen on" during an active timed
session would disrupt the countdown timer. The display setting now
updates directly without restarting the timer, preserving the exact
remaining time.

### Performance Optimizations

- Fixed O(n²) loop in `TrayHelper.CreateAwakeTimeSubMenu` by replacing
`ElementAt(i)` with `foreach` iteration.

- Fixed Observable subscription leak in `Manager.cs` by storing
`IDisposable` and disposing in `CancelExistingThread()`. Also removed
dead `_tokenSource` code that was no longer used.

- Reduced allocations in `SingleThreadSynchronizationContext` by
changing `Tuple<>` to `ValueTuple`.

- Replaced dedicated exit event thread with
`ThreadPool.RegisterWaitForSingleObject()` to reduce resource usage.

### Code Quality

- Replaced `Console.WriteLine` with `Logger.LogError` in `TrayHelper.cs`
for consistent logging.

- Added proper error logging to silent exception catches in
`AwakeService.cs`.

- Removed dead `Math.Min(minutes, int.MaxValue)` code where `minutes` is
already an `int`.

- Extracted hardcoded tray icon ID to named constant `TrayIconId`.

- Standardized null coalescing for `GetSettings<AwakeSettings>()` calls
across all files.

### Debugging Experience Fixes

- Fixed first-chance exceptions in `settings_window.cpp` during
debugging. Added `HasKey()` check before accessing `hotkey_changed`
property to prevent `hresult_error` exceptions when the property doesn't
exist in module settings.

- Fixed first-chance exceptions in FindMyMouse `parse_settings` during
debugging. Refactored to extract the properties object once and added
`HasKey()` checks before all `GetNamedObject()` calls. This prevents
`winrt::hresult_error` exceptions when optional settings keys (like
legacy `overlay_opacity`) don't exist, improving the debugging
experience by eliminating spurious exception breaks.

- Fixed LightSwitch.UITests build failures when building from a clean
state. Added missing project references (`ManagedCommon`,
`LightSwitchModuleInterface`) with `ReferenceOutputAssembly=false` to
ensure proper build ordering, and added existence check for the native
DLL copy operation.

### Developer Experience

- Added `setup-dev-environment.ps1` script to automate development
environment setup.
- Added `clean-artifacts.ps1` script to resolve build errors from
corrupted build state or missing image files.
- Added build script that allows standalone command line build of the
Awake module.
- Added troubleshooting section to
`doc/devdocs/development/debugging.md` with guidance on resolving common
build errors.
2026-01-20 21:27:45 -08:00
leileizhang
2a0d0a1210 [CI] Remove tests folder before code signing to reduce signing workload (#44800)
<!-- 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
Remove the tests folder before ESRP code signing step to significantly
reduce the number of files being signed.

## Problem
The current code signing process signs **8,148 files**, with
approximately **5,000+ files** coming from the `tests/` directory. These
test files (primarily localized `.resources.dll` files from test
frameworks) do not need to be signed since they are not included in the
final release package.

The excessive file count causes:
- HTTP 429 (Too Many Requests) throttling from ESRP Gateway
- Signing operations getting stuck in "Inprogress" status
- Pipeline timeouts after ~57 minutes
<img width="1173" height="59" alt="image"
src="https://github.com/user-attachments/assets/ab077293-7efd-4ffe-a788-cbb6e72df3a1"
/>
<img width="1527" height="140" alt="image"
src="https://github.com/user-attachments/assets/7828474e-8bcc-471b-acbe-c898cf70bc34"
/>
<img width="1487" height="357" alt="image"
src="https://github.com/user-attachments/assets/2239d178-6e71-4349-a114-7e5216cbd8cf"
/>

Fix: 
Reduce signing time by 10+ minutes
From
<img width="480" height="58" alt="image"
src="https://github.com/user-attachments/assets/fb40e768-5700-4c00-af6b-6b7d9bf40360"
/>

to
<img width="480" height="63" alt="image"
src="https://github.com/user-attachments/assets/b7ab02fb-3616-4c7e-8e83-7d3afcbd1df3"
/>


<!-- 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-01-21 13:18:51 +08:00
Kai Tao
662bbf0033 Dev: give back the context window to dev's choice (#44817)
<!-- 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'd rather myself to configure my llm's context window, so this script
is used to clear some instruction temporarily.

<!-- 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
Before :
<img width="498" height="156" alt="image"
src="https://github.com/user-attachments/assets/3a9f9827-8fde-4744-946e-f7c7db0eae05"
/>

After:
After : 
<img width="500" height="445" alt="image"
src="https://github.com/user-attachments/assets/38363e18-32fc-4690-99d6-6d0fdfeddaef"
/>
2026-01-21 13:17:57 +08:00
leileizhang
b7a94eb48d Update README to note PowerToys extension requires Windows 11 (#44863)
<!-- 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
Updates the README.md to clarify that the PowerToys extension feature in
Command Palette requires Windows 11.

<!-- 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
2026-01-21 11:25:04 +08:00
Michael Jolley
b5e9f346da [CmdPal] Fix details pane not hiding when item initialization fails (#44757)
Fixes #44487

## Summary
Fixed issue where the details pane would display stale information when
navigating from an item with details to an item without details or where
details failed to load.

## Changes
1. **ListViewModel.cs**: Added HideDetailsMessage when SafeSlowInit()
fails to ensure previous details are cleared
2. **InstallPackageListItem.cs**: Added exception handling for WinRT
marshaling errors when accessing metadata.Documentations and
metadata.Tags collections

The fix ensures graceful degradation - if certain metadata collections
fail to load due to WinRT issues, the details pane still displays
available information rather than failing completely.
2026-01-20 19:16:43 -06:00
leileizhang
8e2123cfea Draft Release Notes for 0.97 (#44760)
<!-- 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
Draft Release Notes for 0.97

<!-- 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-01-20 19:19:27 +08:00
Ruben Fricke
a9205781d7 [CmdPal] Remove invalid return statement from SDK spec example (#44781)
<!-- 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 syntax errors in the IFallbackHandler code example in the
Command Palette SDK spec documentation.


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

- [ ] Closes: #39352 
<!-- - [ ] 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
- [x] **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 SpongebotPage example in initial-sdk-spec.md had two problems:

  Before:
```cs
  public void IFallbackHandler.UpdateQuery(string query) {
      // ...
      return Task.CompletedTask.AsAsyncCommand();
  }
```

  After:
```cs
  public void UpdateQuery(string query) {
      // ...
  }
```

 The fix aligns the example with actual implementations in the codebase.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-19 18:13:43 -06:00
Kai Tao
086e4b5676 Doc: Add missed entry for telemetry (#44806)
<!-- 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-01-19 17:21:24 +01:00
moooyo
089c5f8b50 refactor(imageresizer): disable AI feature and cache functionality (#44759)
<!-- 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 <yuleng@microsoft.com>
2026-01-19 10:50:05 +08:00
Niels Laute
113639a66c Upgrade MarkdownTextBlock (#44793)
<!-- 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:

- upgrades `CommunityToolkit.WinUI.Labs.MarkdownTextBlock` to version
`0.1.260116-build.2514`. This update includes a bunch of improvements
for markdown rendering in its default config, and fixes a couple of bug
with regards to rendering large images getting clipped when resizing the
window.
- replaces an incorrect image in the `Command Palette Sample Page`
extension for the markdown + images sample.

Before vs after:

<img width="910" height="234" alt="image"
src="https://github.com/user-attachments/assets/b3dad76c-a89e-4b47-90f8-d3c64f00615f"
/>


<img width="1245" height="827" alt="image"
src="https://github.com/user-attachments/assets/00037fb5-453e-4d85-83c9-92c265b9f968"
/>



<!-- 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-01-19 08:54:31 +08:00
leileizhang
3c2cb4516a [ImageResizer] Temporarily disable AI Super Resolution feature (#44768)
<!-- 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
Temporarily disables the AI Super Resolution feature in Image Resizer
while keeping all code intact for re-enabling in a future release.

<!-- 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-01-17 11:22:21 +08:00
Gleb Khmyznikov
53c5e66cce [UI Tests][Light Switch] Fix tests: LS, Hosts, Worspaces, Mouse (#44754)
This pull request refactors the LightSwitch module to introduce a new
shared static library, `LightSwitchLib`, which centralizes theme
management logic and enables code sharing between the service and module
interface. The changes move theme-related code from the service and
module interface into this new library, update project references, and
clean up now-redundant files and includes.

**LightSwitchLib introduction and code deduplication:**

- Added a new static library project, `LightSwitchLib`, containing all
theme management logic (`SetSystemTheme`, `SetAppsTheme`,
`GetCurrentSystemTheme`, `GetCurrentAppsTheme`, `IsNightLightEnabled`)
and related files (`ThemeHelper.cpp`, `ThemeHelper.h`, `pch.h`,
`pch.cpp`). This code was previously duplicated in both the service and
module interface.
(`src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj`
[[1]](diffhunk://#diff-c38e95060ad294c9ed5c2bb769616bb52032a4330af7e268ad63d81a99dc1cadR1-R123)
`LightSwitchLib.vcxproj.filters`
[[2]](diffhunk://#diff-fcfc49f1628c274cd9a40aca385e03a1937f9e42958298f36155ad16a267ba9aR1-R33)
`ThemeHelper.cpp`
[[3]](diffhunk://#diff-f5ab83c022406172501172ee88e21294c7aba2a87fb30334d7c4d4fc9d736a56L1-R3)
`ThemeHelper.h`
[[4]](diffhunk://#diff-6609a7fc7abc61d4d0029f0fb605a9f4732511642af6e12851e86c234108169aR1-R10)
`pch.h`
[[5]](diffhunk://#diff-57e4d6ddad1d356a24555bce4d6cbb0d6a93386515254abf95573324454c94c2R1-R5)
`pch.cpp`
[[6]](diffhunk://#diff-87fbf215a559e7833ec06ff32aa7f8109fdf86d92b360fe44302fc16f1784d52R1)

- Updated the solution file and relevant project files to add and
reference `LightSwitchLib` from both `LightSwitchService` and
`LightSwitchModuleInterface`, ensuring both components use the shared
implementation. (`PowerToys.slnx`
[[1]](diffhunk://#diff-40c552fef4118125c3ccd6b156db518acec74b11150b193b31f18a2cc17a531eR668)
`LightSwitchService.vcxproj`
[[2]](diffhunk://#diff-51f54bd015aa96b38ddf4e96134ea542fac4b648566a23c2c86fe91a2b5a6bdaR58)
[[3]](diffhunk://#diff-51f54bd015aa96b38ddf4e96134ea542fac4b648566a23c2c86fe91a2b5a6bdaR113-R115)
`LightSwitchModuleInterface.vcxproj`
[[4]](diffhunk://#diff-72e859ee44b3f0087018e55708e850fb5040c5b8f72449d1cac30e8efb28e2c2R205-R207)
[[5]](diffhunk://#diff-72e859ee44b3f0087018e55708e850fb5040c5b8f72449d1cac30e8efb28e2c2L169-R179)

**Cleanup and removal of redundant code:**

- Removed old theme management code and headers from
`LightSwitchService` and `LightSwitchModuleInterface` now that logic
resides in `LightSwitchLib`. (`ThemeHelper.cpp`
[[1]](diffhunk://#diff-3e2766504c1cf989390508c613b2177cd5de14fb9de46df3b416f95f955338bfL1-L106)
`ThemeHelper.h`
[[2]](diffhunk://#diff-0e8540cace398ec3eebca416ca38d81262b689eca76a004584e686a605b7a242L1-L5)
`LightSwitchService.vcxproj`
[[3]](diffhunk://#diff-51f54bd015aa96b38ddf4e96134ea542fac4b648566a23c2c86fe91a2b5a6bdaL81)
[[4]](diffhunk://#diff-51f54bd015aa96b38ddf4e96134ea542fac4b648566a23c2c86fe91a2b5a6bdaL96)
`LightSwitchModuleInterface.vcxproj`
[[5]](diffhunk://#diff-72e859ee44b3f0087018e55708e850fb5040c5b8f72449d1cac30e8efb28e2c2L190)

- Removed duplicated registry path constants from `SettingsConstants.h`,
as they are now defined in the shared header. (`SettingsConstants.h`
[src/modules/LightSwitch/LightSwitchService/SettingsConstants.hL15-L17](diffhunk://#diff-e74db005ffb8b881a08c4dae1c1ead9dc732928a69cafb4c9e0bae8b86d4e24aL15-L17))

**Module interface improvements:**

- Added `ExportedFunctions.cpp` to the module interface, exposing theme
management functions as exports and using the shared library
implementation. (`ExportedFunctions.cpp`
[[1]](diffhunk://#diff-48acf3b77a8b6ac6fd1129afe1a677b34447ce39454e86ea04f1a1181a23b546R1-R22)
`LightSwitchModuleInterface.vcxproj`
[[2]](diffhunk://#diff-72e859ee44b3f0087018e55708e850fb5040c5b8f72449d1cac30e8efb28e2c2L169-R179)

**Minor test and logging adjustments:**

- Fixed a UI test to use the correct toggle name for the Hosts File
Editor. (`HostsSettingTests.cs`
[src/modules/Hosts/Hosts.UITests/HostsSettingTests.csL116-R116](diffhunk://#diff-3782109c99cd66a2c1b870a83d1f9d9807422479c89e03799b311ef5f13a2098L116-R116))
- Updated a log message to refer to `LightSwitchLib` instead of
`LightSwitchService` for clarity. (`ThemeHelper.cpp`
[src/modules/LightSwitch/LightSwitchLib/ThemeHelper.cppL66-R63](diffhunk://#diff-f5ab83c022406172501172ee88e21294c7aba2a87fb30334d7c4d4fc9d736a56L66-R63))
2026-01-16 13:58:51 -08:00
moooyo
4cde968c9b chore(imageresizer): fix log folder path formatting in App.xaml.cs (#44761)
<!-- 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 <yuleng@microsoft.com>
2026-01-16 17:10:41 +08:00
Kai Tao
e148a89288 Powertoys Extension: Trigger latest layout/monitor refresh for fancyzone in cmdpal extension (#44756)
<!-- 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
Best effort trigger refresh for the monitor/layout refresh for
fancyzones, user may experience error for first time run but will get
correct result in next visit.

This bring better experience than the always-stale-state, while still
remain performant command.

<!-- 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
Validated locally that second time visit will bring correct monitor when
plug/unplug monitor
2026-01-16 10:40:32 +08:00
Niels Laute
1dddf9fa2c "What's new" improvements (#44638)
<!-- 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 DO: Upgrade to the latest version of MarkdownTextBlock:
https://github.com/CommunityToolkit/Labs-Windows/pull/771

This PR introduces the following changes:
**Removed the custom titlebars on the OOBE Window, and replaced it with
the inbox WinUI `TitleBar` control.**

**New "What's new" experience following the VS Code release notes
experience**
- Created a new SCOOBE Windows that is a standalone window to better
visualize release notes.
- Adding a nav menu on the left to easily switch between release notes,
instead of a long page.
- Point releases are combined with the latest main release.. e.g. 0.96.1
is rendered above 0.96.0.
- The 'hero image' on main release notes will automatically be rendered
at the top of the page.
- Improved markdown styling for better readability.
- Pull requests links can now be clicked.
- Upgraded `CommunityToolkit.Labs.MarkdownTextblock` to the latest
version as it includes much needed bugfixes.

<img width="1234" height="819" alt="image"
src="https://github.com/user-attachments/assets/447b3136-306b-4f24-bc7a-c022a99e8e51"
/>

Note: the blurry image shown above will be replaced in new releases by
an image that fits the right dimensions.

<!-- 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: Leilei Zhang <leilzh@microsoft.com>
2026-01-15 16:37:08 +08:00
Tokenicrat 词元
0d59b9f790 Chore: Fix broken links in README.md (#44658)
The repository README.md has several formatting issues in [Installation
section](https://github.com/microsoft/PowerToys#-installation),
resulting in invalid link references. It's mainly because Markdown
references won't be rendered in HTML blocks.

This trivial PR just fixes that, nothing fancy. Have a nice day!

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-01-15 09:21:12 +01:00
Shawn Yuan
e314485e85 Improve module enable/disable IPC and sorting reliability (#44734)
<!-- 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

- Refactored the runner logic for handling individual module
enable/disable updates. Instead of receiving the entire settings.json
via IPC, it now processes only single-module state updates, which avoids
race conditions and fixes a bug where modules could end up being
skipped.
- Fixed an issue where the sort order option could be deselected — it is
now enforced as a mutually exclusive choice.
- Fixed a potential race condition when updating the AppList control’s
sorting.


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

- [x] Closes: #44697
<!-- - [ ] 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

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-15 15:29:46 +08:00
moooyo
f48c4a9a6f fix(common): correct minor version check for Windows 10 detection (#44716)
<!-- 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 <yuleng@microsoft.com>
2026-01-14 15:56:44 +08:00
moooyo
175403d86d fix: Improve tray icon theming and installer icon handling (#44715)
Add "svgs" directory and icon files to installer, ensuring proper
install/uninstall and registry registration. Enhance logging in
general_settings.cpp for theme-adaptive tray icon config changes.
Refactor tray_icon.cpp to improve icon loading robustness, add detailed
diagnostics, and ensure fallback to default icon if theme-adaptive icon
fails to load. These changes improve error handling and maintainability
for tray icon theming.

<!-- 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 <yuleng@microsoft.com>
2026-01-14 14:03:32 +08:00
moooyo
f7c57b05d7 fix(cmdpal): update copyright year in resources and test assertions (#44714)
<!-- 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 <yuleng@microsoft.com>
2026-01-14 11:29:15 +08:00
Michael Jolley
5098809e14 Devaluing fallback ranks in global sort (#44691)
Fixes #44630

Devaluing fallback ranks by 50% so direct matches are ranked higher.

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2026-01-14 09:52:38 +08:00
Jiří Polášek
c8da70d6fa CmdPal: Replace assembly metadata attributes with preprocessor directives (#44707)
## Summary of the Pull Request

This PR replaces custom metadata attributes used to pass build-time
information with preprocessor directives. It appears that metadata can
be stripped from the final build output, even though it survived AOT in
earlier tests on the main and stable branches.

New preprocesor directives in Microsoft.CmdPal.UI:
- `BUILD_INFO_PUBLISH_AOT` - when `PublishAot` MSBuild parameter is
`true`
- `BUILD_INFO_PUBLISH_TRIMMED `- when `PublishTrimmed` MSBuild parameter
is `true`
- `BUILD_INFO_CIBUILD `- when `CIBuild` MSBuild parameter is `true`

Using preprocessor directives avoids this uncertainty and provides a
more reliable solution.

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

- [x] Closes: #44641
<!-- - [ ] 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-01-14 09:49:51 +08:00
leileizhang
22ce3b81ec Revert "Add Drag and Drop For Environment Variables (#40105)" (#44705)
This reverts commit 1b6b446915.

<!-- 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
Reverting this PR because WinUI 3 doesn’t support drag operations when
running as admin.

<!-- 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-01-13 18:52:30 +08:00
leileizhang
74448355f9 Peek: Show error message when activated in unsupported virtual folders (#44703)
<!-- 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 Peek is activated in virtual folders like Home or Recent, it now
displays a clear error message instead of showing a stuck loading state
or "Search in Microsoft Store" link.

### Problem
When users activate Peek (press the hotkey) in Windows virtual folders
such as Home or Recent, the Shell API (SVGIO_SELECTION) returns 0 items
because these folders don't support the standard file selection
retrieval mechanism. Previously, this caused:

- The Peek window to appear stuck in a loading state
- The "Search in Microsoft Store" fallback UI to display incorrectly
- Subsequent Peek activations to fail until the window was manually
closed
<img width="2550" height="1310" alt="image"
src="https://github.com/user-attachments/assets/fd657e46-97f8-4042-bf43-971055f74700"
/>

### Solution

- Added a check in `Initialize()` to detect when no files are found
after querying the Shell
- Display an error InfoBar with a user-friendly message: "No files
selected or this folder is not supported for preview."
- Hide the `FilePreview` control when the error is shown to prevent
displaying irrelevant fallback UI
- Close the window automatically when the user dismisses the InfoBar
(clicks X)

<img width="1790" height="1193" alt="image"
src="https://github.com/user-attachments/assets/4a5c9bfa-1996-487a-86d3-5458431b14cb"
/>

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

- [x] Closes: #44576
<!-- - [ ] 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-01-13 18:04:28 +08:00
Kai Tao
031e365f57 2 fixes in 97 (#44704)
<!-- 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. Should stop new executable when uninstall
2. Fix a workspaces editor deserialization issue


<!-- 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
It's a regression introduced when implementing the cmdpal workspaces
extension
Before fix:
<img width="235" height="135" alt="image"
src="https://github.com/user-attachments/assets/74bbf3ba-72cb-4a43-bba6-8eb96423f045"
/>

After fix:
<img width="341" height="294" alt="image"
src="https://github.com/user-attachments/assets/ce2236b8-c762-4bbf-85af-6a83a3987492"
/>
2026-01-13 17:18:48 +08:00
Shawn Yuan
569b4eed62 Fixed Quick Access sorting does not update after module status updated. (#44699)
<!-- 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 a small but important improvement to the
user experience in the `AllAppsViewModel`. Now, when a module's enabled
status is changed in the UI, the flyout menu items are immediately
re-sorted to reflect the new state.

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

- [x] Closes: #44634 
<!-- - [ ] 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-01-13 16:29:06 +08:00
leileizhang
b68b84532c Fix ESRP Code Signing Node 16 EOL is blocking app signing (#44695)
<!-- 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’re hitting an issue where ESRP Code Signing (EsrpCodeSigning@5) is
now blocking our app from being signed.
The pipeline reports a Node 16 EOL dependency, and at this point the app
can no longer be signed successfully.

Fix Upgrade the version to 6 

<!-- 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-01-13 12:36:23 +08:00
leileizhang
8b79da5d49 Fix Image Resizer doesn’t work when using the UI. (#44687)
<!-- 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. Update the CLI Log Folder
2. Fixes an `ArgumentOutOfRangeException` that occurs in ImageResizer
when the `CustomSize` or `AiSize` properties change.
<img width="1494" height="530" alt="image"
src="https://github.com/user-attachments/assets/3d8dbe8c-4d21-46bc-9c10-f6d26161787f"
/>

Changed the collection changed notification from `Replace` to `Reset`
for both `CustomSize` and `AiSize` property changes. While `Reset` is
less efficient (it forces a full UI refresh rather than updating a
single item), it avoids the index validation issue since it doesn't
require specifying an index.

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

- [x] Closes: #44686
<!-- - [ ] 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-01-13 12:36:14 +08:00
Gordon Lam
ab28777514 build(packages): pin SixLabors.ImageSharp version to restore functionality and up-to-date patches (#44694)
## Summary of the Pull Request
Pin the `SixLabors.ImageSharp` package version to `2.1.12` to restore
functionality and apply necessary patches.

## 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
Pinning the `SixLabors.ImageSharp` version addresses compatibility
issues with the `CoenM.ImageSharp.ImageHash` package.

## Validation Steps Performed
Manual validation confirmed that functionality is restored with the
pinned version.
```
2026-01-13 11:02:20 +08:00
Kai Tao
febaec0741 Add icon for powertoys extension and quickaccess exe (#44674)
<!-- 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, inject powertoys icon to these two exe

<!-- 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
Add two self contained icon to the two process:
<img width="678" height="382" alt="image"
src="https://github.com/user-attachments/assets/f682ab93-75ed-4292-ba3a-78b65795d3cc"
/>
2026-01-13 10:55:08 +08:00
leileizhang
c88fe1fa0e [FancyZonesCLI] Fix PowerShell GUID parsing and add subcommand help (#44676)
<!-- 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 improves FancyZones CLI usability with three enhancements:

1. **PowerShell GUID compatibility**: Users can now pass GUIDs without
braces (e.g., `0CEBCBA9-9C32-4395-B93E-DC77485AD6D0`), avoiding
PowerShell's script block interpretation issue
2. **Subcommand help**: Added `--help` support for individual commands
(e.g., `FancyZonesCLI set-layout --help`)
3. **Friendly error messages**: When PowerShell incorrectly interprets
`{GUID}` as a script block, displays a helpful message instead of
cryptic errors

<img width="1313" height="476" alt="image"
src="https://github.com/user-attachments/assets/65eb403a-05ec-412b-852d-b20386792b34"
/>
<img width="1311" height="598" alt="image"
src="https://github.com/user-attachments/assets/a07a304e-a353-43c5-9e88-84840ffd86f2"
/>

<img width="1309" height="380" alt="image"
src="https://github.com/user-attachments/assets/3c1a071d-325d-486a-bfa7-f4b974523400"
/>

- [x] Closes: #44633 #44675
<!-- - [ ] 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-01-12 16:40:22 +08:00
Kai Tao
fd88fa18d4 Fancyzones: Fix a custom layout not work in fancyzone and powertoys extension (#44661)
<!-- 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 a issue that fancyzone custom layouts be able to work
2. Fix monitor info build and the icon render

<!-- 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="1172" height="701" alt="image"
src="https://github.com/user-attachments/assets/0cfa71d9-8ce2-4d27-8995-c797f40f927f"
/>
2026-01-12 09:23:40 +08:00
Jaylyn Barbee
a6b8cea7cd GPO configured correctly and tested (#44567)
Ensure that Light Switch respects GPO configuration. 
In "Not configured" --> No message, everything is under the user's
control
In "Enabled" --> Module is forced enabled, policy message shows, able to
change settings
In "Disabled" --> Module is forced disabled, policy message shows,
unable to change settings
2026-01-09 10:29:17 -05:00
Jaylyn Barbee
5f61057b38 Adding a quick access button for Light Switch (#44640)
Adds a button for Light Switch in the Quick Access section of the
Dashboard page. Clicking the button will toggle the theme.
<img width="1886" height="1173" alt="image"
src="https://github.com/user-attachments/assets/7923e1ac-aeea-47ab-b648-2400cb6f3ca4"
/>
2026-01-09 10:28:54 -05:00
Shawn Yuan
0314a709f5 Optimize the module list logic (#44628)
<!-- 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 how module enable/disable state changes are
handled in the settings UI, centralizing and simplifying the logic for
updating and notifying these changes. The main improvements include
unifying the callback mechanism for enable state changes, reducing code
duplication, and making the update process more robust against circular
updates.

**Refactoring and Simplification of Enable State Handling:**

* Introduced a unified `EnabledChangedCallback` and `UpdateStatus`
method in the base `ModuleListItem` class to handle enable/disable state
changes and notifications, replacing redundant logic in derived classes
like `FlyoutMenuItem` and `DashboardListItem`.
[[1]](diffhunk://#diff-23ab2cc13a1098a6071b3e12ce0919b7eba451d7683f6f62e5ec2cf661778a4cR21-R36)
[[2]](diffhunk://#diff-23ab2cc13a1098a6071b3e12ce0919b7eba451d7683f6f62e5ec2cf661778a4cR99-R103)
[[3]](diffhunk://#diff-5033dabc0e3ec7d01509b9d58878b9ee5745378d5e3a7fa92779bf9c111bcffcL25-L39)
[[4]](diffhunk://#diff-9c93f68ee87a48d8affd140224601da95d7fe9642ad24350c7527d0f5773ec7dL29-L43)
* Updated all usages to call `UpdateStatus` instead of directly setting
`IsEnabled`, ensuring callbacks are managed consistently and preventing
unnecessary notifications during programmatic updates.
[[1]](diffhunk://#diff-734ba1b4b3044eb540bba08334bd141c968a113625be2d92c831f3cc3debc62fL108-R109)
[[2]](diffhunk://#diff-aea3404667e7a3de2750bf9ab7ee8ff5e717892caa68ee1de86713cf8e21b44cL261-R260)

**Improvements to Callback and Update Logic:**

* Changed the signature of UI event handlers to use the base
`ModuleListItem` type, improving code maintainability and reducing
casting and duplication.
[[1]](diffhunk://#diff-734ba1b4b3044eb540bba08334bd141c968a113625be2d92c831f3cc3debc62fL160-R161)
[[2]](diffhunk://#diff-aea3404667e7a3de2750bf9ab7ee8ff5e717892caa68ee1de86713cf8e21b44cL278-R287)
* Removed obsolete or redundant flags and logic for tracking update
state, further simplifying the codebase.
[[1]](diffhunk://#diff-aea3404667e7a3de2750bf9ab7ee8ff5e717892caa68ee1de86713cf8e21b44cL53)
[[2]](diffhunk://#diff-aea3404667e7a3de2750bf9ab7ee8ff5e717892caa68ee1de86713cf8e21b44cL328)
[[3]](diffhunk://#diff-aea3404667e7a3de2750bf9ab7ee8ff5e717892caa68ee1de86713cf8e21b44cL343-L346)

**Project and Namespace Adjustments:**

* Updated the project file to include all localized resource files
recursively, improving localization support.
* Added a missing namespace import to ensure proper type resolution.
* Added a missing `using System;` directive for the `Action` delegate.
<!-- 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-01-09 13:06:50 +08:00
Gordon Lam
a246789719 docs(prompts): sync commit/pr guidance and Copilot settings (#44627)
## Summary of the Pull Request
- Clarified the PR-summary prompt to prepend a PR title and to reuse the
Conventional Commit rules from
`.github/prompts/create-commit-title.prompt.md`.
- Expanded the commit-title prompt with clearer purpose, inputs, and
Conventional Commit guidance.
- Added workspace Copilot chat settings in `.vscode/settings.json` to
point review/commit/PR generation at the repo prompt files.

e.g. for commit tile generation:
<img width="562" height="376" alt="image"
src="https://github.com/user-attachments/assets/ca11d117-e4ad-4d1e-abb7-2b4600690f45"
/>


## PR Checklist
- [ ] Closes: N/A
- [ ] Communication: N/A (prompt/settings maintenance)
- [ ] Tests: Not run (prompt/settings-only change)

## Detailed Description of the Pull Request / Additional comments
- The PR-summary workflow now directs PR title generation to the
existing commit-title prompt instead of duplicating rules, and places
the title above the filled template.
- The commit-title prompt now spells out required diff command, decision
steps, and Conventional Commit examples.
- VS Code Copilot chat settings ensure review, commit, and PR
description generation use the repository prompts consistently.

## Validation Steps Performed
- Not run (no product code changes)
2026-01-09 11:38:05 +08:00
Shawn Yuan
af401dd6e9 Fix quickaccess localization issue (#44626)
<!-- 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 the resource file inclusion pattern in the
`PowerToys.QuickAccess.csproj` project file to support localization for
multiple languages.

Localization improvements:

* Changed the `PRIResource` include path to recursively include all
`Resources.resw` files from subdirectories, enabling support for
multiple language resource files instead of just `en-us`.
<!-- 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
- [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
2026-01-09 10:27:30 +08:00
MemphiZ
6c2a99dfd6 Fix FancyZones editor overlay on mixed-DPI multi-monitor setups (#44440)
## Summary of the Pull Request

Use DPI-unaware context when positioning overlay windows to match the
coordinate space from the C++ backend.

The FancyZones editor overlay windows were incorrectly positioned on
secondary monitors when using different DPI scaling (e.g.,
125%/150%/125%). Zones appeared shifted or clipped because they extended
past monitor edges.

## PR Checklist

- [x] Closes: #43363
- [x] Closes: #43386
- [ ] **Communication:** I've discussed this with core contributors
already.
- [ ] **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

## Detailed Description of the Pull Request / Additional comments

### Root Cause
The C++ backend uses a DPI-unaware thread to get virtual screen
coordinates, but the WPF editor (PerMonitorV2 DPI-aware) interpreted
these coordinates with DPI scaling applied, causing misalignment on
non-primary monitors.

### Fix
- **EditorParameters.cpp**: Use consistent virtual coordinates for all
monitor properties (removed `DPIAware::Convert` that was only applied to
dimensions)
- **Monitor.cs**: Reposition overlay windows using DPI-unaware context
after HWND creation, matching the coordinate space from C++ backend
- **NativeMethods.cs**: Added `SetWindowPositionDpiUnaware()` using
`SetThreadDpiAwarenessContext` to temporarily switch DPI awareness

## Validation Steps Performed

Manually tested on 3-monitor setup with 125%/150%/125% DPI scaling -
overlays now correctly cover each monitor's work area.

---

🤖 *This fix was developed with [Claude Code](https://claude.ai/code)
after 6 hours of debugging DPI coordinate systems together.*

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
2026-01-09 09:57:58 +08:00
Mike Griese
7cf32bf204 cmdpal: bump to 0.8 (#44622)
title
2026-01-09 09:55:27 +08:00
Jiří Polášek
ae9ba62a40 CmdPal: Remove subtitle from all built-in top level commands (#44621)
## Summary of the Pull Request

This PR removes subtitles from all built-in top-level commands, except
for fallbacks, apps, and bookmarks.

<img width="885" height="987" alt="image"
src="https://github.com/user-attachments/assets/4da7377d-2c86-4658-a96b-33a881333639"
/>

<!-- 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-01-09 09:42:06 +08:00
Jiří Polášek
d48338bad3 CmdPal: Improve readability and a11y of sections (#44556)
## Summary of the Pull Request

This PR improves visuals and a11y of sections:
- Changes section title color from disabled to secondary text fill.
- Removes separator line if the text is present and indents
- Changes gallery grid subtitle color from tertiary to secondary text
fill.

## Pictures? Pictures!

<img width="850" height="718" alt="image"
src="https://github.com/user-attachments/assets/2e0bffa2-045f-48d9-bff5-dcc561395c6a"
/>

<img width="850" height="773" alt="image"
src="https://github.com/user-attachments/assets/69081472-7f4b-489a-b0e5-5778894fef97"
/>

<img width="850" height="773" alt="image"
src="https://github.com/user-attachments/assets/aa3f0e73-def8-45cb-9f9a-6e9d7e0e6137"
/>

<img width="850" height="773" alt="image"
src="https://github.com/user-attachments/assets/cb8f6bdf-9288-4b6e-b8b8-94f8c83e3ffc"
/>



<!-- 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-01-08 21:23:38 +01:00
Jiří Polášek
fd19168883 CmdPal: Update separator visuals in item details (#44620)
## Summary of the Pull Request

This PR updates separator in the details pane.

- If separator has a label
  - removes the line
  - makes top margin bigger
- keeps it based on BodyStrongTextBlockStyle to provide visual hierarchy
and anchor

- If separator has no label
  - makes line height only 1px 

<img width="399" height="810" alt="image"
src="https://github.com/user-attachments/assets/0ff0eb24-16f3-45a8-b23e-289809dc611d"
/>

<img width="403" height="802" alt="image"
src="https://github.com/user-attachments/assets/4171c954-9cd0-4622-8a95-8acd34ebe4c9"
/>


<!-- 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-01-08 21:22:58 +01:00
Jiří Polášek
db9f8d555e CmdPal: Get version when running as unpacked app (#44540)
## Summary of the Pull Request

This PR updates how the Settings / General page retrieves version
information for unpackaged apps.
It prevents a crash by reading the version from the process executable,
with a fallback to displaying a question mark when the version cannot be
determined.

<!-- 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-01-08 10:46:32 -06:00
Jiří Polášek
be90b587da CmdPal: Update Extension SDK classes to raise property change notifications only on change (#44547)
## Summary of the Pull Request

This PR introduces a new method  
`bool SetProperty<T>(ref T field, T value, [CallerMemberName] string?
propertyName = null)`
on `BaseObservable`.

The method updates the backing field only when the new value differs
from the current one and raises property change notifications only in
that case.

#### Summary

- Adds `SetProperty<T>` to `BaseObservable` to guard property change
notifications behind an actual value change.
- SDK API is not affected.
- Prevents unnecessary notifications from leaving the extension
boundary.
- Reduces redundant updates and saves a few round-trips between COM
objects and view models.
- Improves overall efficiency without changing observable behavior for
consumers.

<!-- 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-01-08 10:42:12 -06:00
Jiří Polášek
a2cd47f36c CmdPal: Hide selection indicator (pill) from items in the context menu (#44563)
## Summary of the Pull Request

This PR removes the selection indicator from the list view used for the
context menu to maintain consistency with Fluent UI design guidelines.

## Pictures? Pictures!

Before:
<img width="338" height="287" alt="image"
src="https://github.com/user-attachments/assets/6b7cba0f-b127-4a6e-a7ee-985865f446c6"
/>


After:
<img width="366" height="372" alt="image"
src="https://github.com/user-attachments/assets/a91b9a88-19e7-47c0-a777-8722757cd874"
/>


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

- [x] Closes: #44611
<!-- - [ ] 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-01-08 14:29:57 +01:00
Jiří Polášek
3167145d42 CmdPal: make spacing in gallery view uniform (#44542)
<!-- 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 ensures the spacing between items in the gallery view is
consistent both vertically and horizontally.

<img width="823" height="599" alt="image"
src="https://github.com/user-attachments/assets/0a2349fa-9c88-4606-82b3-94c21ad37871"
/>


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

- [x] Closes: #44612
<!-- - [ ] 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-01-08 14:29:40 +01:00
Gordon Lam
0899961e56 Docs: consolidate instructions and fix prompt frontmatter (#44610)
Title: Docs: consolidate Copilot instructions and prompt metadata

## Summary
- Consolidated AI guidance into a root AGENTS.md and new
`.github/instructions` files, removing older per-folder instructions.
- Scoped instruction files for pipelines, common libraries,
runner/settings UI, prompts, and simplified
`.github/copilot-instructions.md` to point to the sources of truth.
- Fixed prompt frontmatter (YAML markers, quoted fields, headings)
across built-in prompt files.
- Most instructions.md is from https://github.com/github/awesome-copilot

## Testing
- Not run (documentation/instructions-only change)
2026-01-08 20:04:33 +08:00
Shawn Yuan
8a7503e7dc fix sign issue (#44609)
<!-- 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 updates to the build pipeline and resource
configuration, primarily to support new modules and improve versioning
information for the File Locksmith CLI.

**Pipeline configuration updates:**

* Added new WinUI3 application binaries (`PowerToys.QuickAccess.dll`,
`PowerToys.QuickAccess.exe`, and `PowerToys.Settings.UI.Controls.dll`)
to the ESRP signing pipeline, ensuring these modules are properly signed
during the build process.

**Resource and versioning improvements:**

* Updated the resource file for `FileLocksmithCLI` to include version
information and metadata (such as company name, file description, and
product version) by referencing the shared version header. This improves
traceability and consistency of version details in the executable.
<!-- 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-01-08 18:45:46 +08:00
Mike Hall
4704e3edb8 [CursorWrap] Update coordinate mapping (#43542)
## Summary of the Pull Request
Update coordinate mapping across monitors

---

### Testing instructions

#### Single monitor
- Enable CursorWrap - the cursor should wrap around the top/bottom and
left/right edges of the display.

- Single monitor - Add a second monitor:

- If you have a USB monitor, add the monitor to your PC, CursorWrap
should detect the new monitor and wrapping should occur from the edges
of the monitor depending on monitor layout - for example, if the monitor
is added to the left of the main display then the cursor should move
freely between the left edge of the main monitor to the right edge of
the added monitor - the cursor should wrap from the left edge of the
added monitor to the right edge of the main monitor (same for top/bottom
if the new monitor is added above/below the main monitor).

#### Multi monitor
- If you have a static multi-monitor layout cursor should wrap for outer
edges of the monitor setup, for example, if you have three monitors in a
layout of [1][0][2] then the cursor should wrap from the right edge of
[2] to the left edge of [1], top/bottom should wrap on each monitor.

#### Issues
- If you detect any issues then run the Capture-MonitorLayout.ps1 file,
this will generate a JSON file with your monitor layout, attach the file
to a new comment.

---

<!-- 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

## Validation Steps Performed
validated on three monitor setup and laptop with an external monitor

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-08 17:48:10 +08:00
Kai Tao
4aec8f9d0e Telemetry: Add two traces to understand how auto udpate work (#44602)
<!-- 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

<img width="1189" height="405" alt="image"
src="https://github.com/user-attachments/assets/2835ae5f-99b9-4156-a75f-b63a485ddd61"
/>
2026-01-08 15:57:49 +08:00
Gordon Lam
961a65f470 Update VSCode task for streamline build + fix prompts syntax error (#44605)
<!-- 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 several improvements and updates across the
repository, focusing on build tooling, prompt configuration for AI
agents, and documentation clarity. The most significant changes include
the addition of new VSCode build tasks, updates to prompt files to use a
newer AI model, enhancements to the build script for flexibility, and
refinements to documentation and style rules.

### Enabled scenario
* On any active files in VSCode, do "Ctrl + Shift + B" just build
correctly for you.
* The Run Task (no matter from Terminal or Ctrl + Shift + P), we can see
the build option:
<img width="1210" height="253" alt="image"
src="https://github.com/user-attachments/assets/09fbef16-55ce-42d5-a9ec-74111be83472"
/>

**Build tooling and automation:**

* Added a new `.vscode/tasks.json` file with configurable build tasks
for PowerToys, supporting quick and customizable builds with platform
and configuration selection.
* Enhanced `tools/build/build.ps1` to support an optional `-Path`
parameter for building projects in a specified directory, updated
parameter documentation, and improved logic to resolve the working
directory.
[[1]](diffhunk://#diff-7a444242b2a6d9c642341bd2ef45f51ba5698ad7827e5136e85eb483863967a7R14-R16)
[[2]](diffhunk://#diff-7a444242b2a6d9c642341bd2ef45f51ba5698ad7827e5136e85eb483863967a7R27-R30)
[[3]](diffhunk://#diff-7a444242b2a6d9c642341bd2ef45f51ba5698ad7827e5136e85eb483863967a7R51)
[[4]](diffhunk://#diff-7a444242b2a6d9c642341bd2ef45f51ba5698ad7827e5136e85eb483863967a7L81-R93)


**AI agent prompt configuration:**

* Updated all prompt files in `.github/prompts/` to use the
`GPT-5.1-Codex-Max` model instead of older models, and standardized the
agent field format.
[[1]](diffhunk://#diff-7a5c9b18594ff83fda2c191fd5a401ca01b74451e8949dc09e14eabee15de165L1-R2)
[[2]](diffhunk://#diff-f48674f7557a6c623bb48120c41b4546b20b32f741cc13d82076b0f4b2375d98L1-R2)
[[3]](diffhunk://#diff-a6831d9c98a26487c89c39532ec54d26f8987a8bdc88c5becb9368e9d7e589b9L1-R2)
[[4]](diffhunk://#diff-60e145ef3296b0cb4bec35363cc8afbfe0b6b7bd0c7785fe16a11d98e38c6f29L1-R2)
[[5]](diffhunk://#diff-6a7664740d6984e73a33254333a302a7e258c638a17134921c53967b4965a304L1-R3)
[[6]](diffhunk://#diff-7b246ee6421c503c22d7994406b822ede18d7d0c791b7667a55fcd50524fb0b0L1-R2)
* Improved clarity and consistency in the description and instructions
within the `review-issue.prompt.md` file.

**Documentation and style rules:**

* Updated `.github/copilot-instructions.md` to clarify that C++ and C#
style analyzers and formatters are now enforced from the `src/`
directory, not the repo root, and made the C++ formatting rule more
precise.

## PR Checklist
- [N/A] Closes: #xxx
- [N/A] **Tests:** Added/updated and all pass

## Validation Steps Performed
- Not run (config/docs/build-script changes only).
2026-01-08 15:41:51 +08:00
leileizhang
876130c3cd Fix Peek allowing Local File Inclusion (LFI) and RCE (#44601)
<!-- 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 #44456, we disabled scripts and HTML, but we still want to allow
HTML rendering.

This pull request introduces significant security improvements and UI
enhancements to the file previewer, focusing on safe rendering of files
and better user communication when opening external links. The main
changes include strict resource filtering to prevent external content
loading (and potential XSS attacks), a more informative dialog when
opening external URIs, and improved logic for determining how different
file types are previewed.

**Security enhancements:**

* Added strict resource filtering for non-dev file previews in
`BrowserControl` to block external HTTP/S requests and limit local file
access to the same directory and subdirectories, preventing XSS and
unwanted external content loading.
* Set the `WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS` environment variable
to block new web contents for extra security.
* Removed disabling of HTML rendering in the Markdown pipeline to allow
safe local rendering (now protected by resource filtering).

**File preview logic improvements:**

* Refactored previewer logic to prioritize file type handling: Markdown,
SVG, HTML/HTM, Monaco-supported source code, and fallback types,
ensuring correct preview strategy and context menu behavior for each
type.
* Resource filtering is dynamically applied or removed based on whether
the file is a dev/source code file (Monaco editor) or not, ensuring
compatibility and security.

**User interface enhancements:**

* Updated the open URI dialog to include a warning banner and improved
messaging, informing users about the risks of opening external links.

<img width="1174" height="336" alt="image"
src="https://github.com/user-attachments/assets/db6b2a11-c972-473a-a1bc-a24f3244f18f"
/>

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

- [x] Closes: #44600
<!-- - [ ] 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

use this file for testing

[test-xss-vulnerability.md](https://github.com/user-attachments/files/24486900/test-xss-vulnerability.md)
<img width="1547" height="1257" alt="image"
src="https://github.com/user-attachments/assets/2047007c-1ee1-487c-96aa-30e82ac63f18"
/>
2026-01-08 14:57:10 +08:00
HO-COOH
082ba75ec7 Feat: New tray-icon that adapts to theme change (#33321)
<!-- 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 idea comes from @Shomnipotence. It replaces the old tray icon with
a new outlined design and adapts to windows' theme changes.


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

- [ ] **Closes:** #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If 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
This should be obvious enough with the video



https://github.com/microsoft/PowerToys/assets/42881734/fb8f44c3-5dc0-452a-98c1-636d20b60635



<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
1. Start powertoys, it loads the tray icon of the current theme.
2. Switch theme in windows settings, it dynamically adapts.

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2026-01-08 14:23:59 +08:00
Gordon Lam
8ed090d38e Optimize PowerRename logic on memory allocation based on path depth. (#44603)
<!-- 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 improves the way items are grouped and processed by
depth in the `s_fileOpWorkerThread` function of
`PowerRenameManager.cpp`. Instead of sizing the depth matrix by the
total item count, it now determines the actual maximum depth of items
first, resulting in more efficient memory usage and correctness when
handling items by their depth.

**Improvements to depth-based processing:**

* Added a first pass to determine the maximum depth among all items
before allocating the depth matrix, ensuring the matrix is sized
appropriately and not excessively large.
* Updated the logic to iterate from the maximum depth down to zero when
adding items, aligning with the new matrix sizing and ensuring correct
processing order.
2026-01-08 14:02:32 +08:00
Kai Tao
b9de59ce64 Cmdpal: Peek command in indexer (#44581)
<!-- 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 a peek command, so we could quickly view the files found by indexer

I’m aware that wiring the Peek command directly into the indexer
extension is fairly PowerToys-specific.
I’m open to suggestions if we think this should instead be handled via a
more general extension / plugin mechanism; if a broader framework is
planned, I’m happy to wait and revisit this once that structure is in
place.

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

- [ ] Closes: #43517
<!-- - [ ] 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="279" height="315" alt="image"
src="https://github.com/user-attachments/assets/c095ac55-30a2-49e6-a972-b51b35939c53"
/>
2026-01-08 12:04:03 +08:00
moooyo
72fc8288eb Add HEIF/AVIF EXIF metadata extraction and UI support (#44466)
- Support EXIF extraction from HEIF/HEIC and AVIF images by detecting
container format and using correct WIC metadata paths.
- Extend supported file extensions to include .heic, .heif, and .avif.
- Add unit tests and test data for HEIF/AVIF extraction, with graceful
handling if required Windows Store extensions are missing.
- Update PowerRename settings UI to show HEIF/AVIF extension status and
provide install buttons.
- Extend ViewModel to detect/install required extensions and expose
status for binding.

<!-- 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: #43758
<!-- - [ ] 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: Copilot <198982749+Copilot@users.noreply.github.com>
2026-01-08 11:18:47 +08:00
Kai Tao
9c58574484 Revert "[Light Switch] Switch desktop wallpapers with the Light/Dark mode" (#44588)
This uses IVirtualDesktopManagerInternal*, which is an undocumented
Windows Shell internal API.
These interfaces are not stable and can change across Windows updates,
so using them in PowerToys carries some long-term risk
2026-01-08 10:14:43 +08:00
Kai Tao
08d4689ec5 Add jiri and maintain latest community members (#44580)
<!-- 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. Add jiri
2. Update community member order by alphabetic
3. Maintain latest community state

<!-- 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-01-08 09:08:03 +08:00
leileizhang
03d1dfca2d [UI tests] Fix "UI tests pipeline build failed " (#44574) 2026-01-07 08:08:55 -08:00
Shawn Yuan
9086995eeb Settings Flyout improvement (#43840)
<!-- 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 the new Quick Access feature to PowerToys
by integrating its host process management into the runner and system
tray. The changes add the Quick Access host implementation, update
project and build files to include it, and modify the runner and tray
icon logic to launch and interact with the Quick Access UI.

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

- [x] Closes: #43694
<!-- - [ ] 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
<img width="290" height="420" alt="image"
src="https://github.com/user-attachments/assets/7390a706-171c-479f-a4a2-999b18cfc65f"
/>

<img width="290" height="420" alt="image"
src="https://github.com/user-attachments/assets/99e99bc9-b1a3-46c6-b648-81e3048dec1b"
/>

<img width="490" height="350" alt="image"
src="https://github.com/user-attachments/assets/2cce4ad6-a54e-4587-87b7-fdc7fba1f54f"
/>

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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
Signed-off-by: Shuai Yuan <shuai.yuan.zju@gmail.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-01-07 16:38:09 +08:00
Yexuan Xiao
19c9b4e1fd [Light Switch] Switch desktop wallpapers with the Light/Dark mode (#42624)
I'm not sure how to set the AccentColor and ColorizationColor that is
consistent with the Settings App, and the same goes for switching
themes. If anyone has a solution, please let me know.


<img width="2010" height="1274" alt="2025-10-26 235808"
src="https://github.com/user-attachments/assets/b3eda45a-09f3-43bc-b87c-1b05bc308c24"
/>


- [x] Closes: #42436
- [ ] **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

---------

Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
2026-01-06 12:55:55 -05:00
fm-sys
d9709b2b91 Add non-updating mode for Crop-And-Lock (#40720)
<!-- 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 "screenshot" mode to Crop And Lock, which allows creating a
window showing a freezed snapshot of the original window.


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

- [x] **Closes:** #31799, #33071 (also requested in the already closed
duplicate issues #28633, #33812, #37337, )
- [ ] **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 (crop-and-lock utility
doesn't have any tests)
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** Added/updated
- [x] **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)
- [x] **Documentation updated:**
https://github.com/MicrosoftDocs/windows-dev-docs/pull/5528

<!-- 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 was asked why this feature is needed at all, because it could be done
with snipping tool and just AoT that window as well. While this is true,
PowerToys goal always was to improve and speed up workflows. Instead of
capturing the screenshot, opening it, and then apply "Crop and Lock" or
"Always on Top" on the screenshots window, this PR aims to provide this
functionality in a single step.

Example use cases:
- _when I want to compare between two situations like previous output
result and current output result._ (#31799)
- _Allow cropping a section of a large code file (say top while working
at the bottom) as reference while working elsewhere in the file._
(#33071)
- _Can be useful for the work in the same document, like excel or word
where you are actively checking the data from the same document._
(#28633)
- _In lot's of older applications, if you need to get some information
or data from one dialog do another, but because of dialog modality it's
not possible to have both windows open at the same time._ (#33812)
- _nowadays quite a lot is happening inside the browser. Quite often, I
want to keep a small portion of the current website visible and switch
to e.g. the writing tool also running in a different tab in the same
browser window._ (#31799)


I've used win+ctrl+shift+s as the default activation shortcut, as it's
not yet used by other powertoys utilities, has similarity with the
normal win+shift+s shortcut hotkey and is consistent with the other Crop
and Lock shortcuts win+ctrl+shift+r (Reparent Mode) and win+ctrl+shift+t
(Thumbnail Mode).

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

Compatibility tested manually with a large set of applications I have
installed on my computer. However, automated tests don't really make
sense as there is not much business logic which could be tested.

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: vanzue <vanzue@outlook.com>
2026-01-06 21:08:17 +08:00
Shawn Yuan
03aec1a9a7 [File Locksmith] Add CLI support (#44047)
<!-- 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 a new command-line interface (CLI) project
for the File Locksmith module, enabling users to interact with File
Locksmith functionality directly from the command line. The changes
include project and build configuration, CLI implementation, and
supporting code to integrate with the existing FileLocksmith library.

## Commands and Options

| Command / Option | Alias | Description |
| :--- | :--- | :--- |
| `<path>` | N/A | **Required**. One or more file or directory paths to
check. You can specify multiple paths separated by spaces. |
| `--kill` | N/A | Terminates (kills) all processes that are currently
locking the specified files. |
| `--json` | N/A | Outputs the results in structured **JSON** format
instead of human-readable text. Useful for automation and scripts. |
| `--wait` | N/A | **Blocks execution** and waits until the specified
files are released. The command will not exit until the files are
unlocked. |
| `--help` | N/A | Displays the help message with usage instructions. |

## Usage Examples

### 1. Basic check (Human-readable output)
Check which processes are locking a specific file:
```powershell
FileLocksmithCLI.exe "C:\Users\Docs\report.docx"
```

### 2. Check multiple files and output JSON
Check multiple files and get the output in JSON format for parsing:
```powershell
FileLocksmithCLI.exe --json "C:\File1.txt" "C:\Folder\File2.dll"
```

### 3. Wait for a file to be unlocked
Block script execution until a file is released (useful in build
scripts):
```powershell
FileLocksmithCLI.exe --wait "C:\bin\output.exe"
```

### 4. Force unlock a file
Kill all processes that are locking a specific file:
```powershell
FileLocksmithCLI.exe --kill "C:\LockedFile.dat"
```

<!-- 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
- [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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2026-01-06 15:59:37 +08:00
Jaylyn Barbee
335dcbaae8 [Light Switch] Adding telemetry events (#44241)
Adding events to track the following:
<table style="width:100%">
  <tr>
    <th>Event Name</th>
    <th>Description</th>
<th>Data collected</th>
  </tr>
  <tr>
    <td>Microsoft.PowerToys.LightSwitch_EnableLightSwitch</td>
    <td>Triggered when Light Switch is enabled or disabled.</td>
<td>Whether the module is enabled or disabled (bool)</td>
  </tr>
  <tr>
    <td>Microsoft.PowerToys.LightSwitch_ShortcutInvoked</td>
    <td>Occurs when the shortcut for Light Switch is invoked.</td>
<td></td>
  </tr>
  <tr>
    <td>Microsoft.PowerToys.LightSwitch_ScheduleModeToggled</td>
<td>Occurs when a new schedule mode is selected for Light Switch.</td>
<td>The new mode selected (string)</td>
  </tr>
  <tr>
    <td>Microsoft.PowerToys.LightSwitch_ThemeTargetChanged</td>
<td>Occurs when the options for targeting the system or apps is
updated.</td>
<td>The new options selected (two bools)</td>
  </tr>
</table>

The above events that are related to Light Switch settings are tracked
in the "LoadSettings" function inside the service but only if the value
has changed. The Enabled event as well as the Shortcut event are tracked
in the module interface.
2026-01-06 09:54:37 +08:00
Ruben Fricke
6515985823 CmdPal: Update Extension SDK docs link to Microsoft Learn (#44517)
<!-- 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 CmdPal SDK docs links to point to Microsoft Learn as requested in
#40994.

 

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

  - [x] Closes: #40994
<!-- - [ ] 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
  - [x] **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 links in:
    - src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/GeneralPage.xaml
    - src/modules/cmdpal/extensionsdk/README.md

Note: The issue proposes linking directly to “Command Palette /
Developer Docs / Extensibility overview” on
Learn. I noticed the project often uses fwlink/aka.ms redirects instead
of direct Learn URLs. If creating a
redirect is preferred (or if I can create one), let me know and I’ll
update the links accordingly.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation
  steps taken as well -->
  ## Validation Steps Performed
Manually verified that the links resolve to the Microsoft Learn Command
Palette extensibility overview.

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-01-05 18:43:16 -06:00
Kai Tao
36a64cae90 Find My Mouse: Improve spotlight edge quality (#44533)
<!-- 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

Find my mouse Optimization:
Crisp, soft edge that doesn't scale with radius—avoids overly blurry
edges at large sizes or hard edges at small sizes

<!-- 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

| Optimization | Before | After |
|--------|--------|--------|
| Large Radius |<img width="380" height="257" alt="image"
src="https://github.com/user-attachments/assets/66d3e180-71db-42aa-a003-8178bc9bee0d"
/>|<img width="446" height="420" alt="image"
src="https://github.com/user-attachments/assets/c2bd45ef-2d1d-485c-8669-d478b2bb9ec7"
/>|
|--------|--------|--------|
| Small Radius |<img width="217" height="222" alt="image"
src="https://github.com/user-attachments/assets/c19019fb-1671-460f-b1e5-37eb30e72c9e"
/>|<img width="135" height="123" alt="image"
src="https://github.com/user-attachments/assets/6c6f721b-6b2d-4631-af4c-d03c517a260d"
/>|
2026-01-05 22:41:01 +08:00
NOXX - Commiter
30f832ac65 Fix typo in 'Open With Antigravity' plugin name (#44529)
Fix typo in 'Antygravity' to 'Antigravity' and add Project Launcher
Plugin

<!-- 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-01-05 12:27:40 +01:00
Shawn Yuan
e0c0e7bb76 Fixed keyvisual issue for pt run (#41539)
<!-- 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: #41468 
- [ ] **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

---------

Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2026-01-05 13:38:43 +08:00
Michael Clayton
dfede67993 Ready for Review - [Mouse Without Borders] - refactoring "Common" classes (Part 7 of 7) (#44283)
## Summary of the Pull Request

**Part 7** (last part) of a [slow-running 7-part
refactor](https://github.com/microsoft/PowerToys/issues/35155#issuecomment-2583334110)
of the giant "Common" class in Mouse Without Borders into individual
classes with tighter private scope.

In this PR:

* Extract the "Common" code from the following files:
  * ```Common.cs```-> ```Core/Common.cs```
  * ```IClipboardHelper.cs/Common``` -> ```Core/IpcChannelHelper.cs```
* Update references to the types in the new locations
* Update unit test to verify functionality has only changed in an
expected way
* Make members private or internal as applicable

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

- [x] Addresses #35155 
- [x] **Communication:** I've discussed this with core contributors
already. If 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
   - no changes in this PR
- [x] **Dev docs:** Added/updated
   - no changes in this PR
- [x] **New binaries:** Added on the required places
   - no changes in this PR
- [ ] [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)
- [x] **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
   - no changes in this PR

<!-- 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

### Run manual tests from [Test Checklist
Template](5bc7201ae2/doc/releases/tests-checklist-template.md (mouse-without-borders)):

* Install PowerToys on two PCs in the same local network:
   - [x]     Verify that PowerToys is properly installed on both PCs.
   - [x]     Configure Windows Firewall Rules
- ```netsh advfirewall firewall add rule
name="PowerToys.MouseWithoutBorders - mc" dir=in action=allow
program="C:\src\mc\PowerToys\x64\Debug\PowerToys.exe" enable=yes
remoteip=any profile=any protocol=tcp```
   
 * Setup Connection:
- [x] Open MWB's settings on the first PC and click the "New Key"
button. Verify that a new security key is generated.
- [x] Copy the generated security key and paste it in the corresponding
input field in the settings of MWB on the second PC. Also enter the name
of the first PC in the required field.
- [x] Press "Connect" and verify that the machine layout now includes
two PC tiles, each displaying their respective PC names.
   
 * Verify Connection Status:
- [x] Ensure that the border of the remote PC turns green, indicating a
successful connection.
- [x] Enter an incorrect security key and verify that the border of the
remote PC turns red, indicating a failed connection.
   
 * Test Remote Mouse/Keyboard Control:
- [x] With the PCs connected, test the mouse/keyboard control from one
PC to another. Verify that the mouse/keyboard inputs are correctly
registered on the other PC.
- [ ] Test remote mouse/keyboard control across all four PCs, if
available. Verify that inputs are correctly registered on each connected
PC when the mouse is active there.
     - unable to test - only 2 machines available
   
 * Test Remote Control with Elevated Apps:
- note - the main PowerToys.exe must be running as a **non**-admin for
these tests
- [x] Open an elevated app on one of the PCs. Verify that without "Use
Service" enabled, PowerToys does not control the elevated app.
- [x] Enable "Use Service" in MWB's settings (need to run PowerToys.exe
as admin to enable "Use Service", then restart PowerToys.exe as
non-admin). Verify that PowerToys can now control the elevated app
remotely. Verify that MWB processes are running as LocalSystem, while
the MWB helper process is running non-elevated.
- ```get-process -Name "PowerToys.MouseWithoutBorders*" -IncludeUserName
| format-table Id, ProcessName, UserName```
- [x] Process: ```PowerToys.MouseWithoutBorders.exe``` - running as
```SYSTEM```
- [x] Process: ```PowerToys.MouseWithoutBorders.Helper.exe``` - running
as current user
- ```get-service -Name "PowerToys.*" | ft Status, Name, UserName;
get-ciminstance -Class "Win32_Service" -Filter "Name like 'PowerToys%'"
| ft ProcessId, Name```
- [x] Service: ```PowerToys.MWB.Service``` - running as ```Local
System```
- [x] Toggle "Use Service" again, verify that each time you do that, the
MWB processes are restarted.
- [x] Run PowerToys elevated on one of the machines, verify that you can
control elevated apps remotely now on that machine.

* Test Module Enable Status:
- [x] For all combinations of "Use Service"/"Run PowerToys as admin",
try enabling/disabling MWB module and verify that it's indeed being
toggled using task manager.
   
 * Test Disconnection/Reconnection:
- [x] Disconnect one of the PCs from network. Verify that the machine
layout updates to reflect the disconnection.
   - [x]     Do the same, but now by exiting PowerToys.
   - [x]     Start PowerToys again, verify that the PCs are reconnected.
  
 * Test Various Local Network Conditions:
- [ ] Test MWB performance under various network conditions (e.g., low
bandwidth, high latency). Verify that the tool maintains a stable
connection and functions correctly.

 * Clipboard Sharing:
- [x] Copy some text on one PC and verify that the same text can be
pasted on another PC.
- [x] Use the screenshot key and Win+Shift+S to take a screenshot on one
PC and verify that the screenshot can be pasted on another PC.
- [x] Copy a file in Windows Explorer and verify that the file can be
pasted on another PC. Make sure the file size is below 100MB.
- [x] Try to copy multiple files and directories and verify that it's
not possible (only the first selected file is being copied).
 
 * Drag and Drop:
- [ ] Drag a file from Windows Explorer on one PC, cross the screen
border onto another PC, and release it there. Verify that the file is
copied to the other PC. Make sure the file size is below 100MB.
- [ ] While dragging the file, verify that a corresponding icon is
displayed under the mouse cursor.
- [ ] Without moving the mouse from one PC to the target PC, press
CTRL+ALT+F1/2/3/4 hotkey to switch to the target PC directly and verify
that file sharing/dropping is not working.

 * Lock and Unlock with "Use Service" Enabled:
   - [x]     Enable "Use Service" in MWB's settings.
- [x] Lock a remote PC using Win+L, move the mouse to it remotely, and
try to unlock it. Verify that you can unlock the remote PC.
- [x] Disable "Use Service" in MWB's settings, lock the remote PC, move
the mouse to it remotely, and try to unlock it. Verify that you can't
unlock the remote PC.

 * Test Settings:
- [ ] Change the rest of available settings on MWB page and verify that
each setting works as described.

### Group Policy Tests

See https://learn.microsoft.com/en-us/windows/powertoys/grouppolicy

- [ ] Install *.admx / *.adml and check settings behave as expected
  - [ ] I'll expand the list of settings here when I get this far :-)
- [ ] HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys
  - [x]     ConfigureEnabledUtilityMouseWithoutBorders
- [x] ```[missing]``` - "Activation -> Enable Mouse Without Borders"
enabled, with GPO warning hidden
- ```reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
ConfigureEnabledUtilityMouseWithoutBorders /f```
- [x] ```0``` - "Activation -> Enable Mouse Without Borders" set to
"off" and disabled, with GPO warning visible
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
ConfigureEnabledUtilityMouseWithoutBorders /t REG_DWORD /d 0 /f```
- [x] ```1``` - "Activation -> Enable Mouse Without Borders" set to "on"
and disabled, with GPO warning visible
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
ConfigureEnabledUtilityMouseWithoutBorders /t REG_DWORD /d 1 /f```
  - [ ] MwbClipboardSharingEnabled
  - [ ] MwbFileTransferEnabled
  - [ ] MwbUseOriginalUserInterface
  - [ ] MwbDisallowBlockingScreensaver
  - [ ] MwbSameSubnetOnly
  - [ ] MwbValidateRemoteIp
  - [x]     MwbDisableUserDefinedIpMappingRules
- [x] ```[missing]``` - "Advanced Settings -> IP address mapping"
enabled, with GPO warning hidden
- ```reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbDisableUserDefinedIpMappingRules /f```
- [x] ```0``` - "Advanced Settings -> IP address mapping" enabled, with
GPO warning hidden
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbDisableUserDefinedIpMappingRules /t REG_DWORD /d 0 /f```
- [x] ```1``` - "Advanced Settings -> IP address mapping" disabled, with
GPO warning visible
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbDisableUserDefinedIpMappingRules /t REG_DWORD /d 1 /f```
  - [x]     MwbPolicyDefinedIpMappingRules
- [x] ```[missing]``` - "Advanced Settings -> IP address mapping"
enabled, with GPO warning and GPO values hidden
- ```reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbPolicyDefinedIpMappingRules /f```
- [x] ```[empty value]``` - "Advanced Settings -> IP address mapping"
enabled, with GPO warning hidden and GPO values hidden
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbPolicyDefinedIpMappingRules /t REG_MULTI_SZ /d "" /f```
- [x] ```[non-empty value]``` - "Advanced Settings -> IP address
mapping" enabled, with GPO warning visible and GPO values visible
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbPolicyDefinedIpMappingRules /t REG_MULTI_SZ /d "aaa 10.0.0.1\0bbb
10.0.0.2" /f```
2026-01-05 12:02:12 +08:00
Kai Tao
1438a628ad Find My Mouse: Add telemetry for trigger source (#44446)
<!-- 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
Verified trace successfully locally
2026-01-05 11:12:25 +08:00
Kazeem Quadri
1b6b446915 Add Drag and Drop For Environment Variables (#40105)
<!-- 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 drag-and-drop functionality for environment
variables, allowing users to easily update the order of variables based
on their preferences. Users can now rearrange variables directly in the
UI by dragging and dropping, making it more intuitive and efficient to
customise the order without manual editing.

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

- [X] **Closes:** #33554 33554
- [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
Updated `EnvironmentVariablesMainPage.xaml` to use a `ListView` instead
of an `ItemsControl`, enabling item dragging and reordering. The new
`ListView` features a grid layout with a `FontIcon`, `TextBox`, and
`Button`, while maintaining visibility control through data binding.

Added `EditVariableValuesList_DragItemsCompleted` method in
`EnvironmentVariablesMainPage.xaml.cs` to update the text box with the
new order of items after drag-and-drop operations, ensuring consistency
with the underlying data model.
<!-- 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 affected functionality.
- Change was minimal and did not impact existing automated tests.
- Verified that the new/modified feature works as expected and did not
cause regressions in related areas.

---------

Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
2026-01-05 09:30:02 +08:00
safocl
78b0139bc3 powerrename: fix union usage (#42845)
<!-- 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: #42843
- [ ] **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

<!-- 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
fix undefined behavior when using union in the `IFACEMETHODIMP
CPowerRenameRegEx::PutFileTime(_In_ SYSTEMTIME fileTime)` function

a69f7fa806/src/modules/powerrename/lib/PowerRenameRegEx.cpp (L299)

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-04 19:33:16 +08:00
Kai Tao
709c4bbf6b Cmdpal: PowerToys extension localization (#44520)
<!-- 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
Localization for cmdpal powertoys 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
2026-01-04 15:18:27 +08:00
Ruben Fricke
bb3435322f Fix broken style.md links in devdocs (#44457)
<!-- 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 two broken links to style.md in devcods. This file was moved to
development/style.md in PR #43399, but these references were not
updated.

<!-- 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
- [x] **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
Fixed broken links in:
  - doc/devdocs/readme.md (line 60)
  - doc/devdocs/guidance.md (line 61)
  
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manually verified that the links resolve correctly.
2026-01-04 12:23:45 +08:00
NOXX - Commiter
d43e1d8cb2 Add Antygravity plugin to third-party plugins list (#44392)
<!-- 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-01-04 11:12:47 +08:00
Shawn Yuan
1a145fd136 Fix peek issue (#44456)
<!-- 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 focuses on improving the security and behavior of
Markdown file previews. The main changes include disabling HTML
rendering in Markdown to prevent potential security issues, and ensuring
that the `IsDevFilePreview` flag is set correctly when previewing
Markdown files.

**Markdown rendering and preview behavior:**

* Disabled HTML rendering in the Markdown pipeline by adding
`.DisableHtml()` in `MarkdownHelper.MarkdownHtml`, which helps prevent
XSS and other security issues in file previews.
* Explicitly set `IsDevFilePreview` to `false` when handling Markdown
files in `WebBrowserPreviewer`, ensuring correct preview state.

<!-- 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
2025-12-29 14:23:16 +08:00
leileizhang
673cd5aba3 Add standard CLI support for Image Resizer (#44287)
<!-- 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 dedicated command-line interface (CLI) executable for Image
Resizer (PowerToys.ImageResizerCLI.exe)

## Command
`PowerToys.ImageResizerCLI.exe [options] [files...]`

## Options (High Level)

| Option (aliases) | Description |
|-----------------|-------------|
| `--help` | Show help |
| `--show-config` | Print current effective configuration |
| `--destination`, `-d` | Output directory (optional) |
| `--width`, `-w` | Width |
| `--height`, `-h` | Height |
| `--unit`, `-u` | Unit (Pixel / Percent / Inch / Centimeter) |
| `--fit`, `-f` | Fit mode (Fill / Fit / Stretch) |
| `--size`, `-s` | Preset size index (supports `0` for Custom) |
| `--shrink-only` | Only shrink (do not enlarge) |
| `--replace` | Replace original |
| `--ignore-orientation` | Ignore EXIF orientation |
| `--remove-metadata` | Strip metadata |
| `--quality`, `-q` | JPEG quality (1–100) |
| `--keep-date-modified` | Preserve source last-write time |
| `--file-name` | Output filename format |

## Example usage
```
# Show help
PowerToys.ImageResizerCLI.exe --help

# Show current config
PowerToys.ImageResizerCLI.exe --show-config

# Resize with explicit dimensions
PowerToys.ImageResizerCLI.exe --width 800 --height 600 .\image.png

# Use preset size 0 (Custom) and output to a folder
PowerToys.ImageResizerCLI.exe --size 0 -d "C:\Output" .\photo.png

# Preserve source LastWriteTime
PowerToys.ImageResizerCLI.exe --width 800 --height 600 --keep-date-modified -d "C:\Output" .\image.png
```

![imageresize](https://github.com/user-attachments/assets/437fc1c2-b655-4168-9c85-b1561eeef3b4)

<!-- 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
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** Added/updated
- [x] **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
2025-12-26 12:54:47 +08:00
Dave Rayment
97997035f7 [Awake] Fix issues with help and error text not being visible when running Awake via the command line (#41774)
<!-- 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 fixes issues when running Awake via the command line. It allows for
the display of help/usage information, parsing errors, and normal
logging information to the user, whereas these were not shown
previously.

Note: the GPO check is now deliberately placed _after_ the parameter
parsing, changing previous behaviour. This lets the user view help
information about Awake even if they cannot yet run the application
because of a policy rule. There is no change to the GPO check itself.

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

- [x] Closes: #40511, #41751
- [ ] **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
Awake is compiled as a Windows Executable. When run via the command
line, it does not have a console to which it can log information or
errors. The application does open its own console under certain
circumstances, but this occurs _after_ command line parameter parsing is
done, which means errors and help information cannot be displayed.

This fix attaches to the parent console and moves the parameter parsing
to the start of `Main` so the errors and usage information can now be
seen:

### Help/usage information
<img width="1449" height="501" alt="image"
src="https://github.com/user-attachments/assets/e4d02501-1484-4f5d-a00a-606aaf13973e"
/>

### Parsing error display
<img width="1458" height="570" alt="image"
src="https://github.com/user-attachments/assets/66405db9-0b65-4f07-9af9-d22ecd0da2ba"
/>

### Normal operation
<img width="1585" height="640" alt="image"
src="https://github.com/user-attachments/assets/d393e1dd-6d0f-43d1-9b1c-4922c8aab40f"
/>

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
- Tested that all modes still perform as expected from both the command
line and via PowerToys Runner / settings file.
- Confirmed that there were no side-effects from attaching to the
console when running in non-command line mode (`AttachConsole` fails in
that instance and no other changes are apparent).

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
2025-12-25 16:31:58 +08:00
Dustin L. Howett
59962ffd3a wip: Okay, disable caching for now (#43126) 2025-12-25 12:33:43 +08:00
leileizhang
3f106344b3 [FancyZones CLI] Add localization and telemetry support (#44421)
<!-- 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
FancyZones CLI, 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
2025-12-25 12:23:25 +08:00
Shawn Yuan
ab531b2620 Fix empty endpoint issue (#44415)
<!-- 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 a small but important improvement to the
handling of AI provider endpoint configuration in the advanced paste
settings. Now, if an endpoint is required but not provided by the user,
a placeholder value will be set automatically.

<!-- 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
2025-12-25 11:57:51 +08:00
Dave Rayment
48e95caf39 [PowerRename] Fix Unicode characters and non-breaking spaces not being correctly normalized before matching (#43972)
## Summary of the Pull Request
Fixes PowerRename failing to normalise different Unicode forms before
matching. This results in filenames containing visually identical
characters to the search term from failing to match because their
underlying binary representations differ.

This affects renaming files created on macOS which names files in NFD
(decomposed form) rather than Windows' NFC (precomposed form).

Additionally, this fixes matching to filenames containing non-breaking
space characters, which can be created by automated systems and web
downloaders. Previously, the NBSP character would fail to match a normal
space.

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

- [x] Closes: #43971
- [x] Closes: #43815
- [ ] **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
The underlying issue is a binary mismatch between:

1. Precomposed characters (NFC) typed by Windows users, e.g. `U+0439` -
`й`.
2. Decomposed characters (NFD) found in filenames from other platforms
(or copied from text), e.g. `U+0438` `U+0306` - `и` + `̆ `.
3. Standard spaces (`U+0020`) versus non-breaking spaces (`U+00A0`).

### Updates to PowerRenameRegex.cpp

I added a `SanitizeAndNormalize` function which replaces all
non-breaking spaces with standard spaces and normalises the string to
**Normalization Form C** using Win32's `NormalizeString`.

`PutSearchTerm` and `PutReplaceTerm` now normalise input immediately
before performing any other processing.

`Replace` now normalises the `source` filename before processing.

I updated the RegEx path to ensure it runs against the normalised
`sourceToUse` string instead of the raw `source` string; otherwise regex
matches would fail.

<!-- 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 use case detailed in #43971 with the following
filenames:

- `Testй NFC.txt`
- `Testй NFD.txt`

Result:
<img width="1097" height="542" alt="image"
src="https://github.com/user-attachments/assets/55dd4f01-8ec9-462c-a20f-dd246c368cf5"
/>

There are two new unit tests which exercise both the non-breaking space
and Unicode form normalisation issues. These run on both the Boost- and
non-Boost test paths, adding four tests to the total. All new tests fail
as expected on the prior code and all PowerRename tests pass
successfully with the changes in this PR:

<img width="606" height="276" alt="image"
src="https://github.com/user-attachments/assets/08dc01f6-201c-4d56-8f34-e5043e3d1e86"
/>
2025-12-25 11:34:32 +08:00
Kai Tao
d87dde132d Cmdpal extension: Powertoys extension for cmdpal (#44006)
<!-- 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
Installer built, and every command works as expected,
Now use sparse app deployment, so we don't need an extra msix

---------

Co-authored-by: kaitao-ms <kaitao1105@gmail.com>
2025-12-23 21:07:44 +08:00
Gordon Lam
534c411fd8 Add Review and Fix prompts for acceleration github issues (#43419)
## Summary of the Pull Request

This PR adds comprehensive GitHub PR review tooling infrastructure to
improve review efficiency through incremental review capabilities. The
tooling consists of PowerShell scripts that detect changes between
review iterations, enabling reviewers to focus only on modified files,
and AI prompt templates for structured PR and issue reviews.

**Key additions:**
- `.github/review-tools/`: PowerShell scripts for incremental PR review
detection
- `.github/prompts/`: AI prompt templates for PR reviews, issue reviews,
and issue fixes
- Copilot instructions documentation for review tools integration

## 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 (N/A - tooling scripts with
manual validation)
- [x] **Localization:** All end-user-facing strings can be localized
(N/A - development tooling only)
- [x] **Dev docs:** Added/updated (comprehensive documentation in
`review-tools.instructions.md`)
- [ N/A ] **New binaries:** Added on the required places (N/A -
PowerShell scripts, no binaries)
- [ 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 (N/A - internal development tooling)

## Detailed Description of the Pull Request / Additional comments

### Review Tools Added (`.github/review-tools/`)

**Core Scripts:**
1. **`Get-PrIncrementalChanges.ps1`** (173 lines) - Compares last
reviewed commit SHA with current PR head to identify incremental
changes. Returns JSON with changed files, new commits, and review
recommendations. Handles scenarios: first review, no changes, force-push
detection, and incremental changes.

2. **`Test-IncrementalReview.ps1`** (170 lines) - Helper script to
preview incremental review detection before running full review.
Displays colored console output showing current vs last reviewed SHAs,
changed files, new commits, and recommended review strategy.

3. **`Migrate-ReviewToIncrementalFormat.ps1`** (206 lines) - One-time
migration script to add review metadata sections to existing
`00-OVERVIEW.md` files, enabling incremental review functionality for
legacy PR reviews.

4. **`Get-GitHubRawFile.ps1`** (91 lines) - Downloads file content from
GitHub repository at specific git reference for baseline comparison
during reviews. Supports optional line numbering.

5. **`Get-GitHubPrFilePatch.ps1`** (79 lines) - Fetches unified diff
(patch) for a specific file in a pull request using GitHub API.

6. **`review-tools.instructions.md`** (355 lines) - Comprehensive
documentation covering script usage, workflow integration, error
handling, best practices, and AI integration examples. Serves as Copilot
instructions for the review tools.

### AI Prompt Templates Added (`.github/prompts/`)

1. **`review-pr.prompt.md`** (200 lines) - Structured prompt for
comprehensive PR reviews with incremental review support
2. **`review-issue.prompt.md`** (158 lines) - Template for systematic
issue analysis and triage
3. **`fix-issue.prompt.md`** (71 lines) - Guided workflow for
implementing issue fixes
4. **Minor updates** to `create-commit-title.prompt.md` and
`create-pr-summary.prompt.md` for consistency

### Key Features

**Incremental Review Flow:**
- Initial review (iteration 1): Creates overview with metadata including
HEAD SHA
- Subsequent reviews (iteration 2+): Reads last reviewed SHA, detects
changes, reviews only modified files
- Smart step filtering: Skips irrelevant review steps based on file
types changed (e.g., skip Localization if no `.resx` files changed)

**Error Handling:**
- Detects force-push scenarios (last reviewed SHA no longer in history)
- Validates GitHub CLI authentication
- Provides detailed error messages with actionable solutions
- Exit code 1 on errors for automation compatibility

**Integration:**
- Works with GitHub CLI (`gh`) for API access
- JSON output for programmatic consumption
- Designed for AI-powered review systems (Copilot integration)
- Metadata tracking for context-aware suggestions

## Validation Steps Performed

**Manual Testing:**
1.  Verified all PowerShell scripts follow PSScriptAnalyzer rules
2.  Tested `Get-PrIncrementalChanges.ps1` with various scenarios:
   - First review (no previous SHA)
   - No changes (SHA matches current)
   - Force-push detection (SHA not in history)
   - Incremental changes (multiple commits and files)
3.  Validated `Test-IncrementalReview.ps1` output formatting and
accuracy
4.  Confirmed `Migrate-ReviewToIncrementalFormat.ps1` adds metadata
without corrupting existing reviews
5.  Tested GitHub API integration with `Get-GitHubRawFile.ps1` and
`Get-GitHubPrFilePatch.ps1`
6.  Verified documentation accuracy and completeness in
`review-tools.instructions.md`
7.  Validated prompt templates follow PowerToys repo conventions from
`.github/copilot-instructions.md`

**Dependencies Verified:**
- Requires PowerShell 7+ (or Windows PowerShell 5.1+)
- Requires GitHub CLI (`gh`) installed and authenticated
- All scripts include comprehensive help documentation (`Get-Help`
support)

**No Automated Tests:** These are development/CI tooling scripts used by
maintainers for PR reviews. Manual validation appropriate as they
interact with live GitHub API and require human judgment for review
quality assessment.
2025-12-23 16:18:22 +08:00
Kai Tao
afeeea671f Cmdpal: Fix the path error to pack the sdk (#44390)
<!-- 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 the path change introduced by #44316 when buildsdk standalone
2. Add a build step in CI to make sure sdk build correctly in future
changes

<!-- 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
Pipeline should pack sdk correctly
<img width="329" height="119" alt="image"
src="https://github.com/user-attachments/assets/5f223d82-5213-4735-9b14-1ddad9ec41a2"
/>
2025-12-23 13:46:49 +08:00
Michael Jolley
f1e045751a CmdPal: Fallback ranking and global results (#43549)
> [!IMPORTANT]
> For extension developers, this release includes a new required `string
Id` property for `FallbackCommandItem`. While your existing extensions
will continue to work, without this `Id` being set, your fallbacks will
not display and will not be rankable.
> Before this is released, you will want to prepare your extension
fallbacks.
> 
> As an example, we are naming our built-in extensions as:
> - Calculator extension provider Id:
`com.microsoft.cmdpal.builtin.calculator`
> - Calculator extension fallback:
`com.microsoft.cmdpal.builtin.calculator.fallback`
> 
> While the content of the Id isn't important, what is important is that
it is unique to your extension and fallback to avoid conflicting with
other extensions.

Now the good stuff:

## What the heck does it do!?

### The backstory

In PowerToys 0.95, we released performance improvements to Command
Palette. One of the many ways we improved its speed is by no longer
ranking fallback commands with other "top level" commands. Instead, all
fallbacks would surface at the bottom of the results and be listed in
the order they were registered with Command Palette. But this was only a
temporary solution until the work included in this pull request was
ready.

In reality, not all fallbacks were treated equally. We marked the
calculator and run fallbacks as "special." Special fallbacks **were**
ranked like top-level commands and allowed to surface to the top of the
results.

### The new "hotness"

This PR brings the power of fallback management back to the people. In
the Command Palette settings, you, dear user, can specify what order you
want fallbacks to display in at the bottom of the results. This keeps
those fallbacks unranked by Command Palette but displays them in an
order that makes sense for you. But keep in mind, these will still live
at the bottom of search results.

But alas, we have also heard your cries that you'd like _some_ fallbacks
to be ranked by Command Palette and surface to the top of the results.
So, this PR allows you to mark any fallback as "special" by choosing to
include them in the global results. Special (Global) fallbacks are
treated like "top level" commands and appear in the search result based
on their title & description.

### Screenshots/video

<img width="1005" height="611" alt="image"
src="https://github.com/user-attachments/assets/8ba5d861-f887-47ed-8552-ba78937322d2"
/>

<img width="1501" height="973" alt="image"
src="https://github.com/user-attachments/assets/9edb7675-8084-4f14-8bdc-72d7d06d500e"
/>

<img width="706" height="744" alt="image"
src="https://github.com/user-attachments/assets/81ae0252-b87d-4172-a5ea-4d3102134baf"
/>

<img width="666" height="786" alt="image"
src="https://github.com/user-attachments/assets/acb76acf-531d-4e60-bb44-d1edeec77dce"
/>


### GitHub issue maintenance details

Closes #38312
Closes #38288
Closes #42524
Closes #41024
Closes #40351
Closes #41696
Closes #40193

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2025-12-22 17:08:15 -06:00
Jiří Polášek
8682d0f54d CmdPal: Add a solution filter for Command Palette projects (#44395)
<!-- 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 solution filter (.slnf) to the Command Palette
module, allowing us to quickly open just the subset of projects needed
to build, test, and run our favorite PowerToy.

<!-- 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
2025-12-22 23:12:07 +01:00
Shawn Yuan
1d13779697 [UITest] Add UI Automation for advanced paste (#40803)
<!-- 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

 * Clipboard History
- [x] Open Settings and Enable clipboard history (if not enabled
already). Open Advanced Paste window with hotkey, click Clipboard
history and try deleting some entry. Check OS clipboard history (Win+V),
and confirm that the same entry no longer exist.
- [x] Open Advanced Paste window with hotkey, click Clipboard history,
and click any entry (but first). Observe that entry is put on top of
clipboard history. Check OS clipboard history (Win+V), and confirm that
the same entry is on top of the clipboard.
- [x] Open Settings and Disable clipboard history. Open Advanced Paste
window with hotkey and observe that Clipboard history button is
disabled.
* Disable Advanced Paste, try different Advanced Paste hotkeys and
confirm that it's disabled and nothing happens.

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

- [ ] Closes: #40681
- [ ] **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

---------

Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
2025-12-22 13:14:42 +08:00
Jessica Dene Earley-Cha
37bd24db36 Cmdpal: user research on extension invokes (#43905)
## Summary of the Pull Request

Added two events that Niels asked for:

- `CmdPal_ExtensionInvoked`
- Track which extensions are being used (e.g., file search, app
launching, calculator, etc.).
    - Properties logged
        - ExtensionId - Unique identifier of the extension provider
        - CommandType - Display name of the command being invoked
        - Success - Whether the command executed successfully
        - ExecutionTimeMs - Execution time in milliseconds
- `CmdPal_SessionDuration`
    - Tracks how long Command Palette stays open (launch → close). 
    - Properties logged
        - DurationMs - Session duration in milliseconds
        - CommandsExecuted - Number of commands executed
        - PagesVisited - Number of pages visited
- DismissalReason - Why the session ended (Escape, LostFocus, Command,
etc.)
        - SearchQueriesCount - Number of search queries executed
        - MaxNavigationDepth - Maximum navigation depth reached
        - ErrorCount - Number of errors encountered



<!-- 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
2025-12-19 11:23:16 -08:00
Kai Tao
557a07589d Fix spell check errors (#44358)
<!-- 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
No spell check error appears
2025-12-19 17:03:27 +08:00
Shawn Yuan
2603efc8a9 Fix pipeline with waskd2 experimental version (#44357)
<!-- 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 includes two main groups of changes: improvements to
build configuration (specifically, warning suppression for experimental
features), and refactoring in the `WrapPanelCustom` control to use the
correct `StretchChild` type from the CommunityToolkit. These updates
help streamline the build process and improve code clarity and
maintainability.

**Build configuration improvements:**

* Added `/p:IgnoreExperimentalWarnings=true` to the
`RestoreAdditionalProjectSourcesArg` in the build pipeline to enable
suppression of experimental warnings during project restore.
* Updated `Directory.Build.targets` to append specific warning codes
(`CS8305`, `SA1500`, `CA1852`) to the `NoWarn` property when
`IgnoreExperimentalWarnings` is set, suppressing these warnings during
builds.

**Refactoring in `WrapPanelCustom`:**

* Updated the `WrapPanel` control in `WrapPanel.cs` to use
`ToolkitStretchChild` from `CommunityToolkit.WinUI.Controls` instead of
a local `StretchChild` type, ensuring consistency and leveraging the
toolkit's implementation.
[[1]](diffhunk://#diff-53e4c6a2890b6fb1c66ea8a19f0049070910083608f8fb80c2b1f5a8d254d007R11-R12)
[[2]](diffhunk://#diff-53e4c6a2890b6fb1c66ea8a19f0049070910083608f8fb80c2b1f5a8d254d007L180-R184)
[[3]](diffhunk://#diff-53e4c6a2890b6fb1c66ea8a19f0049070910083608f8fb80c2b1f5a8d254d007L193-R197)
[[4]](diffhunk://#diff-53e4c6a2890b6fb1c66ea8a19f0049070910083608f8fb80c2b1f5a8d254d007L400-R402)
<!-- 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
2025-12-19 16:02:17 +08:00
leileizhang
dd138fb94b FancyZones CLI: migrate to System.CommandLine and centralize data I/O (#44344)
<!-- 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 refactors FancyZones CLI to use System.CommandLine and
consolidates all FancyZones JSON config read/write through
FancyZonesEditorCommon data models and FancyZonesDataIO, so CLI and
Editor share the same serialization and file paths.

For detailed command definitions, see PR #44078
<!-- 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
2025-12-19 11:53:43 +08:00
Noraa Junker
7cd201d355 Remove ISettingsUtils and ISettingsPath interfaces (#44331)
<!-- 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 ISettingsUtils and ISettingsPath interfaces to
reduce some complexity. They only existed so the classes can be used
with moq. But this is also possible by using virtual methods which is
cleaner.

<!-- 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
- [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
2025-12-19 10:30:01 +08:00
Shawn Yuan
9aab0f3893 Fix pipeline with waskd2 exp (#44334)
<!-- 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 the WinAppSDK version used in the build
pipeline to 1.8 and makes related improvements to the NuGet restore
process and configuration handling.

Version update:

* Updated the default value of the `winAppSdkVersionNumber` parameter
from `"1.7"` to `"1.8"` in `.pipelines/UpdateVersions.ps1`, ensuring the
pipeline uses the latest WinAppSDK version.

NuGet restore and configuration improvements:

* Changed the `Add-NuGetSourceAndMapping` call in the
`Resolve-WinAppSdkSplitDependencies` function to use the `$installDir`
variable instead of a hardcoded path, improving flexibility for local
package mapping in `.pipelines/UpdateVersions.ps1`.
* Added a `workingDirectory` property to the NuGet restore step in
`.pipelines/v2/templates/steps-update-winappsdk-and-restore-nuget.yml`
to ensure the restore process operates from the correct directory.
<!-- 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
2025-12-18 14:47:59 +08:00
Shawn Yuan
91b7a99e76 Update BuildWithLatestWinAppSdkDaily pipeline to use 1.8 wasdk (#44183)
<!-- 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 WindowsAppSDK update and NuGet restore
pipeline to improve dependency resolution and configuration management,
especially for version 1.8 and above. The changes streamline how package
versions are detected and updated across multiple project files,
introduce more robust handling of NuGet sources and mappings, and
modernize the restore step to use the `dotnet` CLI for better
compatibility.

<!-- 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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-12-18 11:39:35 +08:00
Gordon Lam
d38edf798d Update a reminding vcxproj that reference WinAppSDK (#44316)
<!-- 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 modernizes NuGet package management for the
`Microsoft.CommandPalette.Extensions` native project by migrating from
the older `packages.config` approach to the newer `PackageReference`
style. It also updates the related project references and output
handling in the toolkit project. These changes simplify dependency
management and align with current best practices for native C++/WinRT
projects.

**NuGet package management modernization:**

* Migrated `Microsoft.CommandPalette.Extensions.vcxproj` from
`packages.config` to `PackageReference` style, specifying dependencies
directly in the project file and removing the `packages.config` file.
[[1]](diffhunk://#diff-ff17a18a84e1c666c8f05468624d55167ac13d2c0e36724e0df3ce1d83bdbbd4L3-L12)
[[2]](diffhunk://#diff-ff17a18a84e1c666c8f05468624d55167ac13d2c0e36724e0df3ce1d83bdbbd4R27-R33)
[[3]](diffhunk://#diff-13e4e73ced13b2508639b5e93c39b0f1ee6a978109c60d33e3a9d16bf24024bfL1-L17)
* Removed legacy NuGet property groups, imports, and error-checking
targets related to manual package restore, as these are now handled
automatically by `PackageReference`.
[[1]](diffhunk://#diff-ff17a18a84e1c666c8f05468624d55167ac13d2c0e36724e0df3ce1d83bdbbd4L3-L12)
[[2]](diffhunk://#diff-ff17a18a84e1c666c8f05468624d55167ac13d2c0e36724e0df3ce1d83bdbbd4L165-L182)

**Project reference and build output updates:**

* Updated the project reference in
`Microsoft.CommandPalette.Extensions.Toolkit.csproj` to not reference
the output assembly directly, and added explicit inclusion and copying
of the native implementation DLL and WinMD files to the output
directory.

**Cleanup of unused files:**

* Removed `packages.config` from both the
`Microsoft.CommandPalette.Extensions` and `PowerRenameUILib` projects,
as dependencies are now managed via `PackageReference`.
[[1]](diffhunk://#diff-13e4e73ced13b2508639b5e93c39b0f1ee6a978109c60d33e3a9d16bf24024bfL1-L17)
[[2]](diffhunk://#diff-98d060eb88d212ec4ce70e1d30ec66043a998d67940648c917aa6609739d10d5L1-L19)
2025-12-17 18:10:21 +08:00
Dave Rayment
17668047bf [PowerRename] Fix date replacement tokens failing if followed by a capital letter (#44267)
## Summary of the Pull Request
Fixes date/time-related replacement tokens being rejected if they were
followed by capital letters in the user's replacement string.

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

- [x] Closes: #44202
- [ ] **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
With the addition of image metadata replacement options, a strict
negative lookahead was added to the date replacement regular expressions
to prevent conflicts. This was required because, for example, `$D` would
otherwise match before `$DATE_TAKEN_YYYY`. Metadata and date-related
replacements are executed separately at the moment, so this awareness of
each other is required.

However, the negative lookahead was far too aggressive:
- It used `(?![A-Z])`, meaning any capital letter after the date token
would reject the match entirely. This caused the problem referred to in
the linked issue, where `$DDT` was rejected instead of matching to the
`$DD` replacement followed by a verbatim `T` character.
- It was applied to the majority of fields, whereas it is only actually
needed where date tokens are prefixes of metadata tokens. Only `$D` and
`$H` are affected.
- There was no need to apply negative lookups to catch 'self-matches'
like preventing `$D`, `$DD`, and `$DDD` from matching when `$DDDD` was
in the replacement string. Instead, the order of processing already
matches the longest token first, so this could never happen.

To fix these issues, I:
- Removed the majority of the negative lookaheads.
- Made the remaining negative lookaheads only match actual conflicting
suffixes, e.g. `$D(?!(ATE_TAKEN_|ESCRIPTION|OCUMENT_ID))` instead of
`$D(?![A-Z])`. This makes mistaken rejections of user-supplied
replacement strings much more unlikely.

Please note: there remain inherent issues with the current token
replacement approach. Tackling these will require a more extensive
refactoring PR which separates replacement string tokenization from
matching and replacement, and which tackles both image metadata and file
date metadata in a unified manner.

## Validation Steps Performed
- Corrected unit tests which classified, for example, `$YYY` as invalid,
instead of identifying it as a valid `$YY` token + verbatim capital Y
replacement.
- Wrote new unit tests to exercise the refined negative lookaheads.
- Wrote tests to confirm certain negative lookaheads were not required
because the order of processing guaranteed the longest match happens
before any prefix matches.
- Wrote a unit test to exercise the specific issue raised in #44202.
- Confirmed that all new and pre-existing PowerRename tests pass.
2025-12-17 16:54:58 +08:00
Shawn Yuan
7b0b284d40 [Advanced Paste] Introduced image-input handling (#44021)
<!-- 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 significant enhancements to the
AdvancedPaste module, enabling AI-powered clipboard transformations to
support both text and image data (notably for image analysis and
transformation tasks), and improving error handling and clipboard
tracking. The changes update the service interfaces, data models, and
processing logic to handle images alongside text, and refine how the
application responds to errors and clipboard state changes.

<img width="470" height="366" alt="image"
src="https://github.com/user-attachments/assets/6ad011e4-a2ba-4e44-b640-739440836de6"
/>

<!-- 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

---------

Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-12-17 11:49:28 +08:00
Gordon Lam
9aca6d136f Revert "Revert commit" - Using centralized package management for vcxproj (#44289)
Reverts microsoft/PowerToys#44208
Basically enable back: https://github.com/microsoft/PowerToys/pull/43920

the core change is adding this new Target to ensure when "building in
Visual Studio", it will restore the nuget package first for vcxproj:
```xml
  <!-- Auto-restore NuGet for native vcxproj (PackageReference) when building inside VS -->
  <Target Name="EnsureNuGetRestoreForVcxproj" BeforeTargets="PrepareForBuild" Condition="
            '$(BuildingInsideVisualStudio)' == 'true'
            and '$(DesignTimeBuild)' != 'true'
            and '$(RestoreInProgress)' != 'true'
            and '$(MSBuildProjectExtension)' == '.vcxproj'
            and '$(RestoreProjectStyle)' == 'PackageReference'
            and '$(MSBuildProjectExtensionsPath)' != ''
            and !Exists('$(MSBuildProjectExtensionsPath)project.assets.json')
          ">

    <Message Importance="normal" Text="NuGet assets missing for $(MSBuildProjectName); running Restore...; IntDir=$(IntDir); BaseIntermediateOutputPath=$(BaseIntermediateOutputPath)" />

    <MSBuild Projects="$(MSBuildProjectFullPath)" Targets="Restore" Properties="RestoreInProgress=true" BuildInParallel="false" />
  </Target>
```
2025-12-16 10:46:39 +08:00
leileizhang
4b2ee60b42 Fix AdvancedPaste Gemini provider saving Azure placeholder endpoint (#44293)
<!-- 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 creating/editing a Paste AI provider in Settings, providers that
don’t require an endpoint (e.g., Google/Gemini) could still end up
persisting the Azure OpenAI placeholder
(https://your-resource.openai.azure.com/) into settings.json.

### Fix:

- On save, for service types that don’t use an endpoint, prevent
placeholder/stale values from being persisted by forcing endpoint-url to
be empty.
- Reuse a single “requires endpoint” check so the dialog visibility and
save behavior stay consistent.

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

- [x] Closes: #44243
<!-- - [ ] 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

## AI Generated Note:
This pull request refactors and improves how endpoint handling is
managed for different AI service types in the
`AdvancedPastePage.xaml.cs` file. The changes centralize the logic for
determining whether an endpoint is required, prevent persisting
placeholder or stale endpoint values for services that do not use them,
and ensure placeholder values are only provided where appropriate.

**Refactoring and logic centralization:**

* Introduced the `RequiresEndpointForService` helper method to
centralize and clarify the logic for determining if a service type
requires an endpoint, replacing inline checks in multiple places.
[[1]](diffhunk://#diff-14126907329c7fcd49dd33bab32283296c7dd68ddc3902163a482a3b3ce58d36L317-R317)
[[2]](diffhunk://#diff-14126907329c7fcd49dd33bab32283296c7dd68ddc3902163a482a3b3ce58d36R838-R845)

**Improved endpoint value handling:**

* Updated the dialog logic to ensure that endpoints are not persisted
for services that do not require them, preventing storage of placeholder
or irrelevant values.
* Modified the `GetEndpointPlaceholder` method to return an empty string
for service types that do not require an endpoint, rather than a generic
placeholder.
2025-12-15 17:07:09 +08:00
Shawn Yuan
e37a328624 [Advanced Paste] Fixed custom hotkey issue (#44288)
<!-- 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
Fixed custom hotkey issue

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

- [x] Closes: #43899 
<!-- - [ ] 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

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
2025-12-15 12:56:35 +08:00
moooyo
66e96bbe9d Super resolution with AI for image resizer (#42331)
<!-- 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
From WinAppSDK 1.8, microsoft announced a new feature AI Imaging. We can
use this ability to enhance our image resizer tools to support scale up
the image resolution by AI.

Doc:
https://learn.microsoft.com/en-us/windows/ai/apis/imaging#what-can-i-do-with-image-super-resolution

Target:
1. Add a new config to control use AI or not.
2. Support model download in image resizer.
3. Auto detect if user's computer support AI feature, if not, do not
show the AI related config.
4. Switch the control part if user enable/disable ai feature.

Demo:
Model not ready, user need to download the model:
<img width="694" height="625" alt="image"
src="https://github.com/user-attachments/assets/8079f047-71fa-4abf-b266-003f74cc5d3e"
/>

Model ready:
<img width="543" height="589" alt="image"
src="https://github.com/user-attachments/assets/952eafc6-0af6-4bea-88d0-0724532f4fac"
/>

User's computer doesn't support AI feature (x86 machine)
<img width="685" height="531" alt="image"
src="https://github.com/user-attachments/assets/522ba300-1505-46a2-a29b-3e8e71c49cdd"
/>


Note: **This feature only support for Arm Windows with the latest
Windows 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

<!-- 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: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: moooyo <lengyuchn@gmail.com>
Co-authored-by: Leilei Zhang <leilzh@microsoft.com>
2025-12-15 09:42:49 +08:00
Jiří Polášek
e13d6a78aa CmdPal: Set image to surface immediately in BlurImageControl (#44222)
## Summary of the Pull Request

This PR resolves issue when the background image is not loaded. When
loading an image, BlurImageControl now sets the image to the surface
immediately, as the LoadComplete handler is not guaranteed to be called.

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

- [x] Closes: #44221
<!-- - [ ] 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
2025-12-11 19:05:01 -06:00
Jiří Polášek
73786cd2be CmdPal: Add drag & drop support (#44165)
## Summary of the Pull Request

This PR adds basic drag-and-drop support for items in list and grid
views.

It introduces two new properties on `ListItem`, backed by
`IExtendedAttributesProvider`: `DataPackage` and `DataPackageView`.
These properties are mutually exclusive.
`DataPackage` serves as a convenience property allowing the item to
retain the underlying object without risk of losing it. Across the
extension boundary, only the immutable `DataPackageView` snapshot is
transferred. When `DataPackage` is set, `DataPackageView` is derived
from it.

This PR includes initial concrete drag-and-drop implementations for:
- File Indexer  
- Clipboard History  

**Todo / Missing pieces** 
- [x] Extend `DataPackage` support to top-level command items, enabling
scenarios such as index fallback ~
- [x] Provide automatic drag-and-drop for unconfigured list items (e.g.,
copying title and subtitle as text)
- [x] Keep CmdPal open
- [ ] ~Clipboard commands (since we have the DataPackage...)~
- [ ] ~Improve logging~

## Pictures? Moving ones!


https://github.com/user-attachments/assets/13eb9a71-e760-43ea-8c2d-cd41cf377905




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

- [x] Closes: #38289 
<!-- - [ ] 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
2025-12-11 08:05:48 -06:00
leileizhang
4de4d5f310 [Advanced Paste] Fix clipboard history item duplication when selecting items (#44212)
<!-- 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 clicking on a clipboard history item creates a
duplicate entry at the top of the history.
## Problem

When a user clicks on a clipboard history item in the Advanced Paste
clipboard history menu, the item gets duplicated to the top of the
history. This makes it impossible to delete items since clicking the
three-dots menu to delete first duplicates the item.

## Root Cause

The `ClipboardHistory_ItemInvoked` handler was using
`ClipboardHelper.SetTextContent()` and
`ClipboardHelper.SetImageContent()`, which internally call
`Clipboard.SetContentWithOptions()`. This creates a new clipboard
history entry with the same content.

## Solution

Use `Clipboard.SetHistoryItemAsContent(ClipboardHistoryItem)` instead,
which sets the clipboard content from an existing history item without
creating a new history entry.


![delete](https://github.com/user-attachments/assets/256407e7-a05f-4cb5-9311-de8918940d66)

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

- [x] Closes: #43945
<!-- - [ ] 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
2025-12-11 14:12:06 +08:00
Kai Tao
f8c5ff8c0c Build: Fix build script for a local installer (#44168)
<!-- 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

Not maintained since wix5 upgrade, so make it build locally for an
installer
1. Do elevation when dev cert is not added to root store
2. Set up version to build arg to build, and build cmdpal version same
with CI
3. cmdpal AOT local build
4. Make sure every msix file is signed successfully

<!-- 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

Verify the script can build an installer on a new devbox, and cmdpal,
filelocksmith etc can be run without problem
<img width="872" height="275" alt="image"
src="https://github.com/user-attachments/assets/cf4cff0d-0d90-4496-a7f8-50c582d9c340"
/>
<img width="1251" height="555" alt="image"
src="https://github.com/user-attachments/assets/6529c1a8-a532-4dfc-9f74-2c2fd37e28e6"
/>
Output for msix packages:
PackageFullName Version
--------------- -------
Microsoft.PowerToys.SparseApp_0.96.2.0_neutral__8wekyb3d8bbwe 0.96.2.0

Microsoft.PowerToys.FileLocksmithContextMenu_0.96.2.0_neutral__8wekyb3d8bbwe
0.96.2.0

Microsoft.PowerToys.ImageResizerContextMenu_0.96.2.0_neutral__8wekyb3d8bbwe
0.96.2.0
Microsoft.PowerToys.NewPlusContextMenu_0.96.2.0_neutral__8wekyb3d8bbwe
0.96.2.0

Microsoft.PowerToys.PowerRenameContextMenu_0.96.2.0_neutral__8wekyb3d8bbwe
0.96.2.0

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-11 13:17:42 +08:00
leileizhang
d32ea86314 [Peek] Use WebView2 for SVG preview to improve compatibility (#44209)
<!-- 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
Improves SVG preview compatibility in Peek by using WebView2 instead of
`SvgImageSource`.
## Problem

`SvgImageSource` has limited SVG feature support and fails to render
SVGs with advanced features like `clipPath`, complex gradients, or
certain namespace configurations. This results in black previews or
icon-only display for many SVG files.

## Solution

Render SVG files using WebView2 which provides full SVG specification
support through the browser engine.

<img width="1973" height="1314" alt="image"
src="https://github.com/user-attachments/assets/a4eb2ff5-d76f-4f7f-87e3-6404e18b2b09"
/>

<img width="1997" height="1358" alt="image"
src="https://github.com/user-attachments/assets/7ce4dd69-7fba-447e-8499-d37af3f02c4d"
/>
<!-- Please review the items on the PR checklist before submitting-->

## PR Checklist

- [x] Closes: #44193
<!-- - [ ] 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
2025-12-11 11:58:01 +08:00
Shawn Yuan
177f144e6d Revert commit (#44208)
<!-- 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
Revert commit of 06fcbdac40 and
60deec6815
<!-- 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
2025-12-11 11:23:18 +08:00
Kai Tao
7b469f6327 Build: Fix a version check failure (#44199)
<!-- 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
Version check failed for a dll, ignore it to let release pipeline pass

<!-- 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
2025-12-11 10:58:30 +08:00
Guilherme
94ace730c8 [CmdPal] Add Sections and Separators for List Pages and Grid Pages (#43952)
<!-- 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 sections and separators to ListPages and
GridPages

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

- [x] Closes: #38267
<!-- - [ ] 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

Since `CollectionViewSource` was causing performance issues and
@zadjii-msft asked for a new approach, I came up with this idea, heavily
inspired by how separators work on the `ContextMenu`, `FiltersDropDown`
and `Details`.

The way this is currently working is: Any ListItem where `Section` is
not null and `Command` is null, is considered a Separator.

On my tests, this seems to be working fine. Tried to make this work
without changes to the API, but I think this needs to be discussed.

### Some of the possible enhancements to existing extensions

### Search apps

<img width="792" height="523" alt="Screenshot 2025-11-27 173618"
src="https://github.com/user-attachments/assets/f9f9a64d-3ec1-4f7e-922b-997a3a4d074d"
/>

### Window Walker

<img width="785" height="518" alt="Screenshot 2025-11-27 173728"
src="https://github.com/user-attachments/assets/230f647d-210a-4b60-9068-c8fff890d2c9"
/>

### Winget

<img width="809" height="497" alt="Screenshot 2025-11-27 174006"
src="https://github.com/user-attachments/assets/547529c1-7600-4438-8c3e-e872e0327650"
/>

### Search files

<img width="819" height="536" alt="image"
src="https://github.com/user-attachments/assets/e86accc0-3f85-412d-8fb0-914a5479baff"
/>

### Grid Pages

<img width="804" height="964" alt="Screenshot 2025-11-27 174055"
src="https://github.com/user-attachments/assets/a3bba7db-95df-47ec-9cfb-f38775ab960e"
/>



<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-12-10 20:51:42 -06:00
Guilherme
a08fc0921f [CmdPal] Introduce Small, Medium, and Large sizing options for Details (#43956)
<!-- 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 3 new sizing options to the Details Panel in the
Extensions API.
- `Small` (Default)
- `Medium`
- `Large`
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #43251
<!-- - [ ] 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

Here's how it looks like:
```csharp
new ListItem(new NoOpCommand())
{
    Title = "Details on ListItems (Medium)",
    Details = new Details()
    {
        Title = "This item has medium details size",
        Body = "Each of these items can have a `Body` formatted with **Markdown**",
        Size = ContentSize.Medium,
    },
},
```

### Moving Pictures


![DetailsSize](https://github.com/user-attachments/assets/ae11b767-ecba-4b39-bd81-3e77eec93ed0)


<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-12-10 19:25:45 -06:00
Gleb Khmyznikov
995bbdc62d Fix fancy zones UI tests #42249 (#44181)
- [ ] Closes: #42249

Contribution to https://github.com/microsoft/PowerToys/issues/40701
2025-12-10 10:04:04 -08:00
Jaylyn Barbee
f822826cf1 [Light Switch] Follow Night Light mode (#43683)
<!-- 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
Introduces a new mode that will have Light Switch follow Windows Night
Light.

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

- [x] Closes: https://github.com/microsoft/PowerToys/issues/42457
- [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
- [ ] **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
Strictly follows the state of Night Light. When NL is on, LS will be
switch to dark mode and when NL is off, LS will switch to light mode
(with respect to the users system/app selection).

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Turn on Follow Night Light mode
Change night light!

## Notes
2025-12-10 08:15:34 -05:00
Jiří Polášek
97c1de8bf6 CmdPal: Light, dark, pink, and unicorns (#43505)
<!-- 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 user settings for app mode themes (dark, light, or
system) and background customization options, including custom colors,
system accent colors, or custom images.

- Adds a new page to the Settings window with new appearance settings
and moves some existing settings there as well.
- Introduces a new core-level service abstraction, `IThemeService`, that
holds the state for the current theme.
- Uses the helper class `ResourceSwapper` to update application-level
XAML resources. The way WinUI / XAML handles these is painful, and XAML
Hot Reload is pain². Initialization must be lazy, as XAML resources can
only be accessed after the window is activated.
- `ThemeService` takes app and system settings and selects one of the
registered `IThemeProvider`s to calculate visuals and choose the
appropriate XAML resources.
  - At the moment, there are two:
    - `NormalThemeProvider`
      - Provides the current uncolorized light and dark styles  
      - `ms-appx:///Styles/Theme.Normal.xaml`
    - `ColorfulThemeProvider`
- Style that matches the Windows 11 visual style (based on the Start
menu) and colors
      - `ms-appx:///Styles/Theme.Colorful.xaml`  
- Applied when the background is colorized or a background image is
selected
- The app theme is applied only on the main window
(`WindowThemeSynchronizer` helper class can be used to synchronize other
windows if needed).
- Adds a new dependency on `Microsoft.Graphics.Win2D`.
- Adds a custom color picker popup; the one from the Community Toolkit
occasionally loses the selected color.
- Flyby: separates the keyword tag and localizable label for pages in
the Settings window navigation.


## Pictures? Pictures!

<img width="2027" height="1276" alt="image"
src="https://github.com/user-attachments/assets/e3485c71-7faa-495b-b455-b313ea6046ee"
/>

<img width="3776" height="2025" alt="image"
src="https://github.com/user-attachments/assets/820fa823-34d4-426d-b066-b1049dc3266f"
/>

Matching Windows accent color and tint:

<img width="3840" height="2160" alt="image"
src="https://github.com/user-attachments/assets/65f3b608-e282-4894-b7c8-e014a194f11f"
/>


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

- [x] Closes: #38444
- [ ] **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>
2025-12-09 18:56:03 -06:00
Kayla Cinnamon
0f8cf94d90 Update Community file (#44175)
<!-- 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
Moved myself to community since I'm now in a new role :)

It's been a blast being on this team <3

<!-- 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: Clint Rutkas <clint@rutkas.com>
2025-12-09 13:04:09 -05:00
Niels Laute
620f67a3ba [UX] Misc consistency improvements in Settings (#44174)
## Summary of the Pull Request

- Minor text changes (e.g. removing "Enable")
- Fixing a few bugs where textblocks did not look disabled
- Sorted mouse utils alphabetically
- Auto-collapsing expanders on the mouse utils to reduce visual clutter

<!-- 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
2025-12-09 17:50:45 +01:00
Kai Tao
23bc278cc8 Cmdpal: Fix cmdpal toolkit restore failure for slnx in release pipeline (#44152)
<!-- 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
Error from pipeline: 

Invalid input 'PowerToys.slnx'. The file type was not recognized.
MSBuild version 17.14.23+b0019275e for .NET Framework
Build started 12/8/2025 6:33:14 AM.

Nuget support for slnx will be ready in nuget version 7, so use msbuild
to restore

<!-- 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="606" height="681" alt="image"
src="https://github.com/user-attachments/assets/ca0486a7-0c07-4fad-a81e-b98767ea8005"
/>
2025-12-09 14:22:18 +08:00
leileizhang
73e379238b Add FancyZones CLI for command-line layout management (#44078)
<!-- 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 command-line interface (CLI) tool for FancyZones, enabling
users and automation scripts to manage window layouts without the GUI.

**Commands:**
| Command | Aliases | Description |
|---------|---------|-------------|
| `help` | | Displays general help information for all commands |
| `open-editor` | `editor`, `e` | Launch FancyZones layout editor |
| `get-monitors` | `monitors`, `m` | List all monitors and their
properties |
| `get-layouts` | `layouts`, `ls` | List all available layouts with
ASCII art preview |
| `get-active-layout` | `active`, `a` | Show currently active layout |
| `set-layout <uuid>` | `set`, `s` | Apply layout by UUID or template
name |
| `open-settings` | `settings` | Open FancyZones settings page |
| `get-hotkeys` | `hotkeys`, `hk` | List all layout hotkeys |
| `set-hotkey <key> <uuid>` | `shk` | Assign hotkey (0-9) to custom
layout |
| `remove-hotkey <key>` | `rhk` | Remove hotkey assignment |

**Key Capabilities:**
- ASCII art visualization of layouts (grid, focus, priority-grid,
canvas)
- Support for both template layouts and custom layouts
- Monitor-specific layout targeting (`--monitor N` or `--all`)
- Real-time notification to FancyZones via Windows messages
- Native AOT compilation support for fast startup

### Example Usage

```bash
# List all layouts with visual previews
FancyZonesCLI.exe ls

# Apply "columns" template to all monitors
FancyZonesCLI.exe s columns --all

# Set custom layout on monitor 2
FancyZonesCLI.exe s {uuid} --monitor 2

# Assign hotkey Win+Ctrl+Alt+3 to a layout
FancyZonesCLI.exe shk 3 {uuid}
```



https://github.com/user-attachments/assets/2b141399-a4ca-4f64-8750-f123b7e0fea7



<!-- 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
2025-12-09 10:13:48 +08:00
Dave Rayment
4710b816b4 [CmdPal] Optimise MainListPage's results display by merging already-sorted lists (#44126)
## Summary of the Pull Request
This PR replaces the current LINQ-based results compilation query of
combining, sorting and filtering the four result sources with a 3-way
merge operation plus a final append. It provides a performance increase
as well as a significant reduction in allocations.

<!-- 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
- [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
The existing code:
1. Limits the number of apps returned to a pre-defined maximum.
2. Sorts the apps list.
3. Appends filtered items, scored fallback items and the apps list
together.
4. Sorts the three lists based on their score.
5. Appends the non-scored fallback items, with empty items excluded.
6. Selects just the `Item` from each.
7. Creates an array from the enumerable.

```csharp
    if (_filteredApps?.Count > 0)
    {
        limitedApps = _filteredApps.OrderByDescending(s => s.Score).Take(_appResultLimit).ToList();
    }

    var items = Enumerable.Empty<Scored<IListItem>>()
                          .Concat(_filteredItems is not null ? _filteredItems : [])
                          .Concat(_scoredFallbackItems is not null ? _scoredFallbackItems : [])
                          .Concat(limitedApps)
                          .OrderByDescending(o => o.Score)

                          // Add fallback items post-sort so they are always at the end of the list
                          // and eventually ordered based on user preference
                          .Concat(_fallbackItems is not null ? _fallbackItems.Where(w => !string.IsNullOrEmpty(w.Item.Title)) : [])
                          .Select(s => s.Item)
                          .ToArray();
```

We can exploit the fact that each of the three 'scored' lists are
pre-ordered, and replace the query with a 3-way merge and final append
of the non-scored fallback items.

By pre-sizing the results array we can avoid all the extra allocations
of the LINQ-based solution.

### Proof of pre-ordering
In `UpdateSearchText`, each of the lists is defined by calling
`ListHelpers.FilterListWithScores`:

```csharp
    // Produce a list of everything that matches the current filter.
    _filteredItems = [.. ListHelpers.FilterListWithScores<IListItem>(newFilteredItems ?? [], SearchText, scoreItem)];
```

```csharp
    _scoredFallbackItems = ListHelpers.FilterListWithScores<IListItem>(newFallbacksForScoring ?? [], SearchText, scoreItem);
```

```csharp
    var scoredApps = ListHelpers.FilterListWithScores<IListItem>(newApps, SearchText, scoreItem);

...

    _filteredApps = [.. scoredApps];
```

In `FilterListWithScores`, the results are ordered by score:

```csharp
   var scores = items
        .Select(li => new Scored<T>() { Item = li, Score = scoreFunction(query, li) })
        .Where(score => score.Score > 0)
        .OrderByDescending(score => score.Score);
```

(This also makes the existing `OrderByDescending()` for `_filteredApps`
before the LINQ query redundant.)

### K-way merge
Since the results are pre-sorted, we can do a direct merge in linear
time. This is what the new `MainListPageResultFactory`'s `Create`
achieves. As the lists may be different sizes, the routine does a 3-way
merge, followed by a 2-way merge and a single list drain to finish. Each
element is only visited once.

### Benchmarks
A separate benchmark project is
[here](https://github.com/daverayment/MainListBench), written with
Benchmark.net.

The project compares the current LINQ-based solution against:
1. An Array-based algorithm which pre-assigns a results array and still
sorts the 3 scored sets of results. This shows a naive non-LINQ solution
which is still _O(n log n)_ because of the sort.
2. The k-way merge, which is described above. _O(n)_ for both time and
space complexity.
3. A heap merge algorithm, which uses a priority queue instead of
tracking each of the lists separately. (This is _O(n log k)_ in terms of
time complexity and _O(n + k)_ for space.)

Care is taken to ensure stable sorting of items. When preparing the
benchmark data, items with identical scores are assigned to confirm each
algorithm performs identically to the LINQ `OrderBy` approach, which
performs a stable sort.

Results show that the merge performs best in terms of both runtime
performance and allocations, sometimes by a significant margin. Compared
to the LINQ approach, merge runs 400%+ faster and with at most ~20% of
the allocations:

<img width="1135" height="556" alt="image"
src="https://github.com/user-attachments/assets/9f9d3932-1592-49d6-8a07-4ea3ba7a0cc5"
/>

<img width="1149" height="553" alt="image"
src="https://github.com/user-attachments/assets/ae9e9e0a-b255-4c1a-af4b-e791dea80fa4"
/>

See here for all charts and raw stats from the run:
https://docs.google.com/spreadsheets/d/1y2mmWe8dfpbLxF_eqPbEGvaItmqp6HLfSp-rw99hzWg/edit?usp=sharing

### Cons

1. Existing performance is not currently an issue. This could be seen as
a premature optimisation.
2. The new code introduces an inherent contract between the results
compilation routine and the lists, i.e. that they must be sorted.

This PR was really for research and learning more about CmdPal (and a
bit of algorithm practice because it's Advent of Code time), so please
feel free to reject if you feel the cons outweigh the pros.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
- Added unit tests to exercise the new code, which confirm that the
specific ordering is preserved, and the filtering and pre-trimming of
the apps list is performed as before.
- Existing non-UI unit tests run. NB: I _could not_ run any UI Tests on
my system and just got an early bail-out each time.
- Manual testing in (non-AOT) Release mode.
2025-12-08 15:01:56 -06:00
Sam Rueby
b8a0163419 CmdPal: Arrow keys move logical grid pages (#43870)
<!-- 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: #41939
<!-- - [ ] 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
Before

![Before](https://github.com/user-attachments/assets/49853e8d-9113-425c-8230-e49fb9b8d640)

After

![After](https://github.com/user-attachments/assets/a4597fe6-6503-4502-99cf-350425f5ef51)

I noticed the double "active" line around the items when the ListPage is
focused. I was unable to find where that is defined. Ideally, the
black-border would go away.

I tested with AOT turned on.

The behavior accounts for suggestions. If the SearchBar is focused and
there is a suggestion, right-arrow will [continue] to complete the
suggestion.
2025-12-08 12:13:33 -06:00
Gordon Lam
06fcbdac40 Update WinAppSDK to 1.8.3 (#44146)
<!-- 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 several dependencies to newer versions in the
`Directory.Packages.props` file. The main focus is on upgrading the
Microsoft Windows App SDK packages to ensure the project uses the latest
features and bug fixes.

Dependency version updates:

* Upgraded `Microsoft.WindowsAppSDK`,
`Microsoft.WindowsAppSDK.Foundation`, `Microsoft.WindowsAppSDK.AI`, and
`Microsoft.WindowsAppSDK.Runtime` to their latest respective versions,
replacing previous 1.8.25* releases with newer builds.
<!-- Please review the items on the PR checklist before submitting-->
2025-12-08 18:52:33 +08:00
leileizhang
d515c67def Improve install scope detection to prevent mixed user/machine installations (#43931)
<!-- 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 old implementation checked
`HKLM\Software\Classes\powertoys\InstallScope` first. If this key
existed (even as a remnant from incomplete uninstall), it would
immediately return `PerMachine` without validating the actual
installation.

### Fix
- Uses Windows standard Uninstall registry (most reliable source of
truth)
- Identifies PowerToys Bundle by exact `BundleUpgradeCode` GUID match 
- MSI component entries (always in HKLM) are automatically ignored since
they don't have `BundleUpgradeCode`
- Checks HKCU first, then HKLM, properly handling the fact that Bundle
location reflects true install scope

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

- [x] Closes: #43696
<!-- - [ ] 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
2025-12-08 13:34:33 +08:00
Noraa Junker
9439b6df41 [Settings] Create a global static instance of SettingsUtils (#44064)
<!-- 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

SettingsUtils is initialized multiple times over the whole solution.
This creates one singeltone instance (with the default settings), so it
only has to be initialized once (and improve performance a bit with
that)

<!-- 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
2025-12-08 11:55:51 +08:00
舰队的偶像-岛风酱!
a37add8f08 feat(cmdpal): add pinyin support for Chinese input method (#39354)
<!-- 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 ToolGood.Words.Pinyin package to support pinyin conversion
- Implement pinyin matching in StringMatcher class
- Update project dependencies and Directory.Packages.props

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

- [x] **Closes:** #38417 #39343
- [ ] **Communication:** I've discussed this with core contributors
already. If 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've completed a rough implementation of pinyin support, but since I'm
currently unsure where to add the toggle for pinyin support, this
feature is enabled by default for now.



https://github.com/user-attachments/assets/59df0180-05ad-4b4a-a858-29aa15e40fd2



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

---------

Signed-off-by: 舰队的偶像-岛风酱! <frg2089@outlook.com>
Co-authored-by: Yu Leng <yuleng@microsoft.com>
2025-12-08 11:14:00 +08:00
Gordon Lam
60deec6815 Using centralized package management for vcxproj (#43920)
## Summary of the Pull Request
This pull request updates the build system for several native and
managed projects, modernizing NuGet package management and improving
code analysis configuration. The main changes involve switching from
legacy `packages.config` and manual `.props`/`.targets` imports to
PackageReference style for native projects, updating package versions,
and streamlining code analysis settings.

**Build system modernization and package management:**

* Migrated native projects (`PowerToys.MeasureToolCore.vcxproj`,
`FindMyMouse.vcxproj`) from legacy `packages.config` and manual
`.props`/`.targets` imports to NuGet PackageReference style, simplifying
dependency management and build configuration. This includes removing
the `packages.config` file and related import/error logic, and
introducing `PackageReference` items for required packages.
[[1]](diffhunk://#diff-76320b3a74a9241df46edb536ba0f817d7150ddf76bb0fe677e2b276f8bae95aL3-R18)
[[2]](diffhunk://#diff-76320b3a74a9241df46edb536ba0f817d7150ddf76bb0fe677e2b276f8bae95aR41-L41)
[[3]](diffhunk://#diff-76320b3a74a9241df46edb536ba0f817d7150ddf76bb0fe677e2b276f8bae95aL145-R153)
[[4]](diffhunk://#diff-d3a7d80ebbca915b42727633451e769ed2306b418ef3d82b3b04fd5f79560f17L1-L17)
[[5]](diffhunk://#diff-0f27869c4e90c8fd2c81f5688c58da99afcc9e5767e69ef7938265dbb6928e0fL3-R13)
* Updated the centralized package versions in
`Directory.Packages.props`, adding new entries for `boost`,
`boost_regex-vc143`, `Microsoft.Windows.ImplementationLibrary`, and
`Microsoft.WindowsAppSDK.Foundation` to support the new build system and
dependencies.
[[1]](diffhunk://#diff-5baf5f9e448ad54ab25a091adee0da05d4d228481c9200518fcb1b53a65d4156R10-R11)
[[2]](diffhunk://#diff-5baf5f9e448ad54ab25a091adee0da05d4d228481c9200518fcb1b53a65d4156R74-R77)

**Code analysis improvements:**

* Added configuration to both native and managed projects
(`PowerToys.MeasureToolCore.vcxproj`, `MeasureToolUI.csproj`) to
suppress specific warnings (81010002) and exclude NuGet cache files from
code analysis, reducing noise and improving build performance.
[[1]](diffhunk://#diff-76320b3a74a9241df46edb536ba0f817d7150ddf76bb0fe677e2b276f8bae95aL3-R18)
[[2]](diffhunk://#diff-4f2b49a1a5cc7da36ee6d5044792ef681fd0ea5bea12db9ebd4c3090680d4b07R6-R11)

**Project reference and output handling:**

* Updated the managed project (`MeasureToolUI.csproj`) to handle native
project outputs more robustly, ensuring the WinMD and DLL files are
available at runtime and configuring the project reference to avoid
assembly reference issues.

**Compiler configuration:**

* Enhanced C++ compiler settings in `Cpp.Build.props` to treat
angle-bracket includes as external, disable warnings and analysis for
external headers, and optimize build performance.
2025-12-08 09:52:55 +08:00
Dave Rayment
7e791f2815 [ImageResizer] Fix Fill mode not cropping image when Shrink Only was engaged and scale was 1 (#43855)
## Summary of the Pull Request
This PR fixes an Image Resizer issue where **Fill** mode operations were
silently aborted when **Shrink Only** was enabled (the default) and
scale was 1.0 on one dimension, resulting in files that were renamed
according to the intended target size but which actually contained the
original, unmodified image.

This also fixes a latent bug regarding square images and the **Ignore
Orientation** setting, and improves the readability of the core
`Transform` method.

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

- [x] Closes: #43772
<!-- - [ ] 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
### Fix **Shrink Only** logic preventing the correct cropping of images
**Issue:**
When using **Fill** mode, the scaling factor is calculated based on the
larger dimension to ensure the image fills the target box. In scenarios
where one dimension matches the target and the other overflows (e.g.
shrinking a 100x100 pixel image to 50x100), the calculated scale factor
is `1.0`.

The previous `ShrinkOnly` logic included this:

```csharp
if (_settings.ShrinkOnly
        && _settings.SelectedSize.Unit != ResizeUnit.Percent
        && (scaleX >= 1 || scaleY >= 1))
    {
        return source;
    }
```

This correctly prevents `ShrinkOnly` operations from returning upscaled
result images, but it also exits too early for cases where the user is
cropping the image across one dimension only, leaving the other at scale
1. Effectively, the later cropping code is never run and instead of
returning the cropped image, the original is returned. The _intended_
target dimensions are correct, which results in the filename parts not
matching the resulting image size.

**Fix:**
The logic has been split between upscaling and cropping, so:

1. If the scale on either dimension is > `1.0`, return the source
(explicitly preventing upscaling for **Shrink Only** mode).
2. If the scale is <= `1.0` then check if the original dimensions exceed
the target dimensions. If a crop is required, proceed with it even if
the scale is exactly `1.0`.

### Fix for square images triggering orientation swap
**Issue:**
The "Ignore Orientation" check in the original code used a compound
boolean check:

```csharp
(originalWidth < originalHeight != width < height)
```

This clever but less than readable statement detects orientation
mismatches. The section also includes a logic issue. When the original
image was square, `originalWidth < originalHeight` evaluated to `false`,
treating it as Landscape. If the target dimensions were Portrait, the
logic detected a mismatch and swapped the target dimensions incorrectly,
which would crop the height instead of the width.

'Fortunately' this bug was masked by the first bug, as the crop code
would never be reached anyway.

**Fix:**
The orientation detection routine was refactored to explicitly check for
Landscape vs. Portrait states. Square images are now naturally excluded,
as they have neither Landscape nor Portrait orientations. This now
prevents the dimensions from being swapped.

### Refactoring/readability
The main `Transform` method has been cleaned up:

- Replaced widespread use of `var` with `double` and `int` for dimension
and scale calculations.
- Replaced the non-obvious XOR orientation check (`a < b != c < d`) with
named booleans (`isInputLandscape`, `isTargetPortrait` etc.) to make the
intent more self-documenting.
- New and expanded comments throughout.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Three new unit tests have been added to `ResizeOperationTests.cs` to
cover the **Fill** mode edge cases:

1. `TransformHonorsFillWithShrinkOnlyWhenCropRequired`: Verifies than an
image requiring a crop but no scaling is processed correctly (tests that
the original bug report is resolved).
2. `TransformHonorsFillWithShrinkOnlyWhenUpscaleAttempted`: Confirms
that when `ShrinkOnly` is set, any upscaling operations are still
blocked.
3. `TransformHonorsFillWithShrinkOnlyWhenNoChangeRequired`: Verifies
that the system returns the source if neither scaling nor cropping is
required.

I also manually verified the bug fix with a test 4000 x 6000 pixel
source file with 1920 x `Auto` **Fill** mode and **Shrink Only**
settings, mirroring the original user's settings, and their source and
target dimensions.
2025-12-08 09:45:46 +08:00
Noraa Junker
2b0ecc2979 Quick accent character set fixes (#43504)
<!-- 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 double uppercase theta character
* Fix some redundant special symbols

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

- [x] Closes: #43457 #43137 #41570
- [ ] **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
2025-12-07 19:36:05 +01:00
Jiří Polášek
45cf3de15d CmdPal: Fix a line-break in RDC extension error toasts (#44129)
<!-- 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 line break in the RDC extension toast message, replacing
unescaped \r with a new line (\r in the XML is not recognized as a new
line escape sequence).

<!-- 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
2025-12-07 10:18:02 +01:00
Jiří Polášek
bf8c548501 CmdPal: Make text of text Settings button on Command Bar localizable (#44128)
## Summary of the Pull Request

See title

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

- [x] Closes: #44108
<!-- - [ ] 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
2025-12-07 10:10:45 +01:00
Carlos Rafael Ramirez
121c6c0712 Add RGB hex color preview to Advanced Paste clipboard history (#43990)
<!-- 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 recognizing and displaying clipboard
items that are valid RGB hex color codes (such as `#FFBFAB` or `#abc`)
in the Advanced Paste module. It introduces logic to detect hex color
strings, converts them to color values, and updates the UI to show a
color preview for these items. The changes also include comprehensive
unit tests for the new functionality.

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

- [x] Closes: #43538
<!-- - [ ] 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

**Clipboard color detection and conversion:**

* Added `ClipboardItemHelper.IsRgbHexColor` method using a compiled
regex to identify valid hex color strings in clipboard text.
[[1]](diffhunk://#diff-7429196ad30cd0bce57b102669da4dc13d43a09579e99ceac7cc0f7dc101cd2bR62-R86)
[[2]](diffhunk://#diff-7429196ad30cd0bce57b102669da4dc13d43a09579e99ceac7cc0f7dc101cd2bR112-R114)
* Introduced `HexColorConverterHelper.ConvertHexColorToRgb` utility to
convert hex color strings to `Windows.UI.Color`, handling both 3-digit
and 6-digit formats.

**UI enhancements for color previews:**

* Updated `ClipboardHistoryItemPreviewControl` to include a color
preview grid that displays an ellipse filled with the detected color and
the color code as text, using the new `HexColorToBrushConverter`.
[[1]](diffhunk://#diff-2ed6014d4c17037b9cd0ab397e40b9069b1e7fe47a700673f34e8217d78124d5R29-R48)
[[2]](diffhunk://#diff-2ed6014d4c17037b9cd0ab397e40b9069b1e7fe47a700673f34e8217d78124d5R14)
[[3]](diffhunk://#diff-0c26c92697f6bb38fa40160fc8b18f0876ddc8d828a510034411001aa2e05063R1-R28)
* Modified logic in `ClipboardHistoryItemPreviewControl.xaml.cs` to
ensure color previews are shown only for detected color items and to
adjust visibility of text and glyph previews accordingly.

**Unit tests for color detection and conversion:**

* Added unit tests for hex color conversion
(`HexColorToColorConverterTests.cs`) and color detection logic
(`ClipboardItemHelperTests.cs`) to verify correct behavior for valid,
invalid, and edge-case inputs.
[[1]](diffhunk://#diff-d81d997d5fb414f1563c31c38681113aaa9c847ef05bb77662d30bd1310d6b8eR1-R61)
[[2]](diffhunk://#diff-185e8954ca6f061bf5d60d0c61ac6cfd87bd1a48ebda11a8172e3496a050fe85R1-R36)

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
* Copied to the clipboard a color encoded text like: #FFBFAB
* Opened Advanced Paste and noticed the color: 

<img width="467" height="309" alt="image"
src="https://github.com/user-attachments/assets/6cedce89-9833-4efb-abf9-3cfe8e8f32f0"
/>

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: crramirez <8397379+crramirez@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-07 09:54:10 +08:00
Jiří Polášek
e68526b8d8 CmdPal: Add configuration option for Escape key behavior (#43354)
## Summary of the Pull Request

This PR adds a new option to the **General** page in **Settings**:

Escape key behavior — a dropdown with the following choices:

- Clear search first, then go back
  - Current behavior.
  - If the search box contains text, it is cleared; otherwise goes back.
  - On the home page, CmdPal is dismissed.

- Go back
  - Leaves the search text intact.
- If the page is not transient, the search text reappears when
returning.
  - On the home page, CmdPal is dismissed.

- Hide window and go home (Always dismiss)
  - Immediately dismisses CmdPal and navigates to the home page.
  - Ignores the **Go home when activated** setting.
  - Search text is cleared.

- Hide window
  - Just hides the window.
  - Intended to be used with #43355.

This implementation preserves existing behavior, except for **Always
dismiss**, which always forces navigation to the home page.

## Pictures? Pictures!

<img width="1305" height="892" alt="image"
src="https://github.com/user-attachments/assets/562e5604-1da6-4fc6-8358-5053df9c573d"
/>


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

- [x] Closes: #38311
- [ ] **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
2025-12-05 16:32:24 -06:00
ruslanlap
995a699de7 [PowerToysRun][Docs] Add QuickAI plugin to third-party plugins list (#43238)
Adds QuickAI plugin to the third-party plugins documentation.

QuickAI is an AI-powered assistance plugin that provides instant, smart
responses from multiple providers (Groq, Together, Fireworks,
OpenRouter, Cohere) directly in PowerToys Run.

Repository: https://github.com/ruslanlap/PowerToysRun-QuickAi

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2025-12-05 10:21:01 -06:00
Copilot
5f6df35d8d Add semantic headings to Dashboard page for accessibility (#42438)
## Summary

Fixes #37668 by adding proper semantic heading structure to the
Dashboard (Home) page, enabling screen reader users to navigate the page
efficiently using heading shortcuts.

## Problem

The Dashboard page lacked semantic heading elements, making it difficult
for users of assistive technologies to understand the page structure and
navigate between sections. When using screen readers with heading
navigation (H key in scan mode), no headings were announced, violating
WCAG 2.2 Success Criterion 1.3.1 (Info and Relationships).

## Solution

Added `AutomationProperties.HeadingLevel` attributes to provide proper
heading hierarchy:

1. **Dashboard Title** - Marked as Level 1 (H1) heading
- Added `AutomationProperties.HeadingLevel="1"` to the "Home" page title
   - Follows the same pattern as `SettingsPageControl.xaml`

2. **Card Titles** - Marked as Level 2 (H2) headings  
- Added `AutomationProperties.HeadingLevel="Level2"` to the Card
component
- Applies to all card sections: "Quick Access", "Shortcuts Overview",
and "Utilities"
   - Follows the same pattern as `SettingsGroup.xaml`

## Resulting Structure

```
H1: Home (Dashboard Title)
├─ H2: Quick Access
├─ H2: Shortcuts Overview  
└─ H2: Utilities
```

## Impact

- Screen reader users can now use heading navigation (H key) to jump
between sections on the Dashboard page
- Provides proper document structure that follows WCAG 2.2 Level A
guidelines
- No visual or functional changes - only accessibility metadata added
- Consistent with existing accessibility patterns used throughout the
Settings UI

## Testing

- Changes follow existing patterns in `SettingsPageControl.xaml` (Level
1) and `SettingsGroup.xaml` (Level 2)
- Only XAML accessibility attributes added - no code logic changes
- Minimal, surgical changes: 2 lines across 2 files

## References

- Issue: #37668
- WCAG 2.2: [Success Criterion 1.3.1 - Info and
Relationships](https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships)

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



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>No Heading Defined on the Home Page.</issue_title>
> <issue_description>### Microsoft PowerToys version
> 
> v0.94.2
> 
> ### Installation method
> 
> PowerToys auto-update
> 
> ### Area(s) with issue?
> 
> New+
> 
> ### Steps to reproduce
> 
> **Repro Steps:**
> 
> 1. Open the Power Toys.
> 2. Now Select Home from the left navigation pane.
> 3. Now Turn on narrator and turn on scan mode.
> 4. Now use Quick navigation H key for headings.
> 5. Observe the issue.
> 
> ### ✔️ Expected Behavior
> 
> The home page should contain at least one semantic heading (typically
an <h1>) that describes the main topic or purpose of the page.
> 
> ###  Actual Behavior
> 
> The home page does not contain any semantic heading tags (e.g., <h1>,
<h2>, etc.). While text may be visually styled to look like headings, no
actual heading elements are present in the page’s HTML structure.
> 
> ### Additional Information
> 
> **User Impact:**
> Users of screen readers and other assistive technologies rely on
headings to understand the structure of the page and navigate
efficiently.
> 
> **WCAG Reference:**
> https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships
> 
> **Attachments:**
> 
>
https://github.com/user-attachments/assets/5140b50c-67fc-40d5-bf80-40e2a2bb7782
> 
> ### Other Software
> 
> _No response_</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>

Fixes microsoft/PowerToys#42421

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

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

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>
2025-12-05 10:20:33 -06:00
Noraa Junker
cffdecbc1b Add documentation of bot commands and fix some devdocs (#43399)
<!-- 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 location of `style.md` file
* Deletes duplicated `localization.md` file
* Adds documentation about the bot commands.
* Adds links to aka.ms link docs and the new document

<!-- 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
- [x] **Dev docs:** Added/updated
2025-12-05 14:55:45 +01:00
Noraa Junker
a4d8405957 Fix dpi issues in Quick Accent (#43314)
<!-- 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: #40865
- [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
2025-12-05 14:54:13 +01:00
Niels Laute
cdf66a70e9 [AdvancedPaste] Fix outdated string in Settings (#44099)
Updating and removing outdated strings.

Updated string:

<img width="1565" height="323" alt="image"
src="https://github.com/user-attachments/assets/3dcad3b9-7ba9-4d87-ab36-405a8e1705db"
/>
2025-12-05 21:33:59 +08:00
Valentin Arthur Thomas
9dcddfd4b8 Quotation mark (#30481)
<!-- 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 Quotation mark
Add local quotation based on ~~VK_OEM_7(0xDE)~~ VK_OEM_COMMA(0xBC) key.
Not all quotes have been added, only `‟ „ ” « » ‚ , ‘ ’ › ‹ '「 」 《 》 『
』〈 〉″ ‴ ⁗`
Why not added :
- ` ⹂ ⌜ ⌝ ❛ ❜ ❝ ❞ 🙶 🙷 🙸 ' 「 」 ` its redundant and would make too much
and not readable.
- ` ﹁ ﹂ ﹃ ﹄ `  I did not put them because there use for horizontal text


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

- [x] Closes: https://github.com/microsoft/PowerToys/issues/29371
https://github.com/microsoft/PowerToys/issues/24832
- [ ] **Communication:** I've discussed this with core contributors
already. If 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 (None)
- [ ] [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 -->
This PR is currently a draft, I still need to know if adding
language-related keyboard management is a good idea or specifying the
use of a gobal key to make it easier to manage all the keyboards in one.
Some languages ​​can use different keyboards, I think this would become
problematic if the keyboard does not match the key used by default.
However, using a universal key can also pose an issue to finding the
key. that remains to be discussed
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-12-05 11:57:01 +01:00
Copilot
503bcbdf2d Restore missing "Quick access" menu item in tray icon context menu (#42676)
## Summary
Restores the "Quick access" menu item that was accidentally removed from
the PowerToys tray icon context menu.

## Issue
Fixes #[issue_number]

The "Quick access" menu item was missing from the tray icon's
right-click context menu, preventing users from accessing this feature
via the tray menu.

**Expected menu:**

![Expected
menu](https://github.com/user-attachments/assets/805b1436-5a08-42e7-a34d-b9848fd9a235)

**Actual menu (before this fix):**

![Actual
menu](https://github.com/user-attachments/assets/7584035d-e893-4f73-acc3-84d789e31e81)

## Changes
- Added the missing `MENUITEM "Quick access\tLeft-click",
ID_QUICK_ACCESS_MENU_COMMAND` entry as the first menu item in the
`ID_TRAY_MENU` definition in `src/runner/runner.base.rc`

## Details
The menu item was accidentally removed in commit
f5797a065a. This PR restores it to its
correct position as the first item in the tray menu.

All supporting code was already in place:
- The resource ID `ID_QUICK_ACCESS_MENU_COMMAND` (40006) is defined in
`resource.base.h`
- The resource string `QUICK_ACCESS_MENU_TEXT` is defined in
`Resources.resx`
- The menu command handler in `tray_icon.cpp` opens the Quick Access
flyout window
- The localization code updates the menu text at runtime

## Testing
-  Verified the menu item syntax is correct and matches existing
patterns
-  Confirmed all supporting resource IDs and handler code exist
-  CI build verification pending

After this fix, the tray menu will correctly display:
1. Quick access (Left-click)
2. Settings (Double-click)
3. Documentation
4. Report Bug
5. Close

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



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Quick Access missing in tray menu</issue_title>
> <issue_description>### Microsoft PowerToys version
> 
> 0.95.0
> 
> ### Installation method
> 
> PowerToys auto-update
> 
> ### Area(s) with issue?
> 
> System tray interaction
> 
> ### Steps to reproduce
> 
> 1. Right click the tray icon
> 2. Look at the list of items which can be selected
> 3. Notice that the "Quick access" is missing
> 
> Expected menu ("Exit" is now "Close" I took this image from initial
implementation):
> 
> <img width="234" height="127" alt="Image"
src="https://github.com/user-attachments/assets/805b1436-5a08-42e7-a34d-b9848fd9a235"
/>
> 
> Actual menu right now:
> 
> <img width="239" height="105" alt="Image"
src="https://github.com/user-attachments/assets/7584035d-e893-4f73-acc3-84d789e31e81"
/>
> 
> ### ✔️ Expected Behavior
> 
> The "Quick access" menu item should be there
> 
> ###  Actual Behavior
> 
> The menu item is missing
> 
> ### Additional Information
> 
> Windows 10 Pro 22H2 19045.6332
> 
> (Also it is the same on my other computers)
> 
> ### Other Software
> 
> _No response_</issue_description>
> 
> <agent_instructions>restore
> 
> MENUITEM "Quick access\tLeft-click", ID_QUICK_ACCESS_MENU_COMMAND
> 
> as first menu item of ID_TRAY_MENU MENU in
src/runner/runner.base.rc</agent_instructions>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> <comment_new><author>@niels9001</author><body>
> @davidegiacometti is this a regression from the PR where we updated
the string names?</body></comment_new>
> <comment_new><author>@davidegiacometti</author><body>
> Hi @niels9001 
> I just realized that the menu was missing in
https://github.com/microsoft/PowerToys/pull/40714 screenshots, but the
regression was caused by
f5797a065a.
> Unfortunately, many of the `.rc` files in the PT codebase have
UTF16-LE encoding and GitHub doesn't show diff.</body></comment_new>
> </comments>
> 


</details>

Fixes microsoft/PowerToys#42618

<!-- 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>
2025-12-05 07:33:37 +01:00
Jiří Polášek
52f2561937 CmdPal: Find app for WinGet package (#43943)
<!-- 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 bit of dark magic to resolve the correct installed
app for a given WinGet package:

- Packaged apps: matched using their package family name.
- Everything else: matched using the product code (GUID) and heuristic
registry lookup.
- The registry rarely stores the executable path directly, so the logic
compares install locations with known apps.
  - It attempts to pick the best candidate while avoiding uninstallers.
  - It’s not science — let’s call it `#666666` magic.
- MSI API support was removed because it's too slow for this scenario.
- If no reliable match is found, the command is skipped for now. The
future plan is to redirect the user to the list of installed apps and
search by display name, but that needs some supporting infrastructure
first.
- The command order for WinGet list entries was updated: **Install /
Uninstall** is now the primary action, ensuring a stable UI since this
command is always available.


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

- [x] Closes: #43671
<!-- - [ ] 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
2025-12-03 10:16:25 -06:00
Dustin L. Howett
dc30f3fd8e build: move main and setup to SLNX (#43478)
Closes #37100

This does not migrate the rest of the solutions (why do we have so
many?)

Not migrated:

- TemplateCmdPalExtension.sln
- FancyZonesEditor.sln
- BugReportTool.sln
- CleanUp_tool.sln
- FancyZones_DrawLayoutTest.sln
- FancyZones_zonable_tester.sln
- FancyZone_HitTest.sln
- MonitorReportTool.sln
- PowerToyTemplate.sln
- StylesReportTool.sln

---------

Co-authored-by: vanzue <vanzue@outlook.com>
2025-12-03 17:59:46 +08:00
Jessica Dene Earley-Cha
8f9a2c32cc add missing powertoys events (#44016)
## Summary of the Pull Request
This added missing telemetry events from modules that were not listed in
DATA_AND_PRIVACY

## 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
2025-12-02 09:59:57 -08:00
moooyo
bcd1583bb7 [AOT] Refactor SettingsLib/SettingsUI for Native AOT compatibility (#42644)
<!-- 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

Key Changes:

1. Settings.UI.Library:
- Added SettingsSerializationContext.cs with comprehensive
JsonSerializable attributes for all settings types
- Updated BasePTModuleSettings.ToJsonString() to use AOT-compatible
serialization
- Updated SettingsUtils.GetFile<T>() to use AOT-compatible
deserialization
- Modified all ToString() methods in Properties classes to use
SettingsSerializationContext
- Converted struct fields to properties in SunTimes and
MouseWithoutBordersProperties for serialization compatibility

2. Settings.UI:
- Fixed namespace alias in SourceGenerationContextContext.cs to avoid
conflicts

For any future developers who discover incorrect settings resolution,
please follow up my changes to add your setting type into
JsonSerilizerContext.



<!-- 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

<!-- 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>
2025-12-02 16:31:02 +08:00
Carlos Zamora
b075a021df Bump our telemetry package version (#44015)
Data collection is still hard.

This just makes it so that the build pipeline uses the updated PowerToys
telemetry NuGet package. The updated package switches us over to use a
diagnostic data provider group for compliance with some new regulations
(i.e. DMA and EU Data Act).
2025-12-02 07:09:08 +01:00
Michael Clayton
9e43c23216 Ready for Review - [Mouse Without Borders] - refactoring "Common" classes (Part 6 of 7) (#43208)
## Summary of the Pull Request

**Part 6** of a [slow-running 7-part
refactor](https://github.com/microsoft/PowerToys/issues/35155#issuecomment-2583334110)
of the giant "Common" class in Mouse Without Borders into individual
classes with tighter private scope.

In this PR:

* Extract the "Common" code from the following files:
  * ```Common.Encryption.cs```-> ```Core/Encryption.cs```
  * ```Common.Package.cs``` -> ```Core/<multiple files>.cs```
* ```Common.ShutdownWithPowerToys.cs``` ->
```Core/ShutdownWithPowerToys.cs```
  * ```Common.VK.cs``` -> ```Core/VK.cs```, ```Core/WM.cs```
  * ```Common.WinAPI.cs``` -> ```Core/WinAPI.cs```
* Update references to the types in the new locations
* Update unit test to verify functionality has only changed in an
expected way

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

- [x]      Partially addresses #35155 
- [x] **Communication:** I've discussed this with core contributors
already. If 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
   - no changes in this PR
- [x]     **Dev docs:** Added/updated
   - no changes in this PR
- [x]     **New binaries:** Added on the required places
   - no changes in this PR
- [ ] [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)
- [x] **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
   - no changes in this PR

<!-- 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

### Run manual tests from [Test Checklist
Template](5bc7201ae2/doc/releases/tests-checklist-template.md (mouse-without-borders)):

* Install PowerToys on two PCs in the same local network:
   - [x]     Verify that PowerToys is properly installed on both PCs.
   - [x]     Configure Windows Firewall Rules
- ```netsh advfirewall firewall add rule
name="PowerToys.MouseWithoutBorders - mc" dir=in action=allow
program="C:\src\mc\PowerToys\x64\Debug\PowerToys.exe" enable=yes
remoteip=any profile=any protocol=tcp```
   
 * Setup Connection:
- [x] Open MWB's settings on the first PC and click the "New Key"
button. Verify that a new security key is generated.
- [x] Copy the generated security key and paste it in the corresponding
input field in the settings of MWB on the second PC. Also enter the name
of the first PC in the required field.
- [x] Press "Connect" and verify that the machine layout now includes
two PC tiles, each displaying their respective PC names.
   
 * Verify Connection Status:
- [x] Ensure that the border of the remote PC turns green, indicating a
successful connection.
- [x] Enter an incorrect security key and verify that the border of the
remote PC turns red, indicating a failed connection.
   
 * Test Remote Mouse/Keyboard Control:
- [x] With the PCs connected, test the mouse/keyboard control from one
PC to another. Verify that the mouse/keyboard inputs are correctly
registered on the other PC.
- [ ] Test remote mouse/keyboard control across all four PCs, if
available. Verify that inputs are correctly registered on each connected
PC when the mouse is active there.
     - unable to test - only 2 machines available
   
 * Test Remote Control with Elevated Apps:
- note - the main PowerToys.exe must be running as a **non**-admin for
these tests
- [x] Open an elevated app on one of the PCs. Verify that without "Use
Service" enabled, PowerToys does not control the elevated app.
- [x] Enable "Use Service" in MWB's settings (need to run PowerToys.exe
as admin to enable "Use Service", then restart PowerToys.exe as
non-admin). Verify that PowerToys can now control the elevated app
remotely. Verify that MWB processes are running as LocalSystem, while
the MWB helper process is running non-elevated.
- ```get-process -Name "PowerToys.MouseWithoutBorders*" -IncludeUserName
| format-table Id, ProcessName, UserName```
- [x] Process: ```PowerToys.MouseWithoutBorders.exe``` - running as
```SYSTEM```
- [x] Process: ```PowerToys.MouseWithoutBorders.Helper.exe``` - running
as current user
- ```get-service -Name "PowerToys.*" | ft Status, Name, UserName;
get-ciminstance -Class "Win32_Service" -Filter "Name like 'PowerToys%'"
| ft ProcessId, Name```
- [x] Service: ```PowerToys.MWB.Service``` - running as ```Local
System```
- [x] Toggle "Use Service" again, verify that each time you do that, the
MWB processes are restarted.
- [x] Run PowerToys elevated on one of the machines, verify that you can
control elevated apps remotely now on that machine.

* Test Module Enable Status:
- [x] For all combinations of "Use Service"/"Run PowerToys as admin",
try enabling/disabling MWB module and verify that it's indeed being
toggled using task manager.
   
 * Test Disconnection/Reconnection:
- [x] Disconnect one of the PCs from network. Verify that the machine
layout updates to reflect the disconnection.
   - [x]     Do the same, but now by exiting PowerToys.
   - [ ]     Start PowerToys again, verify that the PCs are reconnected.
  
 * Test Various Local Network Conditions:
- [ ] Test MWB performance under various network conditions (e.g., low
bandwidth, high latency). Verify that the tool maintains a stable
connection and functions correctly.

 * Clipboard Sharing:
- [x] Copy some text on one PC and verify that the same text can be
pasted on another PC.
- [x] Use the screenshot key and Win+Shift+S to take a screenshot on one
PC and verify that the screenshot can be pasted on another PC.
- [x] Copy a file in Windows Explorer and verify that the file can be
pasted on another PC. Make sure the file size is below 100MB.
- [x] Try to copy multiple files and directories and verify that it's
not possible (only the first selected file is being copied).
 
 * Drag and Drop:
- [ ] Drag a file from Windows Explorer on one PC, cross the screen
border onto another PC, and release it there. Verify that the file is
copied to the other PC. Make sure the file size is below 100MB.
- [ ] While dragging the file, verify that a corresponding icon is
displayed under the mouse cursor.
- [ ] Without moving the mouse from one PC to the target PC, press
CTRL+ALT+F1/2/3/4 hotkey to switch to the target PC directly and verify
that file sharing/dropping is not working.

 * Lock and Unlock with "Use Service" Enabled:
   - [x]     Enable "Use Service" in MWB's settings.
- [x] Lock a remote PC using Win+L, move the mouse to it remotely, and
try to unlock it. Verify that you can unlock the remote PC.
- [x] Disable "Use Service" in MWB's settings, lock the remote PC, move
the mouse to it remotely, and try to unlock it. Verify that you can't
unlock the remote PC.

 * Test Settings:
- [ ] Change the rest of available settings on MWB page and verify that
each setting works as described.

### Group Policy Tests

See https://learn.microsoft.com/en-us/windows/powertoys/grouppolicy

- [ ] Install *.admx / *.adml and check settings behave as expected
  - [ ] I'll expand the list of settings here when I get this far :-)
- [ ] HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys
  - [x]     ConfigureEnabledUtilityMouseWithoutBorders
- [x] ```[missing]``` - "Activation -> Enable Mouse Without Borders"
enabled, with GPO warning hidden
- ```reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
ConfigureEnabledUtilityMouseWithoutBorders /f```
- [x] ```0``` - "Activation -> Enable Mouse Without Borders" set to
"off" and disabled, with GPO warning visible
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
ConfigureEnabledUtilityMouseWithoutBorders /t REG_DWORD /d 0 /f```
- [x] ```1``` - "Activation -> Enable Mouse Without Borders" set to "on"
and disabled, with GPO warning visible
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
ConfigureEnabledUtilityMouseWithoutBorders /t REG_DWORD /d 1 /f```
  - [ ] MwbClipboardSharingEnabled
  - [ ] MwbFileTransferEnabled
  - [ ] MwbUseOriginalUserInterface
  - [ ] MwbDisallowBlockingScreensaver
  - [ ] MwbSameSubnetOnly
  - [ ] MwbValidateRemoteIp
  - [x]     MwbDisableUserDefinedIpMappingRules
- [x] ```[missing]``` - "Advanced Settings -> IP address mapping"
enabled, with GPO warning hidden
- ```reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbDisableUserDefinedIpMappingRules /f```
- [x] ```0``` - "Advanced Settings -> IP address mapping" enabled, with
GPO warning hidden
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbDisableUserDefinedIpMappingRules /t REG_DWORD /d 0 /f```
- [x] ```1``` - "Advanced Settings -> IP address mapping" disabled, with
GPO warning visible
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbDisableUserDefinedIpMappingRules /t REG_DWORD /d 1 /f```
  - [x]     MwbPolicyDefinedIpMappingRules
- [x] ```[missing]``` - "Advanced Settings -> IP address mapping"
enabled, with GPO warning and GPO values hidden
- ```reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbPolicyDefinedIpMappingRules /f```
- [x] ```[empty value]``` - "Advanced Settings -> IP address mapping"
enabled, with GPO warning hidden and GPO values hidden
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbPolicyDefinedIpMappingRules /t REG_MULTI_SZ /d "" /f```
- [x] ```[non-empty value]``` - "Advanced Settings -> IP address
mapping" enabled, with GPO warning visible and GPO values visible
- ```reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\PowerToys /v
MwbPolicyDefinedIpMappingRules /t REG_MULTI_SZ /d "aaa 10.0.0.1\0bbb
10.0.0.2" /f```
2025-12-02 10:43:08 +08:00
Jiří Polášek
bece9c9217 CmdPal: Adds a back button to Settings window (#44013)
## Summary of the Pull Request

This PR introduces proper navigation support in the Settings window.
- Enables the Go back button in the title bar.
- Adds support for Alt + Left Arrow, mouse X1 button, and the Go back
button.
- Fixes breadcrumb updates and localization issues to prevent them from
breaking during navigation.

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

- [x] Closes: #44011
<!-- - [ ] 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
2025-12-01 20:25:38 -06:00
Jiří Polášek
32c13cead4 CmdPal: Remove fallbacks from the home page when there's no query (#44005)
## Summary of the Pull Request

This PR stops fallback commands from showing on the homepage when
there’s no query, with the reasons detailed in the linked issue.

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

- [x] Closes: #44004 
<!-- - [ ] 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
2025-12-01 13:24:54 -06:00
Jiří Polášek
33808fdb9c CmdPal: Hide RDC fallback item by default (#43994)
## Summary of the Pull Request

This fixes few nits with RDC extension:
- hides the RDC fallback item from the home page when there’s no query;
- fixes MSTSC process working directory (must physically exists or be an
empty string)

<!-- 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
2025-12-01 13:23:48 -06:00
dependabot[bot]
f510be4c53 Build(deps): Bump actions/checkout from 3 to 6 (#43838)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to
6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>v6-beta by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2298">actions/checkout#2298</a></li>
<li>update readme/changelog for v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2311">actions/checkout#2311</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v5.0.0...v6.0.0">https://github.com/actions/checkout/compare/v5.0.0...v6.0.0</a></p>
<h2>v6-beta</h2>
<h2>What's Changed</h2>
<p>Updated persist-credentials to store the credentials under
<code>$RUNNER_TEMP</code> instead of directly in the local git
config.</p>
<p>This requires a minimum Actions Runner version of <a
href="https://github.com/actions/runner/releases/tag/v2.329.0">v2.329.0</a>
to access the persisted credentials for <a
href="https://docs.github.com/en/actions/tutorials/use-containerized-services/create-a-docker-container-action">Docker
container action</a> scenarios.</p>
<h2>v5.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v5...v5.0.1">https://github.com/actions/checkout/compare/v5...v5.0.1</a></p>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
<li>Prepare v5.0.0 release by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2238">actions/checkout#2238</a></li>
</ul>
<h2>⚠️ Minimum Compatible Runner Version</h2>
<p><strong>v2.327.1</strong><br />
<a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Release
Notes</a></p>
<p>Make sure your runner is updated to this version or newer to use this
release.</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v5.0.0">https://github.com/actions/checkout/compare/v4...v5.0.0</a></p>
<h2>v4.3.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v4.3.1">https://github.com/actions/checkout/compare/v4...v4.3.1</a></p>
<h2>v4.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>V5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>V5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>V4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1af3b93b68"><code>1af3b93</code></a>
update readme/changelog for v6 (<a
href="https://redirect.github.com/actions/checkout/issues/2311">#2311</a>)</li>
<li><a
href="71cf2267d8"><code>71cf226</code></a>
v6-beta (<a
href="https://redirect.github.com/actions/checkout/issues/2298">#2298</a>)</li>
<li><a
href="069c695914"><code>069c695</code></a>
Persist creds to a separate file (<a
href="https://redirect.github.com/actions/checkout/issues/2286">#2286</a>)</li>
<li><a
href="ff7abcd0c3"><code>ff7abcd</code></a>
Update README to include Node.js 24 support details and requirements (<a
href="https://redirect.github.com/actions/checkout/issues/2248">#2248</a>)</li>
<li><a
href="08c6903cd8"><code>08c6903</code></a>
Prepare v5.0.0 release (<a
href="https://redirect.github.com/actions/checkout/issues/2238">#2238</a>)</li>
<li><a
href="9f265659d3"><code>9f26565</code></a>
Update actions checkout to use node 24 (<a
href="https://redirect.github.com/actions/checkout/issues/2226">#2226</a>)</li>
<li><a
href="08eba0b27e"><code>08eba0b</code></a>
Prepare release v4.3.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2237">#2237</a>)</li>
<li><a
href="631c7dc4f8"><code>631c7dc</code></a>
Update package dependencies (<a
href="https://redirect.github.com/actions/checkout/issues/2236">#2236</a>)</li>
<li><a
href="8edcb1bdb4"><code>8edcb1b</code></a>
Update CODEOWNERS for actions (<a
href="https://redirect.github.com/actions/checkout/issues/2224">#2224</a>)</li>
<li><a
href="09d2acae67"><code>09d2aca</code></a>
Update README.md (<a
href="https://redirect.github.com/actions/checkout/issues/2194">#2194</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/checkout/compare/v3...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3&new-version=6)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-12-01 22:29:21 +08:00
Jiří Polášek
4d3c223402 CmdPal: Fix grid views (#43991)
## Summary of the Pull Request

This PR fixes the crash due to binding to a trimmed property. For this
it converts runtime bindings on GridView to use `{x:Bind}` so this issue
can't happen in the future.

- Fixes a crash related to the `Visibility` property in gallery/grid
views when trimmed during AOT builds.
- Fixes ShowTitle and ShowSubtitle properties, they are now taken into
account in a view.
- Improves UI layout, removes some margins and maches the corner radius
of the item contaienr with the item content in the gallery view.
- Refactores gallery and grid views to move logic from the view to the
view model so we can x:Bind to them.
- Replaces `{Binding}` with `{x:Bind}` to improve performance and enable
compile-time binding validation.
- Properties related to grids are splatted on to the common
`IGridPropertiesViewModel` interface. Subclassing would add extra
overhead without substential benefit.
- Adds new samples to showcase various grid view configurations.

## Pictures? Pictures!

A) Gallery view (with title and subtitle)
<img width="909" height="583" alt="image"
src="https://github.com/user-attachments/assets/b807e7a8-412f-4817-8121-e3470c49e0c0"
/>

B) Gallery view (only title)
<img width="903" height="582" alt="image"
src="https://github.com/user-attachments/assets/b619d63f-04d0-42f2-9207-de256dc5e481"
/>

C) Gallery view (no title or subtitle)
<img width="900" height="583" alt="image"
src="https://github.com/user-attachments/assets/c48cd1fc-8f51-40c1-8bce-607916e9f742"
/>

D) Small icons
<img width="907" height="582" alt="image"
src="https://github.com/user-attachments/assets/8327da0a-fa45-443f-b52c-f0f1edd7b861"
/>

E) Medium icons (with labels)
<img width="914" height="588" alt="image"
src="https://github.com/user-attachments/assets/dee9fab1-54e8-45f8-96d7-502b121a6ac2"
/>

F) Medium icons (no labels)
<img width="915" height="588" alt="image"
src="https://github.com/user-attachments/assets/a32e8af2-6cb1-4106-91db-ca396253c0a3"
/>


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

- [x] Closes: #43973
<!-- - [ ] 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
2025-11-30 19:32:30 -06:00
Jiří Polášek
1ba5a258e9 CmdPal: Add custom search engine option to Web Search extension (#43941)
## Summary of the Pull Request

This PR allows user to customize a search query in Command Palette's Web
Search built-in extension. This will also solve a problem with some
browser that doesn't handle argument in form "? <query>" as it will
allow user to specify the complete URI.

- Introduces a new text box in Web Search extension settings for
specifying a custom search engine URI
- If the text box is non-empty, the provided URI is used for queries
- If left empty, the extension defaults to previous behavior, sending
queries in the format "? query"

## Pictures? Pictures!

<img width="825" height="566" alt="image"
src="https://github.com/user-attachments/assets/fbf3d3a5-ebfe-4c16-a5f1-0d044b6f9047"
/>

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

- [x] Closes: #43940 
- [x] Closes: #42867 
<!-- - [ ] 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
2025-11-29 18:59:58 -06:00
Jiří Polášek
8aea589b01 CmdPal: Align spellchecker and naming to .NET guidelines (#43974)
## Summary of the Pull Request

- Add command-line parameter value (icf)
- Unify file and class name casing to match .NET naming conventions (RDP
-> Rdp as Url, Dns, Xml) -- fixes IRDP spellchecking error
- Rename IRdpConnectionManager to IRdpConnectionsManager (*s) to match
the class name

<!-- 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
2025-11-29 17:36:55 -06:00
Clint Rutkas
afd9d4cc3c Update PowerToys download links to version 0.96.1 (#43965)
<!-- 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
2025-11-30 00:11:17 +01:00
Jiří Polášek
bc0a760aff CmdPal: Add mini dev center (#43939)
## Summary of the Pull Request

This PR introduces a small ribbon to the CmdPal for app developers. The
dev ribbon is dynamically added to the main window in local (non-CI)
builds. It shows the number of logged errors and warnings, the current
build configuration (Debug or Release), and whether it’s built with AOT.

The flyout shows the latest errors and warnings and lets you quickly
access the logs.


## Pictures? Pictures!

<img width="985" height="589" alt="image"
src="https://github.com/user-attachments/assets/6528b02b-b4b4-4968-91bf-e67a29f86415"
/>


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

- [x] Closes: #43318
<!-- - [ ] 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
2025-11-29 16:23:24 -06:00
Michael Jolley
06afe09973 CmdPal: New Remote Desktop built-in extension (#43090)
This PR introduces a new built-in extension for Remote Desktop users.

It allows you to view past RDP connections, save predefined connections,
and connect to any of them. Or start a new RDP connection.


https://github.com/user-attachments/assets/6a5041a6-5741-4df0-a305-da7166f962e1

### GitHub issue maintenance stuff

Closes #38305

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Jiří Polášek <me@jiripolasek.com>
2025-11-29 13:07:19 -06:00
Jiří Polášek
0de60445ea CmdPal: Use Shell API to determine the default browser in WebSearch (#43339)
## Summary of the Pull Request

This PR introduces a new method for determining the default browser
using the Windows Shell API. The new provider selects the browser
associated with the HTTPS protocol (falling back to HTTP if necessary).
The original implementation is retained as a fallback for now, and the
codebase is prepared for future extensions (e.g., manual default-browser
selection).

As a flyby, it also fixes an issue where commands continued showing the
previous browser name if the user changed their default browser while
the Command Palette was running.

## One-liner for change log

Fixed default browser selection in the Web Search built-in extension.

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

- [x] Closes: #42343
- [ ] **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
2025-11-27 09:31:10 -06:00
Jiří Polášek
47d4a65223 CmdPal: Add option to return to home automatically after a delay (#43551)
## Summary of the Pull Request

This PR replaces the Go home when activated setting with a new
Automatically return home option. This allows users to specify how long
the Command Palette should wait after being dismissed before
automatically returning to the home page. It also introduces migration
logic to transition from the old setting to the new one.

## Pictures? Pictures!

<img width="1337" height="762" alt="image"
src="https://github.com/user-attachments/assets/c649ef03-b3ee-40ba-ac67-485bc40efa73"
/>


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

- [x] Closes: #43355 
<!-- - [ ] 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
2025-11-27 09:24:47 -06:00
Kai Tao
1b72c0b969 Update check-spelling expect list (#43925)
<!-- 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

Spell no complain
2025-11-27 17:22:59 +08:00
Pratyush Nalam
9160c82fc2 Update Command Palette's Learn More string to be consistent with other utilities (#43898)
<!-- 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 the PowerToys "What's new" window, every utility has the text "Learn
more about <utility name>" next to the "Settings" button. Examples
below:

<img width="247" height="38" alt="learnmore-fancyzones"
src="https://github.com/user-attachments/assets/fecdeb4b-e01c-438d-8d11-c056e613768e"
/>
<img width="258" height="40" alt="learnmore-textextractor"
src="https://github.com/user-attachments/assets/ffb0c801-5b89-46d1-b493-b57287303e65"
/>

The only exception is the Command Palette utility which just says "Learn
more".

<img width="152" height="32" alt="learnmore-cmdpal"
src="https://github.com/user-attachments/assets/232c11cd-b621-46eb-87f1-d3fc708d6286"
/>

This is an inconsistency and this PR fixes that string.

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

- [x] Closes: #43897
<!-- - [ ] 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
2025-11-27 00:45:06 +01:00
Mike Hall
452e0dcf51 Module Loader tool for rapid testing of modules (#43813)
## Summary of the Pull Request
ModuleLoader tool, a stand-alone Win32 executable for testing of
PowerToy modules without needing branch builds.

sample output from running the tool is below:

.\ModuleLoader.exe .\powertoys.cursorwrap.dll
PowerToys Module Loader v1.0
=============================

Loading module: .\powertoys.cursorwrap.dll
Detected module name: cursorwrap

Loading settings...
Trying settings path:
C:\Users\mikehall\AppData\Local\Microsoft\PowerToys\cursorwrap\settings.json
Settings file loaded (315 characters)
Settings loaded successfully.

Loading module DLL...
Module instance created successfully
Module DLL loaded successfully.
Module key: CursorWrap
Module name: CursorWrap

Applying settings to module...
Settings applied.

Registering module hotkeys...
Module reports 1 legacy hotkey(s)
  Registering hotkey 0: Win+Alt+U - OK
Hotkeys registered: 1

Enabling module...
Module enabled.

=============================
Module is now running!
=============================

Module Status:
  - Name: CursorWrap
  - Key: CursorWrap
  - Enabled: Yes
  - Hotkeys: 1 registered

Registered Hotkeys:
  Win+Alt+U

Press Ctrl+C to exit.
You can press the module's hotkey to toggle its functionality.

Note that this doesn't integrate with Powertoys settings UI - this is
purely to test Powertoys module functionality.

## 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

## Detailed Description of the Pull Request / Additional comments
See details above.

## Validation Steps Performed
ModuleLoader tested on Windows 11, Surface Laptop 7 Pro.
2025-11-26 22:08:34 +08:00
Jiří Polášek
2c9a9e9fca CmdPal: Improve Command Palette behavior in "Last position" mode (#43543)
## Summary of the Pull Request

This PR improves Command Palette behavior in “Last position” mode:
- Correctly handles DPI changes between monitors.
- Ensures the window is always visible — if it’s fully off-screen or has
less than 100px visible on any axis, it is re-centered.



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

- [x] Closes: #43398
- [ ] **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
2025-11-24 16:57:10 -06:00
leileizhang
09c8c1d79a [Hot Fix] Fix Image Resizer not working on Win10 (#43763)
<!-- 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
Windows 10 can’t launch the app using the Sparse Package. Remove the app
manifest so that Image Resizer can start properly on Windows 10.

We will figure out how to support Sparse Packages on Windows 10 in the
next release.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #43747 #43734 #43722 #43759
<!-- - [ ] 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
2025-11-24 10:42:35 +08:00
leileizhang
95c8a83f79 [Hotfix] Remove the properties in Prompt Execution Settings for OpenAI (#43766)
<!-- 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
Remove the properties in Prompt Execution Settings for OpenAI, as the
new models may not support them.

Will try to expose them in the UI so users can add them on their own in
the next release.

<!-- 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
2025-11-24 10:08:12 +08:00
Kai Tao
2830ea919c Advanced Paste: Adjust model parameter to make the result longer (#43768)
<!-- 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
Adjust model parameter to make the result longer
<!-- 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
2025-11-24 09:51:27 +08:00
Dave Rayment
725ad21952 [Awake] Fix issue with timed mode not expiring correctly (#43785)
<!-- 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
Resolves an issue with the timed mode's expiry not completing correctly.

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

- [x] Closes: #43775
<!-- - [ ] 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
This was because of my recent change to the timed mode. The `Subscribe`
method on the `Observable` interval accidentally wired the completion
logic to the **Error** handler instead of the **Completion** handler
because of the use of a discard `_` instead of an empty parameter list
`()`. As a result of the incorrect overload being called, Awake stayed
in the Timed state despite the timer reaching zero.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Confirmed that the timed mode times out and exits upon expiry.
2025-11-24 09:12:54 +08:00
Erik Anderson
ebc3a139c5 Fix typo in AI settings card description (#43757)
## Summary of the Pull Request
The word "cloud" does not use a vowel sound, so the preceding word
should be "A" instead of "An".

## PR Checklist

- [X] Closes: #43756
- [ ] **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

Co-authored-by: Erik Anderson <erikan@ntdev.microsoft.com>
2025-11-21 18:34:34 +08:00
Jaylyn Barbee
28dba2633e [Light Switch][Dev Docs] Clarify LightSwitchService and LightSwitchStateManager roles (#43748)
Updated LightSwitch module documentation to clarify the role of
LightSwitchService and LightSwitchStateManager.

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2025-11-20 15:22:40 -08:00
Jiří Polášek
9fbd3de3a2 CmdPal: Add native debugging launch profile to launchSettings.json (#43718)
## Summary of the Pull Request

See title. 

I’m too lazy to open the dialog and then revert the change later.

<!-- 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
2025-11-20 09:23:42 -06:00
Kai Tao
4a0d9912ae Advanced Paste: No cache for foundry local model list (#43716)
<!-- 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
Cache of the downloaded model will make the newly added model only work
after running of powertoys, this disable the cache, so just downloaded
model will take effect immediately

<!-- 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
Validated locally
2025-11-20 09:57:29 +08:00
Dave Rayment
15c79a0176 [Settings] Fix inconsistent description text for the mouse tools (#43651)
<!-- 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 some of the mouse utilities' descriptions from declarative to
imperative, to match best practice and to be consistent with the other
descriptions.

<!-- 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
- Confirmed the changed descriptions were updated in Settings.
2025-11-19 16:50:25 +08:00
Dave Rayment
97d46efec2 [Settings] Fix Dashboard toggle glitches and sorting UI (#43626)
## Summary of the Pull Request
Fixes two UI bugs in the Settings Dashboard: module list glitching when
toggling modules, and incorrect sort menu checkmarks.

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

- [x] Closes: #43624 
- [x] Closes: #43625
- [ ] **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

### User-Facing Fixes

#### 1. Module list glitching when toggling enabled state
When enabling or disabling a module from the "Utilities" list, the
entire list would flicker and redraw, causing other toggles to glitch.
This made it appear as if multiple modules were being affected by a
single change.

**Root cause**
The `AllModules` ObservableCollection was being completely cleared and
re-populated on every change, forcing the UI to destroy and recreate all
list items.

**Fix**
Refactored collection updates to modify items in-place:
- Introduced `_moduleItems` master list, built once during
initialization.
- `RefreshModuleList()` now updates properties without clearing
collections
- `SortModuleList()` uses `ObservableCollection.Move()` instead of
`Clear()`/`Add()`

#### 2. Incorrect sort menu checkmark behaviour
The checkmark in the "Sort by" menu would not update correctly when
changing sort order, sometimes showing the incorrect item checked, or
even both at once.

**Root cause**
The `IsChecked` prop on the `ToggleMenuFlyoutItem` is bound to
`DashboardSortOrder`, but the binding was not updating because the
ViewModel didn't raise a property change notification when the sort
order was changed.

**Fix**
Added `OnPropertyChanged(nameof(DashboardSortOrder))` in
`SortModuleList()`.

### Code quality improvements

1. Renamed `GetShortcutModules()` to `RefreshShortcutModules()`. The
original name implied a getter, but the routine actually affects state
by rebuilding the shortcut and action lists, violating the Command-Query
Separation principle.
2. Added an `_isUpdatingFromUI` flag as a defensive measure against
circular updates when a UI toggle is changed.
3. Separation of concerns for operations on the modules list. Building,
sorting and refreshing it are separated.
4. Added comments and XML doc headers for new methods. Included brief
description of GPO locking behaviour.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
- Verified that toggling modules in the list no longer causes the list
to flicker or for other toggles to glitch.
- Confirmed that the sort order checkmarks update correctly and reflect
the current sort order.
- Tested GPO policy settings are still queried as before.
- Checked sort behaviour is unaffected.

## Videos

*Sorting UI*

https://github.com/user-attachments/assets/3484bf63-2946-4460-83a5-361fa7e41c82

*Toggle behaviour*

https://github.com/user-attachments/assets/1fae5429-6fa3-4431-80f3-0907dab4f326

---------

Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
2025-11-19 16:49:40 +08:00
Kai Tao
46242b384e 96 release change log (#43330)
<!-- 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
- [ ] **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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
Signed-off-by: Shawn Yuan <shuai.yuan.zju@gmail.com>
Co-authored-by: Jiří Polášek <me@jiripolasek.com>
Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
Co-authored-by: Jeremy Sinclair <4016293+snickler@users.noreply.github.com>
Co-authored-by: leileizhang <leilzh@microsoft.com>
Co-authored-by: Shawn Yuan <128874481+shuaiyuanxx@users.noreply.github.com>
Co-authored-by: Copilot <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>
Co-authored-by: Dave Rayment <dave.rayment@gmail.com>
Co-authored-by: Gleb Khmyznikov <gleb.khmyznikov@gmail.com>
Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
Co-authored-by: Juju Anselum J <106316316+anselumjuju@users.noreply.github.com>
Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
Co-authored-by: Leon Zandman <leon@wirwar.com>
Co-authored-by: Leon Zandman <lzandman@rdw.nl>
Co-authored-by: moooyo <42196638+moooyo@users.noreply.github.com>
Co-authored-by: Yu Leng <yuleng@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
Co-authored-by: Michael Jolley <mike@baldbeardedbuilder.com>
Co-authored-by: Mario Hewardt <marioh@microsoft.com>
Co-authored-by: Alex Mihaiuc <69110671+foxmsft@users.noreply.github.com>
Co-authored-by: Mike Hall <mikehall@microsoft.com>
Co-authored-by: Trevor <ngo.trev.95@gmail.com>
2025-11-19 16:25:52 +08:00
Niels Laute
84be261581 Logo change for Azure Inference (#43686)
<!-- 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
2025-11-19 11:19:38 +08:00
Niels Laute
5a8095b704 Loc bug (#43685)
<!-- 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
2025-11-19 10:32:14 +08:00
Niels Laute
417c1a6b98 Update FoundryLocal.svg (#43682)
<!-- 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
2025-11-19 08:21:14 +08:00
leileizhang
2593149d22 Fix OOBE Mouse Utilities crash by correcting localization key (#43664)
<!-- 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 OOBE Mouse Utilities page crashed when selected because the
TextBlock with x:Uid="Oobe_MouseUtils_MousePointerCrosshairs" tried to
bind a Description property that doesn’t exist.
- Updated Resources.resw so the string entry is named
Oobe_MouseUtils_MousePointerCrosshairs_Description.Text, matching the
markdown description control instead of the TextBlock.
- With the correct resource key, the XAML loader no longer resolves an
invalid property and navigation succeeds.

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

- [x] Closes:  #43663
<!-- - [ ] 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
2025-11-18 14:22:03 +08:00
Kai Tao
0b50c38fe1 Advanced Paste: Refresh environment if foundry is not present (#43662)
<!-- 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

[12:55:29.6763496] [Info] FoundryClient.cs::CreateAsync::23
    [FoundryClient] First attempt failed, refreshing PATH and retrying
[12:55:29.6766491] [Info] FoundryClient.cs::RefreshEnvironmentPath::225
    [FoundryClient] Refreshing PATH environment variable from system
[12:55:29.6768710] [Info] FoundryClient.cs::RefreshEnvironmentPath::266
    [FoundryClient] Updating process PATH with latest system values
[12:55:29.6769080] [Info] FoundryClient.cs::TryCreateClientAsync::33
    [FoundryClient] Creating Foundry Local client
[12:55:29.6769312] [Info] FoundryClient.cs::TryCreateClientAsync::45
[FoundryClient] Starting Foundry service using
manager.StartServiceAsync()
[12:55:29.9807668] [Info] FoundryClient.cs::TryCreateClientAsync::48
    [FoundryClient] Foundry service started successfully


Verified, fist launch successfully
2025-11-18 12:59:52 +08:00
Niels Laute
840808b465 [AP] Adding a single scrollviewer and fixing hidden tabstop (#43660)
<!-- 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: #43655
<!-- - [ ] 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
2025-11-18 10:28:40 +08:00
Jiří Polášek
b50df36b70 Setup: Hide apps in PowerToys.SpareApps package from Start Menu (#43650)
<!-- 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 the Appx manifest for PowerToys.SpareApps to hide the
apps from the Start Menu, as they lack proper visual elements like icons
and text.

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

- [x] Closes: #43647
<!-- - [ ] 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
2025-11-18 10:00:37 +08:00
Jiří Polášek
b94593ef73 Settings: Add ScrollViewer to Command Palette page in PowerToys Settings (#43649) 2025-11-18 00:55:14 +01:00
Mario Hewardt
7a01d56179 Updates version for standalone release (#43645)
<!-- 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
Updates the version for standalone release

<!-- 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
2025-11-17 23:26:42 +08:00
Kai Tao
130e9a0a68 cmdpal: Fix launch by button in settings not work (#43634)
<!-- 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
Shell does not know it's a protocol, so add protocol to 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
Locally verified
2025-11-17 12:55:22 +08:00
Kai Tao
34c37f2d38 Add not signed dll (#43631)
<!-- 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 dll is not signed, will fail the pipeline

<!-- 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
2025-11-17 09:48:32 +08:00
1734 changed files with 132300 additions and 18250 deletions

1
.claude/CLAUDE.md Symbolic link
View File

@@ -0,0 +1 @@
../.github/copilot-instructions.md

1
.claude/agents Symbolic link
View File

@@ -0,0 +1 @@
../.github/agents

1
.claude/commands Symbolic link
View File

@@ -0,0 +1 @@
../.github/prompts

1
.claude/rules Symbolic link
View File

@@ -0,0 +1 @@
../.github/instructions

1
.claude/skills Symbolic link
View File

@@ -0,0 +1 @@
../.github/skills

View File

@@ -95,6 +95,7 @@ OTP
Yubi
Yubico
Perplexity
Groq
svgl
# KEYS
@@ -328,3 +329,16 @@ FFF
HHH
riday
YYY
# Unicode
precomposed
# GitHub issue/PR commands
azp
feedbackhub
needinfo
reportbug
#ffmpeg
crf
nostdin

View File

@@ -0,0 +1,63 @@
acq
APPLYTOSUBMENUS
AUDCLNT
bitmaps
BUFFERFLAGS
centiseconds
Ctl
CTLCOLOR
CTLCOLORBTN
CTLCOLORDLG
CTLCOLOREDIT
CTLCOLORLISTBOX
CTrim
DFCS
dlg
dlu
DONTCARE
DRAWITEM
DRAWITEMSTRUCT
DWLP
EDITCONTROL
ENABLEHOOK
FDE
GETCHANNELRECT
GETCHECK
GETTHUMBRECT
GIFs
HTBOTTOMRIGHT
HTHEME
KSDATAFORMAT
LEFTNOWORDWRAP
letterbox
lld
logfont
lround
MENUINFO
mic
MMRESULT
OWNERDRAW
PBGRA
pfdc
playhead
pwfx
quantums
REFKNOWNFOLDERID
reposted
SCROLLSIZEGRIP
SETDEFID
SETRECT
SHAREMODE
SHAREVIOLATION
STREAMFLAGS
submix
tci
TEXTMETRIC
tme
TRACKMOUSEEVENT
Unadvise
WASAPI
WAVEFORMATEX
WAVEFORMATEXTENSIBLE
wil
WMU

View File

@@ -565,7 +565,7 @@ perl(?:\s+-[a-zA-Z]\w*)+
regexp?\.MustCompile\((?:`[^`]*`|".*"|'.*')\)
# regex choice
\(\?:[^)]+\|[^)]+\)
# \(\?:[^)]+\|[^)]+\)
# proto
^\s*(\w+)\s\g{-1} =

View File

@@ -101,11 +101,16 @@
^doc/devdocs/akaLinks\.md$
^NOTICE\.md$
^src/common/CalculatorEngineCommon/exprtk\.hpp$
^src/common/UnitTests-CommonUtils/
^src/common/ManagedCommon/ColorFormatHelper\.cs$
^src/common/notifications/BackgroundActivatorDLL/cpp\.hint$
^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$
^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/colorPicker/ColorPickerUI/Shaders/GridShader\.cso$
^src/modules/launcher/Plugins/Microsoft\.PowerToys\.Run\.Plugin\.TimeDate/Properties/
^src/modules/MouseUtils/MouseJumpUI/MainForm\.resx$

File diff suppressed because it is too large Load Diff

View File

@@ -273,3 +273,19 @@ St&yle
# Usernames with numbers
# 0x6f677548 is user name but user folder causes a flag
\bx6f677548\b
# Windows API constants and hardware interface terms
\bCOINIT[_A-Z]*\b
\bEOAC[_A-Z]*\b
\b(?:RPC_C_AUTHN_)?WINNT\b
\bUPDATEREGISTRY\b
\b(?:CDS_)?UPDATEREGISTRY\b
# Display interface terms (HDMI, DVI, DisplayPort)
\b(?:HDMI|DVI|DisplayPort)(?:-\d+)?\b
# 2D Region struct names
\bDisplayConfig2?D?Region\b
# Microsoft Store URLs and product IDs
ms-windows-store://\S+

94
.github/agents/FixIssue.agent.md vendored Normal file
View File

@@ -0,0 +1,94 @@
---
description: 'Implements fixes for GitHub issues based on implementation plans'
name: 'FixIssue'
tools: ['read', 'edit', 'search', 'execute', 'agent', 'usages', 'problems', 'changes', 'testFailure', 'github/*', 'github.vscode-pull-request-github/*']
argument-hint: 'GitHub issue number (e.g., #12345)'
infer: true
---
# FixIssue Agent
You are an **IMPLEMENTATION AGENT** specialized in executing implementation plans to fix GitHub issues.
## Identity & Expertise
- Expert at translating plans into working code
- Deep knowledge of the repository's codebase patterns and conventions
- Skilled at writing tests, handling edge cases, and validating builds
- You follow plans precisely while handling ambiguity gracefully
## Goal
For the given **issue_number**, execute the implementation plan and produce:
1. Working code changes applied directly to the repository
2. `Generated Files/issueFix/{{issue_number}}/pr-description.md` — PR-ready description
3. `Generated Files/issueFix/{{issue_number}}/manual-steps.md` — Only if human action needed
## Core Directive
**Follow the implementation plan in `Generated Files/issueReview/{{issue_number}}/implementation-plan.md` as the single source of truth.**
If the plan doesn't exist, invoke PlanIssue agent first via `runSubagent`.
## Working Principles
- **Plan First**: Read and understand the entire implementation plan before coding
- **Validate Always**: For each change: Edit → Build → Verify → Commit. Never proceed if build fails.
- **Atomic Commits**: Each commit must be self-contained, buildable, and meaningful
- **Ask, Don't Guess**: When uncertain, insert `// TODO(Human input needed): <question>` and document in manual-steps.md
## 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`
Never skip steps. Never commit broken code. Never proceed if build fails.
**Feature-by-Feature E2E**: For big scenarios with multiple features, complete each feature end-to-end before moving to the next:
- Settings UI → Functionality → Logging → Tests (for Feature 1)
- Then repeat for Feature 2
- Benefits: Each feature is self-contained, testable, easier to review, can ship incrementally
**Large Changes** (3+ files or cross-module):
- Use `tools\build\New-WorktreeFromBranch.ps1` for isolated worktrees
- Create separate branches per feature (e.g., `issue/{{issue_number}}-export`, `issue/{{issue_number}}-import`)
- Merge feature branches back after each is validated
**Recovery**: If implementation goes wrong:
- Create a checkpoint branch before risky changes
- On failure: branch from last known-good state, cherry-pick working changes, abandon broken branch
- For complex changes, consider multiple smaller PRs
## Guidelines
**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
- Add comprehensive tests for changed behavior
- Use worktrees for large changes (3+ files or cross-module)
- Document deviations from plan
**DON'T**:
- Implement everything in a single massive commit
- Continue after a failed build without fixing
- Make drive-by refactors outside issue scope
- Skip tests for behavioral changes
- Add noisy logs in hot paths
- Break IPC/JSON contracts without updating both sides
- Introduce dependencies without documenting in NOTICE.md
## References
- [Build Guidelines](../../tools/build/BUILD-GUIDELINES.md) — Build commands and validation
- [Coding Style](../../doc/devdocs/development/style.md) — Formatting and conventions
- [AGENTS.md](../../AGENTS.md) — Full contributor guide
## Parameter
- **issue_number**: Extract from `#123`, `issue 123`, or plain number. If missing, ask user.

95
.github/agents/FixPR.agent.md vendored Normal file
View File

@@ -0,0 +1,95 @@
---
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.

99
.github/agents/IssueToPR.agent.md vendored Normal file
View File

@@ -0,0 +1,99 @@
---
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.

67
.github/agents/PlanIssue.agent.md vendored Normal file
View File

@@ -0,0 +1,67 @@
---
description: 'Analyzes GitHub issues to produce overview and implementation plans'
name: 'PlanIssue'
tools: ['execute', 'read', 'edit', 'search', 'web', 'github/*', 'agent', 'github-artifacts/*', 'todo']
argument-hint: 'GitHub issue number (e.g., #12345)'
handoffs:
- label: Start Implementation
agent: FixIssue
prompt: 'Fix issue #{{issue_number}} using the implementation plan'
- label: Open Plan in Editor
agent: agent
prompt: 'Open Generated Files/issueReview/{{issue_number}}/overview.md and implementation-plan.md'
showContinueOn: false
send: true
infer: true
---
# PlanIssue Agent
You are a **PLANNING AGENT** specialized in analyzing GitHub issues and producing comprehensive planning documentation.
## 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
- You research thoroughly before planning, gathering 80% confidence before drafting
## Goal
For the given **issue_number**, produce two deliverables:
1. `Generated Files/issueReview/{{issue_number}}/overview.md` — Issue analysis with scoring
2. `Generated Files/issueReview/{{issue_number}}/implementation-plan.md` — Technical implementation plan
Above is the core interaction with the end user. If you cannot produce the files above, you fail the task. Each time, you must check whether the files exist or have been modified by the end user, without assuming you know their contents.
3. `Generated Files/issueReview/{{issue_number}}/logs/**` — logs for your diagnostic of root cause, research steps, and reasoning
## 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.
- Fetch issue details: reactions, comments, linked PRs, images, logs
- Search related code and similar past fixes
- Ask clarifying questions when ambiguous
- Identify subject matter experts via git history
<stopping_rules>
You are a PLANNING agent, NOT an implementation agent.
STOP if you catch yourself:
- Writing code or editing source files outside `Generated Files/issueReview/`
- Making assumptions without researching
- Skipping the scoring/assessment phase
Plans describe what the USER or FixIssue agent will execute later.
</stopping_rules>
## References
- `{prompts_root}/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
## Parameter
- **issue_number**: Extract from `#123`, `issue 123`, or plain number. If missing, ask user.

79
.github/agents/ReviewIssue.agent.md vendored Normal file
View File

@@ -0,0 +1,79 @@
---
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.

105
.github/agents/ReviewPR.agent.md vendored Normal file
View File

@@ -0,0 +1,105 @@
---
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.

84
.github/agents/ReviewTheReview.agent.md vendored Normal file
View File

@@ -0,0 +1,84 @@
---
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.

100
.github/agents/TriagePR.agent.md vendored Normal file
View File

@@ -0,0 +1,100 @@
---
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

@@ -1,59 +1,36 @@
---
description: PowerToys AI contributor guidance.
applyTo: pullRequests
description: 'PowerToys AI contributor guidance'
---
# PowerToys - Copilot guide (concise)
# PowerToys Copilot Instructions
This is the top-level guide for AI changes. Keep edits small, follow existing patterns, and cite exact paths in PRs.
Concise guidance for AI contributions. For complete details, see [AGENTS.md](../AGENTS.md).
# Repo map (1-line per area)
- Core apps: `src/runner/**` (tray/loader), `src/settings-ui/**` (Settings app)
- Shared libs: `src/common/**`
- Modules: `src/modules/*` (one per utility; Command Palette in `src/modules/cmdpal/**`)
- Build tools/docs: `tools/**`, `doc/devdocs/**`
## Key Rules
# Build and test (defaults)
- Prerequisites: Visual Studio 2022 17.4+, minimal Windows 10 1803+.
- Build discipline:
- One terminal per operation (build -> test). Do not switch or open new ones mid-flow.
- After making changes, `cd` to the project folder that changed (`.csproj`/`.vcxproj`).
- Use scripts to build, synchronously block and wait in foreground for completion: `tools/build/build.ps1|.cmd` (current folder), `build-essentials.*` (once per brand new build for missing nuget packages).
- Treat build exit code 0 as success; any non-zero exit code is a failure. Read the errors log in the build folder (such as `build.*.*.errors.log`) and surface problems.
- Do not start tests or launch Runner until the previous step succeeded.
- Tests (fast and targeted):
- Find the test project by product code prefix (for example FancyZones, AdvancedPaste). Look for a sibling folder or one to two levels up named like `<Product>*UnitTests` or `<Product>*UITests`.
- Build the test project, wait for exit, then run only those tests via VS Test Explorer or `vstest.console.exe` with filters. Avoid `dotnet test` in this repo.
- Add or adjust tests when changing behavior; if skipped, state why (for example comment-only or string rename).
- Atomic PRs: one logical change, no drive-by refactors
- Add tests when changing behavior
- Keep hot paths quiet (no logging in hooks/tight loops)
# Pull requests (expectations)
- Atomic: one logical change; no drive-by refactors.
- Describe: problem, approach, risk, test evidence.
- List: touched paths if not obvious.
## Style Enforcement
# When to ask for clarification
- Ambiguous spec after scanning relevant docs (see below).
- Cross-module impact (shared enum or struct) not clear.
- Security, elevation, or installer changes.
- C#: `src/.editorconfig`, StyleCop.Analyzers
- C++: `src/.clang-format`
- XAML: XamlStyler
# Logging (use existing stacks)
- C++ logging lives in `src/common/logger/**` (`Logger::info`, `Logger::warn`, `Logger::error`, `Logger::debug`). Keep hot paths quiet (hooks, tight loops).
- C# logging goes through `ManagedCommon.Logger` (`LogInfo`, `LogWarning`, `LogError`, `LogDebug`, `LogTrace`). Some UIs use injected `ILogger` via `LoggerInstance.Logger`.
## When to Ask for Clarification
# Docs to consult
- `tools/build/BUILD-GUIDELINES.md`
- `doc/devdocs/core/architecture.md`
- `doc/devdocs/core/runner.md`
- `doc/devdocs/core/settings/readme.md`
- `doc/devdocs/modules/readme.md`
- Ambiguous spec after scanning docs
- Cross-module impact unclear
- Security, elevation, or installer changes
# Language style rules
- Always enforce repo analyzers: root `.editorconfig` plus any `stylecop.json`.
- C# code follows StyleCop.Analyzers and Microsoft.CodeAnalysis.NetAnalyzers.
- C++ code honors `.clang-format` plus `.clang-tidy` (modernize/cppcoreguidelines/readability).
- Markdown files wrap at 80 characters and use ATX headers with fenced code blocks that include language tags.
- YAML files indent two spaces and add comments for complex settings while keeping keys clear.
- PowerShell scripts use Verb-Noun names and prefer single-quoted literals while documenting parameters and satisfying PSScriptAnalyzer.
## Component-Specific Instructions
# Done checklist (self review before finishing)
- Build clean? Tests updated or passed? No unintended formatting? Any new dependency? Documented skips?
These are auto-applied based on file location:
- [Runner & Settings UI](.github/instructions/runner-settings-ui.instructions.md)
- [Common Libraries](.github/instructions/common-libraries.instructions.md)
## Detailed Documentation
- [Architecture](../doc/devdocs/core/architecture.md)
- [Coding Style](../doc/devdocs/development/style.md)

View File

@@ -0,0 +1,261 @@
---
description: 'Guidelines for creating high-quality Agent Skills for GitHub Copilot'
applyTo: '**/.github/skills/**/SKILL.md, **/.claude/skills/**/SKILL.md'
---
# Agent Skills File Guidelines
Instructions for creating effective and portable Agent Skills that enhance GitHub Copilot with specialized capabilities, workflows, and bundled resources.
## What Are Agent Skills?
Agent Skills are self-contained folders with instructions and bundled resources that teach AI agents specialized capabilities. Unlike custom instructions (which define coding standards), skills enable task-specific workflows that can include scripts, examples, templates, and reference data.
Key characteristics:
- **Portable**: Works across VS Code, Copilot CLI, and Copilot coding agent
- **Progressive loading**: Only loaded when relevant to the user's request
- **Resource-bundled**: Can include scripts, templates, examples alongside instructions
- **On-demand**: Activated automatically based on prompt relevance
## Directory Structure
Skills are stored in specific locations:
| Location | Scope | Recommendation |
|----------|-------|----------------|
| `.github/skills/<skill-name>/` | Project/repository | Recommended for project skills |
| `.claude/skills/<skill-name>/` | Project/repository | Legacy, for backward compatibility |
| `~/.github/skills/<skill-name>/` | Personal (user-wide) | Recommended for personal skills |
| `~/.claude/skills/<skill-name>/` | Personal (user-wide) | Legacy, for backward compatibility |
Each skill **must** have its own subdirectory containing at minimum a `SKILL.md` file.
## Required SKILL.md Format
### Frontmatter (Required)
```yaml
---
name: webapp-testing
description: Toolkit for testing local web applications using Playwright. Use when asked to verify frontend functionality, debug UI behavior, capture browser screenshots, check for visual regressions, or view browser console logs. Supports Chrome, Firefox, and WebKit browsers.
license: Complete terms in LICENSE.txt
---
```
| Field | Required | Constraints |
|-------|----------|-------------|
| `name` | Yes | Lowercase, hyphens for spaces, max 64 characters (e.g., `webapp-testing`) |
| `description` | Yes | Clear description of capabilities AND use cases, max 1024 characters |
| `license` | No | Reference to LICENSE.txt (e.g., `Complete terms in LICENSE.txt`) or SPDX identifier |
### Description Best Practices
**CRITICAL**: The `description` field is the PRIMARY mechanism for automatic skill discovery. Copilot reads ONLY the `name` and `description` to decide whether to load a skill. If your description is vague, the skill will never be activated.
**What to include in description:**
1. **WHAT** the skill does (capabilities)
2. **WHEN** to use it (specific triggers, scenarios, file types, or user requests)
3. **Keywords** that users might mention in their prompts
**Good description:**
```yaml
description: Toolkit for testing local web applications using Playwright. Use when asked to verify frontend functionality, debug UI behavior, capture browser screenshots, check for visual regressions, or view browser console logs. Supports Chrome, Firefox, and WebKit browsers.
```
**Poor description:**
```yaml
description: Web testing helpers
```
The poor description fails because:
- No specific triggers (when should Copilot load this?)
- No keywords (what user prompts would match?)
- No capabilities (what can it actually do?)
### Body Content
The body contains detailed instructions that Copilot loads AFTER the skill is activated. Recommended sections:
| Section | Purpose |
|---------|---------|
| `# Title` | Brief overview of what this skill enables |
| `## When to Use This Skill` | List of scenarios (reinforces description triggers) |
| `## Prerequisites` | Required tools, dependencies, environment setup |
| `## Step-by-Step Workflows` | Numbered steps for common tasks |
| `## Troubleshooting` | Common issues and solutions table |
| `## References` | Links to bundled docs or external resources |
## Bundling Resources
Skills can include additional files that Copilot accesses on-demand:
### Supported Resource Types
| Folder | Purpose | Loaded into Context? | Example Files |
|--------|---------|---------------------|---------------|
| `scripts/` | Executable automation that performs specific operations | When executed | `helper.py`, `validate.sh`, `build.ts` |
| `references/` | Documentation the AI agent reads to inform decisions | Yes, when referenced | `api_reference.md`, `schema.md`, `workflow_guide.md` |
| `assets/` | **Static files used AS-IS** in output (not modified by the AI agent) | No | `logo.png`, `brand-template.pptx`, `custom-font.ttf` |
| `templates/` | **Starter code/scaffolds that the AI agent MODIFIES** and builds upon | Yes, when referenced | `viewer.html` (insert algorithm), `hello-world/` (extend) |
### Directory Structure Example
```
.github/skills/my-skill/
├── SKILL.md # Required: Main instructions
├── LICENSE.txt # Recommended: License terms (Apache 2.0 typical)
├── scripts/ # Optional: Executable automation
│ ├── helper.py # Python script
│ └── helper.ps1 # PowerShell script
├── references/ # Optional: Documentation loaded into context
│ ├── api_reference.md
│ ├── step1-setup.md # Detailed workflow (>3 steps)
│ └── step2-deployment.md
├── assets/ # Optional: Static files used AS-IS in output
│ ├── baseline.png # Reference image for comparison
│ └── report-template.html
└── templates/ # Optional: Starter code the AI agent modifies
├── scaffold.py # Code scaffold the AI agent customizes
└── config.template # Config template the AI agent fills in
```
> **LICENSE.txt**: When creating a skill, download the Apache 2.0 license text from https://www.apache.org/licenses/LICENSE-2.0.txt and save as `LICENSE.txt`. Update the copyright year and owner in the appendix section.
### Assets vs Templates: Key Distinction
**Assets** are static resources **consumed unchanged** in the output:
- A `logo.png` that gets embedded into a generated document
- A `report-template.html` copied as output format
- A `custom-font.ttf` applied to text rendering
**Templates** are starter code/scaffolds that **the AI agent actively modifies**:
- A `scaffold.py` where the AI agent inserts logic
- A `config.template` where the AI agent fills in values based on user requirements
- A `hello-world/` project directory that the AI agent extends with new features
**Rule of thumb**: If the AI agent reads and builds upon the file content → `templates/`. If the file is used as-is in output → `assets/`.
### Referencing Resources in SKILL.md
Use relative paths to reference files within the skill directory:
```markdown
## Available Scripts
Run the [helper script](./scripts/helper.py) to automate common tasks.
See [API reference](./references/api_reference.md) for detailed documentation.
Use the [scaffold](./templates/scaffold.py) as a starting point.
```
## Progressive Loading Architecture
Skills use three-level loading for efficiency:
| Level | What Loads | When |
|-------|------------|------|
| 1. Discovery | `name` and `description` only | Always (lightweight metadata) |
| 2. Instructions | Full `SKILL.md` body | When request matches description |
| 3. Resources | Scripts, examples, docs | Only when Copilot references them |
This means:
- Install many skills without consuming context
- Only relevant content loads per task
- Resources don't load until explicitly needed
## Content Guidelines
### Writing Style
- Use imperative mood: "Run", "Create", "Configure" (not "You should run")
- Be specific and actionable
- Include exact commands with parameters
- Show expected outputs where helpful
- Keep sections focused and scannable
### Script Requirements
When including scripts, prefer cross-platform languages:
| Language | Use Case |
|----------|----------|
| Python | Complex automation, data processing |
| pwsh | PowerShell Core scripting |
| Node.js | JavaScript-based tooling |
| Bash/Shell | Simple automation tasks |
Best practices:
- Include help/usage documentation (`--help` flag)
- Handle errors gracefully with clear messages
- Avoid storing credentials or secrets
- Use relative paths where possible
### When to Bundle Scripts
Include scripts in your skill when:
- The same code would be rewritten repeatedly by the agent
- Deterministic reliability is critical (e.g., file manipulation, API calls)
- Complex logic benefits from being pre-tested rather than generated each time
- The operation has a self-contained purpose that can evolve independently
- Testability matters — scripts can be unit tested and validated
- Predictable behavior is preferred over dynamic generation
Scripts enable evolution: even simple operations benefit from being implemented as scripts when they may grow in complexity, need consistent behavior across invocations, or require future extensibility.
### Security Considerations
- Scripts rely on existing credential helpers (no credential storage)
- Include `--force` flags only for destructive operations
- Warn users before irreversible actions
- Document any network operations or external calls
## Common Patterns
### Parameter Table Pattern
Document parameters clearly:
```markdown
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `--input` | Yes | - | Input file or URL to process |
| `--action` | Yes | - | Action to perform |
| `--verbose` | No | `false` | Enable verbose output |
```
## Validation Checklist
Before publishing a skill:
- [ ] `SKILL.md` has valid frontmatter with `name` and `description`
- [ ] `name` is lowercase with hyphens, ≤64 characters
- [ ] `description` clearly states **WHAT** it does, **WHEN** to use it, and relevant **KEYWORDS**
- [ ] Body includes when to use, prerequisites, and step-by-step workflows
- [ ] SKILL.md body kept under 500 lines (split large content into `references/` folder)
- [ ] Large workflows (>5 steps) split into `references/` folder with clear links from SKILL.md
- [ ] Scripts include help documentation and error handling
- [ ] Relative paths used for all resource references
- [ ] No hardcoded credentials or secrets
## Workflow Execution Pattern
When executing multi-step workflows, create a TODO list where each step references the relevant documentation:
```markdown
## TODO
- [ ] Step 1: Configure environment - see [workflow-setup.md](./references/workflow-setup.md#environment)
- [ ] Step 2: Build project - see [workflow-setup.md](./references/workflow-setup.md#build)
- [ ] Step 3: Deploy to staging - see [workflow-deployment.md](./references/workflow-deployment.md#staging)
- [ ] Step 4: Run validation - see [workflow-deployment.md](./references/workflow-deployment.md#validation)
- [ ] Step 5: Deploy to production - see [workflow-deployment.md](./references/workflow-deployment.md#production)
```
This ensures traceability and allows resuming workflows if interrupted.
## Related Resources
- [Agent Skills Specification](https://agentskills.io/)
- [VS Code Agent Skills Documentation](https://code.visualstudio.com/docs/copilot/customization/agent-skills)
- [Reference Skills Repository](https://github.com/anthropics/skills)
- [Awesome Copilot Skills](https://github.com/github/awesome-copilot/blob/main/docs/README.skills.md)

View File

@@ -0,0 +1,791 @@
---
description: 'Guidelines for creating custom agent files for GitHub Copilot'
applyTo: '**/*.agent.md'
---
# Custom Agent File Guidelines
Instructions for creating effective and maintainable custom agent files that provide specialized expertise for specific development tasks in GitHub Copilot.
## Project Context
- Target audience: Developers creating custom agents for GitHub Copilot
- File format: Markdown with YAML frontmatter
- File naming convention: lowercase with hyphens (e.g., `test-specialist.agent.md`)
- Location: `.github/agents/` directory (repository-level) or `agents/` directory (organization/enterprise-level)
- Purpose: Define specialized agents with tailored expertise, tools, and instructions for specific tasks
- Official documentation: https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents
## Required Frontmatter
Every agent file must include YAML frontmatter with the following fields:
```yaml
---
description: 'Brief description of the agent purpose and capabilities'
name: 'Agent Display Name'
tools: ['read', 'edit', 'search']
model: 'Claude Sonnet 4.5'
target: 'vscode'
infer: true
---
```
### Core Frontmatter Properties
#### **description** (REQUIRED)
- Single-quoted string, clearly stating the agent's purpose and domain expertise
- Should be concise (50-150 characters) and actionable
- Example: `'Focuses on test coverage, quality, and testing best practices'`
#### **name** (OPTIONAL)
- Display name for the agent in the UI
- If omitted, defaults to filename (without `.md` or `.agent.md`)
- Use title case and be descriptive
- Example: `'Testing Specialist'`
#### **tools** (OPTIONAL)
- List of tool names or aliases the agent can use
- Supports comma-separated string or YAML array format
- If omitted, agent has access to all available tools
- See "Tool Configuration" section below for details
#### **model** (STRONGLY RECOMMENDED)
- Specifies which AI model the agent should use
- Supported in VS Code, JetBrains IDEs, Eclipse, and Xcode
- Example: `'Claude Sonnet 4.5'`, `'gpt-4'`, `'gpt-4o'`
- Choose based on agent complexity and required capabilities
#### **target** (OPTIONAL)
- Specifies target environment: `'vscode'` or `'github-copilot'`
- If omitted, agent is available in both environments
- Use when agent has environment-specific features
#### **infer** (OPTIONAL)
- Boolean controlling whether Copilot can automatically use this agent based on context
- Default: `true` if omitted
- Set to `false` to require manual agent selection
#### **metadata** (OPTIONAL, GitHub.com only)
- Object with name-value pairs for agent annotation
- Example: `metadata: { category: 'testing', version: '1.0' }`
- Not supported in VS Code
#### **mcp-servers** (OPTIONAL, Organization/Enterprise only)
- Configure MCP servers available only to this agent
- Only supported for organization/enterprise level agents
- See "MCP Server Configuration" section below
## Tool Configuration
### Tool Specification Strategies
**Enable all tools** (default):
```yaml
# Omit tools property entirely, or use:
tools: ['*']
```
**Enable specific tools**:
```yaml
tools: ['read', 'edit', 'search', 'execute']
```
**Enable MCP server tools**:
```yaml
tools: ['read', 'edit', 'github/*', 'playwright/navigate']
```
**Disable all tools**:
```yaml
tools: []
```
### Standard Tool Aliases
All aliases are case-insensitive:
| Alias | Alternative Names | Category | Description |
|-------|------------------|----------|-------------|
| `execute` | shell, Bash, powershell | Shell execution | Execute commands in appropriate shell |
| `read` | Read, NotebookRead, view | File reading | Read file contents |
| `edit` | Edit, MultiEdit, Write, NotebookEdit | File editing | Edit and modify files |
| `search` | Grep, Glob, search | Code search | Search for files or text in files |
| `agent` | custom-agent, Task | Agent invocation | Invoke other custom agents |
| `web` | WebSearch, WebFetch | Web access | Fetch web content and search |
| `todo` | TodoWrite | Task management | Create and manage task lists (VS Code only) |
### Built-in MCP Server Tools
**GitHub MCP Server**:
```yaml
tools: ['github/*'] # All GitHub tools
tools: ['github/get_file_contents', 'github/search_repositories'] # Specific tools
```
- All read-only tools available by default
- Token scoped to source repository
**Playwright MCP Server**:
```yaml
tools: ['playwright/*'] # All Playwright tools
tools: ['playwright/navigate', 'playwright/screenshot'] # Specific tools
```
- Configured to access localhost only
- Useful for browser automation and testing
### Tool Selection Best Practices
- **Principle of Least Privilege**: Only enable tools necessary for the agent's purpose
- **Security**: Limit `execute` access unless explicitly required
- **Focus**: Fewer tools = clearer agent purpose and better performance
- **Documentation**: Comment why specific tools are required for complex configurations
## Sub-Agent Invocation (Agent Orchestration)
Agents can invoke other agents using `runSubagent` to orchestrate multi-step workflows.
### How It Works
Include `agent` in tools list to enable sub-agent invocation:
```yaml
tools: ['read', 'edit', 'search', 'agent']
```
Then invoke other agents with `runSubagent`:
```javascript
const result = await runSubagent({
description: 'What this step does',
prompt: `You are the [Specialist] specialist.
Context:
- Parameter: ${parameterValue}
- Input: ${inputPath}
- Output: ${outputPath}
Task:
1. Do the specific work
2. Write results to output location
3. Return summary of completion`
});
```
### Basic Pattern
Structure each sub-agent call with:
1. **description**: Clear one-line purpose of the sub-agent invocation
2. **prompt**: Detailed instructions with substituted variables
The prompt should include:
- Who the sub-agent is (specialist role)
- What context it needs (parameters, paths)
- What to do (concrete tasks)
- Where to write output
- What to return (summary)
### Example: Multi-Step Processing
```javascript
// Step 1: Process data
const processing = await runSubagent({
description: 'Transform raw input data',
prompt: `You are the Data Processor specialist.
Project: ${projectName}
Input: ${basePath}/raw/
Output: ${basePath}/processed/
Task:
1. Read all files from input directory
2. Apply transformations
3. Write processed files to output
4. Create summary: ${basePath}/processed/summary.md
Return: Number of files processed and any issues found`
});
// Step 2: Analyze (depends on Step 1)
const analysis = await runSubagent({
description: 'Analyze processed data',
prompt: `You are the Data Analyst specialist.
Project: ${projectName}
Input: ${basePath}/processed/
Output: ${basePath}/analysis/
Task:
1. Read processed files from input
2. Generate analysis report
3. Write to: ${basePath}/analysis/report.md
Return: Key findings and identified patterns`
});
```
### Key Points
- **Pass variables in prompts**: Use `${variableName}` for all dynamic values
- **Keep prompts focused**: Clear, specific tasks for each sub-agent
- **Return summaries**: Each sub-agent should report what it accomplished
- **Sequential execution**: Use `await` to maintain order when steps depend on each other
- **Error handling**: Check results before proceeding to dependent steps
### ⚠️ Tool Availability Requirement
**Critical**: If a sub-agent requires specific tools (e.g., `edit`, `execute`, `search`), the orchestrator must include those tools in its own `tools` list. Sub-agents cannot access tools that aren't available to their parent orchestrator.
**Example**:
```yaml
# If your sub-agents need to edit files, execute commands, or search code
tools: ['read', 'edit', 'search', 'execute', 'agent']
```
The orchestrator's tool permissions act as a ceiling for all invoked sub-agents. Plan your tool list carefully to ensure all sub-agents have the tools they need.
### ⚠️ Important Limitation
**Sub-agent orchestration is NOT suitable for large-scale data processing.** Avoid using `runSubagent` when:
- Processing hundreds or thousands of files
- Handling large datasets
- Performing bulk transformations on big codebases
- Orchestrating more than 5-10 sequential steps
Each sub-agent call adds latency and context overhead. For high-volume processing, implement logic directly in a single agent instead. Use orchestration only for coordinating specialized tasks on focused, manageable datasets.
## Agent Prompt Structure
The markdown content below the frontmatter defines the agent's behavior, expertise, and instructions. Well-structured prompts typically include:
1. **Agent Identity and Role**: Who the agent is and its primary role
2. **Core Responsibilities**: What specific tasks the agent performs
3. **Approach and Methodology**: How the agent works to accomplish tasks
4. **Guidelines and Constraints**: What to do/avoid and quality standards
5. **Output Expectations**: Expected output format and quality
### Prompt Writing Best Practices
- **Be Specific and Direct**: Use imperative mood ("Analyze", "Generate"); avoid vague terms
- **Define Boundaries**: Clearly state scope limits and constraints
- **Include Context**: Explain domain expertise and reference relevant frameworks
- **Focus on Behavior**: Describe how the agent should think and work
- **Use Structured Format**: Headers, bullets, and lists make prompts scannable
## Variable Definition and Extraction
Agents can define dynamic parameters to extract values from user input and use them throughout the agent's behavior and sub-agent communications. This enables flexible, context-aware agents that adapt to user-provided data.
### When to Use Variables
**Use variables when**:
- Agent behavior depends on user input
- Need to pass dynamic values to sub-agents
- Want to make agents reusable across different contexts
- Require parameterized workflows
- Need to track or reference user-provided context
**Examples**:
- Extract project name from user prompt
- Capture certification name for pipeline processing
- Identify file paths or directories
- Extract configuration options
- Parse feature names or module identifiers
### Variable Declaration Pattern
Define variables section early in the agent prompt to document expected parameters:
```markdown
# Agent Name
## Dynamic Parameters
- **Parameter Name**: Description and usage
- **Another Parameter**: How it's extracted and used
## Your Mission
Process [PARAMETER_NAME] to accomplish [task].
```
### Variable Extraction Methods
#### 1. **Explicit User Input**
Ask the user to provide the variable if not detected in the prompt:
```markdown
## Your Mission
Process the project by analyzing your codebase.
### Step 1: Identify Project
If no project name is provided, **ASK THE USER** for:
- Project name or identifier
- Base path or directory location
- Configuration type (if applicable)
Use this information to contextualize all subsequent tasks.
```
#### 2. **Implicit Extraction from Prompt**
Automatically extract variables from the user's natural language input:
```javascript
// Example: Extract certification name from user input
const userInput = "Process My Certification";
// Extract key information
const certificationName = extractCertificationName(userInput);
// Result: "My Certification"
const basePath = `certifications/${certificationName}`;
// Result: "certifications/My Certification"
```
#### 3. **Contextual Variable Resolution**
Use file context or workspace information to derive variables:
```markdown
## Variable Resolution Strategy
1. **From User Prompt**: First, look for explicit mentions in user input
2. **From File Context**: Check current file name or path
3. **From Workspace**: Use workspace folder or active project
4. **From Settings**: Reference configuration files
5. **Ask User**: If all else fails, request missing information
```
### Using Variables in Agent Prompts
#### Variable Substitution in Instructions
Use template variables in agent prompts to make them dynamic:
```markdown
# Agent Name
## Dynamic Parameters
- **Project Name**: ${projectName}
- **Base Path**: ${basePath}
- **Output Directory**: ${outputDir}
## Your Mission
Process the **${projectName}** project located at `${basePath}`.
## Process Steps
1. Read input from: `${basePath}/input/`
2. Process files according to project configuration
3. Write results to: `${outputDir}/`
4. Generate summary report
## Quality Standards
- Maintain project-specific coding standards for **${projectName}**
- Follow directory structure: `${basePath}/[structure]`
```
#### Passing Variables to Sub-Agents
When invoking a sub-agent, pass all context through template variables in the prompt:
```javascript
// Extract and prepare variables
const basePath = `projects/${projectName}`;
const inputPath = `${basePath}/src/`;
const outputPath = `${basePath}/docs/`;
// Pass to sub-agent with all variables substituted
const result = await runSubagent({
description: 'Generate project documentation',
prompt: `You are the Documentation specialist.
Project: ${projectName}
Input: ${inputPath}
Output: ${outputPath}
Task:
1. Read source files from ${inputPath}
2. Generate comprehensive documentation
3. Write to ${outputPath}/index.md
4. Include code examples and usage guides
Return: Summary of documentation generated (file count, word count)`
});
```
The sub-agent receives all necessary context embedded in the prompt. Variables are resolved before sending the prompt, so the sub-agent works with concrete paths and values, not variable placeholders.
### Real-World Example: Code Review Orchestrator
Example of a simple orchestrator that validates code through multiple specialized agents:
```javascript
async function reviewCodePipeline(repositoryName, prNumber) {
const basePath = `projects/${repositoryName}/pr-${prNumber}`;
// Step 1: Security Review
const security = await runSubagent({
description: 'Scan for security vulnerabilities',
prompt: `You are the Security Reviewer specialist.
Repository: ${repositoryName}
PR: ${prNumber}
Code: ${basePath}/changes/
Task:
1. Scan code for OWASP Top 10 vulnerabilities
2. Check for injection attacks, auth flaws
3. Write findings to ${basePath}/security-review.md
Return: List of critical, high, and medium issues found`
});
// Step 2: Test Coverage Check
const coverage = await runSubagent({
description: 'Verify test coverage for changes',
prompt: `You are the Test Coverage specialist.
Repository: ${repositoryName}
PR: ${prNumber}
Changes: ${basePath}/changes/
Task:
1. Analyze code coverage for modified files
2. Identify untested critical paths
3. Write report to ${basePath}/coverage-report.md
Return: Current coverage percentage and gaps`
});
// Step 3: Aggregate Results
const finalReport = await runSubagent({
description: 'Compile all review findings',
prompt: `You are the Review Aggregator specialist.
Repository: ${repositoryName}
Reports: ${basePath}/*.md
Task:
1. Read all review reports from ${basePath}/
2. Synthesize findings into single report
3. Determine overall verdict (APPROVE/NEEDS_FIXES/BLOCK)
4. Write to ${basePath}/final-review.md
Return: Final verdict and executive summary`
});
return finalReport;
}
```
This pattern applies to any orchestration scenario: extract variables, call sub-agents with clear context, await results.
### Variable Best Practices
#### 1. **Clear Documentation**
Always document what variables are expected:
```markdown
## Required Variables
- **projectName**: The name of the project (string, required)
- **basePath**: Root directory for project files (path, required)
## Optional Variables
- **mode**: Processing mode - quick/standard/detailed (enum, default: standard)
- **outputFormat**: Output format - markdown/json/html (enum, default: markdown)
## Derived Variables
- **outputDir**: Automatically set to ${basePath}/output
- **logFile**: Automatically set to ${basePath}/.log.md
```
#### 2. **Consistent Naming**
Use consistent variable naming conventions:
```javascript
// Good: Clear, descriptive naming
const variables = {
projectName, // What project to work on
basePath, // Where project files are located
outputDirectory, // Where to save results
processingMode, // How to process (detail level)
configurationPath // Where config files are
};
// Avoid: Ambiguous or inconsistent
const bad_variables = {
name, // Too generic
path, // Unclear which path
mode, // Too short
config // Too vague
};
```
#### 3. **Validation and Constraints**
Document valid values and constraints:
```markdown
## Variable Constraints
**projectName**:
- Type: string (alphanumeric, hyphens, underscores allowed)
- Length: 1-100 characters
- Required: yes
- Pattern: `/^[a-zA-Z0-9_-]+$/`
**processingMode**:
- Type: enum
- Valid values: "quick" (< 5min), "standard" (5-15min), "detailed" (15+ min)
- Default: "standard"
- Required: no
```
## MCP Server Configuration (Organization/Enterprise Only)
MCP servers extend agent capabilities with additional tools. Only supported for organization and enterprise-level agents.
### Configuration Format
```yaml
---
name: my-custom-agent
description: 'Agent with MCP integration'
tools: ['read', 'edit', 'custom-mcp/tool-1']
mcp-servers:
custom-mcp:
type: 'local'
command: 'some-command'
args: ['--arg1', '--arg2']
tools: ["*"]
env:
ENV_VAR_NAME: ${{ secrets.API_KEY }}
---
```
### MCP Server Properties
- **type**: Server type (`'local'` or `'stdio'`)
- **command**: Command to start the MCP server
- **args**: Array of command arguments
- **tools**: Tools to enable from this server (`["*"]` for all)
- **env**: Environment variables (supports secrets)
### Environment Variables and Secrets
Secrets must be configured in repository settings under "copilot" environment.
**Supported syntax**:
```yaml
env:
# Environment variable only
VAR_NAME: COPILOT_MCP_ENV_VAR_VALUE
# Variable with header
VAR_NAME: $COPILOT_MCP_ENV_VAR_VALUE
VAR_NAME: ${COPILOT_MCP_ENV_VAR_VALUE}
# GitHub Actions-style (YAML only)
VAR_NAME: ${{ secrets.COPILOT_MCP_ENV_VAR_VALUE }}
VAR_NAME: ${{ var.COPILOT_MCP_ENV_VAR_VALUE }}
```
## File Organization and Naming
### Repository-Level Agents
- Location: `.github/agents/`
- Scope: Available only in the specific repository
- Access: Uses repository-configured MCP servers
### Organization/Enterprise-Level Agents
- Location: `.github-private/agents/` (then move to `agents/` root)
- Scope: Available across all repositories in org/enterprise
- Access: Can configure dedicated MCP servers
### Naming Conventions
- Use lowercase with hyphens: `test-specialist.agent.md`
- Name should reflect agent purpose
- Filename becomes default agent name (if `name` not specified)
- Allowed characters: `.`, `-`, `_`, `a-z`, `A-Z`, `0-9`
## Agent Processing and Behavior
### Versioning
- Based on Git commit SHAs for the agent file
- Create branches/tags for different agent versions
- Instantiated using latest version for repository/branch
- PR interactions use same agent version for consistency
### Name Conflicts
Priority (highest to lowest):
1. Repository-level agent
2. Organization-level agent
3. Enterprise-level agent
Lower-level configurations override higher-level ones with the same name.
### Tool Processing
- `tools` list filters available tools (built-in and MCP)
- No tools specified = all tools enabled
- Empty list (`[]`) = all tools disabled
- Specific list = only those tools enabled
- Unrecognized tool names are ignored (allows environment-specific tools)
### MCP Server Processing Order
1. Out-of-the-box MCP servers (e.g., GitHub MCP)
2. Custom agent MCP configuration (org/enterprise only)
3. Repository-level MCP configurations
Each level can override settings from previous levels.
## Agent Creation Checklist
### Frontmatter
- [ ] `description` field present and descriptive (50-150 chars)
- [ ] `description` wrapped in single quotes
- [ ] `name` specified (optional but recommended)
- [ ] `tools` configured appropriately (or intentionally omitted)
- [ ] `model` specified for optimal performance
- [ ] `target` set if environment-specific
- [ ] `infer` set to `false` if manual selection required
### Prompt Content
- [ ] Clear agent identity and role defined
- [ ] Core responsibilities listed explicitly
- [ ] Approach and methodology explained
- [ ] Guidelines and constraints specified
- [ ] Output expectations documented
- [ ] Examples provided where helpful
- [ ] Instructions are specific and actionable
- [ ] Scope and boundaries clearly defined
- [ ] Total content under 30,000 characters
### File Structure
- [ ] Filename follows lowercase-with-hyphens convention
- [ ] File placed in correct directory (`.github/agents/` or `agents/`)
- [ ] Filename uses only allowed characters
- [ ] File extension is `.agent.md`
### Quality Assurance
- [ ] Agent purpose is unique and not duplicative
- [ ] Tools are minimal and necessary
- [ ] Instructions are clear and unambiguous
- [ ] Agent has been tested with representative tasks
- [ ] Documentation references are current
- [ ] Security considerations addressed (if applicable)
## Common Agent Patterns
### Testing Specialist
**Purpose**: Focus on test coverage and quality
**Tools**: All tools (for comprehensive test creation)
**Approach**: Analyze, identify gaps, write tests, avoid production code changes
### Implementation Planner
**Purpose**: Create detailed technical plans and specifications
**Tools**: Limited to `['read', 'search', 'edit']`
**Approach**: Analyze requirements, create documentation, avoid implementation
### Code Reviewer
**Purpose**: Review code quality and provide feedback
**Tools**: `['read', 'search']` only
**Approach**: Analyze, suggest improvements, no direct modifications
### Refactoring Specialist
**Purpose**: Improve code structure and maintainability
**Tools**: `['read', 'search', 'edit']`
**Approach**: Analyze patterns, propose refactorings, implement safely
### Security Auditor
**Purpose**: Identify security issues and vulnerabilities
**Tools**: `['read', 'search', 'web']`
**Approach**: Scan code, check against OWASP, report findings
## Common Mistakes to Avoid
### Frontmatter Errors
- ❌ Missing `description` field
- ❌ Description not wrapped in quotes
- ❌ Invalid tool names without checking documentation
- ❌ Incorrect YAML syntax (indentation, quotes)
### Tool Configuration Issues
- ❌ Granting excessive tool access unnecessarily
- ❌ Missing required tools for agent's purpose
- ❌ Not using tool aliases consistently
- ❌ Forgetting MCP server namespace (`server-name/tool`)
### Prompt Content Problems
- ❌ Vague, ambiguous instructions
- ❌ Conflicting or contradictory guidelines
- ❌ Lack of clear scope definition
- ❌ Missing output expectations
- ❌ Overly verbose instructions (exceeding character limits)
- ❌ No examples or context for complex tasks
### Organizational Issues
- ❌ Filename doesn't reflect agent purpose
- ❌ Wrong directory (confusing repo vs org level)
- ❌ Using spaces or special characters in filename
- ❌ Duplicate agent names causing conflicts
## Testing and Validation
### Manual Testing
1. Create the agent file with proper frontmatter
2. Reload VS Code or refresh GitHub.com
3. Select the agent from the dropdown in Copilot Chat
4. Test with representative user queries
5. Verify tool access works as expected
6. Confirm output meets expectations
### Integration Testing
- Test agent with different file types in scope
- Verify MCP server connectivity (if configured)
- Check agent behavior with missing context
- Test error handling and edge cases
- Validate agent switching and handoffs
### Quality Checks
- Run through agent creation checklist
- Review against common mistakes list
- Compare with example agents in repository
- Get peer review for complex agents
- Document any special configuration needs
## Additional Resources
### Official Documentation
- [Creating Custom Agents](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents)
- [Custom Agents Configuration](https://docs.github.com/en/copilot/reference/custom-agents-configuration)
- [Custom Agents in VS Code](https://code.visualstudio.com/docs/copilot/customization/custom-agents)
- [MCP Integration](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/extend-coding-agent-with-mcp)
### Community Resources
- [Awesome Copilot Agents Collection](https://github.com/github/awesome-copilot/tree/main/agents)
- [Customization Library Examples](https://docs.github.com/en/copilot/tutorials/customization-library/custom-agents)
- [Your First Custom Agent Tutorial](https://docs.github.com/en/copilot/tutorials/customization-library/custom-agents/your-first-custom-agent)
### Related Files
- [Prompt Files Guidelines](./prompt.instructions.md) - For creating prompt files
- [Instructions Guidelines](./instructions.instructions.md) - For creating instruction files
## Version Compatibility Notes
### GitHub.com (Coding Agent)
- ✅ Fully supports all standard frontmatter properties
- ✅ Repository and org/enterprise level agents
- ✅ MCP server configuration (org/enterprise)
- ❌ Does not support `model`, `argument-hint`, `handoffs` properties
### VS Code / JetBrains / Eclipse / Xcode
- ✅ Supports `model` property for AI model selection
- ✅ Supports `argument-hint` and `handoffs` properties
- ✅ User profile and workspace-level agents
- ❌ Cannot configure MCP servers at repository level
- ⚠️ Some properties may behave differently
When creating agents for multiple environments, focus on common properties and test in all target environments. Use `target` property to create environment-specific agents when necessary.

View File

@@ -0,0 +1,187 @@
---
description: 'Best practices for Azure DevOps Pipeline YAML files'
applyTo: '**/azure-pipelines.yml, **/azure-pipelines*.yml, **/*.pipeline.yml'
---
# Azure DevOps Pipeline YAML Best Practices
Guidelines for creating maintainable, secure, and efficient Azure DevOps pipelines in PowerToys.
## General Guidelines
- Use YAML syntax consistently with proper indentation (2 spaces)
- Always include meaningful names and display names for pipelines, stages, jobs, and steps
- Implement proper error handling and conditional execution
- Use variables and parameters to make pipelines reusable and maintainable
- Follow the principle of least privilege for service connections and permissions
- Include comprehensive logging and diagnostics for troubleshooting
## Pipeline Structure
- Organize complex pipelines using stages for better visualization and control
- Use jobs to group related steps and enable parallel execution when possible
- Implement proper dependencies between stages and jobs
- Use templates for reusable pipeline components
- Keep pipeline files focused and modular - split large pipelines into multiple files
## Build Best Practices
- Use specific agent pool versions and VM images for consistency
- Cache dependencies (npm, NuGet, Maven, etc.) to improve build performance
- Implement proper artifact management with meaningful names and retention policies
- Use build variables for version numbers and build metadata
- Include code quality gates (lint checks, testing, security scans)
- Ensure builds are reproducible and environment-independent
## Testing Integration
- Run unit tests as part of the build process
- Publish test results in standard formats (JUnit, VSTest, etc.)
- Include code coverage reporting and quality gates
- Implement integration and end-to-end tests in appropriate stages
- Use test impact analysis when available to optimize test execution
- Fail fast on test failures to provide quick feedback
## Security Considerations
- Use Azure Key Vault for sensitive configuration and secrets
- Implement proper secret management with variable groups
- Use service connections with minimal required permissions
- Enable security scans (dependency vulnerabilities, static analysis)
- Implement approval gates for production deployments
- Use managed identities when possible instead of service principals
## Deployment Strategies
- Implement proper environment promotion (dev → staging → production)
- Use deployment jobs with proper environment targeting
- Implement blue-green or canary deployment strategies when appropriate
- Include rollback mechanisms and health checks
- Use infrastructure as code (ARM, Bicep, Terraform) for consistent deployments
- Implement proper configuration management per environment
## Variable and Parameter Management
- Use variable groups for shared configuration across pipelines
- Implement runtime parameters for flexible pipeline execution
- Use conditional variables based on branches or environments
- Secure sensitive variables and mark them as secrets
- Document variable purposes and expected values
- Use variable templates for complex variable logic
## Performance Optimization
- Use parallel jobs and matrix strategies when appropriate
- Implement proper caching strategies for dependencies and build outputs
- Use shallow clone for Git operations when full history isn't needed
- Optimize Docker image builds with multi-stage builds and layer caching
- Monitor pipeline performance and optimize bottlenecks
- Use pipeline resource triggers efficiently
## Monitoring and Observability
- Include comprehensive logging throughout the pipeline
- Use Azure Monitor and Application Insights for deployment tracking
- Implement proper notification strategies for failures and successes
- Include deployment health checks and automated rollback triggers
- Use pipeline analytics to identify improvement opportunities
- Document pipeline behavior and troubleshooting steps
## Template and Reusability
- Create pipeline templates for common patterns
- Use extends templates for complete pipeline inheritance
- Implement step templates for reusable task sequences
- Use variable templates for complex variable logic
- Version templates appropriately for stability
- Document template parameters and usage examples
## Branch and Trigger Strategy
- Implement appropriate triggers for different branch types
- Use path filters to trigger builds only when relevant files change
- Configure proper CI/CD triggers for main/master branches
- Use pull request triggers for code validation
- Implement scheduled triggers for maintenance tasks
- Consider resource triggers for multi-repository scenarios
## Example Structure
```yaml
# azure-pipelines.yml
trigger:
branches:
include:
- main
- develop
paths:
exclude:
- docs/*
- README.md
variables:
- group: shared-variables
- name: buildConfiguration
value: 'Release'
stages:
- stage: Build
displayName: 'Build and Test'
jobs:
- job: Build
displayName: 'Build Application'
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
displayName: 'Use .NET SDK'
inputs:
version: '8.x'
- task: DotNetCoreCLI@2
displayName: 'Restore dependencies'
inputs:
command: 'restore'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'Build application'
inputs:
command: 'build'
projects: '**/*.csproj'
arguments: '--configuration $(buildConfiguration) --no-restore'
- stage: Deploy
displayName: 'Deploy to Staging'
dependsOn: Build
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployToStaging
displayName: 'Deploy to Staging Environment'
environment: 'staging'
strategy:
runOnce:
deploy:
steps:
- download: current
displayName: 'Download drop artifact'
artifact: drop
- task: AzureWebApp@1
displayName: 'Deploy to Azure Web App'
inputs:
azureSubscription: 'staging-service-connection'
appType: 'webApp'
appName: 'myapp-staging'
package: '$(Pipeline.Workspace)/drop/**/*.zip'
```
## Common Anti-Patterns to Avoid
- Hardcoding sensitive values directly in YAML files
- Using overly broad triggers that cause unnecessary builds
- Mixing build and deployment logic in a single stage
- Not implementing proper error handling and cleanup
- Using deprecated task versions without upgrade plans
- Creating monolithic pipelines that are difficult to maintain
- Not using proper naming conventions for clarity
- Ignoring pipeline security best practices

View File

@@ -0,0 +1,61 @@
---
description: 'Guidelines for shared libraries including logging, IPC, settings, DPI, telemetry, and utilities consumed by multiple modules'
applyTo: 'src/common/**'
---
# Common Libraries Shared Code Guidance
Guidelines for modifying shared code in `src/common/`. Changes here can have wide-reaching impact across the entire PowerToys codebase.
## Scope
- Logging infrastructure (`src/common/logger/`)
- IPC primitives and named pipe utilities
- Settings serialization and management
- DPI awareness and scaling utilities
- Telemetry helpers
- General utilities (JSON parsing, string helpers, etc.)
## Guidelines
### API Stability
- Avoid breaking public headers/APIs; if changed, search & update all callers
- Coordinate ABI-impacting struct/class layout changes; keep binary compatibility
- When modifying public interfaces, grep the entire codebase for usages
### Performance
- Watch perf in hot paths (hooks, timers, serialization)
- Avoid avoidable allocations in frequently called code
- Profile changes that touch performance-sensitive areas
### Dependencies
- Ask before adding third-party deps or changing serialization formats
- New dependencies must be MIT-licensed or approved by PM team
- Add any new external packages to `NOTICE.md`
### Logging
- C++ logging uses spdlog (`Logger::info`, `Logger::warn`, `Logger::error`, `Logger::debug`)
- Initialize with `init_logger()` early in startup
- Keep hot paths quiet no logging in tight loops or hooks
## Acceptance Criteria
- No unintended ABI breaks
- No noisy logs in hot paths
- New non-obvious symbols briefly commented
- All callers updated when interfaces change
## Code Style
- **C++**: Follow `.clang-format` in `src/`; use Modern C++ patterns per C++ Core Guidelines
- **C#**: Follow `src/.editorconfig`; enforce StyleCop.Analyzers
## Validation
- Build: `tools\build\build.cmd` from `src/common/` folder
- Verify no ABI breaks: grep for changed function/struct names across codebase
- Check logs: ensure no new logging in performance-critical paths

View File

@@ -0,0 +1,256 @@
---
description: 'Guidelines for creating high-quality custom instruction files for GitHub Copilot'
applyTo: '**/*.instructions.md'
---
# Custom Instructions File Guidelines
Instructions for creating effective and maintainable custom instruction files that guide GitHub Copilot in generating domain-specific code and following project conventions.
## Project Context
- Target audience: Developers and GitHub Copilot working with domain-specific code
- File format: Markdown with YAML frontmatter
- File naming convention: lowercase with hyphens (e.g., `react-best-practices.instructions.md`)
- Location: `.github/instructions/` directory
- Purpose: Provide context-aware guidance for code generation, review, and documentation
## Required Frontmatter
Every instruction file must include YAML frontmatter with the following fields:
```yaml
---
description: 'Brief description of the instruction purpose and scope'
applyTo: 'glob pattern for target files (e.g., **/*.ts, **/*.py)'
---
```
### Frontmatter Guidelines
- **description**: Single-quoted string, 1-500 characters, clearly stating the purpose
- **applyTo**: Glob pattern(s) specifying which files these instructions apply to
- Single pattern: `'**/*.ts'`
- Multiple patterns: `'**/*.ts, **/*.tsx, **/*.js'`
- Specific files: `'src/**/*.py'`
- All files: `'**'`
## File Structure
A well-structured instruction file should include the following sections:
### 1. Title and Overview
- Clear, descriptive title using `#` heading
- Brief introduction explaining the purpose and scope
- Optional: Project context section with key technologies and versions
### 2. Core Sections
Organize content into logical sections based on the domain:
- **General Instructions**: High-level guidelines and principles
- **Best Practices**: Recommended patterns and approaches
- **Code Standards**: Naming conventions, formatting, style rules
- **Architecture/Structure**: Project organization and design patterns
- **Common Patterns**: Frequently used implementations
- **Security**: Security considerations (if applicable)
- **Performance**: Optimization guidelines (if applicable)
- **Testing**: Testing standards and approaches (if applicable)
### 3. Examples and Code Snippets
Provide concrete examples with clear labels:
```markdown
### Good Example
\`\`\`language
// Recommended approach
code example here
\`\`\`
### Bad Example
\`\`\`language
// Avoid this pattern
code example here
\`\`\`
```
### 4. Validation and Verification (Optional but Recommended)
- Build commands to verify code
- Lint checks and formatting tools
- Testing requirements
- Verification steps
## Content Guidelines
### Writing Style
- Use clear, concise language
- Write in imperative mood ("Use", "Implement", "Avoid")
- Be specific and actionable
- Avoid ambiguous terms like "should", "might", "possibly"
- Use bullet points and lists for readability
- Keep sections focused and scannable
### Best Practices
- **Be Specific**: Provide concrete examples rather than abstract concepts
- **Show Why**: Explain the reasoning behind recommendations when it adds value
- **Use Tables**: For comparing options, listing rules, or showing patterns
- **Include Examples**: Real code snippets are more effective than descriptions
- **Stay Current**: Reference current versions and best practices
- **Link Resources**: Include official documentation and authoritative sources
### Common Patterns to Include
1. **Naming Conventions**: How to name variables, functions, classes, files
2. **Code Organization**: File structure, module organization, import order
3. **Error Handling**: Preferred error handling patterns
4. **Dependencies**: How to manage and document dependencies
5. **Comments and Documentation**: When and how to document code
6. **Version Information**: Target language/framework versions
## Patterns to Follow
### Bullet Points and Lists
```markdown
## Security Best Practices
- Always validate user input before processing
- Use parameterized queries to prevent SQL injection
- Store secrets in environment variables, never in code
- Implement proper authentication and authorization
- Enable HTTPS for all production endpoints
```
### Tables for Structured Information
```markdown
## Common Issues
| Issue | Solution | Example |
| ---------------- | ------------------- | ----------------------------- |
| Magic numbers | Use named constants | `const MAX_RETRIES = 3` |
| Deep nesting | Extract functions | Refactor nested if statements |
| Hardcoded values | Use configuration | Store API URLs in config |
```
### Code Comparison
```markdown
### Good Example - Using TypeScript interfaces
\`\`\`typescript
interface User {
id: string;
name: string;
email: string;
}
function getUser(id: string): User {
// Implementation
}
\`\`\`
### Bad Example - Using any type
\`\`\`typescript
function getUser(id: any): any {
// Loses type safety
}
\`\`\`
```
### Conditional Guidance
```markdown
## Framework Selection
- **For small projects**: Use Minimal API approach
- **For large projects**: Use controller-based architecture with clear separation
- **For microservices**: Consider domain-driven design patterns
```
## Patterns to Avoid
- **Overly verbose explanations**: Keep it concise and scannable
- **Outdated information**: Always reference current versions and practices
- **Ambiguous guidelines**: Be specific about what to do or avoid
- **Missing examples**: Abstract rules without concrete code examples
- **Contradictory advice**: Ensure consistency throughout the file
- **Copy-paste from documentation**: Add value by distilling and providing context
## Testing Your Instructions
Before finalizing instruction files:
1. **Test with Copilot**: Try the instructions with actual prompts in VS Code
2. **Verify Examples**: Ensure code examples are correct and run without errors
3. **Check Glob Patterns**: Confirm `applyTo` patterns match intended files
## Example Structure
Here's a minimal example structure for a new instruction file:
```markdown
---
description: 'Brief description of purpose'
applyTo: '**/*.ext'
---
# Technology Name Development
Brief introduction and context.
## General Instructions
- High-level guideline 1
- High-level guideline 2
## Best Practices
- Specific practice 1
- Specific practice 2
## Code Standards
### Naming Conventions
- Rule 1
- Rule 2
### File Organization
- Structure 1
- Structure 2
## Common Patterns
### Pattern 1
Description and example
\`\`\`language
code example
\`\`\`
### Pattern 2
Description and example
## Validation
- Build command: `command to verify`
- Lint checks: `command to lint`
- Testing: `command to test`
```
## Maintenance
- Review instructions when dependencies or frameworks are updated
- Update examples to reflect current best practices
- Remove outdated patterns or deprecated features
- Add new patterns as they emerge in the community
- Keep glob patterns accurate as project structure evolves
## Additional Resources
- [Custom Instructions Documentation](https://code.visualstudio.com/docs/copilot/customization/custom-instructions)
- [Awesome Copilot Instructions](https://github.com/github/awesome-copilot/tree/main/instructions)

View File

@@ -0,0 +1,88 @@
---
description: 'Guidelines for creating high-quality prompt files for GitHub Copilot'
applyTo: '**/*.prompt.md'
---
# Copilot Prompt Files Guidelines
Instructions for creating effective and maintainable prompt files that guide GitHub Copilot in delivering consistent, high-quality outcomes across any repository.
## Scope and Principles
- Target audience: maintainers and contributors authoring reusable prompts for Copilot Chat.
- Goals: predictable behaviour, clear expectations, minimal permissions, and portability across repositories.
- Primary references: VS Code documentation on prompt files and organization-specific conventions.
## Frontmatter Requirements
Every prompt file should include YAML frontmatter with the following fields:
### Required/Recommended Fields
| Field | Required | Description |
|-------|----------|-------------|
| `description` | Recommended | A short description of the prompt (single sentence, actionable outcome) |
| `name` | Optional | The name shown after typing `/` in chat. Defaults to filename if not specified |
| `agent` | Recommended | The agent to use: `ask`, `edit`, `agent`, or a custom agent name. Defaults to current agent |
| `model` | Optional | The language model to use. Defaults to currently selected model |
| `tools` | Optional | List of tool/tool set names available for this prompt |
| `argument-hint` | Optional | Hint text shown in chat input to guide user interaction |
### Guidelines
- Use consistent quoting (single quotes recommended) and keep one field per line for readability and version control clarity
- If `tools` are specified and current agent is `ask` or `edit`, the default agent becomes `agent`
- Preserve any additional metadata (`language`, `tags`, `visibility`, etc.) required by your organization
## File Naming and Placement
- Use kebab-case filenames ending with `.prompt.md` and store them under `.github/prompts/` unless your workspace standard specifies another directory.
- Provide a short filename that communicates the action (for example, `generate-readme.prompt.md` rather than `prompt1.prompt.md`).
## Body Structure
- Start with an `#` level heading that matches the prompt intent so it surfaces well in Quick Pick search.
- Organize content with predictable sections. Recommended baseline: `Mission` or `Primary Directive`, `Scope & Preconditions`, `Inputs`, `Workflow` (step-by-step), `Output Expectations`, and `Quality Assurance`.
- Adjust section names to fit the domain, but retain the logical flow: why → context → inputs → actions → outputs → validation.
- Reference related prompts or instruction files using relative links to aid discoverability.
## Input and Context Handling
- Use `${input:variableName[:placeholder]}` for required values and explain when the user must supply them. Provide defaults or alternatives where possible.
- Call out contextual variables such as `${selection}`, `${file}`, `${workspaceFolder}` only when they are essential, and describe how Copilot should interpret them.
- Document how to proceed when mandatory context is missing (for example, “Request the file path and stop if it remains undefined”).
## Tool and Permission Guidance
- Limit `tools` to the smallest set that enables the task. List them in the preferred execution order when the sequence matters.
- If the prompt inherits tools from a chat mode, mention that relationship and state any critical tool behaviours or side effects.
- Warn about destructive operations (file creation, edits, terminal commands) and include guard rails or confirmation steps in the workflow.
## Instruction Tone and Style
- Write in direct, imperative sentences targeted at Copilot (for example, “Analyze”, “Generate”, “Summarize”).
- Keep sentences short and unambiguous, following Google Developer Documentation translation best practices to support localization.
- Avoid idioms, humor, or culturally specific references; favor neutral, inclusive language.
## Output Definition
- Specify the format, structure, and location of expected results (for example, “Create an architecture decision record file using the template below, such as `docs/architecture-decisions/record-XXXX.md`).
- Include success criteria and failure triggers so Copilot knows when to halt or retry.
- Provide validation steps—manual checks, automated commands, or acceptance criteria lists—that reviewers can execute after running the prompt.
## Examples and Reusable Assets
- Embed Good/Bad examples or scaffolds (Markdown templates, JSON stubs) that the prompt should produce or follow.
- Maintain reference tables (capabilities, status codes, role descriptions) inline to keep the prompt self-contained. Update these tables when upstream resources change.
- Link to authoritative documentation instead of duplicating lengthy guidance.
## Quality Assurance Checklist
- [ ] Frontmatter fields are complete, accurate, and least-privilege.
- [ ] Inputs include placeholders, default behaviours, and fallbacks.
- [ ] Workflow covers preparation, execution, and post-processing without gaps.
- [ ] Output expectations include formatting and storage details.
- [ ] Validation steps are actionable (commands, diff checks, review prompts).
- [ ] Security, compliance, and privacy policies referenced by the prompt are current.
- [ ] Prompt executes successfully in VS Code (`Chat: Run Prompt`) using representative scenarios.
## Maintenance Guidance
- Version-control prompts alongside the code they affect; update them when dependencies, tooling, or review processes change.
- Review prompts periodically to ensure tool lists, model requirements, and linked documents remain valid.
- Coordinate with other repositories: when a prompt proves broadly useful, extract common guidance into instruction files or shared prompt packs.
## Additional Resources
- [Prompt Files Documentation](https://code.visualstudio.com/docs/copilot/customization/prompt-files#_prompt-file-format)
- [Awesome Copilot Prompt Files](https://github.com/github/awesome-copilot/tree/main/prompts)
- [Tool Configuration](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode#_agent-mode-tools)

View File

@@ -0,0 +1,68 @@
---
description: 'Guidelines for Runner and Settings UI components that communicate via named pipes and manage module lifecycle'
applyTo: 'src/runner/**,src/settings-ui/**'
---
# Runner & Settings UI Core Components Guidance
Guidelines for modifying the Runner (tray/module loader) and Settings UI (configuration app). These components communicate via Windows Named Pipes using JSON messages.
## Runner (`src/runner/`)
### Scope
- Module bootstrap, hotkey management, settings bridge, update/elevation handling
### Guidelines
- If IPC/JSON contracts change, mirror updates in `src/settings-ui/**`
- Keep module discovery in `src/runner/main.cpp` in sync when adding/removing modules
- Keep startup lean: avoid blocking/network calls in early init path
- Preserve GPO & elevation behaviors; confirm no regression in policy handling
- Ask before modifying update workflow or elevation logic
### Acceptance Criteria
- Stable startup, consistent contracts, no unnecessary logging noise
## Settings UI (`src/settings-ui/`)
### Scope
- WinUI/WPF UI, communicates with Runner over named pipes; manages persisted settings schema
### Guidelines
- Don't break settings schema silently; add migration when shape changes
- If IPC/JSON contracts change, align with `src/runner/**` implementation
- Keep UI responsive: marshal to UI thread for UI-bound operations
- Reuse existing styles/resources; avoid duplicate theme keys
- Add/adjust migration or serialization tests when changing persisted settings
### Acceptance Criteria
- Schema integrity preserved, responsive UI, consistent contracts, no style duplication
## Shared Concerns
### IPC Contract Changes
When modifying the JSON message format between Runner and Settings UI:
1. Update both `src/runner/` and `src/settings-ui/` in the same PR
2. Preserve backward compatibility where possible
3. Add migration logic for settings schema changes
4. Test both directions of communication
### Code Style
- **C++ (Runner)**: Follow `.clang-format` in `src/`
- **C# (Settings UI)**: Follow `src/.editorconfig`, use StyleCop.Analyzers
- **XAML**: Use XamlStyler or run `.\.pipelines\applyXamlStyling.ps1 -Main`
## Validation
- Build Runner: `tools\build\build.cmd` from `src/runner/`
- Build Settings UI: `tools\build\build.cmd` from `src/settings-ui/`
- Test IPC: Launch both Runner and Settings UI, verify communication works
- Schema changes: Run serialization tests if settings shape changed

View File

@@ -0,0 +1,228 @@
---
description: 'Instructions for building Model Context Protocol (MCP) servers using the TypeScript SDK'
applyTo: '**/*.ts, **/*.js, **/package.json'
---
# TypeScript MCP Server Development
## Instructions
- Use the **@modelcontextprotocol/sdk** npm package: `npm install @modelcontextprotocol/sdk`
- Import from specific paths: `@modelcontextprotocol/sdk/server/mcp.js`, `@modelcontextprotocol/sdk/server/stdio.js`, etc.
- Use `McpServer` class for high-level server implementation with automatic protocol handling
- Use `Server` class for low-level control with manual request handlers
- Use **zod** for input/output schema validation: `npm install zod@3`
- Always provide `title` field for tools, resources, and prompts for better UI display
- Use `registerTool()`, `registerResource()`, and `registerPrompt()` methods (recommended over older APIs)
- Define schemas using zod: `{ inputSchema: { param: z.string() }, outputSchema: { result: z.string() } }`
- Return both `content` (for display) and `structuredContent` (for structured data) from tools
- For HTTP servers, use `StreamableHTTPServerTransport` with Express or similar frameworks
- For local integrations, use `StdioServerTransport` for stdio-based communication
- Create new transport instances per request to prevent request ID collisions (stateless mode)
- Use session management with `sessionIdGenerator` for stateful servers
- Enable DNS rebinding protection for local servers: `enableDnsRebindingProtection: true`
- Configure CORS headers and expose `Mcp-Session-Id` for browser-based clients
- Use `ResourceTemplate` for dynamic resources with URI parameters: `new ResourceTemplate('resource://{param}', { list: undefined })`
- Support completions for better UX using `completable()` wrapper from `@modelcontextprotocol/sdk/server/completable.js`
- Implement sampling with `server.server.createMessage()` to request LLM completions from clients
- Use `server.server.elicitInput()` to request additional user input during tool execution
- Enable notification debouncing for bulk updates: `debouncedNotificationMethods: ['notifications/tools/list_changed']`
- Dynamic updates: call `.enable()`, `.disable()`, `.update()`, or `.remove()` on registered items to emit `listChanged` notifications
- Use `getDisplayName()` from `@modelcontextprotocol/sdk/shared/metadataUtils.js` for UI display names
- Test servers with MCP Inspector: `npx @modelcontextprotocol/inspector`
## Best Practices
- Keep tool implementations focused on single responsibilities
- Provide clear, descriptive titles and descriptions for LLM understanding
- Use proper TypeScript types for all parameters and return values
- Implement comprehensive error handling with try-catch blocks
- Return `isError: true` in tool results for error conditions
- Use async/await for all asynchronous operations
- Close database connections and clean up resources properly
- Validate input parameters before processing
- Use structured logging for debugging without polluting stdout/stderr
- Consider security implications when exposing file system or network access
- Implement proper resource cleanup on transport close events
- Use environment variables for configuration (ports, API keys, etc.)
- Document tool capabilities and limitations clearly
- Test with multiple clients to ensure compatibility
## Common Patterns
### Basic Server Setup (HTTP)
```typescript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import express from 'express';
const server = new McpServer({
name: 'my-server',
version: '1.0.0'
});
const app = express();
app.use(express.json());
app.post('/mcp', async (req, res) => {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
enableJsonResponse: true
});
res.on('close', () => transport.close());
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
app.listen(3000);
```
### Basic Server Setup (stdio)
```typescript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new McpServer({
name: 'my-server',
version: '1.0.0'
});
// ... register tools, resources, prompts ...
const transport = new StdioServerTransport();
await server.connect(transport);
```
### Simple Tool
```typescript
import { z } from 'zod';
server.registerTool(
'calculate',
{
title: 'Calculator',
description: 'Perform basic calculations',
inputSchema: { a: z.number(), b: z.number(), op: z.enum(['+', '-', '*', '/']) },
outputSchema: { result: z.number() }
},
async ({ a, b, op }) => {
const result = op === '+' ? a + b : op === '-' ? a - b :
op === '*' ? a * b : a / b;
const output = { result };
return {
content: [{ type: 'text', text: JSON.stringify(output) }],
structuredContent: output
};
}
);
```
### Dynamic Resource
```typescript
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
server.registerResource(
'user',
new ResourceTemplate('users://{userId}', { list: undefined }),
{
title: 'User Profile',
description: 'Fetch user profile data'
},
async (uri, { userId }) => ({
contents: [{
uri: uri.href,
text: `User ${userId} data here`
}]
})
);
```
### Tool with Sampling
```typescript
server.registerTool(
'summarize',
{
title: 'Text Summarizer',
description: 'Summarize text using LLM',
inputSchema: { text: z.string() },
outputSchema: { summary: z.string() }
},
async ({ text }) => {
const response = await server.server.createMessage({
messages: [{
role: 'user',
content: { type: 'text', text: `Summarize: ${text}` }
}],
maxTokens: 500
});
const summary = response.content.type === 'text' ?
response.content.text : 'Unable to summarize';
const output = { summary };
return {
content: [{ type: 'text', text: JSON.stringify(output) }],
structuredContent: output
};
}
);
```
### Prompt with Completion
```typescript
import { completable } from '@modelcontextprotocol/sdk/server/completable.js';
server.registerPrompt(
'review',
{
title: 'Code Review',
description: 'Review code with specific focus',
argsSchema: {
language: completable(z.string(), value =>
['typescript', 'python', 'javascript', 'java']
.filter(l => l.startsWith(value))
),
code: z.string()
}
},
({ language, code }) => ({
messages: [{
role: 'user',
content: {
type: 'text',
text: `Review this ${language} code:\n\n${code}`
}
}]
})
);
```
### Error Handling
```typescript
server.registerTool(
'risky-operation',
{
title: 'Risky Operation',
description: 'An operation that might fail',
inputSchema: { input: z.string() },
outputSchema: { result: z.string() }
},
async ({ input }) => {
try {
const result = await performRiskyOperation(input);
const output = { result };
return {
content: [{ type: 'text', text: JSON.stringify(output) }],
structuredContent: output
};
} catch (err: unknown) {
const error = err as Error;
return {
content: [{ type: 'text', text: `Error: ${error.message}` }],
isError: true
};
}
}
);
```

View File

@@ -1,16 +1,49 @@
---
mode: 'agent'
model: GPT-5-Codex (Preview)
description: 'Generate an 80-character git commit title for the local diff.'
agent: 'agent'
description: 'Generate an 80-character git commit title for the local diff'
---
**Goal:** Provide a ready-to-paste git commit title (<= 80 characters) that captures the most important local changes since `HEAD`.
# Generate Commit Title
**Workflow:**
1. Run a single command to view the local diff since the last commit:
```@terminal
git diff HEAD
```
2. From that diff, identify the dominant area (reference key paths like `src/modules/*`, `doc/devdocs/**`, etc.), the type of change (bug fix, docs update, config tweak), and any notable impact.
3. Draft a concise, imperative commit title summarizing the dominant change. Keep it plain ASCII, <= 80 characters, and avoid trailing punctuation. Mention the primary component when obvious (for example `FancyZones:` or `Docs:`).
4. Respond with only the final commit title on a single line so it can be pasted directly into `git commit`.
## 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,9 +1,10 @@
---
mode: 'agent'
model: GPT-5-Codex (Preview)
description: 'Generate a PowerToys-ready pull request description from the local diff.'
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:**
@@ -20,3 +21,4 @@ description: 'Generate a PowerToys-ready pull request description from the local
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.

72
.github/prompts/fix-issue.prompt.md vendored Normal file
View File

@@ -0,0 +1,72 @@
---
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

@@ -0,0 +1,70 @@
---
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,15 +1,16 @@
---
mode: 'agent'
model: GPT-5-Codex (Preview)
description: 'Resolve Code scanning / check-spelling comments on the active PR.'
agent: 'agent'
description: 'Resolve Code scanning / check-spelling comments on the active PR'
---
# Fix Spelling Comments
**Goal:** Clear every outstanding GitHub pull request comment created by the `Code scanning / check-spelling` workflow by explicitly allowing intentional terms.
**Guardrails:**
- Update only discussion threads authored by `github-actions` or `github-actions[bot]` that mention `Code scanning results / check-spelling`.
- Resolve findings solely by editing `.github/actions/spell-check/expect.txt`; reuse existing entries.
- Leave all other files and topics untouched.
- Prefer improving the wording in the originally flagged file when it clarifies intent without changing meaning; if the wording is already clear/standard for the context, handle it via `.github/actions/spell-check/expect.txt` and reuse existing entries.
- Limit edits to the flagged text and `.github/actions/spell-check/expect.txt`; leave all other files and topics untouched.
**Prerequisites:**
- Install GitHub CLI if it is not present: `winget install GitHub.cli`.
@@ -18,5 +19,6 @@ description: 'Resolve Code scanning / check-spelling comments on the active PR.'
**Workflow:**
1. Determine the active pull request with a single `gh pr view --json number` call (default to the current branch).
2. Fetch all PR discussion data once via `gh pr view --json comments,reviews` and filter to check-spelling comments authored by `github-actions` or `github-actions[bot]` that are not minimized; when several remain, process only the most recent comment body.
3. For each flagged token, review `.github/actions/spell-check/expect.txt` for an equivalent term (for example an existing lowercase variant); when found, reuse that normalized term rather than adding a new entry, even if the flagged token differs only by casing. Only add a new entry after confirming no equivalent already exists.
4. Add any remaining missing token to `.github/actions/spell-check/expect.txt`, keeping surrounding formatting intact.
3. For each flagged token, first consider tightening or rephrasing the original text to avoid the false positive while keeping the meaning intact; if the existing wording is already normal and professional for the context, proceed to allowlisting instead of changing it.
4. When allowlisting, review `.github/actions/spell-check/expect.txt` for an equivalent term (for example an existing lowercase variant); when found, reuse that normalized term rather than adding a new entry, even if the flagged token differs only by casing. Only add a new entry after confirming no equivalent already exists.
5. Add any remaining missing token to `.github/actions/spell-check/expect.txt`, keeping surrounding formatting intact.

165
.github/prompts/review-issue.prompt.md vendored Normal file
View File

@@ -0,0 +1,165 @@
---
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.

198
.github/prompts/review-pr.prompt.md vendored Normal file
View File

@@ -0,0 +1,198 @@
---
agent: 'agent'
description: 'Perform a comprehensive PR review with per-step Markdown and machine-readable outputs'
---
# Review Pull Request
**Goal**: Given `{{pr_number}}`, run a *one-topic-per-step* review. Write files to `Generated Files/prReview/{{pr_number}}/` (replace `{{pr_number}}` with the integer). Emit machinereadable blocks for a GitHub MCP to post review comments.
## PR selection
Resolve the target PR using these fallbacks in order:
1. Parse the invocation text for an explicit identifier (first integer following patterns such as a leading hash and digits or the text `PR:` followed by digits).
2. If no PR is found yet, locate the newest `Generated Files/prReview/_batch/batch-overview-*.md` file (highest timestamp in filename, fallback newest mtime) and take the first entry in its `## PRs` list whose review folder is missing `00-OVERVIEW.md` or contains `__error.flag`.
3. If the batch file has no pending PRs, query assignments with `gh pr list --assignee @me --state open --json number,updatedAt --limit 20` and pick the most recently updated PR that does not already have a completed review folder.
4. If still unknown, run `gh pr view --json number` in the current branch and use that result when it is unambiguous.
5. If every step above fails, prompt the user for a PR number before proceeding.
## Fetch PR data with `gh`
- `gh pr view {{pr_number}} --json number,baseRefName,headRefName,baseRefOid,headRefOid,changedFiles,files`
- `gh api repos/:owner/:repo/pulls/{{pr_number}}/files?per_page=250` # patches for line mapping
### Incremental review workflow
1. **Check for existing review**: Read `Generated Files/prReview/{{pr_number}}/00-OVERVIEW.md`
2. **Extract state**: Parse `Last reviewed SHA:` from review metadata section
3. **Detect changes**: Run `Get-PrIncrementalChanges.ps1 -PullRequestNumber {{pr_number}} -LastReviewedCommitSha {{sha}}`
4. **Analyze result**:
- `NeedFullReview: true` → Review all files in the PR
- `NeedFullReview: false` and `IsIncremental: true` → Review only files in `ChangedFiles` array
- `ChangedFiles` is empty → No changes, skip review (update iteration history with "No changes since last review")
5. **Apply smart filtering**: Use the file patterns in smart step filtering table to skip irrelevant steps
6. **Update metadata**: After completing review, save current `headRefOid` as `Last reviewed SHA:` in `00-OVERVIEW.md`
### Reusable PowerShell scripts
Scripts live in `.github/review-tools/` to avoid repeated manual approvals during PR reviews:
| Script | Usage |
| --- | --- |
| `.github/review-tools/Get-GitHubRawFile.ps1` | Download a repository file at a given ref, optionally with line numbers. |
| `.github/review-tools/Get-GitHubPrFilePatch.ps1` | Fetch the unified diff for a specific file within a pull request via `gh api`. |
| `.github/review-tools/Get-PrIncrementalChanges.ps1` | Compare last reviewed SHA with current PR head to identify incremental changes. Returns JSON with changed files, new commits, and whether full review is needed. |
| `.github/review-tools/Test-IncrementalReview.ps1` | Test helper to preview incremental review detection for a PR. Use before running full review to see what changed. |
Always prefer these scripts (or new ones added under `.github/review-tools/`) over raw `gh api` or similar shell commands so the review flow does not trigger interactive approval prompts.
## Output files
Folder: `Generated Files/prReview/{{pr_number}}/`
Files: `00-OVERVIEW.md`, `01-functionality.md`, `02-compatibility.md`, `03-performance.md`, `04-accessibility.md`, `05-security.md`, `06-localization.md`, `07-globalization.md`, `08-extensibility.md`, `09-solid-design.md`, `10-repo-patterns.md`, `11-docs-automation.md`, `12-code-comments.md`, `13-copilot-guidance.md` *(only if guidance md exists).*
- **Write-after-step rule:** Immediately after completing each TODO step, persist that step's markdown file before proceeding to the next. Generate `00-OVERVIEW.md` only after every step file has been refreshed for the current run.
## Iteration management
- Determine the current review iteration by reading `00-OVERVIEW.md` (look for `Review iteration:`). If missing, assume iteration `1`.
- Extract the last reviewed SHA from `00-OVERVIEW.md` (look for `Last reviewed SHA:` in the review metadata section). If missing, this is iteration 1.
- **Incremental review detection**:
1. Call `.github/review-tools/Get-PrIncrementalChanges.ps1 -PullRequestNumber {{pr_number}} -LastReviewedCommitSha {{last_sha}}` to get delta analysis.
2. Parse the JSON result to determine if incremental review is possible (`IsIncremental: true`, `NeedFullReview: false`).
3. If force-push detected or first review, proceed with full review of all changed files.
4. If incremental, review only the files listed in `ChangedFiles` array and apply smart step filtering (see below).
- Increment the iteration for each review run and propagate the new value to all step files and the overview.
- Preserve prior iteration notes by keeping/expanding an `## Iteration history` section in each markdown file, appending the newest summary under `### Iteration <N>`.
- Summaries should capture key deltas since the previous iteration so reruns can pick up context quickly.
- **After review completion**, update `Last reviewed SHA:` in `00-OVERVIEW.md` with the current `headRefOid` and update the timestamp.
### Smart step filtering (incremental reviews only)
When performing incremental review, skip steps that are irrelevant based on changed file types:
| File pattern | Required steps | Skippable steps |
| --- | --- | --- |
| `**/*.cs`, `**/*.cpp`, `**/*.h` | Functionality, Compatibility, Performance, Security, SOLID, Repo patterns, Code comments | (depends on files) |
| `**/*.resx`, `**/Resources/*.xaml` | Localization, Globalization | Most others |
| `**/*.md` (docs) | Docs & automation | Most others (unless copilot guidance) |
| `**/*copilot*.md`, `.github/prompts/*.md` | Copilot guidance, Docs & automation | Most others |
| `**/*.csproj`, `**/*.vcxproj`, `**/packages.config` | Compatibility, Security, Repo patterns | Localization, Globalization, Accessibility |
| `**/UI/**`, `**/*View.xaml` | Accessibility, Localization | Performance (unless perf-sensitive controls) |
**Default**: If uncertain or files span multiple categories, run all applicable steps. When in doubt, be conservative and review more rather than less.
## TODO steps (one concern each)
1) Functionality
2) Compatibility
3) Performance
4) Accessibility
5) Security
6) Localization
7) Globalization
8) Extensibility
9) SOLID principles
10) Repo patterns
11) Docs & automation coverage for the changes
12) Code comments
13) Copilot guidance (conditional): if changed folders contain `*copilot*.md` or `.github/prompts/*.md`, review diffs **against** that guidance and write `13-copilot-guidance.md` (omit if none).
## Per-step file template (use verbatim)
```md
# <STEP TITLE>
**PR:** (populate with PR identifier) — Base:<baseRefName> Head:<headRefName>
**Review iteration:** ITERATION
## Iteration history
- Maintain subsections titled `### Iteration N` in reverse chronological order (append the latest at the top) with 24 bullet highlights.
### Iteration ITERATION
- <Latest key point 1>
- <Latest key point 2>
## Checks executed
- List the concrete checks for *this step only* (510 bullets).
## Findings
(If none, write **None**. Defaults have one or more blocks:)
```mcp-review-comment
{"file":"relative/path.ext","start_line":123,"end_line":125,"severity":"high|medium|low|info","tags":["<step-slug>","pr-tag-here"],"related_files":["optional/other/file1"],"body":"Problem → Why it matters → Concrete fix. If spans multiple files, name them here."}
```
Use the second tag to encode the PR number.
```
## Overview file (`00-OVERVIEW.md`) template
```md
# PR Review Overview — (populate with PR identifier)
**Review iteration:** ITERATION
**Changed files:** <n> | **High severity issues:** <count>
## Review metadata
**Last reviewed SHA:** <headRefOid from gh pr view>
**Last review timestamp:** <ISO8601 timestamp>
**Review mode:** <Full|Incremental (N files changed since iteration X)>
**Base ref:** <baseRefName>
**Head ref:** <headRefName>
## Step results
Write lines like: `01 Functionality — <OK|Issues|Skipped> (see 01-functionality.md)` … through step 13.
Mark steps as "Skipped" when using incremental review smart filtering.
## Iteration history
- Maintain subsections titled `### Iteration N` mirroring the per-step convention with concise deltas and cross-links to the relevant step files.
- For incremental reviews, list the specific files that changed and which commits were added.
```
## Line numbers & multifile issues
- Map headside lines from `patch` hunks (`@@ -a,b +c,d @@` → new lines `+c..+c+d-1`).
- For crossfile issues: set the primary `"file"`, list others in `"related_files"`, and name them in `"body"`.
## Posting (for MCP)
- Parse all ```mcp-review-comment``` blocks across step files and post as PR review comments.
- If posting isnt available, still write all files.
## Constraint
Read/analyze only; don't modify code. Keep comments small, specific, and fixoriented.
**Testing**: Use `.github/review-tools/Test-IncrementalReview.ps1 -PullRequestNumber 42374` to preview incremental detection before running full review.
## Scratch cache for large PRs
Create a local scratch workspace to progressively summarize diffs and reload state across runs.
### Paths
- Root: `Generated Files/prReview/{{pr_number}}/__tmp/`
- Files:
- `index.jsonl` — append-only JSON Lines index of artifacts.
- `todo-queue.json` — pending items (files/chunks/steps).
- `rollup-<step>-v<N>.md` — iterative per-step aggregates.
- `file-<hash>.txt` — optional saved chunk text (when needed).
### JSON schema (per line in `index.jsonl`)
```json
{"type":"chunk|summary|issue|crosslink",
"path":"relative/file.ext","chunk_id":"f-12","step":"functionality|compatibility|...",
"base_sha":"...", "head_sha":"...", "range":[start,end], "version":1,
"notes":"short text or key:value map", "created_utc":"ISO8601"}
```
### Phases (stateful; resume-safe)
0. **Discover** PR + SHAs: `gh pr view <PR> --json baseRefName,headRefName,baseRefOid,headRefOid,files`.
1. **Chunk** each changed file (head): split into ~300600 LOC or ~4k chars; stable `chunk_id` = hash(path+start).
- Save `chunk` records. Optionally write `file-<hash>.txt` for expensive chunks.
2. **Summarize** per chunk: intent, APIs, risks per TODO step; emit `summary` records (≤600 tokens each).
3. **Issues**: convert findings to machine-readable blocks and emit `issue` records (later rendered to step MD).
4. **Rollups**: build/update `rollup-<step>-v<N>.md` from `summary`+`issue`. Keep prior versions.
5. **Finalize**: write per-step files + `00-OVERVIEW.md` from rollups. Post comments via MCP if available.
### Re-use & token limits
- Always **reload** `index.jsonl` first; skip chunks with same `head_sha` and `range`.
- **Incremental review optimization**: When `Get-PrIncrementalChanges.ps1` returns a subset of changed files, load only chunks from those files. Reuse existing chunks/summaries for unchanged files.
- Prefer re-summarizing only changed chunks; merge chunk summaries → file summaries → step rollups.
- When context is tight, load only the minimal chunk text (or its saved `file-<hash>.txt`) needed for a comment.
### Original vs diff
- Fetch base content when needed: prefer `git show <baseRefName>:<path>`; fallback `gh api repos/:owner/:repo/contents/<path>?ref=<base_sha>` (base64).
- Use patch hunks from `gh api .../pulls/<PR>/files` to compute **head** line numbers.
### Queue-driven loop
- Seed `todo-queue.json` with all changed files.
- Process: chunk → summarize → detect issues → roll up.
- Append to `index.jsonl` after each step; never rewrite previous lines (append-only).
### Hygiene
- `__tmp/` is implementation detail; do not include in final artifacts.
- It is safe to delete to force a clean pass; the next run rebuilds it.

View File

@@ -0,0 +1,79 @@
<#
.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

@@ -0,0 +1,91 @@
<#
.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

@@ -0,0 +1,173 @@
<#
.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

View File

@@ -0,0 +1,156 @@
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

@@ -0,0 +1,170 @@
<#
.SYNOPSIS
Tests and previews incremental review detection for a pull request.
.DESCRIPTION
This helper script validates the incremental review detection logic by analyzing an existing
PR review folder. It reads the last reviewed SHA from the overview file, compares it with
the current PR state, and displays detailed information about what has changed.
This is useful for:
- Testing the incremental review system before running a full review
- Understanding what changed since the last review iteration
- Verifying that review metadata was properly recorded
.PARAMETER PullRequestNumber
The pull request number to test incremental review detection for.
.PARAMETER RepositoryOwner
The GitHub repository owner. Defaults to "microsoft".
.PARAMETER RepositoryName
The GitHub repository name. Defaults to "PowerToys".
.OUTPUTS
Colored console output displaying:
- Current and last reviewed commit SHAs
- Whether incremental review is possible
- List of new commits since last review
- List of changed files with status indicators
- Recommended review strategy
.EXAMPLE
.\Test-IncrementalReview.ps1 -PullRequestNumber 42374
Tests incremental review detection for PR #42374.
.EXAMPLE
.\Test-IncrementalReview.ps1 -PullRequestNumber 42374 -RepositoryOwner "myorg" -RepositoryName "myrepo"
Tests incremental review for a PR in a different repository.
.NOTES
Requires GitHub CLI (gh) to be installed and authenticated.
Run 'gh auth login' if not already authenticated.
Prerequisites:
- PR review folder must exist at "Generated Files\prReview\{PRNumber}"
- 00-OVERVIEW.md must exist in the review folder
- For incremental detection, overview must contain "Last reviewed SHA" metadata
.LINK
https://cli.github.com/
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, HelpMessage = "Pull request number to test")]
[int]$PullRequestNumber,
[Parameter(Mandatory = $false, HelpMessage = "Repository owner")]
[string]$RepositoryOwner = "microsoft",
[Parameter(Mandatory = $false, HelpMessage = "Repository name")]
[string]$RepositoryName = "PowerToys"
)
# Resolve paths to review folder and overview file
$repositoryRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$reviewFolderPath = Join-Path $repositoryRoot "Generated Files\prReview\$PullRequestNumber"
$overviewFilePath = Join-Path $reviewFolderPath "00-OVERVIEW.md"
Write-Host "=== Testing Incremental Review for PR #$PullRequestNumber ===" -ForegroundColor Cyan
Write-Host ""
# Check if review folder exists
if (-not (Test-Path $reviewFolderPath)) {
Write-Host "❌ Review folder not found: $reviewFolderPath" -ForegroundColor Red
Write-Host "This appears to be a new review (iteration 1)" -ForegroundColor Yellow
exit 0
}
# Check if overview file exists
if (-not (Test-Path $overviewFilePath)) {
Write-Host "❌ Overview file not found: $overviewFilePath" -ForegroundColor Red
Write-Host "This appears to be an incomplete review" -ForegroundColor Yellow
exit 0
}
# Read overview file and extract last reviewed SHA
Write-Host "📄 Reading overview file..." -ForegroundColor Green
$overviewFileContent = Get-Content $overviewFilePath -Raw
if ($overviewFileContent -match '\*\*Last reviewed SHA:\*\*\s+(\w+)') {
$lastReviewedSha = $Matches[1]
Write-Host "✅ Found last reviewed SHA: $lastReviewedSha" -ForegroundColor Green
} else {
Write-Host "⚠️ No 'Last reviewed SHA' found in overview - this may be an old format" -ForegroundColor Yellow
Write-Host "Proceeding without incremental detection (full review will be needed)" -ForegroundColor Yellow
exit 0
}
Write-Host ""
Write-Host "🔍 Running incremental change detection..." -ForegroundColor Cyan
# Call the incremental changes detection script
$incrementalChangesScriptPath = Join-Path $PSScriptRoot "Get-PrIncrementalChanges.ps1"
if (-not (Test-Path $incrementalChangesScriptPath)) {
Write-Host "❌ Script not found: $incrementalChangesScriptPath" -ForegroundColor Red
exit 1
}
try {
$analysisResult = & $incrementalChangesScriptPath `
-PullRequestNumber $PullRequestNumber `
-LastReviewedCommitSha $lastReviewedSha `
-RepositoryOwner $RepositoryOwner `
-RepositoryName $RepositoryName | ConvertFrom-Json
# Display analysis results
Write-Host ""
Write-Host "=== Incremental Review Analysis ===" -ForegroundColor Cyan
Write-Host "Current HEAD SHA: $($analysisResult.CurrentHeadSha)" -ForegroundColor White
Write-Host "Last reviewed SHA: $($analysisResult.LastReviewedSha)" -ForegroundColor White
Write-Host "Base branch: $($analysisResult.BaseRefName)" -ForegroundColor White
Write-Host "Head branch: $($analysisResult.HeadRefName)" -ForegroundColor White
Write-Host ""
Write-Host "Is incremental? $($analysisResult.IsIncremental)" -ForegroundColor $(if ($analysisResult.IsIncremental) { "Green" } else { "Yellow" })
Write-Host "Need full review? $($analysisResult.NeedFullReview)" -ForegroundColor $(if ($analysisResult.NeedFullReview) { "Yellow" } else { "Green" })
Write-Host ""
Write-Host "Summary: $($analysisResult.Summary)" -ForegroundColor Cyan
Write-Host ""
# Display new commits if any
if ($analysisResult.NewCommits -and $analysisResult.NewCommits.Count -gt 0) {
Write-Host "📝 New commits ($($analysisResult.NewCommits.Count)):" -ForegroundColor Green
foreach ($commit in $analysisResult.NewCommits) {
Write-Host " - $($commit.Sha): $($commit.Message)" -ForegroundColor Gray
}
Write-Host ""
}
# Display changed files if any
if ($analysisResult.ChangedFiles -and $analysisResult.ChangedFiles.Count -gt 0) {
Write-Host "📁 Changed files ($($analysisResult.ChangedFiles.Count)):" -ForegroundColor Green
foreach ($file in $analysisResult.ChangedFiles) {
$statusDisplayColor = switch ($file.Status) {
"added" { "Green" }
"removed" { "Red" }
"modified" { "Yellow" }
"renamed" { "Cyan" }
default { "White" }
}
Write-Host " - [$($file.Status)] $($file.Filename) (+$($file.Additions)/-$($file.Deletions))" -ForegroundColor $statusDisplayColor
}
Write-Host ""
}
# Suggest review strategy based on analysis
Write-Host "=== Recommended Review Strategy ===" -ForegroundColor Cyan
if ($analysisResult.NeedFullReview) {
Write-Host "🔄 Full review recommended" -ForegroundColor Yellow
} elseif ($analysisResult.IsIncremental -and ($analysisResult.ChangedFiles.Count -eq 0)) {
Write-Host "✅ No changes detected - no review needed" -ForegroundColor Green
} elseif ($analysisResult.IsIncremental) {
Write-Host "⚡ Incremental review possible - review only changed files" -ForegroundColor Green
Write-Host "💡 Consider applying smart step filtering based on file types" -ForegroundColor Cyan
}
} catch {
Write-Host "❌ Error running incremental change detection: $_" -ForegroundColor Red
exit 1
}

View File

@@ -0,0 +1,313 @@
---
description: PowerShell scripts for efficient PR reviews in PowerToys repository
applyTo: '**'
---
# PR Review Tools - Reference Guide
PowerShell scripts to support efficient and incremental pull request reviews in the PowerToys repository.
## Quick Start
### Prerequisites
- PowerShell 7+ (or Windows PowerShell 5.1+)
- GitHub CLI (`gh`) installed and authenticated (`gh auth login`)
- Access to the PowerToys repository
### Testing Your Setup
Run the full test suite (recommended):
```powershell
cd "d:\PowerToys-00c1\.github\review-tools"
.\Run-ReviewToolsTests.ps1
```
Expected: 9-10 tests passing
### Individual Script Tests
**Test incremental change detection:**
```powershell
.\Get-PrIncrementalChanges.ps1 -PullRequestNumber 42374
```
Expected: JSON output showing review analysis
**Preview incremental review:**
```powershell
.\Test-IncrementalReview.ps1 -PullRequestNumber 42374
```
Expected: Analysis showing current vs last reviewed SHA
**Fetch file content:**
```powershell
.\Get-GitHubRawFile.ps1 -FilePath "README.md" -GitReference "main"
```
Expected: README content displayed
**Get PR file patch:**
```powershell
.\Get-GitHubPrFilePatch.ps1 -PullRequestNumber 42374 -FilePath ".github/actions/spell-check/expect.txt"
```
Expected: Unified diff output
## Available Scripts
### Get-GitHubRawFile.ps1
Downloads and displays file content from a GitHub repository at a specific git reference.
**Purpose:** Retrieve baseline file content for comparison during PR reviews.
**Parameters:**
- `FilePath` (required): Relative path to file in repository
- `GitReference` (optional): Git ref (branch, tag, SHA). Default: "main"
- `RepositoryOwner` (optional): Repository owner. Default: "microsoft"
- `RepositoryName` (optional): Repository name. Default: "PowerToys"
- `ShowLineNumbers` (switch): Prefix each line with line number
- `StartLineNumber` (optional): Starting line number when using `-ShowLineNumbers`. Default: 1
**Usage:**
```powershell
.\Get-GitHubRawFile.ps1 -FilePath "src/runner/main.cpp" -GitReference "main" -ShowLineNumbers
```
### Get-GitHubPrFilePatch.ps1
Fetches the unified diff (patch) for a specific file in a pull request.
**Purpose:** Get the exact changes made to a file in a PR for detailed review.
**Parameters:**
- `PullRequestNumber` (required): Pull request number
- `FilePath` (required): Relative path to file in the PR
- `RepositoryOwner` (optional): Repository owner. Default: "microsoft"
- `RepositoryName` (optional): Repository name. Default: "PowerToys"
**Usage:**
```powershell
.\Get-GitHubPrFilePatch.ps1 -PullRequestNumber 42374 -FilePath "src/modules/cmdpal/main.cpp"
```
**Output:** Unified diff showing changes made to the file.
### Get-PrIncrementalChanges.ps1
Compares the last reviewed commit with the current PR head to identify incremental changes.
**Purpose:** Enable efficient incremental reviews by detecting what changed since the last review iteration.
**Parameters:**
- `PullRequestNumber` (required): Pull request number
- `LastReviewedCommitSha` (optional): SHA of the commit that was last reviewed. If omitted, assumes first review.
- `RepositoryOwner` (optional): Repository owner. Default: "microsoft"
- `RepositoryName` (optional): Repository name. Default: "PowerToys"
**Usage:**
```powershell
.\Get-PrIncrementalChanges.ps1 -PullRequestNumber 42374 -LastReviewedCommitSha "abc123def456"
```
**Output:** JSON object with detailed change analysis:
```json
{
"PullRequestNumber": 42374,
"CurrentHeadSha": "xyz789abc123",
"LastReviewedSha": "abc123def456",
"IsIncremental": true,
"NeedFullReview": false,
"ChangedFiles": [
{
"Filename": "src/modules/cmdpal/main.cpp",
"Status": "modified",
"Additions": 15,
"Deletions": 8,
"Changes": 23
}
],
"NewCommits": [
{
"Sha": "def456",
"Message": "Fix memory leak",
"Author": "John Doe",
"Date": "2025-11-07T10:30:00Z"
}
],
"Summary": "Incremental review: 1 new commit(s), 1 file(s) changed since SHA abc123d"
}
```
**Scenarios Handled:**
- **No LastReviewedCommitSha**: Returns `NeedFullReview: true` (first review)
- **SHA matches current HEAD**: Returns empty `ChangedFiles` (no changes)
- **Force-push detected**: Returns `NeedFullReview: true` (SHA not in history)
- **Incremental changes**: Returns list of changed files and new commits
### Test-IncrementalReview.ps1
Helper script to test and preview incremental review detection before running the full review.
**Purpose:** Validate incremental review functionality and preview what changed.
**Parameters:**
- `PullRequestNumber` (required): Pull request number
- `RepositoryOwner` (optional): Repository owner. Default: "microsoft"
- `RepositoryName` (optional): Repository name. Default: "PowerToys"
**Usage:**
```powershell
.\Test-IncrementalReview.ps1 -PullRequestNumber 42374
```
**Output:** Colored console output showing:
- Current and last reviewed SHAs
- Whether incremental review is possible
- List of new commits and changed files
- Recommended review strategy
## Workflow Integration
These scripts integrate with the PR review prompt (`.github/prompts/review-pr.prompt.md`).
### Typical Review Flow
1. **Initial Review (Iteration 1)**
- Review prompt processes the PR
- Creates `Generated Files/prReview/{PR}/00-OVERVIEW.md`
- Includes review metadata section with current HEAD SHA
2. **Subsequent Reviews (Iteration 2+)**
- Review prompt reads `00-OVERVIEW.md` to get last reviewed SHA
- Calls `Get-PrIncrementalChanges.ps1` to detect what changed
- If incremental:
- Reviews only changed files
- Skips irrelevant review steps (e.g., skip Localization if no `.resx` files changed)
- Uses `Get-GitHubPrFilePatch.ps1` to get patches for changed files
- Updates `00-OVERVIEW.md` with new SHA and iteration number
### Manual Testing Workflow
Preview changes before review:
```powershell
# Check what changed in PR #42374 since last review
.\Test-IncrementalReview.ps1 -PullRequestNumber 42374
# Get incremental changes programmatically
$changes = .\Get-PrIncrementalChanges.ps1 -PullRequestNumber 42374 -LastReviewedCommitSha "abc123" | ConvertFrom-Json
if (-not $changes.NeedFullReview) {
Write-Host "Only need to review $($changes.ChangedFiles.Count) files"
# Review each changed file
foreach ($file in $changes.ChangedFiles) {
Write-Host "Reviewing $($file.Filename)..."
.\Get-GitHubPrFilePatch.ps1 -PullRequestNumber 42374 -FilePath $file.Filename
}
}
```
## Error Handling and Troubleshooting
### Common Requirements
All scripts:
- Exit with code 1 on error
- Write detailed error messages to stderr
- Require `gh` CLI to be installed and authenticated
### Common Issues
**Error: "gh not found"**
- **Solution**: Install GitHub CLI from https://cli.github.com/ and run `gh auth login`
**Error: "Failed to query GitHub API"**
- **Solution**: Verify `gh` authentication with `gh auth status`
- **Solution**: Check PR number exists and you have repository access
**Error: "PR not found"**
- **Solution**: Verify the PR number is correct and still exists
- **Solution**: Ensure repository owner and name are correct
**Error: "SHA not found" or "Force-push detected"**
- **Explanation**: Last reviewed SHA no longer exists in branch history (force-push occurred)
- **Solution**: A full review is required; incremental review not possible
**Tests show "FAIL" but functionality works**
- **Explanation**: Some tests may show exit code failures even when logic is correct
- **Solution**: Check test output message - if it says "Correctly detected", functionality is working
**Error: "Could not find insertion point"**
- **Explanation**: Overview file doesn't have expected "**Changed files:**" line
- **Solution**: Verify overview file format is correct or regenerate it
### Verification Checklist
After setup, verify:
- [ ] `Run-ReviewToolsTests.ps1` shows 9+ tests passing
- [ ] `Get-PrIncrementalChanges.ps1` returns valid JSON
- [ ] `Test-IncrementalReview.ps1` analyzes a PR without errors
- [ ] `Get-GitHubRawFile.ps1` downloads files correctly
- [ ] `Get-GitHubPrFilePatch.ps1` retrieves patches correctly
## Best Practices
### For Review Authors
1. **Test before full review**: Use `Test-IncrementalReview.ps1` to preview changes
2. **Check for force-push**: Review the analysis output - force-pushes require full reviews
3. **Smart step filtering**: Skip review steps for file types that didn't change
### For Script Users
1. **Use absolute paths**: When specifying folders, use absolute paths to avoid ambiguity
2. **Check exit codes**: Scripts exit with code 1 on error - check `$LASTEXITCODE` in automation
3. **Parse JSON output**: Use `ConvertFrom-Json` to work with structured output from `Get-PrIncrementalChanges.ps1`
4. **Handle empty results**: Check `ChangedFiles.Count` before iterating
### Performance Tips
1. **Batch operations**: When reviewing multiple PRs, collect all PR numbers and process in batch
2. **Cache raw files**: Download baseline files once and reuse for multiple comparisons
3. **Filter early**: Use incremental detection to skip unnecessary file reviews
4. **Parallel processing**: Consider processing independent PRs in parallel
## Integration with AI Review Systems
These tools are designed to work with AI-powered review systems:
1. **Copilot Instructions**: This file serves as reference documentation for GitHub Copilot
2. **Structured Output**: JSON output from scripts is easily parsed by AI systems
3. **Incremental Intelligence**: AI can focus on changed files for more efficient reviews
4. **Metadata Tracking**: Review iterations are tracked for context-aware suggestions
### Example AI Integration
```powershell
# Get incremental changes
$analysis = .\Get-PrIncrementalChanges.ps1 -PullRequestNumber $PR | ConvertFrom-Json
# Feed to AI review system
$reviewPrompt = @"
Review the following changed files in PR #$PR:
$($analysis.ChangedFiles | ForEach-Object { "- $($_.Filename) ($($_.Status))" } | Out-String)
Focus on incremental changes only. Previous review was at SHA $($analysis.LastReviewedSha).
"@
# Execute AI review with context
Invoke-AIReview -Prompt $reviewPrompt -Files $analysis.ChangedFiles
```
## Support and Further Information
For detailed script documentation, use PowerShell's help system:
```powershell
Get-Help .\Get-PrIncrementalChanges.ps1 -Full
Get-Help .\Test-IncrementalReview.ps1 -Detailed
```
Related documentation:
- `.github/prompts/review-pr.prompt.md` - Complete review workflow guide
- `doc/devdocs/` - PowerToys development documentation
- GitHub CLI documentation: https://cli.github.com/manual/
For issues or questions, refer to the PowerToys contribution guidelines.

View File

@@ -0,0 +1,201 @@
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

@@ -0,0 +1,346 @@
---
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

@@ -0,0 +1,223 @@
# 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

@@ -0,0 +1,225 @@
# 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

@@ -0,0 +1,432 @@
# 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

@@ -0,0 +1,274 @@
# 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

@@ -0,0 +1,316 @@
# 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

@@ -0,0 +1,340 @@
# 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

@@ -0,0 +1,217 @@
<#
.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

@@ -0,0 +1,376 @@
<#
.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

@@ -0,0 +1,188 @@
<#
.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

@@ -0,0 +1,210 @@
<#
.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

@@ -0,0 +1,692 @@
<#
.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

21
.github/skills/issue-fix/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,21 @@
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.

220
.github/skills/issue-fix/SKILL.md vendored Normal file
View File

@@ -0,0 +1,220 @@
---
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

@@ -0,0 +1,49 @@
---
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

@@ -0,0 +1,24 @@
---
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

@@ -0,0 +1,72 @@
---
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

@@ -0,0 +1,9 @@
{
"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

@@ -0,0 +1,22 @@
<#
.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

@@ -0,0 +1,644 @@
# 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

@@ -0,0 +1,581 @@
<#!
.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

@@ -0,0 +1,86 @@
<#
.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

@@ -0,0 +1,562 @@
<#!
.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

@@ -0,0 +1,21 @@
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

@@ -0,0 +1,184 @@
---
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

@@ -0,0 +1,9 @@
{
"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

@@ -0,0 +1,194 @@
---
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

@@ -0,0 +1,777 @@
# 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

@@ -0,0 +1,298 @@
<#
.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

@@ -0,0 +1,327 @@
<#
.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

@@ -0,0 +1,111 @@
<#
.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

21
.github/skills/issue-review/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,21 @@
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.

148
.github/skills/issue-review/SKILL.md vendored Normal file
View File

@@ -0,0 +1,148 @@
---
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

@@ -0,0 +1,9 @@
{
"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

@@ -0,0 +1,165 @@
---
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

@@ -0,0 +1,777 @@
# 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

@@ -0,0 +1,291 @@
<#!
.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

@@ -0,0 +1,21 @@
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

@@ -0,0 +1,287 @@
---
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

@@ -0,0 +1,370 @@
<#
.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

@@ -0,0 +1,123 @@
# 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

@@ -0,0 +1,679 @@
<#!
.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

@@ -0,0 +1,21 @@
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

@@ -0,0 +1,151 @@
---
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

@@ -0,0 +1,166 @@
# 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

@@ -0,0 +1,358 @@
<#
.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

@@ -0,0 +1,352 @@
<#
.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

21
.github/skills/pr-fix/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,21 @@
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.

238
.github/skills/pr-fix/SKILL.md vendored Normal file
View File

@@ -0,0 +1,238 @@
---
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

@@ -0,0 +1,70 @@
---
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

@@ -0,0 +1,9 @@
{
"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

@@ -0,0 +1,112 @@
<#
.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

@@ -0,0 +1,18 @@
# 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

@@ -0,0 +1,31 @@
<#
.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

@@ -0,0 +1,349 @@
<#
.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

@@ -0,0 +1,165 @@
<#
.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

21
.github/skills/pr-review/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,21 @@
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.

114
.github/skills/pr-review/SKILL.md vendored Normal file
View File

@@ -0,0 +1,114 @@
---
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) |

Some files were not shown because too many files have changed in this diff Show More