docs(cli): events had no schema, and promised a pane-exit event nothing sends

`events` is the streaming interface an agent builds on, and it was the one verb
whose JSON shape the reference did not give — every other one lists its fields
exactly. Now it does: the externally tagged envelope, the four event kinds a
listener sees, and the thirteen `layout` delta kinds.

The prose also listed "pane exits" as an event type. There is no such event.
`ControlEvent::PaneExited` is defined, encodes, and has a line
`tty7 events` would print for it — and nothing anywhere constructs one outside
the round-trip tests in its own file. `AgentStatus`, `Preempted` and
`LayoutResync` have 2, 10 and 6 emitters respectively; this one has none. An
agent waiting for a pane-exit line waits for good.

What actually happens is checked against a running server: exit the shell in a
pane and exactly one event arrives — a `layout` delta carrying `pane_facts` for
that pane with `"live": false`, and the pane is gone from `pane ls --all`. The
docs now say to watch for that, in a note that says outright there is no
pane-exit line whatever the wire protocol's shape suggests.

The variant keeps a comment saying the same thing, and that resolving it means
either emitting it where the pane is reaped or removing it along with the
`event_line` arm — not something to do in passing, since taking a variant out
of a wire enum is a dialect change.

2951 tests pass.
This commit is contained in:
l0ng-ai
2026-08-15 19:30:16 +08:00
parent 27c0c6c399
commit a4d0a10a6e
2 changed files with 35 additions and 3 deletions
+11
View File
@@ -529,6 +529,17 @@ pub enum ControlEvent {
failed: bool,
},
/// Nothing sends this. The variant, its encoding and the line
/// `tty7 events` would print for it all exist, and no code path anywhere
/// constructs one outside this file's own round-trip tests — so an agent
/// waiting on a pane-exit event waits for good.
///
/// A pane exiting *is* reported, as `Layout` carrying a `PaneFacts` delta
/// whose pane has `live: false`, which is what the docs now tell readers to
/// watch. Worth resolving one way or the other: either something emits this
/// where the pane is reaped, or it goes, and the `event_line` arm in
/// `tty7-cli` goes with it. Left in place because removing a variant from a
/// wire enum is a dialect change and this is not one to make in passing.
PaneExited {
pane_id: u64,
code: Option<i32>,
+24 -3
View File
@@ -213,9 +213,30 @@ while you watched.
### `tty7 events`
Streams server events until interrupted, one per line — pane exits, agent status
changes, workspace preemption, layout deltas. `--json` makes it NDJSON. Blocks
forever; run it with a timeout or in the background.
Streams server events until interrupted, one per line — layout changes, agent
status, workspace preemption. `--json` makes it NDJSON. Blocks forever; run it
with a timeout or in the background.
Each line is one externally tagged object, `{"<kind>": {…}}`:
| Kind | Payload |
|---|---|
| `layout` | `{"workspace","delta"}` — the bulk of the stream |
| `agent_status` | `{"pane_id","json"}` — whatever the agent's hooks reported |
| `preempted` | `{"workspace","by"}` — another client took the workspace |
| `layout_resync` | no payload; the tree moved in a way no delta describes, so re-read it |
`delta` is externally tagged the same way. The kinds are `workspace_created`,
`workspace_renamed`, `workspace_deleted`, `workspace_touched`,
`active_tab_changed`, `tab_created`, `tab_closed`, `tab_renamed`, `tab_moved`,
`tab_regrouped`, `tab_restructured`, `ratio_changed` and `pane_facts`.
<Note>
**A pane exiting is not its own event.** It arrives as a `layout` delta:
`pane_facts` carrying that pane with `"live": false`. Watch for that rather
than for a pane-exit line — there is no such line, whatever the shape of the
wire protocol suggests.
</Note>
### `tty7 status`