PowerToys — Engineering Performance
21 engineers all time · Jan 2025 – Aug 2026 · built 2026-08-23 · GitHub
Performance snapshot
Today's rolling 90-day reading for PowerToys, compared with the start of the series. Pick a window to move that comparison point.
Eff. capacity added
+24.5engineers
10 devs deliver like 35 (3.5x pre-AI)
Avg. perf / dev / mo (ETV)
+1218.9%
0.23 → 2.97
Active engineers
−28.6%
14.0 → 10.0
Features
−5.2pp
40.3% → 35.1%
PowerToys vs. Microsoft
Per-engineer ETV for PowerToys against Microsoft as a whole. Both lines are 90-day rolling averages scaled to a 30-day month, so they share one axis and can be read against each other at any point. Pick a window to zoom the chart to it.
Performance over time
ETV stacked by Features / Maintenance / Tests / Docs / Fixes — 90-day moving average, normalized to ETV / month.
Engineering capacity
Effective engineers behind PowerToys, in pre-AI terms. Per-engineer ETV divided by the Q1 2025 baseline of 0.86 ETV / dev / mo gives a capacity multiple, and that multiple applied to the engineers active in the trailing 90 days turns it into engineer-equivalents. The line is the real headcount, so the gap between line and area is what the leverage is worth.
Knowledge concentration
How dependent is this repo on a small number of engineers? Higher top-1 share = higher key-person risk.
Jiří Polášek owns 20.7 % of commits.
Reports
Written summary of the work completed each month.
No monthly reports available yet.
Top engineers
Most impactful commits
Top 10 by ETV in the all-time window.
- 11.5ETVfeat(powerdisplay): add CLI for monitor control (#48632) ## Summary of the Pull Request Adds `PowerToys.PowerDisplay.Cli.exe`, a scriptable interface for controlling monitors through the running PowerDisplay process. It supports `list`, `get`, `set`, `up`, `down`, `capabilities`, `profiles`, and `apply-profile`. The CLI communicates over an authenticated, per-session named pipe; PowerDisplay remains responsible for DDC/CI and WMI access. ## PR Checklist - [x] Closes: #48713 - [x] **Communication:** Discussed with core contributors - [x] **Tests:** Added/updated and all pass - [x] **Localization:** Core errors are localizable; some help and output text remains English-only - [ ] **Dev docs:** N/A; built-in CLI help is the command reference - [x] **New binaries:** Added on the required places - [x] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) - [x] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetupVNext/Resources.wxs) - [x] **YML for CI pipeline:** N/A; test assemblies are auto-discovered - [x] **YML for signed pipeline:** N/A; signing is driven by `ESRPSigning_core.json` - [ ] **Documentation updated:** N/A ## Detailed Description of the Pull Request / Additional comments - Adds an AOT-compatible CLI and shared request/response contracts. - Uses a secured named-pipe server in PowerDisplay, with stable exit codes and a bounded request timeout. - Supports saved profiles by their existing stable profile IDs. - Adds solution, signing, installer, and unit-test project integration. ## Validation Steps Performed - PowerDisplay Lib, Contracts, CLI, and IPC unit-test suites pass. - Native AOT publish completes without analyzer warnings. - Manually validated the CLI on two DDC/CI monitors, including the PowerDisplay-unavailable path. - Rebuilt the PowerDisplay GUI after the shared-library changes. --------- Co-authored-by: Yu Leng <yuleng@microsoft.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>moooyo · 5c9c93d5 · 2026-07-16
- 3.9ETV[CmdPal] Consolidate search ranking changes (#49832) ## What's going on The stacked pull requests are blocked by GitHub's stack merge flow. This gives the full remaining search ranking change set one PR against `main`. ## The plan - Consolidates the open work from #49190, #49191, #49194, #49195, #49197, #49246, #49247, and #49249. - Keeps the existing stack unchanged while this PR provides an alternate merge path. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5459b847-afeb-4163-a803-977759dd92df Copilot-Session: 49185697-186e-406f-b081-8c985c134274 Copilot-Session: 92905c83-2de6-449c-b4a1-a08003fe2576 Copilot-Session: efe987e5-9297-47fc-af99-2f49b057285a Copilot-Session: f42917e2-d298-4bde-9056-79a9e6e17dfaMichael Jolley · 888a1427 · 2026-08-12
- 3.6ETVCmdPal: Add file and list settings controls (#49623) ## Summary of the Pull Request This PR adds reusable Command Palette extension settings controls for selecting files and folders and managing lists. The new controls include: - `FilePathSetting` for selecting a single file or folder. - `FilePathListSetting` for managing multiple file and/or folder paths. - `StringListSetting` for managing plain string values. - `KeyValueListSetting` for managing key-value pairs. - Optional regex validation for strings, keys, and values. - Optional duplicate prevention for strings and key-value keys. - Configurable file picker filters. - Custom persisted-string conversion. - Fallback content when the Command Palette host does not support a control. But this has no direct impact now, because there's a bug in WinUI3 AC renderer that throws it away (sad panda). ## Pictures? Picture! <img width="856" height="974" alt="image" src="https://github.com/user-attachments/assets/2e5d9ee1-9eca-48a7-803a-76a96859722e" /> <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #49622 <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide 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 PR extends `Microsoft.CommandPalette.Extensions.Toolkit` with file-path, file-path-list, string-list, and key-value-list settings. The Command Palette host registers custom Adaptive Card input elements during application startup. The controls use native file and folder pickers parented to the window containing the form, so they work correctly in both the Settings window and palette-hosted forms. List controls render as constrained, scrollable lists with add and remove actions. They support developer-configurable validation, duplicate handling, picker modes, and error messages. List values crossing the extension/host boundary use a structured codec that preserves unknown properties and remains compatible with the previously accepted bare-string representation. Persisted values can use the default newline representation or developer-provided conversion callbacks. The SDK emits Adaptive Card `requires` and fallback information so extensions built with the new controls can provide actionable content when loaded by an older Command Palette host. A Sample Pages extension page demonstrates all new setting types and their validation options. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps PerformedJiří Polášek · 14a966f3 · 2026-08-12
- 3.5ETVHarden IPC pipe ownership and shutdown lifecycle (#48902) ## Summary of the Pull Request The two-way named-pipe IPC server (`TwoWayPipeMessageIPC`, shared by the runner, Settings, and Quick Access host) created every pipe instance without `FILE_FLAG_FIRST_PIPE_INSTANCE`. If a pipe with the same name already existed — for example a leftover instance from a previous run or another process — `CreateNamedPipe` would quietly create an *additional* instance and share the name instead of owning it. This makes `start_named_pipe_server` create the **first** instance with `FILE_FLAG_FIRST_PIPE_INSTANCE`, so `CreateNamedPipe` fails fast on a name collision and the server is the authoritative owner of its pipe name. ## PR Checklist - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [x] **Localization:** All end-user-facing strings can be localized (N/A — no user-facing strings) - [x] **Dev docs:** Added/updated (N/A) - [x] **New binaries:** Added on the required places (N/A — no new binaries) ## Detailed Description of the Pull Request / Additional comments - The flag is applied **only** to the first instance. Subsequent instances continue to omit it, so the existing `PIPE_UNLIMITED_INSTANCES` behavior is fully preserved. - The change is contained to a single function in `src/common/interop/two_way_pipe_message_ipc.cpp`. Public signatures and the `PowerToys.Interop` ABI are unchanged, so the runner, Settings, and Quick Access host all benefit without any code changes on their side. ## Validation Steps Performed - The existing `Common.Interop.UnitTests` `TestSend` exercises the modified first-instance code path (`Start()` → `start_named_pipe_server`) and continues to pass — a full IPC round-trip still works. - Verified the updated `CreateNamedPipe` open-mode logic compiles cleanly. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 49797c8c-784d-47e6-bc0f-53464eecec4bGordon Lam · ed7595f3 · 2026-08-09
- 3.3ETVCmdPal: Update the shell provider to be run (#47642) This PR updates the shell command provider to work (almost) exactly like run. The current shell provider is close, but not technically correct. It does enumerate files. Sure. But as it turns out, it doesn't enumerate things **exactly** correctly. It doesn't handle network paths super well. It doesn't handle NTFS file paths. Basically, there's a lot of weird edge cases in the way the run dialog enumerates file paths for suggestions. And the only way to match that is to just use the code from the old run dialog. This is code that is taken pretty verbatim from the new run dialog. Instead of trying to enumerate paths manually and shellexecuting command lines, We're using the actual APIs that the original run dialog used, more or less. They've been pretty much ported to C#. This should make us feel just as correct as the original run dialog did. And exactly the same as the new Run dialog. The one major change is the introduction of a static item at the top of the list for running the command that the user typed. This command is used to just immediately take whatever is in the search box and fire it off as the command the user typed. This is essentially what happens with the run dialog. When you press the button, we run the command in the text box. See: [The new Run dialog: faster, cleaner, and more capable - Windows Command Line](https://devblogs.microsoft.com/commandline/the-new-run-dialog-faster-cleaner-and-more-capable/) Honestly, most of this PR is just deleting the files we no longer need from the shell list provider and adding the tests from the OS side here. I also had to update CsWinRT for this.Mike Griese · b02e53dd · 2026-05-18
- 3.0ETVNew module: AltWindowCycle (#48281) ## Summary of the Pull Request Introduces a new utility: AltWindowCycle to quickly switch between windows from the same process using Alt + `. In release notes give @wzhudev coauthor credits as he also had an earlier PR It works like Alt + Tab, but scoped to the app you’re already in. Perfect for juggling multiple browser windows, terminals, or editor instances. https://github.com/user-attachments/assets/cd42f6af-fa5d-4f08-8f68-3c4e75c16d94 <img width="1835" height="971" alt="image" src="https://github.com/user-attachments/assets/adea59cb-6c8d-4b44-87e2-0a792c4c0b4f" /> ## PR Checklist - [x] Closes: https://github.com/microsoft/PowerToys/issues/278 - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, 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 adds AltWindowCycle (in-proc module + Settings integration), then addresses follow-up check-spelling feedback without changing runtime behavior: - allow-list update for `ROOTOWNER` - comment text adjustment for forbidden-pattern compliance - local identifier rename (`wpx` → `whitePx`) for spelling compliance ## Validation Steps Performed - Verified `ROOTOWNER` is present in `.github/actions/spell-check/allow/code.txt` - Verified `wpx` is removed and updated occurrences in `src/modules/AltWindowCycle/AltWindowCycle.cpp` - Ran targeted diff/verification for both updated files - Ran final validation (code review + CodeQL trivial-change path) - Ran secret scan for changed files --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Clint Rutkas <crutkas@users.noreply.github.com> Copilot-Session: dd5080ea-5001-4efb-87f8-1e7218e10a4eClint Rutkas · bb99c30e · 2026-07-31
- 3.0ETVCmdPal Dock: Multi-monitor support (#46915) This pull request introduces per-monitor dock customization support and refactors how dock band settings are managed to enable independent layouts on different monitors. The changes add a new `DockMonitorConfigViewModel` for monitor-specific configuration, update `DockViewModel` to handle per-monitor band lists and settings, and refactor band movement and ordering logic to respect per-monitor overrides. **Per-monitor dock customization:** * Added `DockMonitorConfigViewModel` to encapsulate the configuration and state for each monitor, exposing properties for binding and persisting changes using `ISettingsService`. * Updated `DockViewModel` to track an optional `MonitorDeviceId`, enabling docks to be associated with a specific monitor and to expose per-monitor settings and methods. [[1]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L17-R33) [[2]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L41-R56) **Band management refactor for per-monitor settings:** * Refactored band retrieval and update logic in `DockViewModel` to use new helper methods (`GetActiveBands`, `WithActiveBands`) that select and modify either global or per-monitor band lists as appropriate. * Updated band movement and ordering methods (`SyncBandPosition`, `MoveBandWithoutSaving`, `SaveBandOrder`) to operate on the correct band lists for each monitor, ensuring that changes apply to the intended scope (global or per-monitor). [[1]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L205-R399) [[2]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L250-R413) [[3]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L263-R424) [[4]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L280-R437) [[5]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L290-R447) [[6]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L300-R465) [[7]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L329-R491) **Resource management:** * Implemented `IDisposable` on `DockViewModel` to clean up event handlers and prevent resource leaks. [[1]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06L17-R33) [[2]](diffhunk://#diff-b661a9311de64dd1123860e858f1f4963f05ccee06b5bd218916635495b2ff06R85-R235) Closes #46939 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: Mike Griese <migrie@microsoft.com>Michael Jolley · 966c1db7 · 2026-05-13
- 2.9ETVCmdPal: 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>Jiří Polášek · 97c1de8b · 2025-12-10
- 2.8ETV[PowerDisplay] Add stable profile IDs (#49175) ## Summary of the Pull Request Gives every saved PowerDisplay profile a stable, auto-incrementing integer ID and makes the app address profiles by that ID instead of by name. Duplicate profile names are allowed, renames preserve identity, and LightSwitch stores stable profile references. > Split out of the PowerDisplay CLI branch (#48632). CLI-specific contracts and commands remain in that stacked PR. ## PR Checklist - [x] **Closes:** N/A - split from #48632. - [x] **Communication:** Discussed with core contributors. - [x] **Tests:** Added and passing in `PowerDisplay.Lib.UnitTests`. - [x] **Localization:** The composed profile label uses a shared localized format resource. - [x] **New binaries:** None. - [x] **Documentation updated:** `doc/devdocs/modules/powerdisplay/design.md`. ## Implementation ### Profile model and persistence - `PowerDisplayProfile.Id` is the stable JSON `id`; `0` means unassigned. - `PowerDisplayProfiles.NextId` is monotonic and IDs are never reused. - `SetProfile` assigns IDs to new profiles and replaces existing profiles by ID. - Duplicate names are supported; name lookup remains only for migration of legacy references. - `ProfileStore` serializes cross-process load/modify/save operations with a named mutex and atomically replaces `profiles.json`. - Production callers use asynchronous `ProfileHelper` APIs. ### Migration and application - Initial PowerDisplay discovery assigns missing profile IDs and migrates legacy monitor IDs. - LightSwitch legacy name references are reconciled to IDs and written back to the current typed settings schema. - Native LightSwitch publishes pure light/dark theme events; PowerDisplay exclusively validates profile enablement and stable IDs. - Settings UI and Named Pipe ApplyProfile actions send invariant positive profile IDs. - PowerDisplay validates the ID, loads the current profile, and applies its monitor settings. ### Settings UI - Create, edit, apply, and delete operations use stable IDs. - LightSwitch selectors store profile IDs and keep legacy name fields only for migration. - Profile lists use a localized name-and-ID label so duplicate names remain distinguishable. ## Accepted Trade-offs - Profile ID migration remains dependent on the initial monitor discovery; a failed or delayed discovery can temporarily hide legacy ID-less profiles. - The one-time PowerDisplay LightSwitch migration rewrites the complete current typed settings object and does not add a new cross-process settings transaction. ## Validation - Built the affected x64 Debug projects with the repository build scripts. - `PowerDisplay.Lib.UnitTests`: 186 passed, 0 failed. --------- Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>moooyo · 2b8e6247 · 2026-07-16
- 2.8ETV[Image Resizer] Fix CLI input validation and diagnostics (#49854) ## Summary of the Pull Request Closes #49852. Image Resizer CLI previously accepted several invalid inputs as successful work: unknown options could be consumed as file arguments, invalid files were silently dropped, unsafe dimensions could reach the resize engine, and equivalent inputs could process the same source concurrently. This change makes `PowerToys.ImageResizerCLI.exe` strict, deterministic, and diagnosable while preserving the existing lenient command-line behavior used by the GUI and context-menu path. ## PR Checklist - [x] Closes: #49852 - [x] **Communication:** Discussed with core contributors - [x] **Tests:** Added/updated - [x] **Localization:** End-user-facing diagnostics are localizable - [x] **Dev docs:** Built-in CLI help and examples updated; no standalone dev-doc change required - [x] **New binaries:** No new binaries introduced - [x] **Documentation updated:** No external user-documentation change required ## Detailed Description ### Strict CLI parsing without breaking supported syntax - Adds a strict parse path for the public CLI while keeping the GUI/context-menu parser lenient. - Rejects unknown option-like positional tokens before processing. - Preserves `--`, response files, attached values such as `-w100`, legal bundles such as `-rq85`, and explicit attached boolean values such as `-rtrue`. - Preserves valid file, pipe, and destination values for lenient callers when another option fails conversion. ### Deterministic and diagnosable input resolution - Expands wildcards in the final path segment and reports zero-match patterns. - Reports missing, unsupported, invalid, and empty inputs instead of silently filtering them. - Processes valid files in mixed batches, reports every rejected input, and returns a non-zero exit code. - Canonicalizes filesystem paths before deduplication, covering normal, extended (`\\?\`), long, casing, and parent-reparse aliases while preserving distinct hard links, final symbolic links, and files in case-sensitive directories. - Applies the same strict validation and deduplication to public-CLI named-pipe input; the GUI/context-menu pipe remains lenient. - Treats an empty public-CLI pipe as an error. - Reads redirected stdin using the producing shell's output encoding with BOM detection, including non-ASCII paths from default cmd and PowerShell pipelines. ### Validation before file writes - Rejects negative, non-finite, zero/zero, grouped out-of-range, and otherwise unsupported custom dimensions. - Requires a positive effective width for percentage-based Fit and Fill sizes. - Treats an out-of-range preset index as an error instead of continuing with the current preset. - Validates resize-engine dimensions before integer conversion and before destination creation. - Rounds positive fractional Fill targets safely to at least one pixel. - Deduplicates equivalent paths before parallel processing so overlapping explicit/glob/pipe inputs cannot race under `--replace`. ### Diagnostics and compatibility - Includes exception type and HRESULT when a decoder exception has an empty message. - Documents and warns that shrink-only remains ignored for percentage-based sizes, preserving existing behavior. - Preserves the original UTC modified time after `KeepDateModified + Replace` by restoring it on the final replaced file. ## Validation Validation was repeated after merging the latest `main` (`e753ec51fb`) into the PR branch. 1. Restored with the configured host `NuGet.Config` and built `src/modules/imageresizer/ImageResizerCLI/ImageResizerCLI.csproj` in x64 Release using `tools/build/build.ps1`. - Result: exit code 0; errors log empty. 2. Restored and built `src/modules/imageresizer/tests/ImageResizer.UnitTests.csproj` in x64 Release with the same build script and configured package source. - Result: exit code 0; errors log empty. 3. Ran the complete x64 Release Image Resizer unit-test assembly with Visual Studio `vstest.console.exe`. - Result: **205 passed, 0 failed, 0 skipped**. 4. Ran 10 process-level CLI regressions covering: - attached boolean parsing (`-rtrue`); - grouped out-of-range dimensions without source modification; - positive fractional Fill producing a valid `1x100` image; - normal/extended/wildcard path deduplication; - non-ASCII redirected stdin from default PowerShell 7 and cmd pipelines; - empty, invalid, and duplicate named-pipe inputs; - `KeepDateModified + Replace`, including content change and exact UTC timestamp preservation. - Result: **10/10 passed**. 5. Confirmed both build error logs remained empty, all temporary fixtures were removed, and the real Image Resizer settings file retained its original length, timestamp, and SHA-256 hash. The new Image Resizer UI-test project added on `main` was not run locally because it requires the repository's WinAppDriver/local-VM UI-test environment; this PR does not change that UI-test project. --------- Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>moooyo · 75df8d02 · 2026-08-17