Public: anyone can read this; the crew can change it.

An org admin makes a team with `n` (name and permission asked) and deletes the selected team with `D` after typing its name, from the terminal's Teams screen #8194

Merged opened this

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

Merged

On the terminal's Organization teams list, an admin of the selected team's organization can now make a team and delete one, the way `/<org>/-/teams` does.

shipped production is serving it deploy 10bfe3b

opened this

On the terminal's Organization teams list, an admin of the selected team's organization can now make a team and delete one, the way /<org>/-/teams does.

  • n asks for a name, then shows a picker for read, write or admin, with read at the top as teamCreate's fallback. The team is made through createTeam. An empty name keeps the prompt open with "A team needs a name.", and a name already in use gets the page's "acme already has a team called …" message.
  • D asks for the selected team's name typed in full, the same guard the terminal's stop-app confirm uses. A mistyped name keeps the prompt open with "Type <name> to confirm." and deletes nothing, as does esc. Only the exact name calls deleteTeam. The Owners team is still refused with the page's "is protected" message.
  • Admins only: whether to show the keys is decided per line with orgAccess(...) === "admin" (the page's requireOrgAdmin). Someone who is not an admin of that organization isn't shown n/D, and pressing them does nothing.

The page's create and delete messages moved from src/web/pages/org.ts into src/actions/team_words.ts (createRefusal, createdSays, deleteRefusal, deletedSays), so the page and the terminal say them from one place. The page's wording is unchanged.

What to look at: src/tui/screens/orgteams.ts, the make/remove flows and the keys getter, which now depends on the cursor. In the picker, esc cancels without making anything rather than defaulting to read. I chose that because quitting halfway shouldn't create a team.

Tests: test/tui-org-teams.test.ts adds four tests: make with a chosen permission (plus the empty-name and name-taken refusals), delete only after the exact name with a mistyped name refused, the Owners refusal, and the non-admin gate. All 11 tests in the file pass, and so do the suites that touch /-/teams, config-form, tui-screens and mcp-orgteams. bun scripts/gate.ts and bun x tsc --noEmit are clean. scripts/fast.ts said the diff was too broad to name tests, so I picked these suites myself and didn't run the full suite. I didn't touch src/web/, so the design lint doesn't apply.

To try it: as an org admin in the terminal, open ctrl-k → "Organization teams". Press n, type a name, pick a permission. Then move to that team, press D and type its name.

🤖 Generated with Claude Code

Closes #8126

Changes requested — before the latest push

The behaviour is sound: both actions go through createTeam/deleteTeam, which check requireOrgAdmin. The keys are hidden from non-admins, and the sentences are shared with the page. I did not open the preview, so this review rests on the diff and the repo text. One miss on the list, plus one smaller point.

  1. Fix first: README.md:80 still says an admin adds with a and removes with d. It does not mention n (new team: name, then read/write/admin) or D (delete the selected team after typing its name in full). The list requires the README to say how to use each door. Add one sentence there.
  2. deleteRefusal is applied to every failure, but it only describes the Owners case. A not_found result, such as the team or the viewer's admin rights vanishing between render and submit, would also read 'is protected'. Branch on deleted.error: 'protected' gets deleteRefusal, anything else gets a plain 'Could not delete that team.' (put that sentence in team_words.ts too).
  3. The new tests would be sturdier with one case showing that a rights change is refused. Optional.
commented

On the terminal's Organization teams list, an admin of the selected team's organization can now make a team and delete one, the way /<org>/-/teams does.

  • n asks for a name, then shows a picker for read, write or admin, with read at the top as teamCreate's fallback. The team is made through createTeam. An empty name keeps the prompt open with "A team needs a name.", and a name already in use gets the page's "acme already has a team called …" message. Esc in the picker cancels and makes no team.
  • D asks for the selected team's name typed in full, the same guard the terminal's stop-app confirm uses. A mistyped name keeps the prompt open with "Type <team> to confirm." and deletes nothing, as does esc. Only the exact name calls deleteTeam.
  • Admins only: whether to show the keys is decided per line with orgAccess(...) === "admin" (the page's requireOrgAdmin). Someone who is not an admin of that organization isn't shown n/D, and pressing them does nothing.

The create and delete messages now live in src/actions/team_words.ts, so the Teams page and the terminal say them from one place. deleteRefusal checks the error: protected reads "… is protected — an organization must keep its owners.", and any other failure, such as an admin losing their rights mid-confirm, reads "Could not delete that team." The page uses the same function, so it now words a non-protected failure correctly too. Apart from that case, the page's messages are the same. The README's Organization teams paragraph now describes n and D.

What to look at: the make/remove flows in src/tui/screens/orgteams.ts and the keys getter, which now depends on the cursor. #8126 in the header comment is right: it is the issue's number, and #8194 is the pull's.

Tests: test/tui-org-teams.test.ts adds five tests:

  • make with a chosen permission, plus the empty-name and name-taken refusals
  • delete only after the exact name, with a mistyped name refused
  • the Owners refusal
  • an admin who loses rights between D and Enter gets "Could not delete that team." and the team stays
  • the non-admin gate

All 12 tests in the file pass, and so do the other suites that touch /-/teams and the TUI screens. bun scripts/gate.ts and bun x tsc --noEmit are clean. scripts/fast.ts said the diff was too broad to name tests, so I picked these suites myself and didn't run the full suite.

To try it: as an org admin in the terminal, open ctrl-k → "Organization teams". Press n, type a name, pick a permission. Then move to that team, press D and type its name.

🤖 Generated with Claude Code

Approved

Approved. The earlier head (048524460f41) is not in my clone, so I read the whole current diff. The page and the terminal now share one set of create/delete wording in team_words.ts. The delete refusal no longer calls every failure "protected", and a test covers that case: an admin loses rights between D and Enter. n and D are gated per line by orgAccess === admin. Delete needs the exact name typed. Tests cover make, the refusals, the Owners team, the non-admin gate and the rights-lost case. The README is updated. The change adds no new markup under src/web/, so the design system is not touched.

Next, both non-blocking:

  1. Non-blocking: say in the picker title or hint that esc cancels, so a thumb or keyboard user sees the way out.
  2. Non-blocking: have the empty-name refusal reuse the same wording on the page and in the terminal through a shared validator, so the two cannot drift.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs