From 5113760b943f7cea65999c9ca8a168f635f5ec5b Mon Sep 17 00:00:00 2001 From: Ben Tossell Date: Tue, 17 Feb 2026 14:58:19 -0500 Subject: [PATCH 1/3] arch: add baudbot attach and sessions commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit baudbot sessions — lists all tmux sessions and pi agent sessions under the baudbot_agent user, with running/stopped status. baudbot attach [name] — attaches to a tmux session. Defaults to the first available session if no name given. Useful for inspecting the slack-bridge or agent output. --- bin/baudbot | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/bin/baudbot b/bin/baudbot index 8beb868..bd218d7 100755 --- a/bin/baudbot +++ b/bin/baudbot @@ -48,6 +48,8 @@ usage() { echo " restart Restart the agent" echo " status Show agent status" echo " logs Tail agent logs" + echo " attach Attach to a tmux session (default: control-agent)" + echo " sessions List agent tmux and pi sessions" echo "" echo -e "${BOLD}Setup:${RESET}" echo " setup One-time system setup (user, deps, firewall, systemd)" @@ -144,6 +146,78 @@ case "${1:-}" in fi ;; + sessions) + shift + AGENT_USER="baudbot_agent" + echo -e "${BOLD}tmux sessions:${RESET}" + if sudo -u "$AGENT_USER" tmux ls 2>/dev/null; then + : + else + echo " (none)" + fi + echo "" + echo -e "${BOLD}pi sessions:${RESET}" + PI_SESSIONS_DIR="/home/$AGENT_USER/.pi/agent/sessions" + if [ -d "$PI_SESSIONS_DIR" ]; then + found=0 + for sess_dir in "$PI_SESSIONS_DIR"/*/; do + [ -d "$sess_dir" ] || continue + sess_id=$(basename "$sess_dir") + name="" + status="unknown" + # Check if control socket exists (session is live) + if [ -e "$sess_dir/control.sock" ]; then + status="running" + elif [ -f "$sess_dir/pid" ]; then + pid=$(cat "$sess_dir/pid" 2>/dev/null || echo "") + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + status="running" + else + status="stopped" + fi + else + status="stopped" + fi + # Try to read session name + if [ -f "$sess_dir/name" ]; then + name=$(cat "$sess_dir/name" 2>/dev/null || echo "") + fi + if [ -n "$name" ]; then + echo " $name ($sess_id) [$status]" + else + echo " $sess_id [$status]" + fi + found=$((found + 1)) + done + if [ "$found" -eq 0 ]; then + echo " (none)" + fi + else + echo " (no sessions directory)" + fi + ;; + + attach) + shift + AGENT_USER="baudbot_agent" + TARGET="${1:-}" + if [ -z "$TARGET" ]; then + # Default: attach to first available tmux session + FIRST_SESSION=$(sudo -u "$AGENT_USER" tmux ls -F '#{session_name}' 2>/dev/null | head -1) + if [ -n "$FIRST_SESSION" ]; then + TARGET="$FIRST_SESSION" + else + echo "No tmux sessions running. Start the agent first:" + echo " sudo baudbot start" + exit 1 + fi + fi + echo "Attaching to tmux session: $TARGET" + echo "Detach with: Ctrl+b, d" + echo "" + exec sudo -u "$AGENT_USER" tmux attach-session -t "$TARGET" + ;; + setup) shift require_root "setup" From ca6ad3be032793a220d3860b102d9811830d73b9 Mon Sep 17 00:00:00 2001 From: Ben Tossell Date: Tue, 17 Feb 2026 15:03:41 -0500 Subject: [PATCH 2/3] =?UTF-8?q?arch:=20address=20PR=20review=20=E2=80=94?= =?UTF-8?q?=20require=5Froot,=20help=20text,=20stale=20socket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add require_root guard to both sessions and attach commands - Fix help text: 'default: first available' not 'control-agent' - Fix stale socket false-positive: prefer pid file for liveness, fall back to socat socket probe, label stale sockets clearly --- bin/baudbot | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/bin/baudbot b/bin/baudbot index bd218d7..c8b99b3 100755 --- a/bin/baudbot +++ b/bin/baudbot @@ -48,7 +48,7 @@ usage() { echo " restart Restart the agent" echo " status Show agent status" echo " logs Tail agent logs" - echo " attach Attach to a tmux session (default: control-agent)" + echo " attach Attach to a tmux session (default: first available)" echo " sessions List agent tmux and pi sessions" echo "" echo -e "${BOLD}Setup:${RESET}" @@ -148,6 +148,7 @@ case "${1:-}" in sessions) shift + require_root "sessions" AGENT_USER="baudbot_agent" echo -e "${BOLD}tmux sessions:${RESET}" if sudo -u "$AGENT_USER" tmux ls 2>/dev/null; then @@ -165,16 +166,25 @@ case "${1:-}" in sess_id=$(basename "$sess_dir") name="" status="unknown" - # Check if control socket exists (session is live) - if [ -e "$sess_dir/control.sock" ]; then - status="running" - elif [ -f "$sess_dir/pid" ]; then + # Check if the session process is alive via pid file + if [ -f "$sess_dir/pid" ]; then pid=$(cat "$sess_dir/pid" 2>/dev/null || echo "") if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then status="running" else status="stopped" fi + elif [ -S "$sess_dir/control.sock" ]; then + # Socket exists but no pid file — try connecting + if command -v socat &>/dev/null; then + if socat -u OPEN:/dev/null UNIX-CONNECT:"$sess_dir/control.sock" 2>/dev/null; then + status="running" + else + status="stopped (stale socket)" + fi + else + status="unknown (no pid file)" + fi else status="stopped" fi @@ -199,6 +209,7 @@ case "${1:-}" in attach) shift + require_root "attach" AGENT_USER="baudbot_agent" TARGET="${1:-}" if [ -z "$TARGET" ]; then From b029f2a1f70fce32b42192cf4827c085e8afd889 Mon Sep 17 00:00:00 2001 From: Ben Tossell Date: Tue, 17 Feb 2026 15:13:58 -0500 Subject: [PATCH 3/3] arch: fix pi sessions to use session-control dir, not history logs The sessions command was looking in ~/.pi/agent/sessions/ (history logs as .jsonl files) and checking for pid/name files that pi doesn't create. All sessions would report as 'stopped'. Now reads ~/.pi/session-control/*.sock (where pi actually puts live control sockets). Resolves alias symlinks to show session names. Liveness check tries socat, falls back to python3 socket connect. --- bin/baudbot | 60 +++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/bin/baudbot b/bin/baudbot index c8b99b3..2db0e1c 100755 --- a/bin/baudbot +++ b/bin/baudbot @@ -158,39 +158,35 @@ case "${1:-}" in fi echo "" echo -e "${BOLD}pi sessions:${RESET}" - PI_SESSIONS_DIR="/home/$AGENT_USER/.pi/agent/sessions" - if [ -d "$PI_SESSIONS_DIR" ]; then + # Pi stores live session control sockets in ~/.pi/session-control/.sock + # Named sessions have symlinks: .sock → .sock + PI_CONTROL_DIR="/home/$AGENT_USER/.pi/session-control" + if [ -d "$PI_CONTROL_DIR" ]; then found=0 - for sess_dir in "$PI_SESSIONS_DIR"/*/; do - [ -d "$sess_dir" ] || continue - sess_id=$(basename "$sess_dir") - name="" - status="unknown" - # Check if the session process is alive via pid file - if [ -f "$sess_dir/pid" ]; then - pid=$(cat "$sess_dir/pid" 2>/dev/null || echo "") - if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then - status="running" - else - status="stopped" - fi - elif [ -S "$sess_dir/control.sock" ]; then - # Socket exists but no pid file — try connecting - if command -v socat &>/dev/null; then - if socat -u OPEN:/dev/null UNIX-CONNECT:"$sess_dir/control.sock" 2>/dev/null; then - status="running" - else - status="stopped (stale socket)" - fi - else - status="unknown (no pid file)" - fi - else - status="stopped" + # Collect alias symlinks: name → uuid + declare -A ALIASES + for sock in "$PI_CONTROL_DIR"/*.sock; do + [ -e "$sock" ] || continue + base=$(basename "$sock" .sock) + if [ -L "$sock" ]; then + # Symlink = alias. Resolve target to get the uuid. + target=$(readlink "$sock") + target_uuid=$(basename "$target" .sock) + ALIASES[$target_uuid]="$base" fi - # Try to read session name - if [ -f "$sess_dir/name" ]; then - name=$(cat "$sess_dir/name" 2>/dev/null || echo "") + done + # List actual sockets (non-symlinks) + for sock in "$PI_CONTROL_DIR"/*.sock; do + [ -e "$sock" ] || continue + [ -L "$sock" ] && continue # skip alias symlinks + sess_id=$(basename "$sock" .sock) + name="${ALIASES[$sess_id]:-}" + # Liveness check: try connecting to the socket + status="stopped (stale)" + if sudo -u "$AGENT_USER" bash -c "echo '' | socat - UNIX-CONNECT:'$sock' 2>/dev/null" 2>/dev/null; then + status="running" + elif sudo -u "$AGENT_USER" bash -c "python3 -c \"import socket; s=socket.socket(socket.AF_UNIX); s.settimeout(0.3); s.connect('$sock'); s.close()\" 2>/dev/null" 2>/dev/null; then + status="running" fi if [ -n "$name" ]; then echo " $name ($sess_id) [$status]" @@ -203,7 +199,7 @@ case "${1:-}" in echo " (none)" fi else - echo " (no sessions directory)" + echo " (no session-control directory)" fi ;;