feat(stop): fully purge registry entries on stop --purge-conversation and add zombie pre-gate
This commit is contained in:
@@ -27,8 +27,10 @@
|
||||
# Exit codes:
|
||||
# 0 = success (or already-stopped no-op) | 1 = YAML not found / not registered
|
||||
# 2 = invalid args | 3 = interactive confirmation required (--yes 누락)
|
||||
# 4 = purge aborted (tmux session survived the kill chain)
|
||||
set -euo pipefail
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/lib.sh"
|
||||
|
||||
usage() {
|
||||
@@ -68,7 +70,8 @@ done
|
||||
[ -n "$SESSION_NAME" ] || { echo "ERROR: --session required" >&2; usage; 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")"
|
||||
TMUX_SERVER_NAME="$(resolve_tmux_server "$SESSION_NAME")"
|
||||
export TMUX_SERVER_NAME
|
||||
|
||||
# --agent 미지정 시 이름 suffix 로 fallback (P1-F)
|
||||
if [ -z "$AGENT" ]; then
|
||||
@@ -190,6 +193,21 @@ else
|
||||
echo "tmux already dead, just updating YAML"
|
||||
fi
|
||||
|
||||
# Purge pre-gate: 레코드 제거는 tmux 사망이 확인된 경우에만 허용한다.
|
||||
# (kill 체인은 best-effort — 세션이 살아남으면 monitor drift-B 가
|
||||
# 레코드 없는 세션을 running 으로 자동 재등록해 purge 가 조용히 뒤집힌다)
|
||||
if [ "$PURGE" = "1" ] && [ "$TMUX_ALIVE" = "1" ]; then
|
||||
_wait_session_gone "$SESSION_NAME" 5 || true # SIGKILL 폴백의 비동기 회수 윈도우 흡수
|
||||
if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
||||
echo "ERROR: session '$SESSION_NAME' is still alive after the kill chain." >&2
|
||||
echo " Refusing registry removal — records preserved (no state was modified)." >&2
|
||||
echo " Diagnose the stuck TUI (tmux attach -t '$SESSION_NAME'), then re-run" >&2
|
||||
echo " stop_session.sh --purge-conversation --yes (retry is safe/idempotent)." >&2
|
||||
delegate_publish_event "$DELEGATE_JOB_ID" error "purge aborted: tmux session still alive"
|
||||
exit 4
|
||||
fi
|
||||
fi
|
||||
|
||||
atomic_dump_yaml "$AGENT_SESSIONS_YAML" \
|
||||
SESSION_NAME="$SESSION_NAME" AGENT="$AGENT" PURGE="$PURGE" \
|
||||
NOW_ISO="$NOW_ISO" NOW_EPOCH="$NOW_EPOCH" LAST_STATUS="$LAST_STATUS" \
|
||||
@@ -216,12 +234,7 @@ if target is None:
|
||||
print(f"ERROR: disappeared during script: {name}", flush=True)
|
||||
raise SystemExit(1)
|
||||
|
||||
if purge:
|
||||
target['status'] = 'terminated'
|
||||
target['terminated_at'] = now
|
||||
target['terminated_at_epoch'] = int(os.environ['NOW_EPOCH'])
|
||||
target['termination_mode'] = 'purge'
|
||||
else:
|
||||
if not purge:
|
||||
target['status'] = 'stopped'
|
||||
target['stopped_at'] = now
|
||||
target['stopped_at_epoch'] = int(os.environ['NOW_EPOCH'])
|
||||
@@ -324,9 +337,13 @@ elif purge and not purge_uuid:
|
||||
print("WARN: --purge-conversation requested but no workspace-scoped UUID resolved; nothing purged", flush=True)
|
||||
|
||||
if purge:
|
||||
target['resumable'] = False
|
||||
|
||||
print(f"updated: {name} status={target['status']}", flush=True)
|
||||
d['tmux_sessions'] = [s for s in d.get('tmux_sessions', []) if s.get('name') != name]
|
||||
if purge_uuid:
|
||||
print(f"removed: {name} (registry entry fully purged from YAML+DB)", flush=True)
|
||||
else:
|
||||
print(f"removed: {name} (registry entry purged from YAML+DB; WARN: conversation artifacts unresolved — disk copies may remain)", flush=True)
|
||||
else:
|
||||
print(f"updated: {name} status={target['status']}", flush=True)
|
||||
PYEOF
|
||||
|
||||
delegate_publish_event "$DELEGATE_JOB_ID" completed "session terminated"
|
||||
|
||||
Reference in New Issue
Block a user