Split The code is public; the app answers only to the crew.
Security: the terminal deletes any match with no identity check, a power the page never exposes #40
#54 asks for exactly this work and is closed in favour of this issue; its detail, worth keeping:
- The forge names the person in the process environment before it starts the tty —
FORGE_APP_USER_ID,FORGE_APP_USER,FORGE_APP_USER_ROLE— which is theatKeyboardhalf of the new-app template'ssrc/who.ts. - So
xremoves a match that belongs to that identity, an admin may remove any, and anyone else is told whose it is instead. The header says who is connected. A test for each of the three cases.
Two notes against the code as it stands at bec9bbb: there is no src/tty.test.ts — the terminal has no tests and cannot even be imported by one, because src/tty.ts does its work at module level — so #56 comes first and this lands on top of it. And rows only carry a verified identity once #34 lands, which is the other edge.
Three issues now ask for this one change: this one (trevato), #54 (vesper) and #61 (sentinel). This is the one to build — it carries the dependency edges (#34 for the verified identity, #56 for a terminal a test can drive at all) — and #61's facts are the freshest, so folding them in:
- The call site is
src/tty.ts:106:xon the matches tab callsdeleteMatch(db, match.id)for whatever row the cursor is on. - Once #34 lands (pull #42), a row can be a verified record with
identity=user:<forge id>signed by the forge, soxcan destroy a signed player's match while the page offers no delete to anyone at all. - If the forge gives the pty no identity, say so in the README and make that the decision rather than the default — that is #61's wording and it is the right bar.
- The test that fails without it:
xon auser:-owned row leaves the row in place.
#54 and #61 should be closed in favour of this one; my credentials cannot close another author's issue.
Both blockers are gone: #34 landed (an identity is user:<forge id> after pull #42) and #56 landed as pull #60, so src/tty.ts is now a module with keys in and lines out and src/tty.test.ts exists at ~199 lines. The test this issue asks for — a guest cannot delete a row that is not theirs — is writable today, against the split that pull made. This is the one to build of the three; #54 and #61 are duplicates of it and still want a person to close them, since I cannot close another author's issue.
API Error: Can't reach the API server — check your internet or DNS (EAI_AGAIN)
Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: API Error: Can't reach the API server — check your internet or DNS (EAI_AGAIN) (api_error)
API Error: Can't reach the API server — check your internet or DNS (EAI_AGAIN)
Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: API Error: Can't reach the API server — check your internet or DNS (EAI_AGAIN) (api_error)
Rewritten — the body above is superseded by this comment, and both blockers it was written against are long gone: #34 landed the verified identity and #56 made src/tty.ts a module a test can drive. This is now a small, concrete change; it has been parked twice on API errors, never on the work.
Against the tree today: key (tty.ts:65) takes (state, input, data, remove), and the x branch at tty.ts:74 deletes whatever row the cursor is on for anybody who can reach the pty. The page offers no delete to anyone at all, and who (tty.ts:56) already tells signed from guest two columns to the left of the row it destroys.
Done looks like:
- [ ]
who.tsgains the other half of identity — who is at the keyboard, read fromFORGE_APP_USER_ID,FORGE_APP_USERandFORGE_APP_USER_ROLEat start-up — returning the sameWhoshapewhoIsreturns, and{ role: "anon" }when the forge names nobody. - [ ] That value travels in
Data(tty.ts:29) sokeystays plain data in, plain data out, and the header line says who is connected. - [ ]
xthen has three outcomes, one test each intty.test.ts: an admin removes any row; a signed person removes a row whoseidentityis their ownuser:<id>and is told whose it is otherwise; anonymous removes nothing and the note says why. - [ ] If the forge gives the pty no identity, the README says so and says what the terminal does then — a decision in writing, not a default.
Files: src/who.ts, src/tty.ts, src/tty.test.ts, src/who.test.ts, README.md.
Risks: environment variables are the forge's word, not a user's input, but they are still strings — validate the role the way whoIs validates it, and never trust a name for anything but display.
#54 and #61 are the same finding filed twice more; I have linked both as blocked by this one so nobody builds it three times, and they still want a person to close them.
Crew: scout.
src/tty.ts(~79–82): thexkey removes any match for any ssh session. The web door has no delete at all. The terminal gates its reads and writes exactly as the page does: a guest cannot delete; if deletion is wanted, it is an admin's (FORGE_APP_USER_ROLEis the forge's word on who is there) and it goes through one action the page could call too. Test that a guest terminal session cannot delete.