Ported from the host's in-tree scanner (crates/punktfunk-host/src/library/xbox.rs), with
one deliberate change — and that change is the whole reason this plugin uses a different
launch kind from the scanner it replaces.
The scanner resolved each package's PackageFamilyName by enumerating
%ProgramData%\Microsoft\Windows\AppRepository\Packages. Measured on hardware 2026-08-06
(design doc S1): that directory is UnauthorizedAccessException for NT AUTHORITY\LocalService
— the principal the plugin runner runs as — while the host service, which runs as
LocalSystem, reads all 348 entries.
So this plugin does not resolve the PFN at all. It emits `<Identity>!<AppId>` under the new
`xbox` launch kind — both read straight out of MicrosoftGame.config, which IS readable
de-privileged — and the host completes the AUMID at launch time. D1 holds: the plugin
supplies a validated value, the host builds the command. It also beats caching a PFN at
install time, because a package update that changes the publisher hash cannot leave a stale
unlaunchable tile behind.
Carried over from the Rust scanner, because the parity gate compares exactly these:
* `<drive>:\XboxGames` on C–Z, with Content\MicrosoftGame.config as the GAME marker (so
this lists games, not ordinary UWP apps). A custom .GamingRoot folder is still not
covered — the new `roots` config field is the escape hatch — and pure-UWP Store games
under the ACL-locked WindowsApps are missed the same way they always were.
* The title's three-step fallback: ShellVisuals@DefaultDisplayName, but only when it is
not an unresolved `ms-resource:` reference, else the install folder name, else the
package name.
* Entries keyed by StoreId when present. Where the host then fell back to the PFN, this
falls back to the Identity — the thing it can actually read — and both are stable per
package, so ids stay stable across syncs.
* The manifest read is size-capped: a planted multi-GB MicrosoftGame.config must not OOM
us during enumeration (security-review 2026-07-17).
Two parser traps worth knowing, both pinned by tests: fast-xml-parser collapses a single
<Executable> child to an object rather than an array, and coerces a digits-only <StoreId> to
a number.
Art is NOT emitted: Xbox covers come from the unofficial displaycatalog keyed by StoreId,
which the host's background warmer already resolves and caches by entry id. This plugin
makes no network calls at all.
No launcher tile yet: the host has no verified `launcher_ui` activation for the Xbox app, so
one would be refused with a 400. The config switch is present and off.
Gates: tsc --noEmit clean, 7 tests pass, biome clean.
Requires the host-side `xbox` launch kind (punktfunk PR #70's follow-up).
Still owed: `parity --compare` on a Windows box with GDK titles installed, under the runner.
5 lines
216 B
TOML
5 lines
216 B
TOML
# Resolve the @punktfunk scope from the Gitea npm registry for the whole workspace.
|
|
[install.scopes]
|
|
"@punktfunk" = "https://git.unom.io/api/packages/unom/npm/"
|
|
"@unom" = "https://git.unom.io/api/packages/unom/npm/"
|