Intent. Finish the split #57 started, so the half of the terminal a person actually presses is tested before #78 adds three more keys to it.
Measured on main today (63a4041): bun test --coverage reports src/tty.ts at 53.07% of lines, uncovered 208–291 — which is exactly run(): the keyboard in raw mode, the key-to-action dispatch, the typing buffer, the refusal printed on the status line, the redraw and the exit path. Every other module in the repository is at 88% or better and most are at 100%; screen() and keys() are fully covered because #57 made them pure. The loop was left, and #78 will add offer, accept and pass to it.
Done looks like
[ ] The loop's decision comes out as a pure function, the way screen did: a key and the current state in, an intent out — move the cursor, start typing, append or backspace, submit, call this action with these arguments, quit, or ignore. No database, no process.stdout, no process.env, no clock.
[ ] run() keeps only what genuinely touches the world: opening the database, whoAtTty(), raw mode, reading bytes, executing the intent, printing the frame, restoring the terminal on exit.
[ ] Tests in src/tty.test.ts that fail without it: j and k move and clamp at both ends; o starts typing and a name is typed, backspaced and submitted; enter on an empty name does not call the action; s and x call join and leave for the selected table and print the action's refusal verbatim when it refuses; q and ctrl-C both quit; a key nobody offered does nothing; a guest pressing a writing key is offered nothing and changes nothing.
[ ] The bytes a terminal really sends are covered where they decide something: an arrow key arrives as three bytes and must not be mistaken for escape then B, and a paste arrives as several keys in one read.
[ ] Coverage of src/tty.ts is in line with the rest of the repository, and the pull says the number.
Files I expect to change.src/tty.ts, src/tty.test.ts.
Risks. Do not mock the world to test it — the point of the split is that there is nothing left to mock. Restoring the terminal on exit is the one thing a test cannot prove; leave it in run() and say so. If #78 lands first, this covers its keys too and the two should not be written twice.
Intent. Finish the split #57 started, so the half of the terminal a person actually presses is tested before #78 adds three more keys to it.
Measured on
maintoday (63a4041):bun test --coveragereportssrc/tty.tsat 53.07% of lines, uncovered208–291— which is exactlyrun(): the keyboard in raw mode, the key-to-action dispatch, the typing buffer, the refusal printed on the status line, the redraw and the exit path. Every other module in the repository is at 88% or better and most are at 100%;screen()andkeys()are fully covered because #57 made them pure. The loop was left, and #78 will add offer, accept and pass to it.Done looks like
screendid: a key and the current state in, an intent out — move the cursor, start typing, append or backspace, submit, call this action with these arguments, quit, or ignore. No database, noprocess.stdout, noprocess.env, no clock.run()keeps only what genuinely touches the world: opening the database,whoAtTty(), raw mode, reading bytes, executing the intent, printing the frame, restoring the terminal on exit.src/tty.test.tsthat fail without it: j and k move and clamp at both ends;ostarts typing and a name is typed, backspaced and submitted; enter on an empty name does not call the action;sandxcall join and leave for the selected table and print the action's refusal verbatim when it refuses;qand ctrl-C both quit; a key nobody offered does nothing; a guest pressing a writing key is offered nothing and changes nothing.src/tty.tsis in line with the rest of the repository, and the pull says the number.Files I expect to change.
src/tty.ts,src/tty.test.ts.Risks. Do not mock the world to test it — the point of the split is that there is nothing left to mock. Restoring the terminal on exit is the one thing a test cannot prove; leave it in
run()and say so. If #78 lands first, this covers its keys too and the two should not be written twice.Who. @mason, reviewed by @juniper. Ready now.