A vibe-coded siimple and naive utility made to save me from messing with some of the Winget CLI commands, with the UI inspired by Endfield.
For full support of Winget and other Windows package managers, check UniGetUI.
A small desktop front end for winget
on Windows, written in Rust with Slint.
See what can be upgraded, tick the packages you want, and run the upgrade in a real terminal window. Hold packages back with winget's own pins.
Upgrades — lists everything winget upgrade reports, with the installed and
available versions side by side. Filter by name or identifier, tick what you
want, and press Upgrade.
The upgrade runs as a single winget upgrade command with every selected
identifier passed positionally, in a new terminal window hosted by whatever
you have set as your default terminal application:
winget upgrade Comfy.ComfyUI-Desktop Rustlang.Rustup --exact --include-unknown
It is deliberately not silent, and deliberately does not pass
--accept-package-agreements. Installer UI, licence prompts and elevation all
appear in front of you rather than being answered on your behalf. The window
stays open when the run finishes so failures are readable. The exact command is
shown in the app before you press the button.
While it runs, the list goes read-only — refresh, the upgrade button, the tick boxes and every pin button are disabled, and the header rule shows an activity strip. That is not only cosmetic: winget serialises, so a pin issued during an install would block on winget's own lock and look like a hang.
The app does not merely fire and forget. The batch file writes winget's exit code
to a sentinel file before it pauses, so "winget finished" and "you dismissed the
window" stay separate events — the app unlocks and rescans the moment winget is
done, while the terminal stays open for you to read. If the window is closed
early instead, the child process ending is the fallback signal. Per-package
progress is not available: one winget upgrade invocation reports as a whole.
Pins — pin a package to hold it back, in either of winget's two modes:
| Mode | Effect | Command |
|---|---|---|
| Pinning | Held back from bulk upgrades; a direct upgrade still works | winget pin add --id <id> --exact |
| Blocking | Refuses every upgrade until the pin is removed | winget pin add --id <id> --exact --blocking |
A pinned package leaves the upgrade list immediately, because winget upgrade
already excludes both pin types unless --include-pinned is passed — there is no
client-side filter that could drift out of sync with winget's own view. Removing
a pin puts the package back.
Winget's third pin type, Gating (--version 1.2.*), is displayed if a pin
like that already exists, but tinyget does not offer it as a choice.
Needs a Rust toolchain and Windows 10 1709 or newer (for winget itself, and for the Bahnschrift font).
cargo build --release # target/release/tinyget.exe
cargo run # debug build, keeps a console for logging
cargo test # parser tests, no winget calls
winget upgrade and winget pin list have no machine-readable output, so both
are read back from the aligned text table. Three things matter, and all three are
covered by tests in src/winget.rs:
- Output is UTF-8 even when redirected, which is what makes this workable.
- The table is aligned by display width, not character count — a CJK glyph
occupies two cells — so rows are cut with
unicode-width. - Column headers are localized. The header is found relative to the
-----rule rather than by matching names. Where a localized header label contains a space (EnglishPin type), header-based column detection would see an extra column, so parsing falls back to splitting from the right: only the leftmost field, the package name, can contain spaces.
Rows are validated by their identifier column, which keeps trailing summary lines ("7 upgrades available.") out of the results — winget prints them directly under the table with no blank line between.
Pin-type values (Pinning / Blocking / Gating) are English in every locale,
so they are safe to match on.