Files
enricobuehler 554a884682
CI / build (push) Failing after 13s
CI / publish (push) Skipped
feat: the Lutris library source
The pilot of design/library-scanner-plugins.md M5 — the host's in-tree Lutris
scanner, lifted out into its own installable plugin.

The whole package is a config schema, a detect, a scan and a watchDirs. The
store claim, sync engine, __config surface, console registration and the
detect/scan/parity/uninstall CLI verbs all come from
@punktfunk/plugin-kit/library. That is the point of the framework, and the
reason one repo per plugin costs nothing in duplication.

Claiming the `lutris` store means these entries keep exactly the ids the built-in
scanner gave them, so Moonlight pins, cached art and the operator's
enabled/disabled state all survive the migration — and the host suppresses its
own scanner while this is installed.

Two deliberate departures from the Rust original, both documented inline:

  * art is emitted as file:// URLs rather than inlined data: URLs. The host
    proxies the bytes, so the reconcile payload stays small — inlining covers is
    what blew the 2 MB body limit at 49 titles during the playnite work, and is
    exactly why the POSIX art path was added to the host.
  * the untrusted-slug guard is carried over verbatim and tested. The slug comes
    from Lutris's own database and is interpolated into a path whose bytes the
    host's art proxy will serve to any paired client, so an escape there is an
    arbitrary-file-read primitive rather than a cosmetic bug.

effect is pinned to 4.0.0-beta.99 exact, matching what the kit is built against.
The floating ^4.0.0-beta.102 the older plugin repos carry produced two
structurally-incompatible copies of the Schema types and would not compile.

Verified locally against the kit: tsc clean, biome clean, 3 tests, bundle builds,
and the CLI runs (`detect` -> absent, `scan` -> 0 games, usage lists all four
verbs).

Not yet green in CI, and it cannot be until @punktfunk/plugin-kit@0.3.0 is
published — the dependency does not resolve from the registry yet, which is also
why there is no lockfile in this commit. Publish the kit, run one bun install,
commit the lock.

The release gate is `punktfunk-plugin-lutris parity --snapshot` / `--compare` on
a box that actually has Lutris installed. That has NOT been run.
2026-08-05 19:09:01 +02:00

2.8 KiB

@punktfunk/plugin-lutris

Adds your installed Lutris games to a Punktfunk host's library — with their cover art, and with the session ending when you quit the game.

Install it from the host's plugin store (Library → Game sources → Add a source), or:

punktfunk-host plugins add lutris

Nothing to configure: it finds pga.db in the usual places (XDG data dir, ~/.local/share/lutris, Flatpak) and syncs from there. If yours lives somewhere else, set the path in Library → Game sources → Lutris → Settings.

What it replaces

Punktfunk used to scan Lutris from inside the host. This plugin is that scanner, lifted out — so you install it only if you use Lutris, and it can be updated without updating the host.

It claims the lutris store, which means your games keep exactly the ids they had before: Moonlight pins, cached box art, and your enabled/disabled state all carry over, and the host's built-in scanner switches itself off while this is installed. Remove the plugin and the built-in comes straight back.

Commands

punktfunk-plugin-lutris detect            # is Lutris installed on this host?
punktfunk-plugin-lutris scan --preview    # what WOULD be synced, as JSON (works with no host)
punktfunk-plugin-lutris uninstall         # drop the games and release the store claim

Parity — the release gate

Unit tests pin the parsing. What actually has to hold is that this plugin reproduces the in-host scanner it replaces, down to the ids — a plugin that parses perfectly but emits lutris:12.0 instead of lutris:12 breaks every Moonlight pin on the host, and no unit test notices.

So, on a box with Lutris installed, before installing this plugin:

punktfunk-plugin-lutris parity --snapshot before.json   # host still on its built-in scanner
punktfunk-plugin-lutris parity --compare  before.json   # offline; exits non-zero on any difference

--compare runs this plugin's own scan and diffs it: ids, titles, launch recipes, roles and metadata exactly; art by presence, not value — the representation legitimately changes here (the host's scanner inlined covers as data: URLs, this emits file:// paths the host proxies), so spot-check a few covers by eye once.

Do not publish a version whose parity run is red.

Development

bun install
bun run typecheck && bun test && bun run build

The framework — store claim, sync engine, __config, CLI verbs, and the launcher-file parsers — lives in @punktfunk/plugin-kit/library. This package is the Lutris-specific part: find pga.db, read it, map rows to entries. That is the whole design — see design/library-scanner-plugins.md in the main repo.

License

MIT OR Apache-2.0.