diff --git a/cmux-tui/spec/commands.md b/cmux-tui/spec/commands.md index 578d9445e7ee..59f54f4b4d47 100644 --- a/cmux-tui/spec/commands.md +++ b/cmux-tui/spec/commands.md @@ -147,7 +147,7 @@ Size-aware creation commands are `apply-layout`, `new-tab`, `new-browser-tab`, ` | --- | --- | | both `cols` and `rows` supplied | Clamp each to `1..10000`, use the pair for the new surface or surfaces, and record the effective grid as the latest client size | | neither supplied | Use the latest active client size, or the configured server default when no client reports remain | -| only one supplied | Preserve protocol-v6 behavior: the incomplete pair is ignored; clients must always send both | +| only one supplied | Optional-size commands ignore the incomplete pair. `create-terminal`, `create-surface-with-receipt`, and `attach-surface` are strict exceptions: they return an error and require `cols` and `rows` together. | `resize-surface` requires both fields and clamps each to `1..10000`. Attached clients retain the report until release; an unattached one-shot report is @@ -2847,7 +2847,13 @@ Errors: | status | implemented | | since | protocol 5 | -Moves an existing tab, identified by `surface`, into `pane` at zero-based `index`. Moving a tab to its current pane and current index is an `ok:true` no-op. This command is documented from the consumer-side landed contract; it is not present in this branch's `server.rs`, so out-of-range index behavior and event emission could not be verified here. +Moves an existing tab, identified by `surface`, into `pane` at zero-based `index`. +The server clamps an out-of-range destination index to the end. For a same-pane +move, the index is interpreted after removing the tab, so an index after the +current position is reduced by one. Moving a tab to its current position is an +`ok:true` no-op and leaves the active tab unchanged. A cross-pane move removes +the tab from its source, collapses an empty source pane, and inserts it at the +clamped destination index. Params: @@ -2867,10 +2873,8 @@ Errors: | Error | Condition | | --- | --- | -| `unknown surface ` | Surface id does not exist | -| `unknown pane ` | Destination pane does not exist | +| `unknown surface/pane` | The surface, destination pane, or the surface's current pane does not exist | | `bad request: ...` | Missing fields or wrong JSON type | -| unverified error string | Non-same-position out-of-range index behavior could not be checked in this branch | CLI mapping: diff --git a/cmux-tui/spec/events.md b/cmux-tui/spec/events.md index 514c6974def8..f5b56e006864 100644 --- a/cmux-tui/spec/events.md +++ b/cmux-tui/spec/events.md @@ -138,7 +138,12 @@ Payload: object{event:"client-attached",client:uint64,transport:"unix"|"ws",name:string|null,kind:string|null} ``` -Meaning: A control connection attached its first surface. A connection that never calls `attach-surface` does not emit this event, and later surfaces on the same connection do not emit it again. Use `list-clients` for the attached surface set and sizes. +Meaning: The server emits this once when the control connection commits its +first attach stream, whether it comes from the legacy `attach-surface` command +or a resource `terminal.attach` or `browser.attach` operation. A connection +with no committed attachment does not emit it, and later streams or surfaces +on the same connection do not emit it again. Use `list-clients` for the +authoritative attached-surface set and reported sizes. Example: @@ -182,7 +187,9 @@ Payload: object{event:"client-detached",client:uint64} ``` -Meaning: A control connection disconnected naturally or was ended by `detach-client`. This is emitted even if the connection never attached a surface. +Meaning: The server emits this once when it removes a control connection, +whether the connection ended naturally or through `detach-client`. It is +emitted even when the connection never attached a surface. Example: diff --git a/cmux-tui/spec/inventory.json b/cmux-tui/spec/inventory.json index 8ef2558020c4..f60ab0fcdd17 100644 --- a/cmux-tui/spec/inventory.json +++ b/cmux-tui/spec/inventory.json @@ -1131,7 +1131,7 @@ "id": "terminal-rendering", "wire_status": "partial", "programmability": "partial", - "route": "render attach is implemented; terminal-host-v1 resize replay is incompatible until its decoder is repaired; typed SDK parity is incomplete" + "route": "render attach is implemented; terminal-host-v4 resize replay supports negotiated v1-v4 payloads; typed SDK parity is incomplete" }, { "id": "terminal-selection-search-history", @@ -1386,8 +1386,8 @@ "spec": "events.md" }, { - "id": "terminal-host-v1", - "status": "partial", + "id": "terminal-host-v4", + "status": "implemented", "spec": "terminal-host.md" }, { diff --git a/cmux-tui/spec/programmability.md b/cmux-tui/spec/programmability.md index d0d8c6f72f57..f56cae7ea58c 100644 --- a/cmux-tui/spec/programmability.md +++ b/cmux-tui/spec/programmability.md @@ -58,7 +58,7 @@ The implemented v10 inventory is complete as a description of current wire behav | TUI presentation | State stays inside one frontend | `register-frontend`, `describe-frontend-actions`, `invoke-frontend-action`, and `frontend-action-result` | | PTY keyboard | `send-key` emits semantic keyboard input for PTYs | Preserve this route and add negotiated key capability discovery | | PTY mouse and focus | Native TUI encodes mouse/focus bytes locally | `send-mouse` and `send-focus`, with current terminal modes in render state | -| Terminal-host resize | The host produces a length-prefixed replay, while the current consumer includes that length word in replay bytes | Repair the decoder, add producer-consumer and cross-language fixtures, then promote terminal-host v1 from partial | +| Terminal-host resize | The terminal-host v4 decoder accepts the negotiated v1-v4 payload layouts, including the length-prefixed replay and version-specific Kitty state | Keep producer-consumer and cross-language fixtures current, and complete typed SDK coverage before promoting this family to complete | | PTY selection | Native selection is frontend-local and `copy selection` cannot reconstruct it remotely | `extract-text` by absolute range; optional frontend-local selection adapter | | Terminal search | Clients page scrollback and search themselves | Cursor-based `search-scrollback` with revision and match ranges | | Process outcome | `terminal.process.get`, `terminal.wait_exit`, and `TerminalSnapshot.exit` expose one durable child outcome per terminal | Separate execution IDs and lifecycle events for multiple sequential processes in one terminal | @@ -101,7 +101,7 @@ The inventory assigns each command to one disjoint authority group. Generated SD | `local-admin` | `control` plus the `local-admin` group on a trusted Unix-classified transport, including the current stdio relay | | `provider-authority` | `control` plus the `provider-authority` group after separate authority authentication | | `machine-provider` | Separate provider v0/v1 client and server types | -| `terminal-renderer` | Separate terminal-host v1 frame types with a minted capability | +| `terminal-renderer` | Separate terminal-host v4 frame types with a minted capability; legacy v1-v3 negotiation remains supported | An SDK must refuse a profile when the selected transport cannot satisfy its trust boundary.