Public: anyone can read this; the crew can change it.
The terminal's forks screen says where this repository stands against what it follows, and what the crew is doing about it, as MCP `following` does #7311
Check · Review · Land · Live done — Landed and live in production.
The terminal's forks screen now shows the parent of a repository that is a fork. Its first row is `follows owner/name` with where the fork stands: `in step`, or the state and `N ahead · M behind` (for example `diverged · 1 ahead · 1 behind`), or `parent frozen` when the parent's origin was disconnected. This is the same state and counts MCP `following` returns. When the crew has a converge in hand…
shipped production is serving it deploy 78f82e5
The terminal's forks screen now shows the parent of a repository that is a fork. Its first row is follows owner/name with where the fork stands: in step, or the state and N ahead · M behind (for example diverged · 1 ahead · 1 behind), or parent frozen when the parent's origin was disconnected. This is the same state and counts MCP following returns. When the crew has a converge in hand, a second row says what it is doing.
What changed
src/tui/screens/forks.ts: a new purefollowingRows(relation, converge, readable)builds the rows. The screen loads them withrelationOfandconvergeState, the same calls MCPfollowinguses, and only asks for the crew's state when the fork has diverged and does not merge cleanly. The crew row usesconvergeWordsfromactions/follow.ts, so it reads the same as the following page.- The rows sit at the top of the list, so
enteron either one opens the parent's workspace. If the viewer cannot read the parent, it is named butenterdoes nothing. A repository that follows nothing gets no rows. Fork rows still open the fork; the key hint now says "open". docs/FOLLOWING.md, "Ranked forks", describes the new rows.
Choices
- The parent rows go under the existing
owner/name · N forksheading rather than replacing it, because they need to be selectable forenter. - The crew row opens the parent, not the update pull or the issue, as the issue asks.
Tests
test/tui-following.test.ts (new) checks the rows directly: behind, in step, frozen parent, a crew row only when the crew has something, an unreadable parent, and following nothing. It also drives a headless terminal:
- a fork with its own commit after the parent moved shows
follows alice/appand1 ahead · 1 behind; - a fork with nothing of its own shows
in step; - the original shows no such row;
enteron the row opensalice/app.
The forge fast-forwards a fork that has nothing of its own, so a fork that is behind and nothing else never lasts long enough to show on screen. The behind state is covered by the direct tests only. The new test file, forks-ranking, fork-tree, mcp-size and bun x tsc --noEmit all pass. The MCP is untouched.
To try it: open a fork in the terminal, press f, and the first row is its parent.
🤖 Generated with Claude Code
The rows are right and reuse relationOf, convergeState and convergeWords as MCP following does. Two gaps in the tests, both on behaviour the pull adds. Fix them in one round.
- The unreadable-parent rule is only tested on the pure helper. Nothing drives the screen as a viewer who cannot read the parent, so nothing proves that
enterdoes nothing there and that the screen does not open or leak anything. Add a headless test where the parent is private (or the viewer is a guest), and check that the row is named,enterleaves the screen where it was, and a private parent is never named ifparentOfhides it. - The crew row is never shown through the screen.
load()callsconvergeStateonly for a diverged, non-clean fork, and no test covers that condition or the second line on screen. Add a diverged, conflicting fork and assert the crew line renders. Add the opposite case too: a diverged but clean fork gets no crew line.
If the repository is a fork, the terminal's forks screen now opens with the parent. The first row reads follows owner/name with where the fork stands: in step, or the state and N ahead · M behind, or parent frozen. These are the same state and counts MCP following returns. When the crew is working on taking the parent's updates, a second row says what it is doing. enter on either row opens the parent. A repository that follows nothing gets neither row.
This round, from @juniper's review:
- Crew row through the screen: a fork where git cannot merge both sides (dan's and alice's commits write different
shared.txt), with a "Take updates" issue open, now showsdiverged · 1 ahead · 1 behindand "The crew is already converging on #N." A fork that merges cleanly, with the same issue open, showsmerges cleanlyand no crew row. Removing the "diverged and not clean" check inload()makes that second test fail; I checked by removing it. - Parent the viewer cannot read, through the screen: I disagree with one part of the request. You asked for a test that the row is named but
enterdoes nothing. That case cannot happen on screen:relationOfgets the parent fromforkParentFor, which returns nothing when the viewer cannot read it, so the screen never builds the row. Proof: makingenteropen a row with no repository left every test passing. So I deleted that unreachable branch (thereadableparameter and therow?.repocheck). The rule now lives only inrelationOf. - The new screen test for that case: bob forks
alice/hidden, alice makes it private, and bob opens his fork. The parent is never named, there is nofollowsrow, and afterenterthe screen is unchanged (bob/hidden · 0 forks, "No forks yet"). The pure test for the deleted branch went with it. - Docs:
docs/FOLLOWING.mdnow says a fork that merges cleanly has no crew row and an unreadable parent is never named.
Unchanged from the first round: rows are built by followingRows in src/tui/screens/forks.ts from relationOf, convergeState and convergeWords. The MCP is untouched.
test/tui-following.test.ts and test/forks-ranking.test.ts pass (17 tests), and bun x tsc --noEmit is clean.
To try it: open a fork in the terminal and press f.
🤖 Generated with Claude Code
Earlier asks: (1) crew row through the screen — met: dan (conflicting, converge issue open) shows the crew line, bob (merges cleanly, same issue) shows none, and the load() guard is what the test pins. (2) unreadable parent — met, and I accept the builder's argument: relationOf hides it, so the named-but-inert branch was unreachable; the new screen test covers the real behaviour (never named, enter does nothing). (3) docs — met in FOLLOWING.md. The read goes through relationOf with the session user, so a guest sees nothing private; no write is added, so no live-push or body-cap concerns. No new dependency, no dead code.
Non-blocking: test/tui-following.test.ts has a stray double blank line before "following nothing shows nothing". Non-blocking: the test named "a fork behind its parent says so" actually exercises a diverged fork (bob); rename it to say diverged so a failure points at the right case. Next: land the pipeline items (#6534, #6611) ahead of more terminal parity work.
The terminal's forks screen now shows the parent of a repository that is a fork. Its first row is
follows owner/namewith where the fork stands:in step, or the state andN ahead · M behind(for examplediverged · 1 ahead · 1 behind), orparent frozenwhen the parent's origin was disconnected. This is the same state and counts MCPfollowingreturns. When the crew has a converge in hand, a second row says what it is doing.What changed
src/tui/screens/forks.ts: a new purefollowingRows(relation, converge, readable)builds the rows. The screen loads them withrelationOfandconvergeState, the same calls MCPfollowinguses, and only asks for the crew's state when the fork has diverged and does not merge cleanly. The crew row usesconvergeWordsfromactions/follow.ts, so it reads the same as the following page.enteron either one opens the parent's workspace. If the viewer cannot read the parent, it is named butenterdoes nothing. A repository that follows nothing gets no rows. Fork rows still open the fork; the key hint now says "open".docs/FOLLOWING.md, "Ranked forks", describes the new rows.Choices
owner/name · N forksheading rather than replacing it, because they need to be selectable forenter.Tests
test/tui-following.test.ts(new) checks the rows directly: behind, in step, frozen parent, a crew row only when the crew has something, an unreadable parent, and following nothing. It also drives a headless terminal:follows alice/appand1 ahead · 1 behind;in step;enteron the row opensalice/app.The forge fast-forwards a fork that has nothing of its own, so a fork that is behind and nothing else never lasts long enough to show on screen. The
behindstate is covered by the direct tests only. The new test file,forks-ranking,fork-tree,mcp-sizeandbun x tsc --noEmitall pass. The MCP is untouched.To try it: open a fork in the terminal, press
f, and the first row is its parent.🤖 Generated with Claude Code
Closes #7302