feat: WinGet COM backend enrichment — richer details, dynamic sources, Repair, version badge#10
Merged
Conversation
…cation handoff Windows COM-backend verification run against WINDOWS-TESTING.md (paused mid-P1). P0 (foundational COM-on-AOT runtime): all 9 items PASS on a real ARM64 Windows host (x64 AOT, ~23.3 MB, no coreclr.dll). The AOT InvalidCastException risk does not occur in the app — the indexed Materialize<T> pattern holds across search/list/upgrades/show. Fixes applied (compile clean; runtime-verify on Windows still pending): - src/App.cs: DetailLoadDebounceMs=200 before uncached ShowAsync so fast list-scrolling no longer fires a COM detail fetch per row (was throttling/wedging the WinGet COM server and stalling the detail panel 30-60s). - src/App.cs: Source-column ColorGetter no longer overrides the selected-row foreground, fixing msstore rows rendering Accent-on-Accent (invisible) when highlighted. - spikes/ComBackendSpike/Program.cs: added a GetCatalogPackageMetadata field probe (Step 5) that proved the COM richer-detail data (Tags/SupportUrl/Documentations) IS present and readable via the indexed pattern from a single-catalog connect. Open: P1 #17 (richer detail panel) is a CONFIRMED BUG — Tags/Support/Documentation never render though the data exists; suspect is ShowAsync's composite-All catalog path. Root cause unconfirmed (needs a --comshow dump on Windows with a healthy COM server). Rest of P1 (install/version-picker/download/advanced/verify/progress/cancellation) and P2 are untested — all need COM. Full status, build instructions, repro, and resume plan in HANDOFF.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ve AOT Session 2 of the Windows verification uncovered the central result: the AOT build cannot activate the WinGet PackageManager COM class (0x80073D54 APPMODEL_ERROR_NO_PACKAGE), so SelectBackend silently falls back to the CLI backend (the stderr note is hidden by the TUI). Proven via the COM-only `V` action reporting "only available on the COM backend". - Same source built non-AOT (JIT, self-contained x64) activates COM fine (3 catalogs), even with the server warm — so it's AOT-specific, not server state, not apartment (MTA). - A clean AOT spike (no coreclr.dll) also fails — not app-vs-spike. - Did NOT fix: CsWinRT AOT optimizer; app.manifest supportedOS+longPathAware; warming server. - Caveat: an early-session AOT spike DID activate COM, so AOT-COM isn't categorically impossible — current failure may be entangled with COM-server state the diagnostic abuse + reboot left odd. Decisive next step: clean-reboot `--comdiag` as the first COM activity. Consequences recorded in WINDOWS-TESTING.md + HANDOFF.md: - P0 item 3 (default = COM) FAILS; most "P0 on COM" passes were actually the CLI backend. - #17 (missing Tags/Support/Docs) is a SYMPTOM of the CLI fallback, not a composite bug (that hypothesis withdrawn). All experimental changes (CsWinRT optimizer, app.manifest, --comshow/--comdiag diagnostics) reverted; tree carries only the committed debounce + contrast fixes. --comdiag snippet and the clean-reboot resume plan are in HANDOFF.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tracks the develop prerelease per the csproj policy. Picks up the 2.4.4-line render/input fixes for free: viewport-local NeedsDrawRect normalization, draw-pipeline narrowing for child-only redraws, WSL/Linux clipboard Unicode, Windows VT input encoding for IME/non-ASCII, and the AnsiOutput resize fix. All other packages (ComInterop, xunit, Test.Sdk) were already latest. Builds clean on both TFMs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… Repair Leverages more of the WinGet COM API surface and adds the Repair action. Detail panel enrichment: surface Author, Copyright, Privacy/Purchase links, Installation notes, and (for installed packages) Scope + Installed-to from CatalogPackageMetadata / PackageVersionInfo.GetMetadata. Each renders only when present. Dynamic sources: replace the hard-coded winget/msstore SourceFilter enum with string-based source names discovered via PackageManager.GetPackageCatalogs() (COM) / 'winget source list' (CLI). The f filter now cycles through all configured sources, so custom/enterprise REST sources are filterable. 'All' now expands to every configured source. Backend badge: IBackend.DescribeAsync surfaces the live backend + winget version (PackageManager.Version) in a header badge and the help dialog — a quick tell of whether the AOT build activated COM or fell back to CLI. Search match hint: annotate non-obvious search matches (tag/moniker/command/etc.) via MatchResult.MatchCriteria with a dim 'matched on …' footnote. Search cap: bound COM search at 1000 via FindPackagesOptions.ResultLimit and nudge the user to refine when hit. Repair (COM-only, like Verify): new R action and a Verify->Repair offer, backed by PackageManager.RepairPackageAsync. Reuses the existing operation/progress plumbing (Esc-cancel, one-op gate, progress bar). CLI reports it unavailable; the mock synthesizes it for Linux dev. Design spec under docs/superpowers/specs. Both TFMs build with 0 warnings; 95 tests pass (incl. new source-list parser and repair tests). COM-only paths captured in WINDOWS-TESTING.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-state messages
- Click a Name/Id/Version column header to sort by it (ascending);
click the active column again to reverse. Marker/Available/Source
headers are no-ops. Keyboard 'S' cycling is unchanged. Implemented
via a SortableTableView that reports header clicks through ScreenToCell.
- Upgrading a row whose id winget truncated with '…' no longer blocks:
AskUpgrade now confirms and hands the backend the package name, which
the CLI backend resolves via '--name --exact'. Other operations keep
the truncated-id guard.
- Empty package list now shows a contextual reason ("All packages are up
to date\!", "No unpinned packages with upgrades found.", a local-filter
note, etc.) instead of a bare header.
Adds unit tests for UpgradeQueryFor, EmptyStateMessage, and
SortFieldForHeader; logs the interactive/real-winget verification steps
to WINDOWS-TESTING.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR extends the WinGet backend abstraction to surface richer package details and operational capabilities, while improving UI behavior and diagnostics around which backend (COM/CLI/Mock) is currently active.
Changes:
- Enriches the COM backend (more detail metadata, match-hint, result cap, Repair operation) and expands
IBackendwith dynamic sources + backend description. - Updates the UI to support click-to-sort headers, contextual empty-state messaging, backend/version badge, and debounced detail loading.
- Refactors source filtering from a fixed enum to dynamic source names discovered at runtime (COM + CLI), with corresponding unit tests.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| WingetTuiSharp.csproj | Bumps Terminal.Gui dependency version. |
| WINDOWS-TESTING.md | Updates Windows manual verification checklist and documents AOT/COM activation finding. |
| tests/ParserTests.cs | Updates source-filter arg tests and adds CLI source-list parsing tests. |
| tests/AppBehaviorTests.cs | Adds tests for truncated-id upgrade query, empty-state messaging, header sort mapping, and mock repair. |
| src/Ui.cs | Moves source filter to string? and adds backend line to help dialog. |
| src/Models.cs | Removes SourceFilter enum; adds match-field + enriched detail fields; adds Repair operation/phase. |
| src/MockBackend.cs | Adapts to string source filters; adds ListSources, Repair, and Describe. |
| src/DetailPanel.cs | Renders new metadata fields, match hint, installation notes, and Repair action. |
| src/ComBackend.cs | Adds search cap, match-field extraction, enriched metadata, dynamic sources, Repair, and Describe. |
| src/CliBackend.cs | Adapts to string source filters; adds ListSources, ParseSourceNames, Repair unavailable, and Describe. |
| src/Backend.cs | Extends IBackend with dynamic sources, Repair capability, and backend description. |
| src/AppState.cs | Adds dynamic source list and cycling; adds search result limit constant; stores backend description. |
| src/App.cs | Adds backend badge, loads sources at startup, debounces detail loading, click-to-sort, empty-state message row, upgrade truncated-id fallback, and Verify→Repair flow. |
| spikes/ComBackendSpike/Program.cs | Extends spike diagnostic probing for richer metadata field access. |
| HANDOFF.md | Adds detailed Windows verification handoff notes and AOT/COM activation findings. |
| docs/superpowers/specs/2026-06-12-repair-feature-design.md | Adds Repair feature design spec. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+437
to
443
| // Render a single message row explaining *why* the list is empty, instead of a bare | ||
| // headered table. The message is contextual: "All packages are up to date!" vs. a | ||
| // filter/pin-specific note. Mirrors upstream winget-tui's empty-state messages (#228). | ||
| _packageTable.Table = new EnumerableTableSource<string> ([EmptyStateMessage (_state)], new () | ||
| { | ||
| { _state.Mode == AppMode.Upgrades ? "Name" : "Name", _ => string.Empty } | ||
| { " ", message => message } | ||
| }); |
Comment on lines
+121
to
+123
| - [ ] On a stock machine, `f` still cycles **All → Winget → MsStore → All** (the discovered list matches the two predefined sources). | ||
| - [ ] **Add a custom source** (`winget source add -n contoso <url>`), relaunch, and confirm `f` now includes **contoso** in the cycle and filtering to it scopes the list/search to that source. (This is the whole point of going dynamic — verify it on both COM and `--cli`.) | ||
| - [ ] With a source selected that no longer exists (remove it while the app holds it selected, then refresh), the filter resets to **All** rather than erroring. |
Comment on lines
+77
to
+80
| // Cap a pathologically broad query (e.g. a one-letter term) so it can't materialize tens | ||
| // of thousands of rows. The app already blocks empty queries; this guards the merely-broad | ||
| // ones. result.WasLimitExceeded below tells the UI to nudge the user to refine. | ||
| opts.ResultLimit = AppState.SearchResultLimit; |
Comment on lines
+388
to
+393
| // A search that hit the result cap means there's more the user can't see; | ||
| // nudge them to narrow it (only the COM backend actually caps). | ||
| if (mode == AppMode.Search && packages.Count >= AppState.SearchResultLimit) | ||
| { | ||
| _state.StatusMessage = $"{AppState.SearchResultLimit}+ matches — refine your search to narrow"; | ||
| } |
Comment on lines
+597
to
+599
| AppMode.Search => string.IsNullOrEmpty (state.SearchQuery) | ||
| ? "Type to search for packages." | ||
| : "No packages found.", |
harder
added a commit
that referenced
this pull request
Jun 13, 2026
…OM tell The COM backend work merged to main (PR #10), so the checklist no longer references a feature branch. Elevate the top-right backend badge (COM/CLI/Mock, from PackageManager.Version) to the primary COM-vs-CLI tell, and turn the default-backend P0 item into a re-check against the badge on a freshly-pulled main build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Builds on the initial WinGet COM backend (merged in #7) to cover more of the COM API surface, add the Repair operation, make source filtering dynamic, and surface which backend is actually live. It also folds in a full Windows verification pass — whose headline result is a confirmed finding (below) — plus a few UI parity/quality fixes.
Both target frameworks (
net10.0,net10.0-windows10.0.26100.0) build with 0 warnings; the test suite is green (109 tests).🚨 Headline finding — COM does not activate under Native AOT
Verification on a real Windows host showed the Native-AOT build cannot activate the WinGet
PackageManagerCOM class (0x80073D54 APPMODEL_ERROR_NO_PACKAGE).SelectBackendcatches it and silently falls back to the CLI backend (the stderr note is painted over by the TUI), so the default AOT launch is effectively CLI-backed.app.manifestwithsupportedOS+longPathAware, or warming the server first.--comdiagas the first COM activity) and the full resume plan are inHANDOFF.md.Consequence: items previously believed "verified on COM" were largely exercising the CLI path (which also returns structured data). The richer-detail gap (#17) is a symptom of the CLI fallback, not a separate bug. This PR documents the finding rather than working around it.
COM backend enrichment
CatalogPackageMetadata/PackageVersionInfo.GetMetadata. Each field renders only when present, so sparse packages stay clean.winget/msstoreenum with source names discovered viaPackageManager.GetPackageCatalogs()(COM) /winget source list(CLI). Theffilter now cycles every configured source — custom/enterprise REST sources included — and All expands to all of them.IBackend.DescribeAsyncshows the live backend and winget version (PackageManager.Version) in a header badge and the help dialog: a quick tell of whether AOT activated COM or fell back to CLI.MatchResult.MatchCriteriaget a dim "matched on …" footnote.FindPackagesOptions.ResultLimit, with a nudge to refine when hit.Repair operation (COM-only)
Raction and a Verify → Repair offer, backed byPackageManager.RepairPackageAsync. Reuses the existing operation/progress plumbing (Esc-cancel, single-op gate, progress bar). CLI reports it unavailable; the mock synthesizes it for Linux dev. Design spec indocs/superpowers/specs/.COM stability/perf fixes
ShowAsync, so fast list-scrolling no longer fires a COM detail fetch per row — that was throttling/wedging the out-of-proc COM server and stalling the detail panel for 30–60 s.UI parity & quality
Scycling unchanged.…no longer blocks; it confirms and resolves the package by exact name (--name --exact). Other operations keep the truncated-id guard.Dependencies
2.4.7-develop.1, picking up the 2.4.4-line render/input fixes (viewport-local redraw narrowing, WSL/Linux clipboard Unicode, Windows VT input for IME/non-ASCII, AnsiOutput resize).Testing
WINDOWS-TESTING.mdwith repro steps, and session state/resume plan inHANDOFF.md.🤖 Generated with Claude Code