Public: anyone can read this; the crew can change it.
The terminal, under test: src/tty.ts split so every screen is a pure function of state #57
Check · Review · Land · Live done — Landed and live in production.
`src/tty.ts` now splits along the line it already had: `screen(state)` builds a frame as a pure function — the loop's state, the actions' data and the forge's environment in, the lines of the screen out, with no database, no `process.stdout`, no `process.env` and no clock — and `run()` is the loop around it, guarded by `import.meta.main` so importing the module does not start a terminal. `src/tty.…
shipped production is serving it deploy 6ecafc0
Sign in to join this conversation.
new above
offline
src/tty.tsnow splits along the line it already had:screen(state)builds a frame as a pure function — the loop's state, the actions' data and the forge's environment in, the lines of the screen out, with no database, noprocess.stdout, noprocess.envand no clock — andrun()is the loop around it, guarded byimport.meta.mainso importing the module does not start a terminal.src/tty.test.tsis new: sixteen tests over the empty lobby as player and as guest, one open table, a table you are seated at, a full one, the key legend for each, the charge shown only at your own seat, the status line after a named refusal, the name-a-table prompt, cursor clamping and the frame itself. Escape sequences live in one named block at the top with aplain()that strips them, so the tests assert the words a person reads.Three things fell out of the split, and are the parts worth reading: the selected table's seats now come from the row
listTablesalready returned (redacted for its viewer) instead of a secondtableStateread — same text, one query fewer; the legend is data (keys(who, table)— a key, what it does, whether it writes) rendered to the same line as before, so the guest test asserts "no key that writes" against the rules rather than against a string; and pressingoas a guest now asksopenTableand prints its refusal, so the sentence "Sign in to open a table." is the action's, not the terminal's.Two outputs change deliberately. With
FORGE_APP_SSHunset the header saysthe terminal is off: FORGE_APP_SSH is not setinstead of printing a blank line (set, it is still printed verbatim and never guessed), and every value drawn from data — title, host name, player name, the command — has control characters stripped, so a name in the database cannot move the cursor. Everything else is byte-identical; I diffed the real frames before and after against a seeded database, as guest and as player. I did not touch what the keys do: #14 builds on these tests.bun testis green, 98 tests. To try it:FORGE_APP_DATA=./data bun run src/tty.ts, or open the preview's terminal with the command inFORGE_APP_SSH.🤖 Generated with Claude Code
Closes #41