#!/usr/bin/env bash # resume_session.sh — resume a stopped session set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LIB_SH="$(cd "$SCRIPT_DIR/../.." && pwd)/lib.sh" [ -f "$LIB_SH" ] || LIB_SH="${WORKSPACE_ROOT:-$PWD}/.agents/skills/lib.sh" source "$LIB_SH" usage() { cat < --agent --session [options] Options: --herdr-session NAME specify isolated herdr session name (alias: --herdr-server) --dry-run Simulates resume flow (resolves binary, environment) without writing any updates to YAML or DB. Safe to execute inside active write transactions. EOF } WORKSPACE="" AGENT="" SESSION_NAME="" HERDR_SERVER_OPT="" HERDR_WORKSPACE_OPT="" DRY_RUN=0 while [ $# -gt 0 ]; do case "$1" in --workspace) WORKSPACE="$2"; shift 2 ;; --agent) AGENT="$2"; shift 2 ;; --session) SESSION_NAME="$2"; shift 2 ;; --herdr-session|--herdr-server) HERDR_SERVER_OPT="$2"; shift 2 ;; --herdr-workspace) HERDR_WORKSPACE_OPT="$2"; shift 2 ;; --dry-run) DRY_RUN=1; shift ;; -h|--help) usage; exit 0 ;; *) echo "ERROR: unknown arg: $1" >&2; exit 2 ;; esac done [ -n "$WORKSPACE" ] || { echo "ERROR: --workspace required" >&2; exit 2; } [ -n "$AGENT" ] || { echo "ERROR: --agent required" >&2; exit 2; } case "$AGENT" in claude|agy|hermes|cline) ;; *) echo "ERROR: unsupported agent: $AGENT" >&2; exit 2 ;; esac [ -n "$SESSION_NAME" ] || { echo "ERROR: --session required" >&2; exit 2; } # 1. Resolve the session id UUID=$(bash "$(dirname "${BASH_SOURCE[0]}")/resolve_session_id.sh" \ --workspace "$WORKSPACE" --agent "$AGENT" --session "$SESSION_NAME") if [ -z "$UUID" ]; then echo "ERROR: No saved session for $WORKSPACE ($AGENT). Use multi-agent-mux-create first." >&2 exit 1 fi if [ -n "$HERDR_SERVER_OPT" ]; then export HERDR_SESSION_NAME="$HERDR_SERVER_OPT" else HERDR_SESSION_NAME="$(resolve_herdr_session "$SESSION_NAME" "$WORKSPACE")" export HERDR_SESSION_NAME fi if [ -n "$HERDR_WORKSPACE_OPT" ]; then export MAM_WS_LABEL="$HERDR_WORKSPACE_OPT" else export MAM_WS_LABEL="$(resolve_herdr_workspace "$SESSION_NAME" "$WORKSPACE")" fi # 2. If herdr is alive, print warning or attach. if herdr has-session -t "$SESSION_NAME" 2>/dev/null; then if [ "${DRY_RUN:-0}" = "1" ]; then echo "[dry-run] herdr '$SESSION_NAME' already running — nothing to validate" exit 0 fi echo "herdr '$SESSION_NAME' already running." # Just update YAML to make sure it's set to running bash "$(dirname "${BASH_SOURCE[0]}")/update_yaml_resumed.sh" \ --session "$SESSION_NAME" --uuid "$UUID" --agent "$AGENT" --workspace "$WORKSPACE" \ --herdr-session "$HERDR_SESSION_NAME" \ ${HERDR_WORKSPACE_OPT:+--herdr-workspace "$HERDR_WORKSPACE_OPT"} exit 0 fi # Resolve absolute path of the agent command to prevent herdr PATH inheritance issues (especially on macOS) RESOLVED_BIN="$AGENT" if [ "$AGENT" = "cline" ]; then if command -v cline >/dev/null 2>&1; then RESOLVED_BIN="$(command -v cline)" fi else if command -v "$AGENT" >/dev/null 2>&1; then RESOLVED_BIN="$(command -v "$AGENT")" fi fi # On macOS, clear quarantine attribute for the agent binary to prevent Gatekeeper hangs if [ "$(uname)" = "Darwin" ] && [ -f "$RESOLVED_BIN" ]; then xattr -d com.apple.quarantine "$RESOLVED_BIN" 2>/dev/null || true fi # Determine CMD_FULL via adapter CMD_FULL="$("$(_delegate_py_bin)" -m lib_py.agents resume-spec "$AGENT" "$RESOLVED_BIN" "$UUID" "$WORKSPACE" 2>/dev/null || true)" if [ -z "$CMD_FULL" ]; then case "$AGENT" in claude) CMD_FULL="${RESOLVED_BIN} --dangerously-skip-permissions -r $UUID" ;; agy) CMD_FULL="${RESOLVED_BIN} --dangerously-skip-permissions --conversation $UUID" ;; hermes) CMD_FULL="${RESOLVED_BIN} --resume $UUID" ;; cline) CMD_FULL="${RESOLVED_BIN} -i --id $UUID" ;; grok) CMD_FULL="${RESOLVED_BIN} --resume $UUID --permission-mode bypassPermissions" ;; *) echo "ERROR: unsupported agent: $AGENT" >&2; exit 2 ;; esac fi # Validate binary exists and is executable if [ -f "$RESOLVED_BIN" ] || [[ "$RESOLVED_BIN" == /* ]] || [[ "$RESOLVED_BIN" == ~/* ]]; then if [ ! -x "$RESOLVED_BIN" ]; then echo "ERROR: Agent binary is not executable: $RESOLVED_BIN" >&2 exit 1 fi else if ! command -v "$RESOLVED_BIN" >/dev/null 2>&1; then echo "ERROR: Agent binary not found in PATH: $RESOLVED_BIN" >&2 exit 1 fi fi if [ "${DRY_RUN:-0}" = "1" ]; then echo "[dry-run] would spawn: $CMD_FULL" exit 0 fi # 4. Spawn new agent session (delegates to herdr translation shim) _herdr new-session -d -s "$SESSION_NAME" -c "$WORKSPACE" "$CMD_FULL" if [ "$AGENT" = "claude" ]; then # auto-handle trust / bypass dialogs handle_startup_dialogs "$SESSION_NAME" 20 fi # Wait for TUI readiness or let it settle sleep 2 # 5. Update agent-sessions.yaml: status running, last_visible_status bash "$(dirname "${BASH_SOURCE[0]}")/update_yaml_resumed.sh" \ --session "$SESSION_NAME" --uuid "$UUID" --agent "$AGENT" --workspace "$WORKSPACE" \ --herdr-session "$HERDR_SESSION_NAME" \ ${HERDR_WORKSPACE_OPT:+--herdr-workspace "$HERDR_WORKSPACE_OPT"} echo "Successfully resumed $SESSION_NAME ($AGENT)"