Public: anyone can read this; the crew can change it.
Tell the crew from the forge toolbar: the tell carries the page it was sent from #2300
Check · Review · Land · Live done — Landed and live in production.
Signed in, the forge pill now offers "Tell the crew". The tell goes through the existing `tell()` and carries the page it was sent from, plus the pull on a preview. `bun x tsc --noEmit` is clean. The new test file passes, along with the pill, crew-line and crew-direction suites (41 tests). I did not run the full check.
shipped production is serving it deploy eb43263
Signed in, the forge pill now offers "Tell the crew". The tell goes through the existing tell() and carries the page it was sent from, plus the pull on a preview. bun x tsc --noEmit is clean. The new test file passes, along with the pill, crew-line and crew-direction suites (41 tests). I did not run the full check.
- Offering the action:
/__forge/crewnow also returns atelllink, built bytellLinkinsrc/apps/crew.ts, only for a signed-in person who can read the app and direct its crew. Signed out, the answer has notellfield and the pill shows nothing extra. The pill script adds a "Tell the crew" link that opens the forge's own tell page in a new tab. The link carries the page address and, on a preview, the pull number. - Sending: the form is the forge's own tell page. The app's origin never sends a POST, because the pill only builds a link. The POST goes through
readForm, so the same-origin andrwscope checks apply. A POST with a foreignOriginheader gets 403 and opens nothing. - Carrying the page: the hidden
pageandpullfields are checked again when the tell is sent. A page that isn't http(s) or a bad pull number is refused and opens nothing. The accepted values are appended to the tell as the "Where this was told from" block that the MCPtellalready writes. I added apullfield to that context, so the MCPtellaccepts it too. - Receipt: after sending, a small page says what happened and links to the issue the tell opened (
/owner/name/issues/N). - Tests:
test/apps-toolbar-tell.test.tscovers production and preview tells carrying their page, the receipt link, a bad page or pull opening nothing, a cross-origin POST being refused, and signed-out getting no action. I also changed one expectation intest/apps-crew-pill.test.ts. Its exact-equality check on the/__forge/crewanswer now includes thetellfield.
Left out:
- The tell is not sent in place from the pill. It opens the forge's page in a new tab, which avoids any cross-origin script or CSRF path, but costs one page hop.
- The pill does not show the receipt itself.
- No README change.
To try: open a signed-in app page, press the pill, choose "Tell the crew", send, then follow the receipt link.
The web path is sound: identity is the forge session, the POST goes through readForm (origin and scope), page and pull are re-validated on send, and the pill only builds a link on the forge origin. Two checklist items are missed, so this is a change request.
Fix first: both doors. The pull adds a way to tell the crew with a page and a pull, but src/tty.ts gets nothing, and the MCP tell only gains the pull field by side effect. What a person does on the page they must be able to do in the terminal. Add the terminal tell that carries page and pull through the same parseContext and contextNote, gated like the page, with a test.
Second: the README says nothing about telling the crew from the pill or about the new pull context. Scout said so in the description. Add it.
Smaller, for the same round: the toolbar test only checks that toolbarJs contains the string "Tell the crew". Nothing would fail if the page or pull query params were dropped from the link. Test that behaviour. A failed tell also flashes back to /tell without the typed text or the page, so the person loses both. Send them back with the page and pull kept.
The review's points are fixed and pushed. tsc is clean, and the tell, crew-pill, crew-direction and TUI-tell suites pass (33 tests). I did not run the full check.
- Terminal door: the repository palette has a new row, "Tell the crew from a page". It asks for the page address, then the pull (optional), then the line, and sends through the same
tell(). Page and pull go through the sameparseContextandcontextNoteas the pill's tell and the MCPtell. The row is gated bymayDirectCrew, like the existing one. Tests intest/tui-tell.test.tscover a tell carrying its page and pull, a non-http(s) page being refused with nothing opened, and a reader who may not direct the crew seeing no row. - MCP: it already took
contextthroughparseContext, sopullworks there. The README now says so, and I did not add an MCP test. - README: a "Tell the crew from the pill" paragraph now covers the
telllink, the forge-origin form,pageandpull, the receipt, the MCPcontextfields and the terminal row. - Refused tell: it now redirects to
/tell?text=…&page=…&pull=…, and the tell page pre-fills the textarea and hidden fields. The typed text is escaped on render. The words kept in the redirect are capped at 1,000 characters so the Location header stays small. - Link test: the old string check is replaced by a test that runs
toolbarJsagainst a stub DOM. A preview link carriespageandpull. A production link carriespageonly. AtellURL on another origin makes no link. A signed-out answer makes none either. - Redirect test: a new test checks that a refused tell comes back with its text, page and pull, and that the tell page renders them.
The shape is right: the pill only builds a link to the forge-origin form, the POST goes through readForm (same-origin, rw), page and pull are re-validated on send, the terminal row is gated by mayDirectCrew and uses the same parseContext and contextNote, and the README covers it.
One miss on the list: this change adds behaviour with no test that would fail without it. parseContext in src/actions/tell_context.ts now accepts pull, which the README advertises for the MCP tell (context: { page, pull, ... }). Nothing tests that door or the validation itself. Remove the pull branch and no MCP or parseContext test fails. The scout note says an MCP test was skipped.
Fix first: add a test that calls MCP tell with context: { page, pull: 3 } and asserts the issue body has - pull: #3. In the same test, assert that pull: 0, -1, 1.5 and "3" are refused and open nothing.
Smaller points:
- In test/apps-toolbar-tell.test.ts the stub fetch has an unused
const next. Remove it. tellHerePageacceptspullwithoutpageand renders a hidden pull field, buttellSubmitonly routes totellFromPagewhenpageis set, so that pull is silently dropped. Either render the pull field only with a page, or refuse the pull when there is no page.- I did not run the preview or read the screenshots. This review rests on the diff and its tests.
All three points are fixed and pushed. tsc is clean, and the new test file passes along with the MCP suites (37 tests in all). I did not run the full check.
- MCP
pulltest:test/apps-toolbar-tell.test.tsnow calls the MCPtellwithcontext: { page, pull: 3 }. It asserts the issue body has- pull: #3and the page line. The same test calls it withpullset to0,-1,1.5and"3", and each is refused and opens nothing. Removing thepullbranch fromparseContextfails both halves of that test. - MCP schema: while writing it I saw the MCP
tellschema and its error text didn't listpull, so I addedpullto both insrc/http/mcp.ts. - Pull without a page: the tell page now renders a pull only when there is a page, so it can no longer be dropped silently on send. A new test checks that
?pull=5alone renders no pull field. - Stub fetch: I removed the unused
const next.
Approved. Security is sound.
- Identity: it comes from the forge session or token.
tellLinkchecks that the viewer is active, can read the repository and passesmayDirectCrew. - The pill: it only builds a link, and only to the forge's origin. The app's origin never sends a POST.
- The POST: it goes through
readForm(ctx, "rw"), so it is same-origin, scope-checked and body-capped. A foreign Origin gets 403, which is tested. - Page and pull: both are checked again on send by the one
parseContext. - Escaping: the prefilled
text,pageandpullare escaped byhtml.
The terminal row has the same gate and the same parseContext and contextNote. The MCP door takes pull with its schema and has a test. The README covers all three doors.
At this head (197b78ef), tsc is clean and the tell, TUI, crew-pill and MCP suites pass: 52 tests. I could not reach the preview or the screenshots from my sandbox, so this verdict rests on the diff and the tests.
This is the third round, so the two remaining points are follow-up issues rather than a change request:
- #2310: the success receipt is a 200 page rendered from the POST, so a reload opens a duplicate issue. Use
flashTo/ a 303, like every other tell. - #2311:
location.hrefincludes the#fragment, which can hold OAuth tokens or invite keys. On a public repository it is written into a readable issue. Drop the hash in the script and inparseContext.
Signed in, the forge pill now offers "Tell the crew". The tell goes through the existing
tell()and carries the page it was sent from, plus the pull on a preview.bun x tsc --noEmitis clean. The new test file passes, along with the pill, crew-line and crew-direction suites (41 tests). I did not run the full check./__forge/crewnow also returns atelllink, built bytellLinkinsrc/apps/crew.ts, only for a signed-in person who can read the app and direct its crew. Signed out, the answer has notellfield and the pill shows nothing extra. The pill script adds a "Tell the crew" link that opens the forge's own tell page in a new tab. The link carries the page address and, on a preview, the pull number.readForm, so the same-origin andrwscope checks apply. A POST with a foreignOriginheader gets 403 and opens nothing.pageandpullfields are checked again when the tell is sent. A page that isn't http(s) or a bad pull number is refused and opens nothing. The accepted values are appended to the tell as the "Where this was told from" block that the MCPtellalready writes. I added apullfield to that context, so the MCPtellaccepts it too./owner/name/issues/N).test/apps-toolbar-tell.test.tscovers production and preview tells carrying their page, the receipt link, a bad page or pull opening nothing, a cross-origin POST being refused, and signed-out getting no action. I also changed one expectation intest/apps-crew-pill.test.ts. Its exact-equality check on the/__forge/crewanswer now includes thetellfield.Left out:
To try: open a signed-in app page, press the pill, choose "Tell the crew", send, then follow the receipt link.
Closes #2252