minesweeper: extracted from the platform
Minesweeper X under wine on a headless display, as a plugin. It was /api/minesweeper, a Dashboard screen, an officerdev panel, a permission registry entry and a hand-written websocket provider in server.tsx. The socket is why it had to live in the platform: Bun's route table is fixed at serve(), so nothing installed later could add one. That ceiling is gone, and this is the first plugin through the per-plugin relay. Three things changed rather than moved: The sidecar owns the session. The platform used to spawn bin/session.sh detached, so the game outlived every restart, nothing supervised it, and a crashed run left wine processes holding the prefix — the next start hung rather than failed. PM2 supervises a sidecar, and stop() uses 'wineserver -k' scoped by WINEPREFIX instead of 'pkill -f wineserver', which would have killed every other wine prefix on the machine. x11vnc moved from 127.0.0.1:5907 to a unix socket in a mode-0700 directory. -nopw was only ever safe because of the machine, not the platform: any local account could open that port and take the display. A fixed port is squattable too. There is now no listener to authenticate against. The wine prefix is confined to C:. This is the one that mattered. The platform classified Minesweeper as kind:'execution' — never grantable — because a fresh prefix maps the whole filesystem to Z: and symlinks the profile into the owner's real home, and the game has Open and Save dialogs. A plugin permission has no kind and is always grantable, so extracting it without this would have converted a sealed capability into a file picker running as the owner. Re-asserted on every start, because wine restores z: whenever it updates a prefix. Not solved: one display and one game, so two grantees share a board. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { join } from 'node:path';
|
||||
import { mkdirSync } from 'node:fs';
|
||||
import { DATA_PATH } from '@@/data-path';
|
||||
|
||||
/**
|
||||
* Where the session's state lives, and why none of it is in the plugin's own directory.
|
||||
*
|
||||
* A plugin directory is a git checkout that `plugins:update` will `git pull` over and `plugins:delete` will
|
||||
* remove. The wine prefix is ~600 MB of generated state that takes minutes to rebuild — putting it there
|
||||
* would mean an update fights the working tree and a reinstall costs a fresh download of the VB6 runtime.
|
||||
*
|
||||
* So it goes under `DATA_PATH/minesweeper/`, the same convention music's cache uses. The game executable
|
||||
* DOES ship in the repository: it is 68 KB, it is the thing being run rather than state produced by running
|
||||
* it, and its checksum is in the README.
|
||||
*/
|
||||
export const STATE_DIR = join(DATA_PATH, 'minesweeper');
|
||||
|
||||
/** The wine prefix — a `win32` one, because the game is an i386 PE. Generated; never committed. */
|
||||
export const WINEPREFIX = join(STATE_DIR, 'prefix');
|
||||
|
||||
/**
|
||||
* Runtime scratch: pid files, logs, and the VNC socket.
|
||||
*
|
||||
* Created mode 0700 and that is load-bearing rather than tidy — it is the ONLY thing standing between
|
||||
* another local account and an unauthenticated VNC display. x11vnc runs with `-nopw`, which is correct
|
||||
* precisely because this directory refuses everyone but the owner. See `vnc.ts`.
|
||||
*/
|
||||
export const RUN_DIR = join(STATE_DIR, 'run');
|
||||
|
||||
/** x11vnc's listening socket. A path, not a port: unreachable without traversing RUN_DIR. */
|
||||
export const VNC_SOCKET = join(RUN_DIR, 'vnc.sock');
|
||||
|
||||
/** Ships with the plugin. `import.meta.dir` is `<plugin>/sidecar`. */
|
||||
export const GAME_EXE = join(import.meta.dir, '..', 'game', 'Minesweeper X.exe');
|
||||
|
||||
export function ensureDirs(): void {
|
||||
mkdirSync(STATE_DIR, { recursive: true, mode: 0o700 });
|
||||
mkdirSync(RUN_DIR, { recursive: true, mode: 0o700 });
|
||||
}
|
||||
Reference in New Issue
Block a user