#!/usr/bin/env bash # update_yaml_resumed.sh — tmux-agent-orchestrate-resume 의 부속 스크립트 # Resume 한 세션의 agent-sessions.yaml 엔트리를 status=running + resume 메타로 갱신. # resume UUID 를 per-row own id (claude_session_id_own / agy_conversation_id_own) # 에 박는다 — agent_identities 전역은 더 이상 primary 아님 (cache 로 강등, P0-C/단계 e). # # Usage: bash update_yaml_resumed.sh --session --uuid [--agent claude|agy] set -euo pipefail source "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib.sh" usage() { cat < --uuid [--agent claude|agy] EOF } SESSION_NAME="" UUID="" AGENT="" while [ $# -gt 0 ]; do case "$1" in --session) SESSION_NAME="$2"; shift 2 ;; --uuid) UUID="$2"; shift 2 ;; --agent) AGENT="$2"; shift 2 ;; -h|--help) usage; exit 0 ;; *) echo "ERROR: unknown arg: $1" >&2; exit 2 ;; esac done [ -n "$SESSION_NAME" ] || { echo "ERROR: --session required" >&2; exit 2; } [ -n "$UUID" ] || { echo "ERROR: --uuid required" >&2; exit 2; } [ -f "$AGENT_SESSIONS_YAML" ] || { echo "ERROR: $AGENT_SESSIONS_YAML not found" >&2; exit 1; } export TMUX_SERVER_NAME="$(resolve_tmux_server "$SESSION_NAME")" # --agent 미지정 시 이름 suffix 로 fallback (P1-F: 가능하면 --agent 명시) if [ -z "$AGENT" ]; then case "$SESSION_NAME" in *-creator-claude) AGENT=claude ;; *-creator-agy) AGENT=agy ;; *) echo "ERROR: cannot infer agent from '$SESSION_NAME'; pass --agent" >&2; exit 2 ;; esac fi NOW_ISO=$(date -u +'%Y-%m-%dT%H:%M:%SZ') # 새 tmux pane pid / 자식 pid 를 bash 에서 캡처 (env 로 전달, P1-B) PANE_PID=$(tmux list-panes -t "$SESSION_NAME" -F '#{pane_pid}' 2>/dev/null | head -1 || true) PANE_PID="${PANE_PID:-}" CHILD_PID=0 if [ "$AGENT" = "agy" ] && [ -n "$PANE_PID" ]; then CHILD_PID=$(pgrep -P "$PANE_PID" -x agy 2>/dev/null | head -1 || true) CHILD_PID="${CHILD_PID:-0}" fi DELEGATE_JOB_ID=$(env_python "$AGENT_SESSIONS_YAML" SESSION_NAME="$SESSION_NAME" <<'PYEOF' import os, yaml name = os.environ['SESSION_NAME'] with open(os.environ['YAML_PATH']) as f: d = yaml.safe_load(f) or {} for s in d.get('tmux_sessions', []): if s.get('name') == name: print(s.get('delegate_job_id', '') or '') raise SystemExit(0) raise SystemExit(0) PYEOF ) atomic_dump_yaml "$AGENT_SESSIONS_YAML" \ SESSION_NAME="$SESSION_NAME" UUID="$UUID" AGENT="$AGENT" NOW_ISO="$NOW_ISO" \ PANE_PID="$PANE_PID" CHILD_PID="$CHILD_PID" <<'PYEOF' name = os.environ['SESSION_NAME'] uuid = os.environ['UUID'] agent = os.environ['AGENT'] now = os.environ['NOW_ISO'] pane_pid = os.environ.get('PANE_PID', '') target = None for s in d.get('tmux_sessions', []): if s.get('name') == name: target = s break if target is None: print(f"ERROR: session not in YAML: {name}", flush=True) raise SystemExit(1) target['status'] = 'running' target.pop('terminated_at', None) target.pop('terminated_at_epoch', None) target.pop('termination_mode', None) target.pop('archived_at', None) # stop 메타도 정리 — resume 하면 더 이상 stopped 상태가 아니므로 잔존 필드를 제거. target.pop('stopped_at', None) target.pop('stopped_at_epoch', None) target.pop('stop_reason', None) target.pop('resumable', None) target['last_visible_status'] = f'resumed conversation {uuid} at {now}' target.setdefault('pane', {}) if pane_pid.isdigit(): target['pane']['pid'] = int(pane_pid) if agent == 'claude': target['pane']['cmd'] = 'claude' target['pane']['cmd_full'] = f'claude --dangerously-skip-permissions -r {uuid}' target['claude_session_id_own'] = uuid elif agent == 'agy': target['pane']['cmd'] = 'agy' target['pane']['cmd_full'] = f'agy --dangerously-skip-permissions --conversation {uuid}' target['agy_conversation_id_own'] = uuid cp = os.environ.get('CHILD_PID', '0') if cp.isdigit() and int(cp) > 0: target['child_pid'] = int(cp) snap = d.setdefault('snapshot', {}) snap['taken_at'] = now snap.pop('terminated_at', None) snap.pop('terminated_at_epoch', None) print(f"updated: {name} status=running (resume id -> per-row own id)", flush=True) PYEOF delegate_publish_event "$DELEGATE_JOB_ID" progress "resumed"