#!/usr/bin/env bash # auto-submit-drafts.sh — watchdog for Claude Code panes that receive channel # messages but leave them as unsubmitted prompt drafts. Intended for Mos only. set -uo pipefail TARGET="${1:-mos-claude}" INTERVAL="${INTERVAL:-2}" STABLE_SECONDS="${STABLE_SECONDS:-4}" LOG_PREFIX="[auto-submit-drafts:$TARGET]" last_prompt="" first_seen=0 prompt_text() { tmux capture-pane -t "$TARGET" -p 2>/dev/null | python3 -c ' import sys, re lines = sys.stdin.read().splitlines() idx = None for i in range(len(lines)-1, -1, -1): if "❯" in lines[i]: idx = i break if idx is None: raise SystemExit parts = [] after = lines[idx].split("❯", 1)[1] parts.append(after) for line in lines[idx+1:]: # Stop at Claude Code separator/border lines. if "─" in line or "╰" in line or "╭" in line: break s = line.replace("\u00a0", " ") s = re.sub(r"[\x00-\x1f\x7f]", "", s).strip() if s: parts.append(s) text = " ".join(parts).replace("\u00a0", " ") text = re.sub(r"[\x00-\x1f\x7f]", "", text).strip() print(text) ' } while true; do if ! tmux has-session -t "$TARGET" 2>/dev/null; then echo "$LOG_PREFIX target missing; waiting" >&2 sleep "$INTERVAL" last_prompt="" first_seen=0 continue fi current="$(prompt_text || true)" now="$(date +%s)" if [[ -z "$current" ]]; then last_prompt="" first_seen=0 sleep "$INTERVAL" continue fi if [[ "$current" != "$last_prompt" ]]; then last_prompt="$current" first_seen="$now" sleep "$INTERVAL" continue fi age=$(( now - first_seen )) if (( age >= STABLE_SECONDS )); then echo "$LOG_PREFIX submitting stable draft after ${age}s: ${current:0:120}" >&2 tmux send-keys -t "$TARGET" C-j sleep 0.8 tmux send-keys -t "$TARGET" C-m sleep 2 last_prompt="" first_seen=0 else sleep "$INTERVAL" fi done