Nesting prevention: refuse client-inside-a-client for attach, interactive, restart-then-attach, and run -a when target is running
Request from pty-layout-claude: every pty-layout pane runs a shell
with PTY_SESSION set, so commands that silently started a nested pty
client routed detach keybindings to the outer client and left users
tangled with no clean way to exit.
New helper ensureNotNested(cmd, { force?, hint? }) in cli.ts. Called
from:
- pty attach / pty a / pty attach -r: refuse early (before
resolveRef) so even a mistyped ref yields the nesting hint instead
of a "not found" error. Hint mentions Ctrl+\\ to detach and pty-
layouts ^]n picker.
- pty restart <ref>: restart still runs (its independent of attach),
but the trailing doAttach is skipped and a one-line "(not attached:
already inside pty session X)" notice prints. -y / --yes still
skips the kill-confirm prompt; --force restores restart+attach.
- pty / pty i / pty interactive: refuse to open the TUI picker;
picker rendering inside a session with broken detach was the worst
footgun of the bunch.
- pty run -a: narrows the existing "already inside pty session,
running directly" behavior — if the target is already running,
refuse rather than silently dropping -a. Target-not-running case
keeps the run-directly behavior; -a is a no-op in that situation
anyway.
--force across all four to opt back into the old behavior (nested
clients are occasionally intentional: debugging, screen-sharing
demos).
Latent test-harness bug surfaced by the guard: Session.spawn
(@myobie/pty/testing) was leaking the harness's own PTY_SESSION into
the child env, so every interactive-TUI test in tui.test.ts tripped
the new guard. Scrub PTY_SESSION alongside the existing
PTY_SERVER_CONFIG scrubbing so Session.spawn simulates a clean user
shell regardless of what the harness is running inside.