feat(isolation): implement Phase 1-3 session isolation with stop purge and resume safety

This commit is contained in:
2026-07-10 12:24:35 +09:00
parent 35068f7a9e
commit 768cfe5c6d
6 changed files with 451 additions and 62 deletions
+68 -18
View File
@@ -64,17 +64,18 @@ WORKSPACE=/path/to/project
AGENT=claude # or agy or hermes
SESSION_NAME=<workspace>-creator-<agent> # same convention as multi-agent-mux-create
# 1. Resolve the session id
# Resolve the isolated tmux server name & load isolation utils
source .agents/skills/lib.sh
# 1. Resolve the session id (T5: pass session name for target-row isolation check)
UUID=$(bash .agents/skills/multi-agent-mux-resume/scripts/resolve_session_id.sh \
--workspace "$WORKSPACE" --agent "$AGENT")
--workspace "$WORKSPACE" --agent "$AGENT" --session "$SESSION_NAME")
if [ -z "$UUID" ]; then
echo "No saved session for $WORKSPACE ($AGENT). Use multi-agent-mux-create first."
exit 1
fi
# Resolve the isolated tmux server name
source .agents/skills/lib.sh
export TMUX_SERVER_NAME="$(resolve_tmux_server "$SESSION_NAME")"
# 2. If tmux is alive, attach. Done.
@@ -83,11 +84,69 @@ if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
exec tmux attach -t "$SESSION_NAME"
fi
# 3. Spawn new tmux session + run agent with the saved id
# 3. Resolve isolation settings for this session (T4/T5 re-apply)
# _get_session_isolation resolves isolation block for the session row
ISO_ROOT=""
ISO_ENV=""
ISO_ARGS=""
ISO_DATA=$(env_python "$AGENT_SESSIONS_YAML" SESSION_NAME="$SESSION_NAME" <<'PYEOF'
import os, json, yaml, sqlite3
name = os.environ['SESSION_NAME']
yaml_path = os.environ['YAML_PATH']
db_path = os.path.splitext(yaml_path)[0] + '.db'
d = {}
try:
if os.path.exists(db_path):
conn = sqlite3.connect(db_path, timeout=60.0)
row = conn.execute('SELECT data FROM sessions WHERE name=?', (name,)).fetchone()
if row:
s = json.loads(row[0])
print(json.dumps(s.get('isolation') or {}))
raise SystemExit(0)
elif os.path.exists(yaml_path):
with open(yaml_path) as f:
d = yaml.safe_load(f) or {}
except Exception:
pass
for s in d.get('tmux_sessions', []):
if s.get('name') == name:
print(json.dumps(s.get('isolation') or {}))
raise SystemExit(0)
print("{}")
PYEOF
)
ISO_ROOT=$(printf '%s' "$ISO_DATA" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("root",""))')
if [ -n "$ISO_ROOT" ]; then
ISO_ENV="$(isolation_env_prefix "$AGENT" "$ISO_ROOT")"
ISO_ARGS="$(isolation_cmd_args "$AGENT" "$ISO_ROOT")"
echo "Re-applying isolation: root=$ISO_ROOT env=$ISO_ENV args=$ISO_ARGS"
fi
# Determine CMD_FULL with isolation applied
case "$AGENT" in
claude) CMD_FULL="claude --dangerously-skip-permissions -r $UUID" ;;
agy) CMD_FULL="agy --dangerously-skip-permissions --conversation $UUID" ;;
hermes) CMD_FULL="hermes --resume $UUID" ;;
cline) CMD_FULL="cline -i --id $UUID" ;;
esac
# Prepend env prefix and append command args (T4)
if [ -n "$ISO_ENV" ]; then
CMD_FULL="$ISO_ENV $CMD_FULL"
fi
if [ -n "$ISO_ARGS" ]; then
CMD_FULL="$CMD_FULL $ISO_ARGS"
fi
# 4. Spawn new tmux session + run agent with the saved id (and re-applied isolation)
case "$AGENT" in
claude)
tmux new-session -d -s "$SESSION_NAME" -x 140 -y 40 -c "$WORKSPACE" \
"claude --dangerously-skip-permissions -r $UUID"
if [ -z "$ISO_ROOT" ] && [ -x "$HOME/.local/bin/canary-projects-multi-agent-mux-creator-claude" ]; then
START_CMD="tmux new-session -d -s \"$SESSION_NAME\" -x 140 -y 40 -c \"$WORKSPACE\" \"$HOME/.local/bin/canary-projects-multi-agent-mux-creator-claude\""
else
START_CMD="tmux new-session -d -s \"$SESSION_NAME\" -x 140 -y 40 -c \"$WORKSPACE\" \"$CMD_FULL\""
fi
eval "$START_CMD"
# auto-handle trust / bypass dialogs
sleep 5
tmux send-keys -t "$SESSION_NAME" Enter 2>/dev/null || true
@@ -96,17 +155,8 @@ case "$AGENT" in
sleep 0.3
tmux send-keys -t "$SESSION_NAME" Enter 2>/dev/null || true
;;
agy)
tmux new-session -d -s "$SESSION_NAME" -x 140 -y 40 -c "$WORKSPACE" \
"agy --dangerously-skip-permissions --conversation $UUID"
;;
hermes)
tmux new-session -d -s "$SESSION_NAME" -x 140 -y 40 -c "$WORKSPACE" \
"hermes --resume $UUID"
;;
cline)
tmux new-session -d -s "$SESSION_NAME" -x 140 -y 40 -c "$WORKSPACE" \
"cline -i --id $UUID"
agy|hermes|cline)
eval "tmux new-session -d -s \"$SESSION_NAME\" -x 140 -y 40 -c \"$WORKSPACE\" \"$CMD_FULL\""
;;
esac