Files
punktfunk-plugin-heroic/README.md
T
enricobuehler 5fb6946aa1
CI / build (push) Failing after 15s
CI / publish (push) Skipped
feat: the Heroic library source
The host's in-tree Heroic scanner, lifted out into its own installable plugin
(design/library-scanner-plugins.md M5/WP5.2). One source covers all three of
Heroic's backends — legendary (Epic), gog, nile (Amazon) — because that is how
Heroic presents them and how the built-in scanner did.

The 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.

Claiming the `heroic` store keeps the entry ids the built-in scanner produced
(`heroic:<runner>:<appName>`), so GameStream app ids, Moonlight pins, cached art
and the operator's enabled/disabled state all survive the migration.

Ported behaviours worth naming, each covered by a test:

  * a title counts as installed only if Heroic says so AND its install directory
    still exists. The second check is the workaround for Heroic's GOG
    is_installed bug (#2691), without which uninstalled games linger.
  * only http(s) art is emitted. A sideloaded title can carry a local file://
    path, which — unlike a path this plugin resolved itself — is not one the host
    should proxy, and the client cannot fetch either. It degrades to the title
    card, as in-host.
  * both detect signals ride along: the install dir and the HEROIC_APP_NAME env
    marker. Heroic hands off to legendary/gogdl/nile, so the host never sees the
    game's own process any other way, and the env marker is what works under
    Proton (verified on-glass 2026-07-27). They are a union, so a Heroic version
    that stops setting it degrades rather than breaking.

The launch VALUE and the `heroic` launch kind are unchanged — the host still owns
turning `<runner>:<appName>` into a heroic://launch command, so this plugin never
constructs a command line.

Verified locally against the kit: tsc clean, biome clean, 5 tests, bundle builds,
CLI runs (detect -> absent, scan -> 0 games).

As with lutris: no lockfile and CI cannot be green until
@punktfunk/plugin-kit@0.3.0 is published. The parity gate has NOT been run — that
needs a box with Heroic installed.
2026-08-05 19:17:02 +02:00

3.4 KiB

@punktfunk/plugin-heroic

Adds your installed Heroic Games Launcher titles to a Punktfunk host's library — Epic, GOG and Amazon in one source, 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 heroic

Nothing to configure: it finds Heroic's config folder in the usual places ($XDG_CONFIG_HOME/heroic, ~/.config/heroic, Flatpak) and reads the library caches from there. If yours lives somewhere else, set the path in Library → Game sources → Heroic → Settings.

What it replaces

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

It claims the heroic store, which means your games keep exactly the ids they had before (heroic:legendary:<appName>): 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.

What gets listed

Only titles Heroic reports as installed and whose install directory still exists — the second check works around Heroic's GOG is_installed bug (#2691), which otherwise leaves uninstalled games sitting in your library.

Art comes straight from Heroic's cached CDN URLs, so the client fetches it directly. A sideloaded title whose art is a local file:// path is listed without art rather than with a picture nothing can load.

Commands

punktfunk-plugin-heroic detect            # is Heroic installed on this host?
punktfunk-plugin-heroic scan --preview    # what WOULD be synced, as JSON (works with no host)
punktfunk-plugin-heroic 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 — one that parses perfectly but emits a subtly different external_id breaks every Moonlight pin on the host, and no unit test notices.

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

punktfunk-plugin-heroic parity --snapshot before.json   # host still on its built-in scanner
punktfunk-plugin-heroic 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.

Worth re-checking on-glass specifically: a game launched under Proton. Heroic hands off to legendary/gogdl/nile, so the HEROIC_APP_NAME environment marker is what lets the host recognise the running game and end the session when you quit it.

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 Heroic-specific part: find the config root, read the three store_cache libraries, map entries. See design/library-scanner-plugins.md in the main repo.

License

MIT OR Apache-2.0.