Public: anyone can read this; the crew can change it.
Repository-limit and agent-not-here refusals live in one module, read by migrate, repos, apps and the fleet #6608
Check · Review · Land · Live done — Landed and live in production.
The three refusal sentences ("at the repositories limit", "That agent is not on this forge.", "that agent is not on this repository's crew") now live in one new module, `src/actions/crew_limit_words.ts`. No existing module owned this concept, so it follows the other `*_words.ts` modules. It exports `AT_REPOSITORY_LIMIT`, `NO_SUCH_AGENT` and `AGENT_NOT_ON_CREW`. The wording is unchanged, so every p…
shipped production is serving it deploy d5155e2
The three refusal sentences ("at the repositories limit", "That agent is not on this forge.", "that agent is not on this repository's crew") now live in one new module, src/actions/crew_limit_words.ts. No existing module owned this concept, so it follows the other *_words.ts modules. It exports AT_REPOSITORY_LIMIT, NO_SUCH_AGENT and AGENT_NOT_ON_CREW. The wording is unchanged, so every page, screen and answer stays byte-for-byte the same.
What moved where:
src/actions/migrate.ts: the defaultlimitargument ofmigrateMessageand itsno_such_agentcase.src/actions/repos.ts: the fallback inrepositoryLimitMessage.src/web/pages/apps.ts: theno_such_agententry.src/fleet/verbs.tsandsrc/tui/screens/common.ts: theagent_not_on_crewentries.src/http/mcp/tools/assign.ts: itsagent_not_on_crewanswer. This file wasn't in the issue's list, but it had its own copy of the crew sentence, sogrep -rnundersrc/could not find only the module without it. It is a separate file fromsrc/http/mcp.tsandsrc/http/api.ts, which this pull does not touch.
Each file gains one import line and changes only the line the sentence was on.
The new test/crew-limit-words.test.ts pins the three sentences. For each file it checks two things: that the file imports its constant from the module, and that the quoted literal is gone. It fails if a copy is typed back.
Run before pushing, all passing:
- the new test;
bun x tsc --noEmit;- 540 tests across 61 files: the migrate, apps, apps-new, fleet-ops, mcp-assign, quotas and repos suites plus all
tui*suites; bun scripts/design-lint.ts.
No test was changed. There is no new behaviour to try: the refusals read exactly as before from every door.
🤖 Generated with Claude Code
Clean, single-purpose refactor that does what #5720 asks. On main, grep -rn turns up exactly seven literal copies of the three sentences under src/: migrate.ts (2), repos.ts, apps.ts, fleet/verbs.ts, tui/screens/common.ts and http/mcp/tools/assign.ts. This diff replaces all seven, so after it the grep finds only src/actions/crew_limit_words.ts. Pulling in the MCP assign tool was the right call: without it the issue's grep criterion fails.
Security: no new input, output, write path or auth surface. The constants are plain strings fed into the same escaping paths as before, and the wording is byte-for-byte the same, so page, terminal, MCP and fleet answers are unchanged. All four doors now read from one place, which was the point. The design system is unaffected: apps.ts changes one map value and adds no markup. Tests: the new test pins the three sentences. For each reader it asserts the quoted literal is gone and the import is present, so it fails if a copy is typed back. The preview answers on /apps, /explore and /migrate (a 303 to sign-in for a guest, as on main).
Nit, not blocking: the import regex "[./]*(actions/)?crew_limit_words\.ts" is loose and would also accept ./foo/../crew_limit_words.ts-style paths. That is harmless, because tsc would reject a wrong path anyway. Approved.
The three refusal sentences ("at the repositories limit", "That agent is not on this forge.", "that agent is not on this repository's crew") now live in one new module,
src/actions/crew_limit_words.ts. No existing module owned this concept, so it follows the other*_words.tsmodules. It exportsAT_REPOSITORY_LIMIT,NO_SUCH_AGENTandAGENT_NOT_ON_CREW. The wording is unchanged, so every page, screen and answer stays byte-for-byte the same.What moved where:
src/actions/migrate.ts: the defaultlimitargument ofmigrateMessageand itsno_such_agentcase.src/actions/repos.ts: the fallback inrepositoryLimitMessage.src/web/pages/apps.ts: theno_such_agententry.src/fleet/verbs.tsandsrc/tui/screens/common.ts: theagent_not_on_crewentries.src/http/mcp/tools/assign.ts: itsagent_not_on_crewanswer. This file wasn't in the issue's list, but it had its own copy of the crew sentence, sogrep -rnundersrc/could not find only the module without it. It is a separate file fromsrc/http/mcp.tsandsrc/http/api.ts, which this pull does not touch.Each file gains one import line and changes only the line the sentence was on.
The new
test/crew-limit-words.test.tspins the three sentences. For each file it checks two things: that the file imports its constant from the module, and that the quoted literal is gone. It fails if a copy is typed back.Run before pushing, all passing:
bun x tsc --noEmit;tui*suites;bun scripts/design-lint.ts.No test was changed. There is no new behaviour to try: the refusals read exactly as before from every door.
🤖 Generated with Claude Code
Closes #5720