diff options
| author | blasty <peter@haxx.in> | 2026-09-29 13:55:30 +0200 |
|---|---|---|
| committer | blasty <peter@haxx.in> | 2026-09-29 13:55:30 +0200 |
| commit | 432a8e5f57b65d38a2a377a54994dd6b73216742 (patch) | |
| tree | 5e76ece8bbb9576b6ce3fe11074635073c115cea /tests | |
| parent | Offer a writable database location instead of failing the open (diff) | |
| download | ida-tui-432a8e5f57b65d38a2a377a54994dd6b73216742.tar.gz ida-tui-432a8e5f57b65d38a2a377a54994dd6b73216742.tar.xz ida-tui-432a8e5f57b65d38a2a377a54994dd6b73216742.zip | |
Spawn TUI panes in slosh, the multiplexer we actually use
`pane spawn` knew tmux and zellij, so under slosh every entry point
answered "error: not inside tmux or zellij" — the agent skill described a
workflow that could not run. slosh is now the first thing autodetected
($SLOSH, then $ZELLIJ, then $TMUX), and a slosh pane id is a bare integer,
so a registry row written before this commit still routes its own
stop/capture/keys.
Everything goes through the control socket, always the JSON form
($SLOSH_BIN -s $SLOSH_SESSION cmd): the bare-verb alias answers unwrapped,
and a parser written for one shape silently finds nothing in the other.
$SLOSH_BIN rather than `slosh` because a session may have been started
from a build tree that is not on $PATH.
Spawning is the one place slosh differs in kind. Its `split` verb only
ever makes a shell pane, and typing a command into somebody's shell is
the thing not to do — a pane that was *given* a command is the one with
alive/exit_code to poll and `rerun` to repeat. So spawn applies a one-tab
layout whose pane carries command= and a declared purpose=idatui:<hex>,
finds it by that purpose (declared purposes are locked, so the TUI cannot
relabel itself out from under us, and titles change anyway), then
move-panes it into the tab we were called from: it lands beside the
caller with its pty and scrollback intact, and the layout's now-empty tab
removes itself. --detached restores focus afterwards, since slosh focuses
what it creates and moves.
The rest follows the zellij precedent. A dead command pane stays on
screen as a husk, which _pane_alive must read as dead or a launcher that
died on startup would burn the whole 300s readiness timeout instead of
reporting "pane exited during startup". `capture` cuts the pane's
content_* rect out of `snapshot` (which is the whole composited session)
and hops tabs if the pane is parked in another one, because only the
active tab is composed at all. `keys` keeps taking tmux-flavoured names
and turns them into the bytes a terminal sends: it focuses the target,
writes with `raw`, and restores focus — `send` would be decoded as
session input first, where C-a is slosh's own leader and never reaches
the TUI. --size stays tmux-only and now says so for whichever mux is in
play.
The two RPC integration tests gated on $TMUX/$ZELLIJ, so they skipped
silently under slosh; they accept $SLOSH now.
Verified against the live session, not just in unit checks: a probe pane
spawns, reports alive, captures its own output, receives real keystrokes
and dies on close; `pane spawn --open targets/echo` reaches ready:true
with 128 functions, `drive where` answers, `pane keys Tab` flips listing
to pseudocode on screen, and `pane stop` leaves an empty registry and no
husk. Env inheritance is unchanged from zellij (a pane gets the session
server's environment, not the caller's) — the probe printed PROBE_VAR=[].
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_rawimage_rpc.py | 6 | ||||
| -rw-r--r-- | tests/test_trace_rpc.py | 6 |
2 files changed, 6 insertions, 6 deletions
diff --git a/tests/test_rawimage_rpc.py b/tests/test_rawimage_rpc.py index a6e7661..4e00b35 100644 --- a/tests/test_rawimage_rpc.py +++ b/tests/test_rawimage_rpc.py @@ -16,7 +16,7 @@ fall apart: This test spawns a real pane on a real Thumb blob and checks all three. -Requires: tmux or zellij, IDA (idalib). ~2min. +Requires: slosh or tmux, IDA (idalib). ~2min. ~/ida-venv/bin/python tests/test_rawimage_rpc.py """ @@ -96,8 +96,8 @@ def stop_pane(sock, timeout=60): def main() -> int: - if not os.environ.get("TMUX") and not os.environ.get("ZELLIJ"): - print("SKIP: not inside tmux or zellij (test spawns a pane)") + if not any(os.environ.get(v) for v in ("SLOSH", "TMUX", "ZELLIJ")): + print("SKIP: not inside slosh or tmux (test spawns a pane)") return 0 if not os.path.exists(BLOB): print(f"SKIP: no blob at {BLOB}") diff --git a/tests/test_trace_rpc.py b/tests/test_trace_rpc.py index 9b0f2e0..0baab22 100644 --- a/tests/test_trace_rpc.py +++ b/tests/test_trace_rpc.py @@ -7,7 +7,7 @@ every trace verb through the RPC socket, validating the JSON responses an agent would see. It exercises the serialization, the settle/timeout machinery, and the response shape that a driver depends on. -Requires: tmux or zellij, IDA (idalib), and a trace. Records a fresh trace with the QEMU +Requires: slosh or tmux, IDA (idalib), and a trace. Records a fresh trace with the QEMU tracer if built; falls back to /tmp/echotrace.0.log if present; skips with a message otherwise. @@ -105,8 +105,8 @@ def stop_pane(sock, timeout=60): def main() -> int: global PASS, FAIL - if not os.environ.get("TMUX") and not os.environ.get("ZELLIJ"): - print(" skip: not inside tmux or zellij (test spawns a pane)") + if not any(os.environ.get(v) for v in ("SLOSH", "TMUX", "ZELLIJ")): + print(" skip: not inside slosh or tmux (test spawns a pane)") return 0 with tempfile.TemporaryDirectory() as tmp: |
