From 8c8035582368f496859d377aeceaee7bb14e6182 Mon Sep 17 00:00:00 2001 From: Demitrius Nelon Date: Sun, 3 May 2026 20:19:06 -0700 Subject: [PATCH 1/2] Specification: UserMessages manifest field Add specification for UserMessages manifest field (#3483). Includes: - New UserMessages manifest field for displaying messages to users - Flow behavior matrix for install, upgrade, uninstall, and download - CLI arguments for UserMessages settings overrides - Settings object for global UserMessages configuration - PowerShell cmdlet integration details - Deprecation path and schema impact guidance Also updates spec-template.md with Deprecation Path section and settings/arguments guidance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/actions/spelling/expect.txt | 2 + doc/specs/#3483 - UserMessages.md | 562 ++++++++++++++++++++++++++++ doc/specs/spec-template.md | 8 +- 3 files changed, 571 insertions(+), 1 deletion(-) create mode 100644 doc/specs/#3483 - UserMessages.md diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 53175f0afa..f05833e366 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -428,6 +428,7 @@ PEGI pfn pgp Pherson +phishing pid pidl pidlist @@ -586,6 +587,7 @@ TLSCAs tombstoned Toolhelp transitioning +Trenly trimstart ttl twgc diff --git a/doc/specs/#3483 - UserMessages.md b/doc/specs/#3483 - UserMessages.md new file mode 100644 index 0000000000..1fd7c6b777 --- /dev/null +++ b/doc/specs/#3483 - UserMessages.md @@ -0,0 +1,562 @@ +--- +author: Demitrius Nelon denelon, GitHub Copilot +created on: 2026-05-03 +last updated: 2026-05-03 +issue id: 3483 +--- + +# UserMessages + +For [#3483](https://github.com/microsoft/winget-cli/issues/3483) + +## Abstract + +This specification proposes adding an optional `UserMessages` object to the WinGet package manifest schema. The new field provides structured, flow-dependent messaging to users before and after install, upgrade, and uninstall operations. It is designed as a non-breaking, additive change that coexists with the existing `InstallationNotes` string field during a transition period and eventually replaces it. + +## Inspiration + +The existing `InstallationNotes` field is a single string displayed after a successful install. Community feedback in [#3483](https://github.com/microsoft/winget-cli/issues/3483) identified several limitations: + +1. **No flow specificity.** The same message appears regardless of whether the user is installing, upgrading, or uninstalling. Upgrade and uninstall operations have no mechanism for user-facing notes at all. +2. **No pre-action messaging.** Some packages need to inform users of prerequisites, data-loss risks, or configuration steps before an operation begins. Today there is no way to surface this information through the manifest. +3. **No structured extensibility.** The single string cannot be extended to support new scenarios without breaking the schema contract. + +Changing `InstallationNotes` from a string to an object (as originally proposed in #3483) would break existing manifests and clients. This specification introduces a new field alongside the existing one, providing a clean migration path. + +## Solution Design + +### Schema Changes + +A new optional `UserMessages` object is added to the **defaultLocale** and **locale** manifest types. The field is localizable — locale-specific manifests may override any or all messages defined in the defaultLocale manifest, following the existing locale fallback behavior. + +```json +"UserMessages": { + "type": ["object", "null"], + "description": "Optional messages displayed to the user before or after specific package operations.", + "properties": { + "PreInstall": { + "type": ["string", "null"], + "minLength": 1, + "maxLength": 2048, + "description": "Confirmation request displayed to the user before a package installation begins." + }, + "PostInstall": { + "type": ["string", "null"], + "minLength": 1, + "maxLength": 10000, + "description": "Message displayed to the user upon completion of a package installation. This is the designated successor to InstallationNotes." + }, + "PreUpgrade": { + "type": ["string", "null"], + "minLength": 1, + "maxLength": 2048, + "description": "Confirmation request displayed to the user before a package upgrade begins." + }, + "PostUpgrade": { + "type": ["string", "null"], + "minLength": 1, + "maxLength": 10000, + "description": "Message displayed to the user upon completion of a package upgrade." + }, + "PreUninstall": { + "type": ["string", "null"], + "minLength": 1, + "maxLength": 2048, + "description": "Confirmation request displayed to the user before a package uninstall begins." + }, + "PostUninstall": { + "type": ["string", "null"], + "minLength": 1, + "maxLength": 10000, + "description": "Message displayed to the user upon completion of a package uninstall." + } + }, + "additionalProperties": false +} +``` + +> [!NOTE] +> **Field limits:** Pre-action messages use a lower `maxLength` of 2048 characters because they gate the operation with a user prompt in interactive mode. Shorter messages improve readability and reduce the risk of users dismissing important information. Post-action messages retain the 10000-character limit consistent with the existing `InstallationNotes` field. + +### Schema Version + +This change requires a new manifest schema version (the next minor version after the current release, e.g., 1.13.0). The `UserMessages` field is added to: + +- `defaultLocale.schema.json` +- `locale.schema.json` + +The `installer.schema.json` is not affected. User-facing messages are locale-sensitive content and belong in the locale manifests. + +### Existing `InstallationNotes` Field + +The existing `InstallationNotes` field is **unchanged** in this schema version. It continues to function as it does today. During the transition period, manifests may include both fields for backward compatibility. + +### Client Behavior + +#### Precedence Rules + +When both `InstallationNotes` and `UserMessages.PostInstall` are present in a manifest: + +- **Clients that support `UserMessages`:** Display `UserMessages.PostInstall` and ignore `InstallationNotes`. +- **Clients that do not support `UserMessages`:** Display `InstallationNotes` (current behavior, unaffected by the unknown field). + +#### Pre-Action Messages (PreInstall, PreUpgrade, PreUninstall) + +Pre-action messages are displayed **before** the operation begins and represent information the user should be aware of before proceeding. + +**Interactive mode (default):** + +``` +The following information has been provided by the manifest author: + + This package requires 2 GB of disk space and will modify your PATH. + +Do you wish to continue? [Y/n]: +``` + +The user is prompted to confirm. Entering `N` cancels the operation. Entering `Y` or pressing Enter proceeds. + +**Non-interactive mode (`--disable-interactivity`):** + +The pre-action message is displayed (rendered to the output stream) but no prompt is shown and the operation proceeds automatically. This ensures automation pipelines see the message in logs without being blocked. + +``` +The following information has been provided by the manifest author: + + This package requires 2 GB of disk space and will modify your PATH. + +Proceeding automatically (non-interactive mode)... +``` + +> [!NOTE] +> **Design rationale:** Pre-action messages are informational, not contractual agreements. Unlike license terms (which require explicit acceptance via `--accept-package-agreements`), user messages are manifest-author-provided guidance. The `--disable-interactivity` flag is the appropriate suppressor because it already governs all interactive prompts in WinGet. A new flag is not warranted. + +#### Post-Action Messages (PostInstall, PostUpgrade, PostUninstall) + +Post-action messages are displayed **after** the operation completes successfully. They are informational only — no prompt is shown. + +``` +Successfully installed ExampleApp [Publisher.ExampleApp] v2.0.0 + + Restart your terminal to use the CLI. +``` + +Post-action messages are displayed in both interactive and non-interactive modes. They are suppressed when the `userMessages.disablePostActionMessages` setting is enabled. + +#### Flow Behavior Matrix + +| Scenario | Pre-message | Post-message | Notes | +|----------|-------------|--------------|-------| +| `winget install` | `PreInstall` shown, prompt Y/n | `PostInstall` shown | Standard single-package install | +| `winget upgrade ` | `PreUpgrade` shown, prompt Y/n | `PostUpgrade` shown | Single-package upgrade | +| `winget upgrade --all` | Each package's `PreUpgrade` shown, prompt Y/n per package | Each package's `PostUpgrade` shown | See "Bulk Operations" below | +| `winget uninstall` | `PreUninstall` shown, prompt Y/n | `PostUninstall` shown | Standard uninstall | +| `winget install --disable-interactivity` | `PreInstall` displayed, no prompt | `PostInstall` shown | Non-interactive install | +| `winget install --silent` | `PreInstall` displayed, no prompt | `PostInstall` shown | Silent implies non-interactive | +| Dependency packages | Not shown | Not shown | Messages apply to the root package only, not transitive dependencies | +| `winget import` | Each package's `Pre*` shown, prompt Y/n per package | Each package's `Post*` shown | Follows the same per-package model | +| WinGet Configuration (DSC) | Displayed in log output, no prompt | Displayed in log output | Configuration is inherently non-interactive | +| `winget show` | N/A | N/A | `show` displays `UserMessages` as package metadata (see below) | +| `winget repair` | `PreInstall` shown, prompt Y/n | `PostInstall` shown | Repair reuses install messages | +| `winget export` | N/A | N/A | Export captures package list, not messages | +| Operation failure | `Pre*` shown before attempt | `Post*` NOT shown | Post-messages only appear on success | +| `disableInstallNotes` setting enabled | `Pre*` still shown (not affected) | `Post*` still shown (controlled by `userMessages` settings, not `disableInstallNotes`) | Legacy setting does not affect new fields | +| `userMessages.disablePostActionMessages` enabled | `Pre*` still shown | `Post*` suppressed | New setting for new fields | +| `userMessages.disablePreActionMessages` enabled | `Pre*` suppressed, no prompt | `Post*` still shown | Suppresses both display and prompt | +| `--ignore-user-messages` | `Pre*` suppressed, no prompt | `Post*` suppressed | CLI argument overrides settings for this invocation | +| `--ignore-pre-action-messages` | `Pre*` suppressed, no prompt | `Post*` still shown | CLI argument overrides `disablePreActionMessages` setting | +| `--ignore-post-action-messages` | `Pre*` still shown | `Post*` suppressed | CLI argument overrides `disablePostActionMessages` setting | +| `winget validate` | Not shown, not prompted | Not shown | Validation checks schema correctness only; messages are not rendered | + +#### Bulk Operations (`upgrade --all`, `import`) + +For bulk operations, pre-action messages are shown per-package. In interactive mode, each package with a pre-action message prompts individually. This is consistent with how `--accept-package-agreements` works today — per-package, not a single blanket prompt. + +A future enhancement could aggregate pre-messages and present them as a summary before beginning the batch, but that is out of scope for this specification. + +### Settings + +A new `userMessages` settings object is introduced under the root of the WinGet settings file. The existing `installBehavior.disableInstallNotes` setting is **not modified** and continues to control only the legacy `InstallationNotes` field. + +```json +{ + "userMessages": { + "disablePreActionMessages": false, + "disablePostActionMessages": false + } +} +``` + +| Setting | Default | Description | +|---------|---------|-------------| +| `userMessages.disablePreActionMessages` | `false` | When `true`, suppresses all pre-action messages (`PreInstall`, `PreUpgrade`, `PreUninstall`) and their associated prompts. The operation proceeds as if the user confirmed. | +| `userMessages.disablePostActionMessages` | `false` | When `true`, suppresses all post-action messages (`PostInstall`, `PostUpgrade`, `PostUninstall`). | + +**Interaction with existing settings:** + +The following table shows what is displayed on **clients that support `UserMessages`** during an install operation when both `InstallationNotes` and `UserMessages.PostInstall` are present. Per the precedence rules above, supporting clients display `UserMessages.PostInstall` and ignore `InstallationNotes`. + +| `disableInstallNotes` | `userMessages.disablePostActionMessages` | `InstallationNotes` | `UserMessages.Post*` | +|----------------------|------------------------------------------|---------------------|----------------------| +| `false` | `false` | Ignored (superseded) | Shown | +| `true` | `false` | Ignored (superseded) | Shown | +| `false` | `true` | Ignored (superseded) | Suppressed | +| `true` | `true` | Ignored (superseded) | Suppressed | + +On **older clients** that do not support `UserMessages`, only `InstallationNotes` is relevant and `disableInstallNotes` controls it as it does today. + +### CLI Arguments + +Corresponding CLI arguments are provided so users can override the settings on a per-invocation basis. + +| Argument | Applies to | Description | +|----------|-----------|-------------| +| `--ignore-user-messages` | `install`, `upgrade`, `uninstall`, `repair`, `import` | Suppresses all `UserMessages` (both pre- and post-action) for this invocation. Pre-action prompts are skipped and the operation proceeds. | +| `--ignore-pre-action-messages` | `install`, `upgrade`, `uninstall`, `repair`, `import` | Suppresses pre-action messages and their prompts for this invocation. Post-action messages are still shown. | +| `--ignore-post-action-messages` | `install`, `upgrade`, `uninstall`, `repair`, `import` | Suppresses post-action messages for this invocation. Pre-action messages and prompts are still shown. | + +**Precedence:** CLI arguments override settings. If a user has `userMessages.disablePreActionMessages` set to `false` in settings but passes `--ignore-pre-action-messages`, the pre-action messages are suppressed for that invocation. + +**Relationship to `--disable-interactivity`:** The `--disable-interactivity` flag suppresses the **prompt** on pre-action messages but still displays the message text. The `--ignore-pre-action-messages` flag suppresses both the message and the prompt entirely. + +Example usage: + +``` +winget upgrade --all --ignore-pre-action-messages +winget install Publisher.ExampleApp --ignore-user-messages +``` + +### COM API + +The COM API must surface `UserMessages` in a structured manner for programmatic consumers. + +A new `IPackageUserMessages` interface is introduced, and a new versioned interface (e.g., `IPackageCatalogInfo2` or `IPackageVersionInfo2`) exposes a `UserMessages` property that returns this object. This follows the established WinGet pattern for additive COM API changes — new interface versions are introduced rather than modifying existing interfaces, ensuring existing consumers remain compatible. + +```idl +interface IPackageUserMessages : IInspectable +{ + String PreInstall { get; }; + String PostInstall { get; }; + String PreUpgrade { get; }; + String PostUpgrade { get; }; + String PreUninstall { get; }; + String PostUninstall { get; }; +} +``` + +Consumers query for the new interface version to access `UserMessages`. Existing consumers that use the original interface are unaffected. + +COM consumers are responsible for their own interactivity model. The WinGet COM API does not prompt — it returns the data and the consumer decides how to handle it. + +### PowerShell Cmdlets + +The WinGet PowerShell module cmdlets consume the COM API and must surface `UserMessages` appropriately. + +#### Affected Cmdlets + +| Cmdlet | Pre-message field | Post-message field | +|--------|-------------------|-------------------| +| `Install-WinGetPackage` | `PreInstall` | `PostInstall` | +| `Update-WinGetPackage` | `PreUpgrade` | `PostUpgrade` | +| `Uninstall-WinGetPackage` | `PreUninstall` | `PostUninstall` | +| `Repair-WinGetPackage` | `PreInstall` (reuses install messages) | `PostInstall` (reuses install messages) | + +#### Interactive Behavior + +When running interactively in a PowerShell session, cmdlets follow the same pattern as the CLI: + +```powershell +PS> Install-WinGetPackage -Id Publisher.ExampleApp + +The following information has been provided by the manifest author: + + This package requires 2 GB of disk space and will modify your PATH. + +Do you wish to continue? +[Y] Yes [N] No (default is "Y"): +``` + +The prompt uses `$Host.UI.PromptForChoice` (or equivalent) to integrate with PowerShell's native prompting, supporting `-Confirm` and `-WhatIf` patterns where applicable. + +#### Non-Interactive / Pipeline Behavior + +When running non-interactively (e.g., in a script with no host, or when the user passes `-Force`), pre-action messages are written to the verbose stream (`Write-Verbose`) and the operation proceeds without prompting: + +```powershell +PS> Install-WinGetPackage -Id Publisher.ExampleApp -Force -Verbose +VERBOSE: Manifest author message (PreInstall): This package requires 2 GB of disk space and will modify your PATH. +``` + +Post-action messages are written to the information stream (`Write-Information`) so they appear by default but can be suppressed with `-InformationAction SilentlyContinue`. + +#### Output Object + +The result objects returned by cmdlets should include UserMessages in their output when present: + +```powershell +PS> $result = Install-WinGetPackage -Id Publisher.ExampleApp +PS> $result.UserMessages + +PreInstall : This package requires 2 GB of disk space and will modify your PATH. +PostInstall : Restart your terminal to use the CLI. +``` + +This allows scripts to programmatically inspect messages after an operation: + +```powershell +$result = Install-WinGetPackage -Id Publisher.ExampleApp -Force +if ($result.UserMessages.PostInstall) { + Write-Host "Note from manifest author: $($result.UserMessages.PostInstall)" -ForegroundColor Yellow +} +``` + +#### Find-WinGetPackage / Show-WinGetPackage + +The `Show-WinGetPackage` (or `Get-WinGetPackage`) cmdlet should include `UserMessages` in its output when displaying package metadata, allowing users to review messages before deciding to install: + +```powershell +PS> Show-WinGetPackage -Id Publisher.ExampleApp | Select-Object -ExpandProperty UserMessages + +PreInstall : This package requires 2 GB of disk space and will modify your PATH. +PostInstall : Restart your terminal to use the CLI. +PreUpgrade : Back up your configuration file before upgrading. +PostUpgrade : Review the changelog for breaking changes. +``` + +`Find-WinGetPackage` returns search results and does not include `UserMessages` in its default output. Users should use `Show-WinGetPackage` to inspect messages for a specific package before installation. + +### Validation Pipeline (winget-pkgs) + +The `winget validate` command and the automated validation pipeline in the winget-pkgs repository must handle `UserMessages` correctly: + +1. **Schema validation:** Validate `UserMessages` against the JSON schema (field types, lengths, required/optional). +2. **Non-interactive execution:** The validation pipeline runs with `--disable-interactivity`. Pre-messages must not block validation. +3. **Content validation:** The pipeline should validate that: + - Messages do not contain ANSI escape sequences or control characters. + - Messages do not contain URLs that appear to be phishing attempts (leveraging existing content moderation if applicable). +4. **Deprecation warnings:** During the transition period, if a manifest contains `InstallationNotes` but no `UserMessages.PostInstall`, a warning (not an error) may be emitted suggesting the manifest author add the `UserMessages` equivalent. +5. **Rendering validation:** Validate that pre-messages render cleanly when displayed (no truncation at the 2048-character limit that would break mid-word or mid-sentence). + +### Additional CLI Commands + +#### `winget show` + +The `winget show` command displays package metadata. When `UserMessages` is present, the messages are displayed as part of the package details: + +``` +Found Example App [Publisher.ExampleApp] v2.0.0 +... +Installer: + Type: Exe + ... +User Messages: + Pre-Install: This package requires 2 GB of disk space and will modify your PATH. + Post-Install: Restart your terminal to use the CLI. + Pre-Upgrade: Back up your configuration file before upgrading. +``` + +No prompt is displayed — `show` is read-only. + +#### `winget repair` + +The `repair` command reuses `PreInstall` and `PostInstall` messages. The behavior is identical to `install` — pre-message with prompt in interactive mode, post-message after success. + +#### `winget export` + +The `export` command captures the list of installed packages. `UserMessages` are not included in the export output since they are part of the source manifest, not the installed state. + +### WinGet Configuration (DSC) + +WinGet Configuration is inherently non-interactive. When a configuration file references a package that has `UserMessages`: + +- **Pre-messages** are written to the configuration log output as informational entries. They do not block or prompt. +- **Post-messages** are written to the configuration log output after the resource completes successfully. +- The COM API provides the `IPackageUserMessages` interface so the configuration engine can access messages programmatically. + +### Group Policy + +This specification does not introduce new Group Policy settings. Group Policy controls for `UserMessages` (e.g., enforcing or suppressing messages across managed devices) are deferred to a future specification. The existing Group Policy infrastructure is not affected. + +### REST Source (winget-cli-restsource) + +The [winget-cli-restsource](https://github.com/microsoft/winget-cli-restsource) reference implementation must be updated to support the new `UserMessages` fields so enterprise REST sources can serve this data. Changes include: + +- **Schema update** — Add `UserMessages` fields to the REST source data model and API response contracts. +- **API versioning** — Introduce a new API version that includes `UserMessages` in the package version response. Older API versions continue to function without the new fields. +- **Storage** — The backing data store (Azure Cosmos DB / SQL) must accommodate the new fields. + +> [!NOTE] +> Enterprise REST sources do not carry the same deprecation concerns as the WinGet Community Repository. Organizations control their own source update cadence and can adopt new schema fields on their own timeline. + +### Community Repository (winget-pkgs) + +The [winget-pkgs](https://github.com/microsoft/winget-pkgs) community repository is impacted in two ways: + +1. **Validation pipeline** — The automated validation tooling must be updated to: + - Accept `UserMessages` fields in manifests using the new schema version. + - Validate field lengths (2048 for pre-action, 10000 for post-action) and structure. + - Ensure validation runs are non-interactive — pre-action messages must not block the pipeline. + +2. **Schema version acceptance policy** — The community repository accepts manifests at schema version **n** or **n-1**. As the minimum accepted version advances to include the `UserMessages` schema, manifest authors will be required to adopt the new fields and migrate away from `InstallationNotes`. This is the practical mechanism that drives deprecation of the older field. + +### Manifest Examples + +#### Transition period — both fields for compatibility + +```yaml +# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.13.0.schema.json + +PackageIdentifier: Publisher.ExampleApp +PackageVersion: 2.0.0 +PackageLocale: en-US +PackageName: Example App +ShortDescription: An example application. +InstallationNotes: "Restart your terminal to use the CLI." +UserMessages: + PreInstall: "This package requires 2 GB of disk space and will modify your PATH." + PostInstall: "Restart your terminal to use the CLI." + PreUpgrade: "Back up your configuration file at ~/.example/config.yaml before upgrading." + PostUpgrade: "Review the changelog at https://example.com/changelog for breaking changes." + PreUninstall: "Run 'example cleanup' to remove cached data before uninstalling." + PostUninstall: "Restart your terminal to remove the CLI from your PATH." +ManifestType: defaultLocale +ManifestVersion: 1.13.0 +``` + +#### Pre-install warning only + +```yaml +InstallationNotes: "Restart your terminal to use the CLI." +UserMessages: + PreInstall: "This package requires 2 GB of disk space and will modify your PATH." + PostInstall: "Restart your terminal to use the CLI." +``` + +#### Legacy only — no change required + +```yaml +InstallationNotes: "Restart your terminal to use the CLI." +``` + +Existing manifests are unaffected. `UserMessages` is entirely optional. + +## UI/UX Design + +### Pre-Action Message Display + +Pre-action messages are displayed in a visually distinct block before the operation begins. The message is attributed to the manifest author to establish trust context. + +``` +Found Example App [Publisher.ExampleApp] v2.0.0 +This application is licensed to you by its owner. +Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. + +The following information has been provided by the manifest author: + + This package requires 2 GB of disk space and will modify your PATH. + +Do you wish to continue? [Y/n]: +``` + +### Post-Action Message Display + +Post-action messages appear after the success message, indented and visually separated. + +``` +Successfully installed Example App [Publisher.ExampleApp] v2.0.0 + + Restart your terminal to use the CLI. +``` + +### Message Attribution + +All messages include clear attribution language ("provided by the manifest author") to ensure users understand the content originates from the manifest author, not from Microsoft or WinGet. This distinction is important because in the WinGet community repository, manifests are frequently authored by community contributors rather than the software publisher. This is critical for trust and security. + +### Localization + +Messages in locale manifests override those in the defaultLocale manifest on a per-field basis. If a locale manifest provides `UserMessages.PreInstall` but not `UserMessages.PostInstall`, the client falls back to the defaultLocale value for `PostInstall`. + +## Capabilities + +### Accessibility + +- Pre-action messages and prompts are rendered as standard text output, compatible with screen readers. +- The Y/n prompt follows existing WinGet prompt patterns for consistency with assistive technology expectations. +- Post-action messages are rendered as standard text, identical to current `InstallationNotes` behavior. +- No color-only information is used; messages are plain text. + +### Security + +- **Phishing and social engineering:** Pre-action messages create a stronger social-engineering surface than post-action notes because they appear before the user commits to an action. A malicious manifest author could craft a message like "Enter your password at https://evil.example.com to continue." Mitigations: + - Clear attribution language ("provided by the manifest author") helps users assess trust. + - Content validation in the winget-pkgs pipeline strips or rejects ANSI escape sequences and control characters. + - The winget-pkgs community review process provides human review of manifest content. + - Future enhancement: automated content moderation for suspicious URLs or social-engineering patterns. +- **Content sanitization:** All message fields must have ANSI escape sequences and control characters stripped before display to prevent terminal manipulation. +- **No elevation bypass:** Displaying a message does not grant any additional permissions. The prompt is a user experience feature, not a security boundary. + +### Reliability + +- The feature is additive and optional. No existing behavior changes unless the manifest includes `UserMessages`. +- Clients that do not understand `UserMessages` ignore it (unknown fields are skipped in manifest parsing). +- Schema validation catches malformed `UserMessages` objects at submission time in the winget-pkgs pipeline. + +### Compatibility + +- **No breaking changes.** `InstallationNotes` is unchanged. Existing manifests and existing clients continue to work exactly as they do today. +- **Older clients:** Ignore the `UserMessages` field (unknown fields are silently ignored in manifest parsing). They continue to display `InstallationNotes` if present. +- **Newer clients:** Read `UserMessages` and prefer `UserMessages.PostInstall` over `InstallationNotes` when both are present. +- **Schema version:** The new schema version (e.g., 1.13.0) is required. Clients that cannot parse manifests at this schema version will receive manifests at the highest version they support from the source. In the winget-pkgs repository, manifests can exist at multiple schema versions to support this. +- **Minimum client version:** Only clients at or above the version that implements this specification will process `UserMessages`. The exact version will be determined during implementation. + +### Performance, Power, and Efficiency + +- Negligible impact. The feature adds string parsing and display of up to six optional text fields. No network calls, no computation, no background processing. +- Pre-action prompts add user wait time in interactive mode only. + +## Potential Issues + +1. **Prompt fatigue.** If many packages include pre-action messages, users may develop "prompt blindness" and reflexively confirm without reading. Mitigation: the 2048-character limit keeps messages concise, and community review in winget-pkgs ensures messages are meaningful. + +2. **Bulk operation noise.** `upgrade --all` with many packages containing pre-messages could be verbose and slow. A future enhancement to aggregate messages would address this, but is out of scope here. + +3. **Transition-period duplication.** During the transition, manifest authors must duplicate their install note in both `InstallationNotes` and `UserMessages.PostInstall`. This is a known trade-off for backward compatibility and is temporary. + +4. **Content moderation burden.** The winget-pkgs community reviewers now have six new fields to review per manifest. Automated tooling to flag suspicious content in these fields would reduce this burden. + +5. **Locale fallback complexity.** Per-field fallback from locale to defaultLocale adds implementation complexity. However, this follows the existing pattern for all other localizable fields and is well-understood. + +## Deprecation Path for `InstallationNotes` + +| Phase | Client behavior | Manifest guidance | +|-------|----------------|-------------------| +| **1. Introduction** | Newer clients read `UserMessages`; older clients read `InstallationNotes` | Include both fields. Duplicate the install note in `InstallationNotes` and `UserMessages.PostInstall`. | +| **2. Transition** | Older client versions age out of support | Continue including both fields. Document `InstallationNotes` as deprecated in schema docs. | +| **3. Deprecation** | All supported clients understand `UserMessages` | `InstallationNotes` marked deprecated. Manifests may omit it. Validation warns but does not reject. | +| **4. Removal** (future) | N/A | `InstallationNotes` removed in a future schema version. `UserMessages.PostInstall` is the canonical replacement. | + +The timeline for each phase is driven by client adoption telemetry, not fixed dates. Phase 4 (removal) is explicitly deferred to a future specification. + +> [!IMPORTANT] +> There is no intent to make breaking changes in WinGet 1.X. The WinGet CLI will continue to function normally with manifests that use `InstallationNotes`, regardless of deprecation phase. The practical driver for deprecation is the **WinGet Community Repository** (winget-pkgs) schema version policy. The community repository requires new manifest submissions to use schema version **n** or **n-1** (the current or immediately prior version). As the repository moves forward to schema versions where `UserMessages` is the expected field, publishers and manifest authors will be required to adopt the new field and stop using `InstallationNotes` as a condition of submitting to the community repository — not because the client rejects it, but because the repository's validation pipeline enforces the current schema versions. + +## Future Considerations + +The `UserMessages` object is designed to be extended. Potential future additions include: + +- **`PostReboot`** — Message displayed after a reboot triggered by the package. +- **`PreDownload` / `PostDownload` ** — Message displayed before the package is downloaded, if different from pre-install. Also applies to `winget download` +- **`Configuration`** — Message displayed when the package is processed as part of a WinGet Configuration. +- **Structured message types** — Replacing plain strings with objects that include severity, category, or formatting hints. +- **Aggregate pre-message summary** — For bulk operations, presenting all pre-messages in a single summary before beginning the batch. +- **Rich formatting** — Support for basic markdown or structured text in messages (requires careful consideration of terminal rendering). +- **Group Policy controls** — Admin policies to enforce or suppress user messages across managed devices. + +New keys can be added in future schema versions without breaking existing manifests. + +## Resources + +- [#3483 — Make InstallationNotes flow-dependent](https://github.com/microsoft/winget-cli/issues/3483) — Original community request by @Trenly. +- [WinGet Manifest Schema Documentation](https://learn.microsoft.com/windows/package-manager/) — Current schema reference. +- [WinGet CLI Settings](https://github.com/microsoft/winget-cli/blob/master/doc/Settings.md) — Settings documentation including `disableInstallNotes`. +- [Manifest Schema JSON](https://github.com/microsoft/winget-cli/tree/master/schemas/JSON/manifests/) — JSON schema source files. diff --git a/doc/specs/spec-template.md b/doc/specs/spec-template.md index 940ce6a267..7572191a87 100644 --- a/doc/specs/spec-template.md +++ b/doc/specs/spec-template.md @@ -20,6 +20,8 @@ issue id: ## Solution Design [comment]: # Outline the design of the solution. Feel free to include ASCII-art diagrams, etc. +[comment]: # When proposing new settings, also propose corresponding CLI arguments (and vice versa). Settings define user defaults; CLI arguments provide per-invocation overrides. +[comment]: # When proposing schema changes, address the cross-repository impact: winget-cli (client and schema), winget-cli-restsource (enterprise REST source), and winget-pkgs (validation pipeline and deprecation policy). ## UI/UX Design @@ -51,7 +53,11 @@ issue id: [comment]: # What are some of the things that might cause problems with the fixes/features proposed? Consider how the user might be negatively impacted. -## Future considerations +## Deprecation Path + +[comment]: # If this spec replaces an existing field or feature, outline the phased deprecation plan. If not applicable, state that explicitly. + +## Future Considerations [comment]: # What are some of the things that the fixes/features might unlock in the future? Does the implementation of this spec enable scenarios? From 86a91f2115fa1327428784b3d58837018f0e0439 Mon Sep 17 00:00:00 2001 From: Demitrius Nelon Date: Wed, 6 May 2026 10:18:03 -0700 Subject: [PATCH 2/2] Address review feedback on UserMessages specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add PreRepair/PostRepair dedicated fields (8 fields total) - Nest settings under userExperience section - Add --show-user-messages CLI override - Standardize table language (Displayed/Suppressed/Prompted) - Clarify no cross-field fallback between operations - Define uninstall message sourcing (target → latest → none) - Schema versions align with client versions - may → should for backward compat guidance - Add automation impact callout - Remove --silent from behavior matrix - Bulk operations present pre-messages upfront - Simplify interaction table - COM API section goes vague - Add consideration for exposing settings via COM - Replace Show-WinGetPackage with Find-WinGetPackage - Add locale translation validation note - Remove rendering validation item - disableInstallNotes also suppresses PostInstall Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- doc/specs/#3483 - UserMessages.md | 178 ++++++++++++++++-------------- 1 file changed, 98 insertions(+), 80 deletions(-) diff --git a/doc/specs/#3483 - UserMessages.md b/doc/specs/#3483 - UserMessages.md index 1fd7c6b777..6f0b9544ea 100644 --- a/doc/specs/#3483 - UserMessages.md +++ b/doc/specs/#3483 - UserMessages.md @@ -11,7 +11,7 @@ For [#3483](https://github.com/microsoft/winget-cli/issues/3483) ## Abstract -This specification proposes adding an optional `UserMessages` object to the WinGet package manifest schema. The new field provides structured, flow-dependent messaging to users before and after install, upgrade, and uninstall operations. It is designed as a non-breaking, additive change that coexists with the existing `InstallationNotes` string field during a transition period and eventually replaces it. +This specification proposes adding an optional `UserMessages` object to the WinGet package manifest schema. The new field provides structured, flow-dependent messaging to users before and after install, upgrade, uninstall, and repair operations. It is designed as a non-breaking, additive change that coexists with the existing `InstallationNotes` string field during a transition period and eventually replaces it. ## Inspiration @@ -69,6 +69,18 @@ A new optional `UserMessages` object is added to the **defaultLocale** and **loc "minLength": 1, "maxLength": 10000, "description": "Message displayed to the user upon completion of a package uninstall." + }, + "PreRepair": { + "type": ["string", "null"], + "minLength": 1, + "maxLength": 2048, + "description": "Confirmation request displayed to the user before a package repair begins." + }, + "PostRepair": { + "type": ["string", "null"], + "minLength": 1, + "maxLength": 10000, + "description": "Message displayed to the user upon completion of a package repair." } }, "additionalProperties": false @@ -80,7 +92,7 @@ A new optional `UserMessages` object is added to the **defaultLocale** and **loc ### Schema Version -This change requires a new manifest schema version (the next minor version after the current release, e.g., 1.13.0). The `UserMessages` field is added to: +This change requires a new manifest schema version that aligns with the client version at the time of implementation. The `UserMessages` field is added to: - `defaultLocale.schema.json` - `locale.schema.json` @@ -89,7 +101,7 @@ The `installer.schema.json` is not affected. User-facing messages are locale-sen ### Existing `InstallationNotes` Field -The existing `InstallationNotes` field is **unchanged** in this schema version. It continues to function as it does today. During the transition period, manifests may include both fields for backward compatibility. +The existing `InstallationNotes` field is **unchanged** in this schema version. It continues to function as it does today. During the transition period, manifests should include both fields for backward compatibility. ### Client Behavior @@ -100,7 +112,18 @@ When both `InstallationNotes` and `UserMessages.PostInstall` are present in a ma - **Clients that support `UserMessages`:** Display `UserMessages.PostInstall` and ignore `InstallationNotes`. - **Clients that do not support `UserMessages`:** Display `InstallationNotes` (current behavior, unaffected by the unknown field). -#### Pre-Action Messages (PreInstall, PreUpgrade, PreUninstall) +> [!NOTE] +> Each operation displays only its corresponding `UserMessages` field. There is no cross-field fallback between operations — for example, if a manifest defines `PreInstall` but not `PreUpgrade`, no pre-action message is displayed during an upgrade. + +#### Uninstall Message Sourcing + +For uninstall operations, `PreUninstall` and `PostUninstall` are sourced as follows: + +- If the package is correlated to a specific installed version, use that version's manifest messages. +- If the package is correlated but no target version manifest exists, use the latest available version's messages. +- If the package is not correlated (for example, it was not installed through WinGet), no uninstall message is displayed. + +#### Pre-Action Messages (PreInstall, PreUpgrade, PreUninstall, PreRepair) Pre-action messages are displayed **before** the operation begins and represent information the user should be aware of before proceeding. @@ -116,6 +139,9 @@ Do you wish to continue? [Y/n]: The user is prompted to confirm. Entering `N` cancels the operation. Entering `Y` or pressing Enter proceeds. +> [!IMPORTANT] +> **Automation impact:** The introduction of pre-action prompts in interactive mode will affect existing automation scripts that do not use `--disable-interactivity`. Automation authors should ensure their scripts pass `--disable-interactivity` or use the PowerShell module with `-Force` to avoid being blocked by prompts. The COM API does not prompt and is unaffected. + **Non-interactive mode (`--disable-interactivity`):** The pre-action message is displayed (rendered to the output stream) but no prompt is shown and the operation proceeds automatically. This ensures automation pipelines see the message in logs without being blocked. @@ -131,7 +157,7 @@ Proceeding automatically (non-interactive mode)... > [!NOTE] > **Design rationale:** Pre-action messages are informational, not contractual agreements. Unlike license terms (which require explicit acceptance via `--accept-package-agreements`), user messages are manifest-author-provided guidance. The `--disable-interactivity` flag is the appropriate suppressor because it already governs all interactive prompts in WinGet. A new flag is not warranted. -#### Post-Action Messages (PostInstall, PostUpgrade, PostUninstall) +#### Post-Action Messages (PostInstall, PostUpgrade, PostUninstall, PostRepair) Post-action messages are displayed **after** the operation completes successfully. They are informational only — no prompt is shown. @@ -141,67 +167,67 @@ Successfully installed ExampleApp [Publisher.ExampleApp] v2.0.0 Restart your terminal to use the CLI. ``` -Post-action messages are displayed in both interactive and non-interactive modes. They are suppressed when the `userMessages.disablePostActionMessages` setting is enabled. +Post-action messages are displayed in both interactive and non-interactive modes. They are suppressed when the `userExperience.userMessages.disablePostActionMessages` setting is enabled. #### Flow Behavior Matrix | Scenario | Pre-message | Post-message | Notes | |----------|-------------|--------------|-------| -| `winget install` | `PreInstall` shown, prompt Y/n | `PostInstall` shown | Standard single-package install | -| `winget upgrade ` | `PreUpgrade` shown, prompt Y/n | `PostUpgrade` shown | Single-package upgrade | -| `winget upgrade --all` | Each package's `PreUpgrade` shown, prompt Y/n per package | Each package's `PostUpgrade` shown | See "Bulk Operations" below | -| `winget uninstall` | `PreUninstall` shown, prompt Y/n | `PostUninstall` shown | Standard uninstall | -| `winget install --disable-interactivity` | `PreInstall` displayed, no prompt | `PostInstall` shown | Non-interactive install | -| `winget install --silent` | `PreInstall` displayed, no prompt | `PostInstall` shown | Silent implies non-interactive | -| Dependency packages | Not shown | Not shown | Messages apply to the root package only, not transitive dependencies | -| `winget import` | Each package's `Pre*` shown, prompt Y/n per package | Each package's `Post*` shown | Follows the same per-package model | -| WinGet Configuration (DSC) | Displayed in log output, no prompt | Displayed in log output | Configuration is inherently non-interactive | +| `winget install` | `PreInstall` Displayed; Prompted (Y/n) | `PostInstall` Displayed | Standard single-package install | +| `winget upgrade ` | `PreUpgrade` Displayed; Prompted (Y/n) | `PostUpgrade` Displayed | Single-package upgrade | +| `winget upgrade --all` | All `PreUpgrade` messages Displayed together; Prompted (Y/n) once | Each `PostUpgrade` Displayed | See "Bulk Operations" below | +| `winget uninstall` | `PreUninstall` Displayed; Prompted (Y/n) | `PostUninstall` Displayed | Uses uninstall message sourcing rules above | +| `winget install --disable-interactivity` | `PreInstall` Displayed; Prompt Suppressed | `PostInstall` Displayed | Non-interactive install | +| Dependency packages | Suppressed | Suppressed | Messages apply to the root package only, not transitive dependencies | +| `winget import` | All `Pre*` messages Displayed together; Prompted (Y/n) once | Each `Post*` Displayed | Follows the same batch model | +| WinGet Configuration (DSC) | Displayed | Displayed | Configuration is inherently non-interactive | | `winget show` | N/A | N/A | `show` displays `UserMessages` as package metadata (see below) | -| `winget repair` | `PreInstall` shown, prompt Y/n | `PostInstall` shown | Repair reuses install messages | +| `winget repair` | `PreRepair` Displayed; Prompted (Y/n) | `PostRepair` Displayed | Repair has dedicated fields | | `winget export` | N/A | N/A | Export captures package list, not messages | -| Operation failure | `Pre*` shown before attempt | `Post*` NOT shown | Post-messages only appear on success | -| `disableInstallNotes` setting enabled | `Pre*` still shown (not affected) | `Post*` still shown (controlled by `userMessages` settings, not `disableInstallNotes`) | Legacy setting does not affect new fields | -| `userMessages.disablePostActionMessages` enabled | `Pre*` still shown | `Post*` suppressed | New setting for new fields | -| `userMessages.disablePreActionMessages` enabled | `Pre*` suppressed, no prompt | `Post*` still shown | Suppresses both display and prompt | -| `--ignore-user-messages` | `Pre*` suppressed, no prompt | `Post*` suppressed | CLI argument overrides settings for this invocation | -| `--ignore-pre-action-messages` | `Pre*` suppressed, no prompt | `Post*` still shown | CLI argument overrides `disablePreActionMessages` setting | -| `--ignore-post-action-messages` | `Pre*` still shown | `Post*` suppressed | CLI argument overrides `disablePostActionMessages` setting | -| `winget validate` | Not shown, not prompted | Not shown | Validation checks schema correctness only; messages are not rendered | +| Operation failure | `Pre*` Displayed before attempt | Suppressed | Post-messages only appear on success | +| `disableInstallNotes` setting enabled | `Pre*` Displayed | `PostInstall` Suppressed; other `Post*` Displayed | Backward compatibility behavior for migrated install notes | +| `userExperience.userMessages.disablePostActionMessages` enabled | `Pre*` Displayed | `Post*` Suppressed | New setting for new fields | +| `userExperience.userMessages.disablePreActionMessages` enabled | Suppressed; Prompt Suppressed | `Post*` Displayed | Suppresses both display and prompt | +| `--show-user-messages` | `Pre*` Displayed; Prompted (Y/n) in interactive mode | `Post*` Displayed | Overrides settings that suppress messages for this invocation | +| `--ignore-user-messages` | Suppressed; Prompt Suppressed | `Post*` Suppressed | CLI argument overrides settings for this invocation | +| `--ignore-pre-action-messages` | Suppressed; Prompt Suppressed | `Post*` Displayed | CLI argument overrides `userExperience.userMessages.disablePreActionMessages` | +| `--ignore-post-action-messages` | `Pre*` Displayed | `Post*` Suppressed | CLI argument overrides `userExperience.userMessages.disablePostActionMessages` | +| `winget validate` | Suppressed | Suppressed | Validation checks schema correctness only; messages are not rendered | #### Bulk Operations (`upgrade --all`, `import`) -For bulk operations, pre-action messages are shown per-package. In interactive mode, each package with a pre-action message prompts individually. This is consistent with how `--accept-package-agreements` works today — per-package, not a single blanket prompt. +For bulk operations, pre-action messages for all packages in the batch are collected and presented together before any operations begin. -A future enhancement could aggregate pre-messages and present them as a summary before beginning the batch, but that is out of scope for this specification. +In interactive mode, the user is prompted once after seeing the full set of pre-action messages. This is consistent with how preconditions are already handled in WinGet. ### Settings -A new `userMessages` settings object is introduced under the root of the WinGet settings file. The existing `installBehavior.disableInstallNotes` setting is **not modified** and continues to control only the legacy `InstallationNotes` field. +A new `userExperience.userMessages` settings object is introduced in the WinGet settings file. The `userExperience` section is a new organizational grouping that could eventually house other user-facing settings such as `visual` and `interactivity` in a future settings schema revision. ```json { - "userMessages": { - "disablePreActionMessages": false, - "disablePostActionMessages": false + "userExperience": { + "userMessages": { + "disablePreActionMessages": false, + "disablePostActionMessages": false + } } } ``` | Setting | Default | Description | |---------|---------|-------------| -| `userMessages.disablePreActionMessages` | `false` | When `true`, suppresses all pre-action messages (`PreInstall`, `PreUpgrade`, `PreUninstall`) and their associated prompts. The operation proceeds as if the user confirmed. | -| `userMessages.disablePostActionMessages` | `false` | When `true`, suppresses all post-action messages (`PostInstall`, `PostUpgrade`, `PostUninstall`). | +| `userExperience.userMessages.disablePreActionMessages` | `false` | When `true`, suppresses all pre-action messages (`PreInstall`, `PreUpgrade`, `PreUninstall`, `PreRepair`) and their associated prompts. The operation proceeds as if the user confirmed. | +| `userExperience.userMessages.disablePostActionMessages` | `false` | When `true`, suppresses all post-action messages (`PostInstall`, `PostUpgrade`, `PostUninstall`, `PostRepair`). | **Interaction with existing settings:** -The following table shows what is displayed on **clients that support `UserMessages`** during an install operation when both `InstallationNotes` and `UserMessages.PostInstall` are present. Per the precedence rules above, supporting clients display `UserMessages.PostInstall` and ignore `InstallationNotes`. +Since `UserMessages.PostInstall` takes precedence over `InstallationNotes` on supporting clients (as described in the Precedence Rules section), the settings that affect post-action messages are: + +- `userExperience.userMessages.disablePostActionMessages` — suppresses `UserMessages.Post*` +- `disableInstallNotes` — also suppresses `UserMessages.PostInstall` for backward compatibility (see below) -| `disableInstallNotes` | `userMessages.disablePostActionMessages` | `InstallationNotes` | `UserMessages.Post*` | -|----------------------|------------------------------------------|---------------------|----------------------| -| `false` | `false` | Ignored (superseded) | Shown | -| `true` | `false` | Ignored (superseded) | Shown | -| `false` | `true` | Ignored (superseded) | Suppressed | -| `true` | `true` | Ignored (superseded) | Suppressed | +For backward compatibility, when `disableInstallNotes` is `true`, it also suppresses `UserMessages.PostInstall`. This ensures users who previously disabled install notes continue to have a consistent experience when manifests migrate to the new field. On **older clients** that do not support `UserMessages`, only `InstallationNotes` is relevant and `disableInstallNotes` controls it as it does today. @@ -212,10 +238,11 @@ Corresponding CLI arguments are provided so users can override the settings on a | Argument | Applies to | Description | |----------|-----------|-------------| | `--ignore-user-messages` | `install`, `upgrade`, `uninstall`, `repair`, `import` | Suppresses all `UserMessages` (both pre- and post-action) for this invocation. Pre-action prompts are skipped and the operation proceeds. | -| `--ignore-pre-action-messages` | `install`, `upgrade`, `uninstall`, `repair`, `import` | Suppresses pre-action messages and their prompts for this invocation. Post-action messages are still shown. | -| `--ignore-post-action-messages` | `install`, `upgrade`, `uninstall`, `repair`, `import` | Suppresses post-action messages for this invocation. Pre-action messages and prompts are still shown. | +| `--ignore-pre-action-messages` | `install`, `upgrade`, `uninstall`, `repair`, `import` | Suppresses pre-action messages and their prompts for this invocation. Post-action messages are still displayed. | +| `--ignore-post-action-messages` | `install`, `upgrade`, `uninstall`, `repair`, `import` | Suppresses post-action messages for this invocation. Pre-action messages and prompts are still displayed. | +| `--show-user-messages` | `install`, `upgrade`, `uninstall`, `repair`, `import` | Forces all `UserMessages` to be displayed for this invocation, overriding any settings that disable them. | -**Precedence:** CLI arguments override settings. If a user has `userMessages.disablePreActionMessages` set to `false` in settings but passes `--ignore-pre-action-messages`, the pre-action messages are suppressed for that invocation. +**Precedence:** CLI arguments override settings. If a user has `userExperience.userMessages.disablePreActionMessages` set to `false` in settings but passes `--ignore-pre-action-messages`, the pre-action messages are suppressed for that invocation. `--show-user-messages` overrides settings but does not override `--ignore-user-messages` if both are passed; ignore wins. **Relationship to `--disable-interactivity`:** The `--disable-interactivity` flag suppresses the **prompt** on pre-action messages but still displays the message text. The `--ignore-pre-action-messages` flag suppresses both the message and the prompt entirely. @@ -224,30 +251,17 @@ Example usage: ``` winget upgrade --all --ignore-pre-action-messages winget install Publisher.ExampleApp --ignore-user-messages +winget install Publisher.ExampleApp --show-user-messages ``` ### COM API -The COM API must surface `UserMessages` in a structured manner for programmatic consumers. - -A new `IPackageUserMessages` interface is introduced, and a new versioned interface (e.g., `IPackageCatalogInfo2` or `IPackageVersionInfo2`) exposes a `UserMessages` property that returns this object. This follows the established WinGet pattern for additive COM API changes — new interface versions are introduced rather than modifying existing interfaces, ensuring existing consumers remain compatible. - -```idl -interface IPackageUserMessages : IInspectable -{ - String PreInstall { get; }; - String PostInstall { get; }; - String PreUpgrade { get; }; - String PostUpgrade { get; }; - String PreUninstall { get; }; - String PostUninstall { get; }; -} -``` - -Consumers query for the new interface version to access `UserMessages`. Existing consumers that use the original interface are unaffected. +The `UserMessages` data will be available in the COM API as eight string properties (one per message field). The specific interface shape and versioning will be determined during implementation, following the established WinGet pattern for additive COM API changes. COM consumers are responsible for their own interactivity model. The WinGet COM API does not prompt — it returns the data and the consumer decides how to handle it. +The `userExperience.userMessages` settings should also be exposed via the COM API so that well-behaved callers (such as the WinGet PowerShell module) can query the user's settings and make informed decisions about whether to display messages. + ### PowerShell Cmdlets The WinGet PowerShell module cmdlets consume the COM API and must surface `UserMessages` appropriately. @@ -259,7 +273,7 @@ The WinGet PowerShell module cmdlets consume the COM API and must surface `UserM | `Install-WinGetPackage` | `PreInstall` | `PostInstall` | | `Update-WinGetPackage` | `PreUpgrade` | `PostUpgrade` | | `Uninstall-WinGetPackage` | `PreUninstall` | `PostUninstall` | -| `Repair-WinGetPackage` | `PreInstall` (reuses install messages) | `PostInstall` (reuses install messages) | +| `Repair-WinGetPackage` | `PreRepair` | `PostRepair` | #### Interactive Behavior @@ -310,21 +324,21 @@ if ($result.UserMessages.PostInstall) { } ``` -#### Find-WinGetPackage / Show-WinGetPackage +#### Find-WinGetPackage -The `Show-WinGetPackage` (or `Get-WinGetPackage`) cmdlet should include `UserMessages` in its output when displaying package metadata, allowing users to review messages before deciding to install: +`Find-WinGetPackage` should include `UserMessages` in its output when displaying package metadata from the source, allowing users to review messages before deciding to install. ```powershell -PS> Show-WinGetPackage -Id Publisher.ExampleApp | Select-Object -ExpandProperty UserMessages - -PreInstall : This package requires 2 GB of disk space and will modify your PATH. -PostInstall : Restart your terminal to use the CLI. -PreUpgrade : Back up your configuration file before upgrading. -PostUpgrade : Review the changelog for breaking changes. +PS> Find-WinGetPackage -Id Publisher.ExampleApp | Select-Object -ExpandProperty UserMessages + +PreInstall : This package requires 2 GB of disk space and will modify your PATH. +PostInstall : Restart your terminal to use the CLI. +PreUpgrade : Back up your configuration file before upgrading. +PostUpgrade : Review the changelog for breaking changes. +PreRepair : Close the application before starting repair. +PostRepair : Restart the application to verify the repair completed successfully. ``` -`Find-WinGetPackage` returns search results and does not include `UserMessages` in its default output. Users should use `Show-WinGetPackage` to inspect messages for a specific package before installation. - ### Validation Pipeline (winget-pkgs) The `winget validate` command and the automated validation pipeline in the winget-pkgs repository must handle `UserMessages` correctly: @@ -335,7 +349,6 @@ The `winget validate` command and the automated validation pipeline in the winge - Messages do not contain ANSI escape sequences or control characters. - Messages do not contain URLs that appear to be phishing attempts (leveraging existing content moderation if applicable). 4. **Deprecation warnings:** During the transition period, if a manifest contains `InstallationNotes` but no `UserMessages.PostInstall`, a warning (not an error) may be emitted suggesting the manifest author add the `UserMessages` equivalent. -5. **Rendering validation:** Validate that pre-messages render cleanly when displayed (no truncation at the 2048-character limit that would break mid-word or mid-sentence). ### Additional CLI Commands @@ -353,13 +366,15 @@ User Messages: Pre-Install: This package requires 2 GB of disk space and will modify your PATH. Post-Install: Restart your terminal to use the CLI. Pre-Upgrade: Back up your configuration file before upgrading. + Pre-Repair: Close the application before starting repair. + Post-Repair: Restart the application to verify the repair completed successfully. ``` No prompt is displayed — `show` is read-only. #### `winget repair` -The `repair` command reuses `PreInstall` and `PostInstall` messages. The behavior is identical to `install` — pre-message with prompt in interactive mode, post-message after success. +The `repair` command uses the dedicated `PreRepair` and `PostRepair` fields. Its behavior mirrors the other operation-specific flows — pre-message with prompt in interactive mode, post-message after success. #### `winget export` @@ -371,7 +386,7 @@ WinGet Configuration is inherently non-interactive. When a configuration file re - **Pre-messages** are written to the configuration log output as informational entries. They do not block or prompt. - **Post-messages** are written to the configuration log output after the resource completes successfully. -- The COM API provides the `IPackageUserMessages` interface so the configuration engine can access messages programmatically. +- The COM API provides the message data so the configuration engine can access it programmatically. ### Group Policy @@ -404,7 +419,7 @@ The [winget-pkgs](https://github.com/microsoft/winget-pkgs) community repository #### Transition period — both fields for compatibility ```yaml -# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.13.0.schema.json +# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.X.0.schema.json PackageIdentifier: Publisher.ExampleApp PackageVersion: 2.0.0 @@ -419,8 +434,10 @@ UserMessages: PostUpgrade: "Review the changelog at https://example.com/changelog for breaking changes." PreUninstall: "Run 'example cleanup' to remove cached data before uninstalling." PostUninstall: "Restart your terminal to remove the CLI from your PATH." + PreRepair: "Close the application before starting repair." + PostRepair: "Restart the application to verify the repair completed successfully." ManifestType: defaultLocale -ManifestVersion: 1.13.0 +ManifestVersion: 1.X.0 ``` #### Pre-install warning only @@ -476,6 +493,8 @@ All messages include clear attribution language ("provided by the manifest autho Messages in locale manifests override those in the defaultLocale manifest on a per-field basis. If a locale manifest provides `UserMessages.PreInstall` but not `UserMessages.PostInstall`, the client falls back to the defaultLocale value for `PostInstall`. +Locale manifests may provide different message content per locale, following the existing localization model. Ensuring that translations are accurate and not misleading is the responsibility of the manifest author. A future enhancement to the validation infrastructure could automate checks for potentially misleading translations across locales. + ## Capabilities ### Accessibility @@ -506,23 +525,23 @@ Messages in locale manifests override those in the defaultLocale manifest on a p - **No breaking changes.** `InstallationNotes` is unchanged. Existing manifests and existing clients continue to work exactly as they do today. - **Older clients:** Ignore the `UserMessages` field (unknown fields are silently ignored in manifest parsing). They continue to display `InstallationNotes` if present. - **Newer clients:** Read `UserMessages` and prefer `UserMessages.PostInstall` over `InstallationNotes` when both are present. -- **Schema version:** The new schema version (e.g., 1.13.0) is required. Clients that cannot parse manifests at this schema version will receive manifests at the highest version they support from the source. In the winget-pkgs repository, manifests can exist at multiple schema versions to support this. +- **Schema version:** The new schema version must align with the client version at the time of implementation. Clients that cannot parse manifests at this schema version will receive manifests at the highest version they support from the source. In the winget-pkgs repository, manifests can exist at multiple schema versions to support this. - **Minimum client version:** Only clients at or above the version that implements this specification will process `UserMessages`. The exact version will be determined during implementation. ### Performance, Power, and Efficiency -- Negligible impact. The feature adds string parsing and display of up to six optional text fields. No network calls, no computation, no background processing. +- Negligible impact. The feature adds string parsing and display of up to eight optional text fields. No network calls, no computation, no background processing. - Pre-action prompts add user wait time in interactive mode only. ## Potential Issues 1. **Prompt fatigue.** If many packages include pre-action messages, users may develop "prompt blindness" and reflexively confirm without reading. Mitigation: the 2048-character limit keeps messages concise, and community review in winget-pkgs ensures messages are meaningful. -2. **Bulk operation noise.** `upgrade --all` with many packages containing pre-messages could be verbose and slow. A future enhancement to aggregate messages would address this, but is out of scope here. +2. **Bulk operation noise.** `upgrade --all` with many packages containing pre-messages could still be verbose even when those messages are presented together before execution. 3. **Transition-period duplication.** During the transition, manifest authors must duplicate their install note in both `InstallationNotes` and `UserMessages.PostInstall`. This is a known trade-off for backward compatibility and is temporary. -4. **Content moderation burden.** The winget-pkgs community reviewers now have six new fields to review per manifest. Automated tooling to flag suspicious content in these fields would reduce this burden. +4. **Content moderation burden.** The winget-pkgs community reviewers now have eight new fields to review per manifest. Automated tooling to flag suspicious content in these fields would reduce this burden. 5. **Locale fallback complexity.** Per-field fallback from locale to defaultLocale adds implementation complexity. However, this follows the existing pattern for all other localizable fields and is well-understood. @@ -548,7 +567,6 @@ The `UserMessages` object is designed to be extended. Potential future additions - **`PreDownload` / `PostDownload` ** — Message displayed before the package is downloaded, if different from pre-install. Also applies to `winget download` - **`Configuration`** — Message displayed when the package is processed as part of a WinGet Configuration. - **Structured message types** — Replacing plain strings with objects that include severity, category, or formatting hints. -- **Aggregate pre-message summary** — For bulk operations, presenting all pre-messages in a single summary before beginning the batch. - **Rich formatting** — Support for basic markdown or structured text in messages (requires careful consideration of terminal rendering). - **Group Policy controls** — Admin policies to enforce or suppress user messages across managed devices.