marketplace: minesweeper in the catalogue

Without an entry the plugin is invisible to every server but this one — the
catalogue is what a remote host reads, and the bundled constant is only the
fallback when marketplace.officer.dev cannot be reached.

Its git remote was the tailnet address, which marketplace-sync would have
published verbatim: a clone URL that works on this network and nowhere else,
failing at authentication in a way that reads as a broken plugin rather than a
wrong catalogue. Repointed at gitea.officer.dev, which is the rule the sync
script's own comment already spells out.

Synced. 18/18, and the entry is live with the right source, permissions and six
osDependencies; the repo answers an anonymous https clone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
2026-08-23 18:07:50 +00:00
co-authored by Claude Opus 5
parent 1ff271bb5e
commit 6e092c32ea
10 changed files with 196 additions and 115 deletions
+69
View File
@@ -241,6 +241,75 @@ const BUNDLED: CatalogueEntry[] = [
// No db/ — the mirror keeps nothing. The password lives in the owner's ~/.vnc, written by the sidecar.
has: { api: true, schema: false, sidecar: true, web: true },
},
{
appName: 'minesweeper',
publisher: 'officerdev',
version: '1.0.0',
platform: '>=1.0.0',
label: 'Minesweeper',
summary: 'Minesweeper X under wine, on a headless display, streamed to the browser',
color: '#64748b',
icon: 'Bomb',
source: 'https://gitea.officer.dev/plugins/minesweeper.git',
permissions: [
{
key: 'minesweeper',
label: 'Minesweeper',
description:
'Play Minesweeper on the server display. The game is confined to its own wine prefix and can reach nothing else on the machine.',
},
],
// Six binaries, and this is the entry where the duplication above earns its keep: the owner sees what
// installing this will make the machine acquire BEFORE consenting, and for wine that is not a small ask.
//
// `apt: 'wine'` is deliberately not the whole story and cannot be. The game is a 32-bit VB6 executable,
// so the host also needs `dpkg --add-architecture i386` and `wine32:i386` — a system-wide change that no
// package name can express, which is why the reason carries the command instead of pretending.
//
// Xvfb has no dnf entry because Fedora spells it `xorg-x11-server-Xvfb`, with a capital X, and a
// manifest package name must be lowercase. Absent means "cannot be installed automatically here", which
// becomes an instruction rather than a wrong guess.
osDependencies: [
{
binary: 'wine',
reason:
'Runs the game. Minesweeper X is a 32-bit Windows executable, so this host also needs i386 multiarch (`dpkg --add-architecture i386`) and the 32-bit wine package — a 64-bit-only wine cannot load it.',
packages: { apt: 'wine', dnf: 'wine', pacman: 'wine', brew: 'wine-stable' },
},
{
binary: 'Xvfb',
reason:
'The virtual display the game draws on. A framebuffer with no hardware behind it, so nothing appears on any real monitor.',
packages: { apt: 'xvfb', pacman: 'xorg-server-xvfb' },
},
{
binary: 'x11vnc',
reason:
'Reads that display and serves it, so the browser has something to draw. Bound to a private unix socket, never a port.',
packages: { apt: 'x11vnc', dnf: 'x11vnc', pacman: 'x11vnc' },
},
{
binary: 'xdotool',
reason:
'Finds the game window and reads its size, so the panel can fit its canvas to the board instead of the whole framebuffer.',
packages: { apt: 'xdotool', dnf: 'xdotool', pacman: 'xdotool' },
},
{
binary: 'xdpyinfo',
reason:
'Waits for the display to be usable. A live Xvfb process is not the same as a display that answers, and starting the game too early fails silently.',
packages: { apt: 'x11-utils', dnf: 'xorg-x11-utils', pacman: 'xorg-xdpyinfo' },
},
{
binary: 'winetricks',
reason:
'Installs the Visual Basic 6 runtime into the wine prefix on first start. Minesweeper X needs MSVBVM60.DLL, which wine does not ship; without it the process exits immediately with nothing but an unresolved-import line.',
packages: { apt: 'winetricks', dnf: 'winetricks', pacman: 'winetricks' },
},
],
// No schema. The session is processes and a wine prefix on disk, and none of that belongs in Postgres.
has: { api: true, schema: false, sidecar: true, web: true },
},
{
appName: 'jellyfin',
publisher: 'officerdev',