Skip to content

feat(ipc): Attach stops kicking other clients and resizes in place - #309

Merged
afitzgerald merged 1 commit into
mainfrom
alan/attach-resize-no-kick
Sep 30, 2026
Merged

afitzgerald merged 1 commit into
mainfrom
alan/attach-resize-no-kick

Conversation

@afitzgerald

Copy link
Copy Markdown
Collaborator

Two backward-compatible changes to the core's Attach (contract: docs/wire-protocol.md), matching an iPhone client change in moomux-mac.

1. Don't kick other clients

Attach ran tmux attach -d, which detached the Mac app's pane (and any other client) every time the phone attached. -d is gone; tmux's default window-size latest follows whoever typed last. EnsureTmux, TERM=xterm-256color and the TMUX/TMUX_PANE stripping are unchanged.

2. Resize a live attach instead of reattaching

  • A successful attach's single response line now carries a token: {"result":{"ok":true,"attach":"<32 hex chars>"}} (128 random bits). It is valid only while that attach connection is open.
  • New one-shot method ResizeAttach {"attach":"<token>","cols":N,"rows":M} calls pty.Setsize on that attach's pty (same 80x24 floor as Attach) and returns {"result":{"ok":true}}, or err: "unknown attach" for a token that isn't live. It goes through dispatch, so it follows the same listener/auth rules as every other method, tailnet included.
  • Old clients ignore the extra result key. New clients fall back to reattaching when attach is absent or ResizeAttach fails.
  • Go client: Attachment.Token and Client.ResizeAttach.

Tests

  • TestAttachKeepsEveryByteWrittenBehindTheResponseLine now sends a token and checks it's parsed without moving the response-line/pty split.
  • TestResizeAttachSetsTheLivePtySize (unit, real pty): resize, the 80x24 floor, token format, and unknown attach for a dead or empty token.
  • e2e TestAttachIsAPtyOverTheWire: resize to 70 columns reaches the tmux window; the token returns unknown attach after close.
  • e2e TestAttachDoesNotDetachOtherClients: two attaches give two tmux clients, and both stay attached.

Each new test fails when its fix is reverted. go test ./... -race -shuffle=on and go test -tags e2e ./e2e/... -race -shuffle=on both pass locally.

session.Session is untouched. The only thing the Swift side sees is the new optional attach key.

Attach ran `tmux attach -d`, so the phone attaching detached the Mac app's
pane (and any other client). Drop -d: tmux's default window-size latest
follows whoever typed last, so neither front end needs to kick the other.

The pty size was also fixed at attach time, so the phone reattached (and
redrew the pane from scratch) whenever the software keyboard showed or it
rotated. A successful Attach now returns an `attach` token in its one
response line, and the new one-shot ResizeAttach method sets that live
attach's pty size by token. The token is forgotten when the attach closes.

Both are backward compatible: old clients ignore the extra result key, and
new clients fall back to reattaching when `attach` is absent or
ResizeAttach fails.
@afitzgerald
afitzgerald merged commit 364223a into main Sep 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant