docs(cli): say what attach, ATTACHED and tab move INDEX actually do

Found by driving a dev instance with the CLI rather than by reading, which is
the only way any of these would have surfaced.

`ws attach` is documented as "become its controlling client", and the CLI
cannot be one: the claim belongs to the connection that made it and the
connection ends when the command does, so `tty7 ls` reads unattached again the
moment it returns. Its real and only lasting effect is displacing whoever held
it — which is exactly what the human output says (`took over from HOST`) and
what the docs never did.

`ATTACHED` said it names "a GUI window, or another client". A GUI only claims a
workspace it is showing as a *remote* one; a window on a workspace of its own
machine claims nothing, because there is no second client to arbitrate against.
So with a window sitting on it `tty7 ls` prints `-`, and the column read as
"nothing has this open" when it means "no remote client holds this".

`tab move @TAB INDEX` never said which end `INDEX` counts from. It is 0-based —
beside an `@N` address that is 1-based, on the same command line — so
`tab move @1 2` moves the first tab to the third slot. Verified against a
running server: `@1 0` leaves it, `@1 1` puts it second, past the end clamps to
last the way `split --ratio` already documents. `to` in the JSON echoes the
number you asked for rather than where the tab landed, which is worth saying
since the clamp makes those differ.

Also records why `WorkspaceDetach` throws away the one thing it computes: the
reply has always been `Unit`, and the dialect is spoken to whatever build was
pushed to a remote machine, so widening it to `Bool` would break every server
already out there.

2932 tests pass.
This commit is contained in:
l0ng-ai
2026-08-15 18:11:17 +08:00
parent e530d5f778
commit a5229e18fa
2 changed files with 34 additions and 4 deletions
+25 -3
View File
@@ -58,8 +58,13 @@ GUI on *this* machine.
Same as `ws ls`. Table: `WORKSPACE NAME TABS PANES ATTACHED`.
JSON: `{"workspaces":[{"id","name","tabs","panes","attached"}]}`.
`ATTACHED` names the host holding the workspace — a GUI window, or another
client — and is `-` when nobody is.
`ATTACHED` names the client that has *claimed* the workspace over a control
link, and a claim lasts exactly as long as that client's link. A GUI claims a
workspace it is showing as a **remote** one; a GUI window on a workspace of its
own machine does not claim anything, because there is no second client to
arbitrate against. So `-` for a local workspace means "no remote client holds
this", not "nothing has it open" — with a window sitting on it, `tty7 ls` still
prints `-`.
### `tty7 run [--keep] [--cwd DIR] [--ws WORKSPACE] -- CMD...`
@@ -243,9 +248,19 @@ candidates.
| `ws new [NAME]` | An empty workspace (no tab, no pane) | `{"id","name"}` |
| `ws rename WORKSPACE NAME` | Name or rename | `{"id","name"}` |
| `ws rm WORKSPACE` | Delete the workspace and hang up its panes | `{"removed"}` |
| `ws attach WORKSPACE` | Become its controlling client | `{"attached","took_over_from"}` |
| `ws attach WORKSPACE` | Take it back from whoever holds it | `{"attached","took_over_from"}` |
| `ws detach WORKSPACE` | Let go without interrupting anything | `{"detached"}` |
`ws attach` is a takeover, not a subscription: the claim belongs to the
connection that made it, and the CLI's connection ends when the command does.
So it prints `took over from HOST` when it displaced someone and nothing when
it did not, and either way the workspace reads as unattached again immediately
afterwards. Displacing the holder is the whole of what it does from here —
staying attached is a thing only a client that keeps its link open can do.
For the same reason `ws detach` reports `{"detached"}` whether or not there was
a claim to release: it says "you do not hold this", which was already true.
<Warning>
`ws rm` hangs up the panes the workspace held. If the command reports that
some panes could not be hung up, they keep running as orphans with no
@@ -274,6 +289,13 @@ resolve it immediately before use. A full tab UUID also works: `@<uuid>`.
| `tab rename @TAB NAME` | Name or rename | `{"tab","name"}` |
| `tab move @TAB INDEX` | Reposition within its workspace | `{"tab","to"}` |
`INDEX` counts from **0**, unlike the `@N` address beside it — `tab move @1 0`
leaves the first tab where it is, and `tab move @1 1` puts it second. It is a
position in the workspace's own tab list, not an `@N`, so it does not move a tab
between workspaces. Past the end it clamps to last rather than failing, the way
`split --ratio` does; `to` in the JSON echoes the number you asked for, so read
the position back from `tab ls` rather than from the reply.
`GROUP` is the heading the GUI's sidebar files the tab under, shown by its last
segment. Read-only from here: with the default repo grouping the GUI recomputes
it from the tab's working directory.