@@ -48,6 +48,8 @@ usage() {
4848 echo " restart Restart the agent"
4949 echo " status Show agent status"
5050 echo " logs Tail agent logs"
51+ echo " attach Attach to a tmux session (default: first available)"
52+ echo " sessions List agent tmux and pi sessions"
5153 echo " "
5254 echo -e " ${BOLD} Setup:${RESET} "
5355 echo " setup One-time system setup (user, deps, firewall, systemd)"
@@ -144,6 +146,85 @@ case "${1:-}" in
144146 fi
145147 ;;
146148
149+ sessions)
150+ shift
151+ require_root " sessions"
152+ AGENT_USER=" baudbot_agent"
153+ echo -e " ${BOLD} tmux sessions:${RESET} "
154+ if sudo -u " $AGENT_USER " tmux ls 2> /dev/null; then
155+ :
156+ else
157+ echo " (none)"
158+ fi
159+ echo " "
160+ echo -e " ${BOLD} pi sessions:${RESET} "
161+ # Pi stores live session control sockets in ~/.pi/session-control/<uuid>.sock
162+ # Named sessions have symlinks: <name>.sock → <uuid>.sock
163+ PI_CONTROL_DIR=" /home/$AGENT_USER /.pi/session-control"
164+ if [ -d " $PI_CONTROL_DIR " ]; then
165+ found=0
166+ # Collect alias symlinks: name → uuid
167+ declare -A ALIASES
168+ for sock in " $PI_CONTROL_DIR " /* .sock; do
169+ [ -e " $sock " ] || continue
170+ base=$( basename " $sock " .sock)
171+ if [ -L " $sock " ]; then
172+ # Symlink = alias. Resolve target to get the uuid.
173+ target=$( readlink " $sock " )
174+ target_uuid=$( basename " $target " .sock)
175+ ALIASES[$target_uuid ]=" $base "
176+ fi
177+ done
178+ # List actual sockets (non-symlinks)
179+ for sock in " $PI_CONTROL_DIR " /* .sock; do
180+ [ -e " $sock " ] || continue
181+ [ -L " $sock " ] && continue # skip alias symlinks
182+ sess_id=$( basename " $sock " .sock)
183+ name=" ${ALIASES[$sess_id]:- } "
184+ # Liveness check: try connecting to the socket
185+ status=" stopped (stale)"
186+ if sudo -u " $AGENT_USER " bash -c " echo '' | socat - UNIX-CONNECT:'$sock ' 2>/dev/null" 2> /dev/null; then
187+ status=" running"
188+ 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
189+ status=" running"
190+ fi
191+ if [ -n " $name " ]; then
192+ echo " $name ($sess_id ) [$status ]"
193+ else
194+ echo " $sess_id [$status ]"
195+ fi
196+ found=$(( found + 1 ))
197+ done
198+ if [ " $found " -eq 0 ]; then
199+ echo " (none)"
200+ fi
201+ else
202+ echo " (no session-control directory)"
203+ fi
204+ ;;
205+
206+ attach)
207+ shift
208+ require_root " attach"
209+ AGENT_USER=" baudbot_agent"
210+ TARGET=" ${1:- } "
211+ if [ -z " $TARGET " ]; then
212+ # Default: attach to first available tmux session
213+ FIRST_SESSION=$( sudo -u " $AGENT_USER " tmux ls -F ' #{session_name}' 2> /dev/null | head -1)
214+ if [ -n " $FIRST_SESSION " ]; then
215+ TARGET=" $FIRST_SESSION "
216+ else
217+ echo " No tmux sessions running. Start the agent first:"
218+ echo " sudo baudbot start"
219+ exit 1
220+ fi
221+ fi
222+ echo " Attaching to tmux session: $TARGET "
223+ echo " Detach with: Ctrl+b, d"
224+ echo " "
225+ exec sudo -u " $AGENT_USER " tmux attach-session -t " $TARGET "
226+ ;;
227+
147228 setup)
148229 shift
149230 require_root " setup"
0 commit comments