Files
multi-agent-mux/.agents/skills/multi-agent-mux-resume/scripts/resume_session.sh
T
Godopu b4821fafa8 feat(a4,c3b): complete A-4 Phase 2 agent knowledge migration & Option B isolation removal
- Option B / C-3b: Deprecate isolation.root and remove its 4 legacy consumers in lib.sh, workspace_uuid.py, verify_session.py, and stop_session.sh.
- M2~M7 Migration: Implement artifact_path, verify_artifact, purge_artifacts, spawn_spec, resume_spec, auth_ok, discover, ready_tokens, exit_key, and delegate_agent_key across BaseAgentAdapter and all 4 adapters (Claude, Agy, Hermes, Cline).
- Migrate shell duplications in lib.sh, create_session.sh, resume_session.sh, stop_session.sh, and reconcile.sh to python -m lib_py.agents facts.
- Hardening & Corrections: Fix Cline resume_spec flag to '-i --id', apply shlex.quote across all facts variables with MAM_ prefix, add safe fallback in wait_for_tui_ready.
- Add comprehensive contract tests in tests/test_a4_adapter_contract.py and sync IMPROVEMENTS.md / LOG.md.
- Verified: 100% PASS across unit, component, contract, and integration tests.
2026-08-16 23:15:24 +09:00

128 lines
4.4 KiB
Bash
Executable File

#!/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/../.." 2>/dev/null || pwd)/lib.sh"
[ -f "$LIB_SH" ] || LIB_SH="${WORKSPACE_ROOT:-$PWD}/.agents/skills/lib.sh"
source "$LIB_SH"
usage() {
cat <<EOF
Usage: $0 --workspace <path> --agent <claude|agy|hermes|cline> --session <name> [--dry-run]
Options:
--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=""
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 ;;
--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; }
[ -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
HERDR_SESSION_NAME="$(resolve_herdr_session "$SESSION_NAME" "$WORKSPACE")"
export HERDR_SESSION_NAME
# 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"
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)" -c "from lib_py.agents.registry import get_adapter; from lib_py.agents.base import DiscoveryContext; a = get_adapter('$AGENT'); ctx = DiscoveryContext('$WORKSPACE', '$AGENT'); mat = a.verify_artifact('$UUID', ctx) if a else False; print(a.resume_spec('$RESOLVED_BIN', '$UUID', mat) if a else '')" 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" ;;
*) 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"
echo "Successfully resumed $SESSION_NAME ($AGENT)"