Release 0.19.0: message delivery into agent context, room fan-out, Grok hooks - #83
Merged
Merged
Conversation
A full-screen pane has no scrollback, so herdr and other terminals could neither scroll nor select the conversation. Print into the normal screen with a single readline prompt instead, and keep the pinned layout behind --fullscreen.
Bare readline submitted each line of a bracketed paste and a one-row clear corrupted wrapped drafts. Drive inline mode through ChatInputController and draw the composer directly, erasing every row it drew before printing or redrawing.
A resize recomputed the erase from the new width, which stranded a copy of the panel. Track the drawn geometry, erase the larger of the old and reflowed heights on resize, cover a severe shrink in the terminal test, and document the one artifact that reflow can still leave behind.
Grok Build fires a Claude-compatible Stop hook but sends camelCase keys, so the existing guard fail-opened in every Grok session. Read both spellings, install a dedicated ~/.grok/hooks/talking-stick-stop.json carrying the same command so Grok's identical-handler dedup collapses it with the imported Claude entry, and block only an ordinary turn end: a session teardown and a subagent stop are observed, never blocked. GROK_AGENT=1 now marks a Grok session and carries GROK_SESSION_ID as its anchor, with the recorded hook log as fallback. GROK_SESSION_ID alone stays inert so an inherited value cannot masquerade as a harness. No native wake transport is added: Grok has no out-of-process inject API, so it remains reachable only through cmux.
Grok's live payload carries session_id as well as sessionId, so the guard was already reachable from Grok, and its Stop fires for turn ends, shutdowns and subagent gates alike. Recognise a Grok payload by its camelCase event name and demand reason == end_turn there, while Claude Code, which sends no reason at all, keeps blocking as before.
The per-turn guardian joins with the agent id as its display name, and its presence outranks the harness's when metadata merges onto the member row. For as long as a turn was held the member was renamed to its full id, so short chat mentions such as @claude stopped resolving. Liveness was unaffected because it already reads the harness pid.
GROK_AGENT became a harness marker, and tt detects Grok by process ancestry without TT_HARNESS_EXPORT, so running the suite from a Grok session promoted every whoami and text-mode assertion to a Grok identity. Scrub GROK_AGENT with the other harness variables and hide a grok ancestor from the process inspector while keeping its pid and start time for liveness.
Node's readline replaces its line editor with a dumb writer whenever TERM=dumb, even when terminal mode is requested, so tt chat submitted arrows and Ctrl+A as literal text and drew panel escapes a dumb terminal cannot render. Treat such a terminal as non-interactive and use plain line mode. The terminal-mode chat tests drive readline directly and failed the same way when run from a Grok tool shell, which exports TERM=dumb. Pin a capable TERM in the global test setup so they no longer depend on the caller.
An operator typing in tt chat addresses the room, but room messages never woke anyone, so only an agent already inside tt wait saw them. A room message from a human sender now reaches every agent that is a member when it is sent, standby included, as one event with a receipt per recipient; later joiners do not inherit it. Agents' room messages still wake nobody so replies cannot loop, and an agent's room interrupt still reaches only the owner. Chat sends a plain message or @everyone once to the room, and several @NAMEs share one event that lists them instead of one copy per agent. Each recipient's status is reported as soon as its own wake settles, and labels say only what is known: unreachable requires a definite transport failure. Native envelopes become attributed plain text: a header with the room path and ack command, a #seq sender -> you|room line per event with every content line indented, and a closing boundary. A short chat line drops from about 600 characters to about 190.
The operator wants one block per message whose header names every recipient, with a single-character state after each name instead of a receipt line under the body: … not delivered yet, ✓ delivered, ! failed. Every mark is one cell wide and reserved from the first paint, so an acknowledgement repaints the header in place without changing how many rows it occupies. Room messages from an operator record who they went to at send time, for display only. Also render plain string artifacts from tt release in envelopes instead of undefined, and stop creating native receipts for chat consoles, which never consume them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cuts 0.19.0. The operator asked for this release after live acceptance in their own terminal.
What changes for users
tt wait;tt ack <token>records receipt for exactly those events and grants no turn.@namenarrows, several@namesshare one message,!@is urgent.…pending,✓delivered,!failed), renders inline by default, and keeps native scrollback and selection.Not included:
/invite, and a guarded herdr wake for idle Grok sessions.Verification
TERM=dumb; typecheck and build clean.