fix(tui): establish 2-tier readiness model, modal/hint token separation, and adapter modal contracts
- Separate TUI dialog detection into blocking gate layer (_MAM_MODAL_TOKENS) and recovery layer (_MAM_HINT_TOKENS) to eliminate idle dialog starvation - Add modal_tokens contract across agent adapters (claude, cline) with dynamic scope facts resolution in send_keys_safe - Implement fail-closed resolution for ambiguous same-kind panes (R-1) and enforce WORKSPACE_ROOT export (R-2) - Preserve session on TUI readiness timeout when PID is alive for diagnostics - Add comprehensive test suite in tests/test_c1_tui_readiness.py and adapter contract assertions in test_a4
This commit is contained in:
@@ -225,7 +225,7 @@ spawn
|
||||
cleanup_herdr_on_error() {
|
||||
local exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
echo "⚠️ Error occurred during initialization. Rolling back and killing herdr session '$SESSION_NAME'..." >&2
|
||||
echo "⚠️ Error occurred during initialization (exit code $exit_code). Rolling back and killing herdr session '$SESSION_NAME'..." >&2
|
||||
_herdr kill-session -t "$SESSION_NAME" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
@@ -237,11 +237,48 @@ if [ -z "$HERDR_SERVER_OPT" ]; then
|
||||
fi
|
||||
|
||||
# TUI 준비 대기
|
||||
if ! wait_for_tui_ready "$SESSION_NAME" "$AGENT"; then
|
||||
echo "ERROR: agent TUI never became ready — aborting (rollback via trap)" >&2
|
||||
exit 1
|
||||
TUI_READY_RC=0
|
||||
wait_for_tui_ready "$SESSION_NAME" "$AGENT" || TUI_READY_RC=$?
|
||||
LAST_VISIBLE_STATUS_OVERRIDE=""
|
||||
|
||||
if [ "$TUI_READY_RC" -ne 0 ]; then
|
||||
# 1. Diagnostic dump
|
||||
DIAG_DIR="${WORKSPACE:-$PWD}/.mam/diagnostics"
|
||||
mkdir -p "$DIAG_DIR" 2>/dev/null || true
|
||||
DIAG_FILE="$DIAG_DIR/${SESSION_NAME}-$(date +%s).txt"
|
||||
{
|
||||
echo "=== MAM Diagnostic Dump ==="
|
||||
echo "Date: $(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
||||
echo "Session: $SESSION_NAME"
|
||||
echo "Agent: $AGENT"
|
||||
echo "ReturnCode: $TUI_READY_RC"
|
||||
echo "--- Pane Raw Capture ---"
|
||||
_pane_capture "$SESSION_NAME" 2>/dev/null || true
|
||||
} > "$DIAG_FILE" 2>/dev/null || true
|
||||
if [ ! -f "$DIAG_FILE" ]; then
|
||||
echo "WARNING: Failed to write diagnostic dump to $DIAG_FILE" >&2
|
||||
fi
|
||||
|
||||
# 2. Check pane PID liveness
|
||||
PANE_PID_CHECK=$(_herdr list-panes -t "$SESSION_NAME" -F '#{pane_pid}' 2>/dev/null || echo "")
|
||||
ALIVE=false
|
||||
if [ -n "$PANE_PID_CHECK" ] && [[ "$PANE_PID_CHECK" =~ ^[0-9]+$ ]]; then
|
||||
if kill -0 "$PANE_PID_CHECK" 2>/dev/null; then
|
||||
ALIVE=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$ALIVE" = true ] && [ "${MAM_KILL_ON_READY_TIMEOUT:-0}" != "1" ]; then
|
||||
echo "WARNING: agent TUI never became ready within timeout, but process (PID $PANE_PID_CHECK) is alive. Preserving session for diagnosis." >&2
|
||||
LAST_VISIBLE_STATUS_OVERRIDE="tui-ready-timeout"
|
||||
SUBMIT_JOB_PROMPT="" # disable instruction injection on unready session
|
||||
else
|
||||
echo "ERROR: agent TUI never became ready — aborting (rollback via trap)" >&2
|
||||
exit 42
|
||||
fi
|
||||
fi
|
||||
if [ "$AGENT" = "claude" ]; then
|
||||
|
||||
if [ "$AGENT" = "claude" ] && [ -z "$LAST_VISIBLE_STATUS_OVERRIDE" ]; then
|
||||
handle_startup_dialogs "$SESSION_NAME" 15
|
||||
fi
|
||||
|
||||
@@ -257,8 +294,8 @@ NOW_ISO=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
# herdr server shim (HERDR_SESSION_NAME picked up by the lib.sh shim).
|
||||
START_CMD="HERDR_SESSION_NAME=${HERDR_SESSION_NAME:-default} herdr new-session -d -s \"$SESSION_NAME\" -x 140 -y 40 -c \"$WORKSPACE\" \"$CMD_FULL\""
|
||||
|
||||
# If --onboard is specified, automatically build the onboarding prompt
|
||||
if [ "$ONBOARD" = "1" ] && [ -z "$SUBMIT_JOB_PROMPT" ]; then
|
||||
# If --onboard is specified, automatically build the onboarding prompt (if session is ready)
|
||||
if [ "$ONBOARD" = "1" ] && [ -z "$SUBMIT_JOB_PROMPT" ] && [ -z "$LAST_VISIBLE_STATUS_OVERRIDE" ]; then
|
||||
SUBMIT_JOB_PROMPT="You are a newly spawned $ROLE Team Leader agent in this workspace. Without making any non-standard pre-preparations or modifying files directly, proceed immediately to align yourself with the project context by performing the following tasks:
|
||||
1. Read the project documentation at README.md and the multi-agent protocol guidelines at .agents/MULTI_AGENT_RULES.md to understand the design rules.
|
||||
2. Run 'git status' and 'git diff' to analyze the current modifications and active work in the repository.
|
||||
@@ -268,6 +305,9 @@ fi
|
||||
|
||||
# agent-sessions.yaml 에 append
|
||||
DELEGATE_JOB_ID=""
|
||||
if [ -n "$LAST_VISIBLE_STATUS_OVERRIDE" ]; then
|
||||
SUBMIT_JOB_PROMPT=""
|
||||
fi
|
||||
if [ -n "$SUBMIT_JOB_PROMPT" ]; then
|
||||
delegate_agent="${MAM_DELEGATE_AGENT_KEY:-}"
|
||||
if [ -z "$delegate_agent" ]; then
|
||||
@@ -306,6 +346,7 @@ atomic_dump_yaml "$AGENT_SESSIONS_YAML" \
|
||||
HERDR_SESSION_NAME="${HERDR_SESSION_NAME:-default}" \
|
||||
MAM_WS_LABEL="$MAM_WS_LABEL" \
|
||||
SESSION_UUID="$SESSION_UUID" \
|
||||
LAST_VISIBLE_STATUS_OVERRIDE="${LAST_VISIBLE_STATUS_OVERRIDE:-}" \
|
||||
DELEGATE_JOB_ID="$DELEGATE_JOB_ID" ROLE="$ROLE" <<'PYEOF'
|
||||
name = os.environ['SESSION_NAME']
|
||||
agent = os.environ['AGENT']
|
||||
@@ -389,6 +430,10 @@ elif agent == 'grok':
|
||||
entry['session_id_verified'] = False
|
||||
entry['last_visible_status'] = "assigned (awaiting first message)" if assigned else "unverified"
|
||||
|
||||
last_vis_override = os.environ.get('LAST_VISIBLE_STATUS_OVERRIDE', '')
|
||||
if last_vis_override:
|
||||
entry['last_visible_status'] = last_vis_override
|
||||
|
||||
sessions.append(entry)
|
||||
|
||||
snap = d.setdefault('snapshot', {})
|
||||
|
||||
Reference in New Issue
Block a user