mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 02:49:33 +01:00
fix: apply the review items for #688 at merge
disarmTuiSwitchGuard matches the closed `#{client_tty},<tty>}` form, so a TUI on /dev/pts/4 no longer removes the hook armed for a second TUI on /dev/pts/41 (unit test plus a real-tmux case)
beginAttachHandoff arms the one-shot attach hook as its last tmux call before spawnSync, after the switch keys and the per-session dressing loop, with an order assertion in tui-app.test.ts and a sentence in the invariants paragraph
docs/remote-sessions.md and the buildRemoteLaunchCommand JSDoc show `remain-on-exit failed` at the end of the remote create chain
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
9fc2773176
commit
311d01c52b
8 files changed
+69
-10
No files matched your search
+1
-1
@@ -1231,7 +1231,7 @@ export function remoteTmuxLocation(remote: SessionRemote, sessionId: string): {
|
||||
* \; set -t codeman-ssh-<id> status off \; set -t codeman-ssh-<id> mouse off \
|
||||
* \; set -t codeman-ssh-<id> prefix C-q \; set -s escape-time 0 \; \
|
||||
* bind-key -T prefix C-q send-prefix \; unbind-key -a -T prefix \; \
|
||||
* bind-key -T prefix C-q send-prefix'
|
||||
* bind-key -T prefix C-q send-prefix \; set -t codeman-ssh-<id> remain-on-exit failed'
|
||||
*
|
||||
* COD-107 — the connection options (`-p`, `-i`, `-J`, SOCKS `-o ProxyCommand`,
|
||||
* arbitrary `-o`) come from the shared `buildSshConnectionArgs(remote)`, so the
|
||||
|
||||
+12
-3
@@ -603,9 +603,9 @@ export async function beginAttachHandoff(
|
||||
const tty = clientTty === undefined ? readControllingTty() : clientTty || null;
|
||||
const switchTabs = tabs.slice(0, 9).filter((tab) => tab.index >= 1 && tab.index <= 9 && tab.muxName);
|
||||
const guarded = Boolean(tty && isTuiClientTty(tty));
|
||||
if (!guarded) {
|
||||
for (let index = 1; index <= 9; index++) await client.unbindSwitchKey(`M-${index}`, '');
|
||||
} else if (switchTabs.length > 0 && (await client.armTuiSwitchGuard(tty as string))) {
|
||||
// The keys are bound here but stay inert until the attach hook records this
|
||||
// client's pid, and that hook is armed at the very end (see below).
|
||||
if (guarded && switchTabs.length > 0) {
|
||||
for (let index = 1; index <= 9; index++) await client.unbindSwitchKey(`M-${index}`);
|
||||
for (const tab of switchTabs) {
|
||||
const key = `M-${tab.index}`;
|
||||
@@ -660,6 +660,15 @@ export async function beginAttachHandoff(
|
||||
if (cols && rows && rows > 1) await client.presizeWindow(target, cols, rows - 1);
|
||||
if (target === muxName) await client.followAttachingClient(target);
|
||||
}
|
||||
// ⚠️ Armed LAST, as the final tmux call before the caller's `spawnSync`. The
|
||||
// hook is one-shot for this tty, so a TUI killed between arming and attaching
|
||||
// leaves it armed, and Linux hands the lowest free pty to the next opener: a
|
||||
// browser tab's attach client could land on this tty and have its pid
|
||||
// recorded, which would make these keys move that tab. Arming after the
|
||||
// dressing loop above shrinks that window to the attach's own startup. A
|
||||
// failed arm leaves the keys inert (the closed direction), and `restore()`
|
||||
// still unbinds them.
|
||||
if (switchKeys.length > 0) await client.armTuiSwitchGuard(tty as string);
|
||||
return {
|
||||
chord: oneKey ? ONE_KEY_DETACH : fallbackDetachChord(prefix, detachKey, claimed && alias ? alias : undefined),
|
||||
async restore(): Promise<void> {
|
||||
|
||||
@@ -1111,7 +1111,10 @@ export class TuiClient {
|
||||
try {
|
||||
const { stdout } = await this.exec('tmux', ['-L', this.socket, 'show-hooks', '-g']);
|
||||
const hook = stdout.split('\n').find((line) => line.startsWith(`${TUI_SWITCH_ATTACH_HOOK} `));
|
||||
if (hook?.includes(clientTty)) {
|
||||
// The closed form, not the bare tty: `/dev/pts/4` is a substring of a
|
||||
// hook armed for `/dev/pts/41`, and removing that one would leave the
|
||||
// second TUI's Alt keys dead for its whole attach.
|
||||
if (hook?.includes(`#{client_tty},${clientTty}}`)) {
|
||||
await this.exec('tmux', ['-L', this.socket, 'set-hook', '-gu', TUI_SWITCH_ATTACH_HOOK]);
|
||||
}
|
||||
} catch {
|
||||
|
||||
Reference in new issue
Block a user