Files
minesweeper/README.md
T
pastilhasandClaude Opus 5 b8a4f56c7c fold in the provenance from the standalone build
wine-minesweeper/ was where this was built before it was a plugin, and it is
about to be deleted — it has no git remote, so its history lives on one machine
and nowhere else. Two things in it are still true and not captured here.

Why wine comes from Ubuntu rather than WineHQ: the distro package is older and
sufficient, and the alternative is a third-party apt source on a machine running
a wallet and a mail store, for a game. And that enabling i386 pulled four krb5
libraries forward, checked before installing rather than after — the one step
here that changes how the whole machine resolves packages, and one that
uninstalling the plugin never undoes.

Also the original verification baseline, which is useful for comparison when
something feels wrong: the board is 152x214, a synthetic click really does reach
the game, RFB 003.008, and cold start under two seconds excluding the prefix.

The shell prototype is not kept. What it knew is in sidecar/session.ts next to
the code that depends on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
2026-08-23 20:33:02 +00:00

99 lines
5.1 KiB
Markdown

# Minesweeper
Minesweeper X, running under wine on a headless X display, streamed into an Officer panel.
It is a game. It is also the smallest honest proof that Officer can put an arbitrary X11 program in a
panel — a framebuffer, a process on it, a VNC server reading it, a client in the browser — and it is the
first plugin to use the platform's per-plugin websocket relay.
## What it needs
Six host binaries, declared in `manifest.ts` and checked before install: `wine`, `Xvfb`, `x11vnc`,
`xdotool`, `xdpyinfo`, `winetricks`.
The awkward one is wine. Minesweeper X is a **32-bit** PE (machine `0x014c`, Visual Basic 6), so the host
needs i386 multiarch and a `win32` prefix. A 64-bit-only wine cannot load it, and the failure is a bare
`Bad EXE format`. On Debian or Ubuntu:
```
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install wine wine32:i386 xvfb x11vnc x11-utils xdotool winetricks
```
## The game
[Minesweeper X](https://minesweepergame.com/download/minesweeper-x.zip) — the competition build, with
timing and replay extras. `game/Minesweeper X.exe` is committed; it is 68 KB and it is the thing being
run rather than state produced by running it.
| | |
| --- | --- |
| zip sha256 | `21089193924919ef876a5b464f06bed9cc149867c51e40c259288ebe623014f0` |
| exe sha256 | `e414c207adaa14999b0464c3d0a701f20ed11282d5ed0f84b27b62d25389f661` |
The download needs a browser `User-Agent`; the site answers `403` to curl's default.
## Where its state lives
`DATA_PATH/minesweeper/` — never in this directory, which `plugins:update` will `git pull` over.
- `prefix/` — the wine prefix, ~600 MB, built on first `POST /start`. Deleting it is the standard fix for
a wedged wine, and it is safe: the next start rebuilds it.
- `run/` — pid state, logs, and `vnc.sock`. **Mode 0700, and that is load-bearing.**
## Two things worth knowing before you change anything
**x11vnc has no password, and that is correct.** It binds a unix socket inside `run/`, not a port. The
kernel refuses every other account before x11vnc is asked anything, so a password would be a second lock
on a door only one person can reach. The version this replaced bound `127.0.0.1:5907` with `-nopw`, which
is a different claim entirely — every local account could open it and take the display.
**The wine prefix is confined to `C:` on every start.** A fresh prefix maps the whole filesystem to `Z:`
and symlinks the profile into the real home, and Minesweeper X has Open and Save dialogs for its replays.
That is why this was an ungrantable `execution` capability in the platform. `sidecar/prefix.ts` closes it
instead, which is what makes the plugin's permission safe to grant. Wine restores `z:` whenever it updates
a prefix, so the confinement is re-asserted rather than done once.
## Contract
```
GET /api/minesweeper/status { installed, running, window, error? }
POST /api/minesweeper/start idempotent; builds the prefix on a cold install (minutes)
POST /api/minesweeper/stop
/api/plugin-ws/minesweeper the display, as RFB
```
## Where this came from
Built first as a standalone directory, `officer-dev/wine-minesweeper`, and folded in here when it became a
plugin. Two things from that work are worth keeping, because both are judgement calls somebody will
otherwise make again from scratch.
**Wine came from Ubuntu noble, not the WineHQ repository.** The distribution package is older — 9.0 — and
that is fine for a 2017 VB6 application. The alternative was adding a third-party apt source, with its key
and its update cadence, to a machine that runs a bitcoin wallet and a mail store, for a game of Minesweeper.
If a future version genuinely needs newer wine, that trade is worth revisiting; until then it is not.
**Enabling i386 pulled four krb5 libraries forward** within noble-updates. That was checked before
installing rather than after: nothing moved near libc, systemd, openssl or postgres. Worth re-checking on
any host where `dpkg --add-architecture i386` is new, since it is the one step here that changes how the
whole machine resolves packages and is never undone by uninstalling the plugin.
### The original verification baseline
From the standalone build, on Ubuntu noble with wine 9.0. Useful as a comparison when something feels wrong
rather than as a test to run:
- The game launches in about a second and draws the classic beginner board at **152x214**.
- A synthetic `xdotool` click opens a region and starts the timer — so **input reaches the game**, which is
the part that matters for a playable stream and the part a screenshot cannot tell you.
- x11vnc completes an **RFB 003.008** handshake and reports an 800x600 32bpp framebuffer.
- Cold start, display through to game window, in under two seconds. That excludes building the prefix,
which happens once and takes minutes.
The shell prototype that ran all this (`bin/session.sh`) is not kept. Everything it knew — waiting for a
usable display rather than a live pid, parking the window at the origin, and clearing the whole wine
process family on stop — is in `sidecar/session.ts`, with the reasoning attached to the code that depends
on it.