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

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

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

opened this

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 pure followingRows(relation, converge, readable) builds the rows. The screen loads them with relationOf and convergeState, the same calls MCP following uses, and only asks for the crew's state when the fork has diverged and does not merge cleanly. The crew row uses convergeWords from actions/follow.ts, so it reads the same as the following page.
  • The rows sit at the top of the list, so enter on either one opens the parent's workspace. If the viewer cannot read the parent, it is named but enter does 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 forks heading rather than replacing it, because they need to be selectable for enter.
  • 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/app and 1 ahead · 1 behind;
  • a fork with nothing of its own shows in step;
  • the original shows no such row;
  • enter on the row opens alice/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

Closes #7302

commented

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 pure followingRows(relation, converge, readable) builds the rows. The screen loads them with relationOf and convergeState, the same calls MCP following uses, and only asks for the crew's state when the fork has diverged and does not merge cleanly. The crew row uses convergeWords from actions/follow.ts, so it reads the same as the following page.
  • The rows sit at the top of the list, so enter on either one opens the parent's workspace. If the viewer cannot read the parent, it is named but enter does 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 forks heading rather than replacing it, because they need to be selectable for enter.
  • 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/app and 1 ahead · 1 behind;
  • a fork with nothing of its own shows in step;
  • the original shows no such row;
  • enter on the row opens alice/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

Changes requested — before the latest push

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.

  1. 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 enter does 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, enter leaves the screen where it was, and a private parent is never named if parentOf hides it.
  2. The crew row is never shown through the screen. load() calls convergeState only 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.
commented

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 shows diverged · 1 ahead · 1 behind and "The crew is already converging on #N." A fork that merges cleanly, with the same issue open, shows merges cleanly and no crew row. Removing the "diverged and not clean" check in load() 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 enter does nothing. That case cannot happen on screen: relationOf gets the parent from forkParentFor, which returns nothing when the viewer cannot read it, so the screen never builds the row. Proof: making enter open a row with no repository left every test passing. So I deleted that unreachable branch (the readable parameter and the row?.repo check). The rule now lives only in relationOf.
  • 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 no follows row, and after enter the screen is unchanged (bob/hidden · 0 forks, "No forks yet"). The pure test for the deleted branch went with it.
  • Docs: docs/FOLLOWING.md now 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

Approved

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.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs