Skip to content

fix(terminal): read pty client identity via list-clients instead of display-message -c#165

Open
0x79H wants to merge 1 commit into
gbasin:masterfrom
0x79H:fix/pty-switch-verify
Open

fix(terminal): read pty client identity via list-clients instead of display-message -c#165
0x79H wants to merge 1 commit into
gbasin:masterfrom
0x79H:fix/pty-switch-verify

Conversation

@0x79H

@0x79H 0x79H commented Jul 22, 2026

Copy link
Copy Markdown

Fixes #161.

What

display-message -p -c <tty> expands formats against the most-recently-active client's session, not the -c client (verified on tmux 3.4 and 3.5a — minimal repro in the issue). This made pty-mode switch verification report false ERR_TMUX_SWITCH_FAILED whenever any other tmux client on the server was more recently active — i.e. whenever the user also uses tmux locally while agentboard is open.

readClientIdentity() now enumerates list-clients -F '#{client_tty}\t#{session_name}\t#{window_id}' and picks the row matching our client tty — the same approach discoverClientTty() already relies on. Rows that don't parse (e.g. control-mode clients with an empty tty) are skipped. No other behavior change.

Test changes

The spawn harness in isolated/terminalProxy.test.ts needed two deliberate changes (context in this comment on #161):

  • Harness fidelity: the mock's display-message -c branch replays the last switch-client target — it implements the semantics the production code assumed, which is how this bug survived with all unit tests green. The list-clients branch now answers per requested -F format like real tmux does. No existing assertion was loosened; all 12 prior test cases are unchanged and still pass.
  • New regression test: switchTo verifies against our own client when another client is more recently active — the harness lists a foreign, more recently active client first, the exact condition that fooled display-message -p -c. Sanity-checked by mutation: this test fails against master's implementation, as intended.

Verification

  • Container (Debian trixie, tmux 3.5a, non-root, HOSTNAME=127.0.0.1): full suite including the real-tmux integration layer that CI skips — green; coverage mode and vite build also pass.
  • Host (Ubuntu 24.04, tmux 3.4): reproduced the original end-to-end failure before the fix; gone after.
  • The underlying tmux behavior was verified identical on 3.4 and 3.5a, so the fix needs no version gate (list-clients -F is available on all supported versions, including the 3.2a from PTY mode fails on tmux 3.2a with ERR_TMUX_SWITCH_FAILED and display-message usage error #156).

Feel free to rework or take this over entirely — happy either way.

…isplay-message -c

- display-message -p -c expands formats against the most recently
  active client's session, not the -c client (verified on tmux 3.4
  and 3.5a), causing false ERR_TMUX_SWITCH_FAILED whenever another
  tmux client on the server was more recently active
- resolve the identity from list-clients -F filtered by client_tty,
  the same approach discoverClientTty already uses
- teach the spawn harness to answer list-clients per requested
  format like real tmux (its display-message -c mock implemented
  the semantics the code assumed, which is how this survived the
  unit tests), and add a regression test where a foreign client is
  the most recently active one
spawnSyncCalls.push({ args, options: _options })
const command = getTmuxCommand(args)
if (command === 'list-clients') {
// Real tmux expands list-clients formats per client, so answer by the

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old canned two-field reply here is what made this harness assert the wrong reality: combined with the display-message -c branch below (which replays the last switch-client target), the fake tmux behaved exactly as the production code assumed — so the bug in #161 was invisible to these tests. Answering per requested format matches what real list-clients does; none of the existing assertions changed.

expect(proxy.getCurrentWindow()).toBe('@2')
})

test('switchTo verifies against our own client when another client is more recently active', async () => {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regression tripwire for #161: the foreign client is listed first and is the most recently active — the row display-message -p -c semantics would pick. Verified by mutation: this test fails against master's implementation.

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.

PTY mode: switch verification reads the wrong client identity — false ERR_TMUX_SWITCH_FAILED whenever another tmux client is more recently active

1 participant