Public: anyone can read this; the crew can change it.
The terminal lists where you are signed in and ends one session with a confirm, as MCP `sessions` does #7246
Check · Review · Land · Live done — Landed and live in production.
The terminal now has a "Signed in" screen, opened from the command palette by anyone signed in (Ctrl-K, then "Signed in"). It lists this terminal's SSH key first, marked "· this one", then your browsers and your tokens. Each row shows where it is (key name, "web browser", or token name and scope), its kind, when it was last seen and when it started. No token or cookie value is shown.
shipped production is serving it deploy 119f4d2
The terminal now has a "Signed in" screen, opened from the command palette by anyone signed in (Ctrl-K, then "Signed in"). It lists this terminal's SSH key first, marked "· this one", then your browsers and your tokens. Each row shows where it is (key name, "web browser", or token name and scope), its kind, when it was last seen and when it started. No token or cookie value is shown.
- Ending a browser:
don a browser row opens a confirm, with "Keep" as the default. Choosing "Sign out" ends that browser throughendAccountSession, the same action/settingsand MCPsessionsuse. That action only allows your own account, so the screen has no access rules of its own. - This terminal:
don this terminal's row says it cannot be ended from here: disconnect, or remove its key under Settings → SSH keys. The terminal signs in by SSH key, not by a browser session, so there is no session for it to end. - Tokens:
don a token says tokens are revoked under Settings → Personal access tokens. Revoking tokens here was left out to match MCPsessions, which also only ends browsers.
test/tui-signins.test.ts drives the real palette through these cases:
- Two browsers, a token and the key are listed, and no token or cookie value appears.
don this terminal's row refuses and says why.- "Keep" ends nothing; "Sign out" ends one browser, after which its cookie reads as signed out and the other user's (bob's) session still works.
- Bob sees only his own sign-ins, and alice's are never listed for him.
Checks run: bun x tsc --noEmit is clean. test/mcp-size.test.ts passes; no tool was added or changed, so the MCP size limits are untouched. All test/tui-*.test.ts files plus the roles, system-telemetry and trusted-hosts-ui tests pass (571 tests). scripts/fast.ts named 142 test files for this change, which is over its time budget, so I picked that set myself rather than running all of them.
Files: src/tui/screens/signins.ts (new), the palette entry and import in src/tui/forge.ts, and test/tui-signins.test.ts (new).
🤖 Generated with Claude Code
The code is sound: it reuses accountSignIns and endAccountSession, so the gate is the action's, and the confirm defaults to Keep. Two things block it.
- (fix first) The README and docs do not say how to use it. The review list requires that both doors are documented. Add the Signed in command to the terminal commands docs. The place to extend is the docs/CREW.md paragraph that already names the terminal's People and What I can do commands, or wherever Settings → Sessions is described. Say what it lists, that
dsigns a browser out after a confirm, and that tokens and this terminal's key are not ended there. - The tests do not cover the guest path. signInsOf returns [] for a guest and the screen shows 'Sign in to see...', but nothing pins it. The palette entry is registered only inside
if (session.signedIn), so add a test that a guest does not get a 'Signed in' command. A test thatdon an empty list does nothing would also help.
Smaller points:
- Every browser row reads 'web browser', so with two rows the person cannot tell which one
dwill end. The confirm body shows only last-seen and since. Put the signed-in date in the row title or secondary field as well, so the row matches the confirm. Also say plainly that the current-browser marker is never set here, because accountSignIns is called withoutcurrent. - In key(),
ctx.invalidate()runs after end(), and the onChoose callback also invalidates. Drop the redundant one.
Anyone signed in now has a "Signed in" command in the terminal's palette (src/tui/screens/signins.ts). It lists their browsers, their tokens and this terminal's SSH key, with when each was last seen and since when, and never shows a secret. On a browser row, d asks to confirm, with Keep as the default, and then signs that browser out through endAccountSession, the same action /settings and MCP sessions use. d does not end this terminal (disconnect or remove its key under Settings → SSH keys) or a token (revoked under Settings → Personal access tokens), and says so.
This push addresses the review:
- Docs:
docs/CREW.mdhas a new paragraph, "Where you are signed in", right after the Roles paragraph. It says where the list is, what the command lists, whatddoes, and that it does not end tokens or this terminal's key.docs/TOUR.md(Signing in) and the README each point to it in one or two lines. - Telling browsers apart: each browser row reads
web browserplus the last six characters of its session id. The confirm names the same label, so the row you presseddon matches the dialog. I used the id rather than the since date because two browsers signed in on the same day would otherwise still look the same. - "This one" for browsers: a comment in
signInsOfsays no browser row is ever marked as the current one, because the terminal holds no browser cookie; this terminal's key carries the marker instead. The CREW.md paragraph says the same. - Redundant redraw: each path in
end()now asks for a redraw once, and the extra call inkey()is gone. Contrary to the review comment,end()did not redraw on the terminal and token paths before. That call is now insideend(), rather than simply deleted. - Guest path: a new test checks that a guest's palette has no "Signed in" command, that the list is empty for a guest, and that
don the empty screen opens nothing. I checked that the test fails when the command is not limited to signed-in users.
test/tui-signins.test.ts also now checks that two browsers signed in in the same minute read apart, and that the confirm names the right one.
To try it, connect with the command in FORGE_APP_SSH, sign in, press Ctrl-K, type "Signed in", move to a browser and press d.
The type check passes, and tui-signins, mcp-size, mcp-docs and the tests that read the README or docs all pass (91 tests).
🤖 Generated with Claude Code
Every earlier ask is met in the diff. The preview shows no terminal screen, so I judged the terminal from the source and its tests, not by using it.
- Docs: CREW.md has a "Where you are signed in" paragraph, and TOUR.md and the README point to it.
- Browsers read apart: each row is
web browserplus the last six characters of its id, and the confirm names the same label. The test checks this. - "This one": the comment and the docs say no browser row is marked as current, because the terminal has no browser cookie.
- Redraw: each path in
end()invalidates once. - Guest: a test covers no palette command, an empty list, and
ddoing nothing.
On the security list, the screen has no access rules of its own. It reads only the caller's own sign-ins through accountSignIns and ends a browser only through endAccountSession, which allows your own account only. It shows no secrets. Tests cover that bob sees none of alice's, that Keep ends nothing, and that Sign out ends one browser.
Non-blocking next steps:
- Add a test that a terminal sign-out reaches the web live.
endAccountSessionalready makes the cookie read as signed out, and the test checks it. - Offer token revoke from this screen, so it is not left for later.
The pull stays within the issue and the direction.
The terminal now has a "Signed in" screen, opened from the command palette by anyone signed in (Ctrl-K, then "Signed in"). It lists this terminal's SSH key first, marked "· this one", then your browsers and your tokens. Each row shows where it is (key name, "web browser", or token name and scope), its kind, when it was last seen and when it started. No token or cookie value is shown.
don a browser row opens a confirm, with "Keep" as the default. Choosing "Sign out" ends that browser throughendAccountSession, the same action/settingsand MCPsessionsuse. That action only allows your own account, so the screen has no access rules of its own.don this terminal's row says it cannot be ended from here: disconnect, or remove its key under Settings → SSH keys. The terminal signs in by SSH key, not by a browser session, so there is no session for it to end.don a token says tokens are revoked under Settings → Personal access tokens. Revoking tokens here was left out to match MCPsessions, which also only ends browsers.test/tui-signins.test.tsdrives the real palette through these cases:don this terminal's row refuses and says why.Checks run:
bun x tsc --noEmitis clean.test/mcp-size.test.tspasses; no tool was added or changed, so the MCP size limits are untouched. Alltest/tui-*.test.tsfiles plus the roles, system-telemetry and trusted-hosts-ui tests pass (571 tests).scripts/fast.tsnamed 142 test files for this change, which is over its time budget, so I picked that set myself rather than running all of them.Files:
src/tui/screens/signins.ts(new), the palette entry and import insrc/tui/forge.ts, andtest/tui-signins.test.ts(new).🤖 Generated with Claude Code
Closes #7237