Files
PowerToys/doc/devdocs/modules
Jiří Polášek c4ff073d01 CmdPal: Extension Gallery (#46636)
## Summary of the Pull Request

Adds the **Extension Gallery** to Command Palette — a built-in page
where users can discover, browse, and install community extensions
without leaving the app.


https://github.com/user-attachments/assets/e4565333-b970-4085-9e40-5cfd207e533b

## How it works

### 1. The extension author's side

Extensions are listed in the external repo
**[`microsoft/CmdPal-Extensions`](https://github.com/microsoft/CmdPal-Extensions)**.
To get an extension into the in-app gallery, an author opens a PR there
that adds a single entry to `extensions.json`. Nothing in PowerToys
itself needs to change. A typical entry looks like:

```json
{
  "id": "contoso.sample",
  "title": "Sample Extension",
  "description": "Short blurb shown in the list and detail view.",
  "author": { "name": "Contoso", "url": "https://github.com/contoso" },
  "homepage": "https://github.com/contoso/sample",
  "iconUrl": "https://.../icon.png",
  "screenshotUrls": ["https://.../screenshot-1.png"],
  "tags": ["sample"],
  "installSources": [
    { "type": "winget",  "id":  "Contoso.SampleExtension" },
    { "type": "msstore", "id":  "9P..." },
    { "type": "url",     "uri": "https://github.com/contoso/sample/releases/latest" }
  ],
  "detection": { "packageFamilyName": "Contoso.SampleExtension_8wekyb..." }
}
```

- `id`, `title`, `description`, `author.name`, and at least one
`installSources` entry are required; everything else is optional.
- `installSources` can mix and match `winget` / `msstore` / `url`. The
gallery shows an install button for the first source it can handle
(WinGet preferred) and exposes any remaining sources as links.
- `detection.packageFamilyName` lets CmdPal recognise an
already-installed packaged extension before any WinGet lookup resolves,
so the "Installed" badge appears instantly.

Once the PR is merged into `CmdPal-Extensions`, every running copy of
CmdPal picks the new entry up the next time its feed cache expires
(within 4 hours) or when the user clicks **Refresh**.

### 2. What CmdPal does with it

`ExtensionGalleryService` (in `Microsoft.CmdPal.Common`) owns the whole
pipeline:

1. **Resolve the feed URL.** Default is
`https://raw.githubusercontent.com/microsoft/CmdPal-Extensions/refs/heads/main/extensions.json`.
A hidden setting (`GalleryFeedUrl`) lets developers point at a custom
URL or a `file://` path for local testing.
2. **Fetch** the feed through `ExtensionGalleryHttpClient`, which wraps
`HttpCachingClient` — a conditional-GET + on-disk cache layer built on
`HttpClient` (ETag / `If-None-Match`, 30 s timeout, UA
`PowerToys-CmdPal/1.0`).
3. **Parse** with the source-generated `GallerySerializationContext`
into a strongly-typed `GalleryRemoteIndex` (`{ "extensions": [ ... ]
}`). Entries without an `id` are dropped.
4. **Normalize** relative `iconUrl` / `screenshotUrls` against the feed
URL (useful for local `file://` feeds).
5. **Localize icons.** Each HTTP icon URL is pulled through the same
cache and rewritten to a local `file://` URI before the view model binds
to it, so the list renders instantly on subsequent loads and works
offline.
6. **Prune** cached resources that are no longer referenced, but only
after a successful forced refresh.

The gallery page itself is built on top of `ExtensionGalleryViewModel`,
with `ExtensionGalleryItemViewModel` handling per-entry concerns —
install/update/uninstall (via the shared WinGet service),
installed-state detection, and joining in-flight install progress so the
global `WinGetOperationsButton` in the top bar stays in sync.

### 3. Caching + offline behaviour

The cache lives under
`ApplicationData.Current.LocalCacheFolder\GalleryCache\` when CmdPal
runs packaged, or
`%LOCALAPPDATA%\Microsoft\PowerToys\Microsoft.CmdPal\Cache\GalleryCache\`
when unpackaged.

| Resource        | TTL      |
|-----------------|----------|
| `extensions.json` feed | 4 hours |
| Icons (per URL) | 24 hours |

Each fetch returns a `GalleryFetchResult` whose flags drive the UI:

- `FromCache` — cache was still fresh, no network call was made.
- `UsedFallbackCache` — network failed; the last-known-good cached copy
was served instead. The page shows a "showing cached data" info bar.
- `RateLimited` — origin returned `429` and no fallback was available.
The page shows a rate-limit error.

`RefreshAsync` (wired up to the gallery's refresh button) forces a fresh
conditional GET, then prunes any cached files that the new feed no
longer references.

### 4. WinGet install flow

- `installSources[type=winget].id` is handed to the shared WinGet
service for install/update/uninstall.
- In-flight operations are surfaced by `WinGetOperationsButton` in the
top bar with per-operation progress.
- `detection.packageFamilyName` is consulted first so that the gallery
can show "Installed" / "Update available" without waiting on WinGet
metadata.

### Top-level command cleanup

- Removed the separate "Find extensions from WinGet" and "Find
extensions from the Store" top-level commands — the gallery replaces
both.
- Renamed the gallery command to **"Find and install Command Palette
extensions"** and gave it the extensions puzzle-piece icon.

## PR Checklist

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

## New projects / areas

| Area | What |
|------|------|
| Microsoft.CmdPal.Common | Gallery models, `ExtensionGalleryService`
(fetch + cache), HTTP caching layer (`HttpCachingClient`,
`FileSystemHttpResourceCacheStore`), WinGet service abstractions and
implementations |
| Microsoft.CmdPal.UI.ViewModels | `ExtensionGalleryViewModel`,
`ExtensionGalleryItemViewModel`, WinGet operation view models, gallery
sort options |
| Microsoft.CmdPal.UI | `ExtensionGalleryPage.xaml`,
`ExtensionGalleryItemPage.xaml`, `IconCarouselControl`,
`WinGetOperationsButton`, service registrations |
| Microsoft.CmdPal.Ext.WinGet | Streamlined — removed the two redundant
"find extensions" top-level commands, kept the general WinGet search
page |
| Tests | Unit tests for gallery service, gallery view models, WinGet
services |
| Docs |
[`doc/devdocs/modules/cmdpal/extension-gallery/extension-gallery.md`](https://github.com/microsoft/PowerToys/blob/dev/jpolasek/f/46628-cmdpal-extension-gallery/doc/devdocs/modules/cmdpal/extension-gallery/extension-gallery.md)
— dev reference for the runtime, caching, and feed shape |

## Validation Steps Performed

- Gallery loads and displays extensions from the remote index
- Search, sort, and filtering work as expected
- WinGet install/update/uninstall flow works end-to-end with progress
tracking
- Loading state correctly hides all content until data is fetched
- Offline / cache-fallback path surfaces the info bar as expected
- Spell-check CI workflow passes

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-05-14 16:30:20 -05:00
..
2026-05-14 16:30:20 -05:00

PowerToys Modules

This section contains documentation for individual PowerToys modules, including their architecture, implementation details, and debugging tools.

Available Modules

Module Description
Advanced Paste Tool for enhanced clipboard pasting with formatting options
Always on Top Tool for pinning windows to stay on top of other windows
Awake Tool to keep your computer awake without modifying power settings
Color Picker Tool for selecting and managing colors from the screen
Command Not Found Tool suggesting package installations for missing commands
Crop and Lock Tool for cropping application windows into smaller windows or thumbnails
Environment Variables Tool for managing user and system environment variables
FancyZones (debugging tools) Window manager utility for custom window layouts
File Explorer add-ons Extensions for enhancing Windows File Explorer functionality
File Locksmith Tool for finding processes that lock files
Hosts File Editor Tool for managing the system hosts file
Image Resizer Tool for quickly resizing images within File Explorer
Keyboard Manager Tool for remapping keys and keyboard shortcuts
Mouse Utilities Collection of tools to enhance mouse and cursor functionality
Mouse Without Borders Tool for controlling multiple computers with a single mouse and keyboard
NewPlus Context menu extension for creating new files in File Explorer
Peek File preview utility for quick file content viewing
Power Rename Bulk file renaming tool with search and replace functionality
PowerToys Run (deprecation soon) Quick application launcher and search utility
Quick Accent Tool for quickly inserting accented characters and special symbols
Registry Preview Tool for visualizing and editing Registry files
Screen Ruler Tool for measuring pixel distances and color boundaries on screen
Shortcut Guide Tool for displaying Windows keyboard shortcuts when holding the Windows key
Text Extractor Tool for extracting text from images and screenshots
Workspaces Tool for saving and restoring window layouts for different projects
ZoomIt Screen zoom and annotation tool

Adding New Module Documentation

When adding documentation for a new module:

  1. Create a dedicated markdown file for the module (e.g., modulename.md)
  2. If the module has specialized debugging tools, consider creating a separate tools document (e.g., modulename-tools.md)
  3. Update this index with links to the new documentation
  4. Follow the existing documentation structure for consistency