6 Commits
Author SHA1 Message Date
enricobuehler 4efc10dc90 Merge pull request 'plugin-kit 0.3.1 — the SQLite reader that made this plugin find nothing' (#2) from chore/plugin-kit-0.3.1 into main
CI / build (push) Successful in 22s
CI / publish (push) Successful in 19s
Reviewed-on: #2
v0.1.0
2026-08-06 19:05:27 +00:00
enricobuehler 4f9744db23 chore: plugin-kit 0.3.1 — the SQLite reader that made this plugin find nothing
CI / build (pull_request) Successful in 36s
CI / publish (pull_request) Skipped
The kit's `openReadOnly` built a `file:<path>?immutable=1` URI but opened it with
`{ readonly: true }`, which does not enable SQLite's URI filename parsing. On
Linux — Bun's bundled SQLite, unlike macOS's system one — that open always threw,
and every layer degrades an open failure to "this launcher isn't installed". So
this plugin reported 0 games on every box it has ever run on, while `detect`
happily said "present" (it only stats the file).

Nothing here was wrong; the parsing and the ids were right all along. Fixed in
punktfunk#78, published as plugin-kit 0.3.1.

The caret range already allowed it, but bun.lock pinned 0.3.0 exactly, so CI kept
testing against the broken reader.

Parity, run on .21 against a live host with the PUBLISHED 0.3.1 (not a patched
copy) — the gate that caught this in the first place:

    scan:   present: 1 games, 1 launcher entries   (was 0 games)
    parity: OK — 1 entries identical               (was: FAILED — 1 missing)

Gates: biome clean, tsc clean, 5/5 tests, bundle builds.
2026-08-06 20:28:54 +02:00
enricobuehler 0e89cc4c9d Merge pull request 'A tile that opens Lutris itself' (#1) from feat/launcher-tile into main
CI / build (push) Successful in 17s
CI / publish (push) Skipped
Reviewed-on: #1
2026-08-06 17:24:23 +00:00
enricobuehler bedf43214c feat: a tile that opens Lutris itself
CI / build (pull_request) Successful in 17s
CI / publish (pull_request) Skipped
`defineLibraryPlugin` has taken a `launchers()` hook since kit 0.3.0 — entries that
open the LAUNCHER rather than a title (design D4) — and nothing implemented it. The
host has resolved `launcher_ui` valued `"lutris"` since the same release. So the
whole path existed end to end with no producer at either end.

One entry, config-toggled and on by default: it is the one tile that lets someone
install or fix a game from the couch, and it costs a single card.

`launcher_ui` is valued by STORE ID, never a command: the host turns "lutris" into
the command that opens the window (D1). That is also the only shape available to a
plugin at all — the 2026-08-05 review made `launch.kind = "command"` operator-only,
so a plugin publishing one has its entire reconcile refused.

Deliberately art-less. Lutris ships a square app icon and every client cover-crops a
2:3 tile, so an icon would arrive as a cropped strip. The clients render an art-less
launcher entry on purpose — accent face, the launcher named — which reads as "opens
Lutris" rather than as a game whose poster failed to load.

`launcherEntries` is exported for the same reason `artFile` is: so the shape is
testable without standing up the whole plugin.

Gates: tsc --noEmit clean, 5 tests pass (2 new), biome clean.
Needs a host carrying the M2 wire (`role` + `launcher_ui`), which is on main.
2026-08-06 15:17:12 +02:00
enricobuehler 850154df5e chore: lock @punktfunk/plugin-kit@0.3.0
CI / build (push) Successful in 28s
CI / publish (push) Skipped
The kit is on the registry now, so the dependency resolves and CI's
`bun install --frozen-lockfile` has something to be frozen against.

Verified against the PUBLISHED package rather than the local file: link: tsc
clean, biome clean, 3 tests, bundle builds.
2026-08-05 19:29:00 +02:00
enricobuehler 554a884682 feat: the Lutris library source
CI / build (push) Failing after 13s
CI / publish (push) Skipped
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