#!/bin/bash
# Run a ralph loop on a constitution file.
#
# Loops while the constitution's YAML frontmatter `status:` is `open` or
# `active`. Each iteration starts a fresh Claude (or Codex) session with
# the constitution injected as the system prompt; the worker surveys,
# works, commits, and exits via `kill $PPID`. Termination is by an
# iteration flipping `status:` to `closed` on a cold survey.
#
# Usage:
#   ralph <constitution.md> [--backend claude|codex] [-- extra-flags...]
#
# Default backend: claude. Override with --backend codex or RALPH_BACKEND=codex.

set -e

SPEC_FILE="${1:?Usage: ralph <constitution.md> [--backend claude|codex] [-- extra-flags...]}"
shift

BACKEND="${RALPH_BACKEND:-claude}"
if [[ "$1" == "--backend" ]]; then
    BACKEND="$2"
    shift 2
fi

EXTRA_FLAGS=""
if [[ "$1" == "--" ]]; then
    shift
    EXTRA_FLAGS="$*"
fi

# Resolve to absolute path
SPEC_FILE="$(cd "$(dirname "$SPEC_FILE")" && pwd)/$(basename "$SPEC_FILE")"

if [[ ! -f "$SPEC_FILE" ]]; then
    echo "Constitution file not found: $SPEC_FILE"
    exit 1
fi

SESSION="ralph-$(basename "$(dirname "$SPEC_FILE")")-$(basename "$SPEC_FILE" .md)"
WORK_DIR="$(dirname "$SPEC_FILE")"

# Anchor status check to the YAML frontmatter so body prose describing
# this very check ("status: open|active") can't self-match.
check_status() {
    head -50 "$SPEC_FILE" | sed -n '/^---$/,/^---$/p' | grep -qiE '^status:[[:space:]]*(open|active)'
}

if ! check_status; then
    echo "Constitution $SPEC_FILE must have YAML frontmatter status: open or active."
    echo "  Fix: add"
    echo "         ---"
    echo "         status: active"
    echo "         ---"
    echo "       at the top of the file."
    exit 1
fi

# Refuse to double-launch
if tmux has-session -t "$SESSION" 2>/dev/null; then
    echo "Ralph already running: $SESSION"
    echo "  Attach: tmux attach -t $SESSION"
    exit 0
fi

# Write loop script to temp file (avoids heredoc quoting hell)
LOOP_SCRIPT=$(mktemp "${TMPDIR:-/tmp}/ralph-loop.XXXXXX")
cat > "$LOOP_SCRIPT" << 'LOOP'
#!/bin/bash
SPEC_FILE="$1"
WORK_DIR="$2"
BACKEND="$3"
EXTRA_FLAGS="$4"

iteration=0

check_status() {
    head -50 "$SPEC_FILE" | sed -n '/^---$/,/^---$/p' | grep -qiE '^status:[[:space:]]*(open|active)'
}

while check_status; do
    cd "$WORK_DIR"
    iteration=$((iteration + 1))
    echo ""
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo "Ralph iteration $iteration — $(date '+%H:%M:%S')"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

    SPEC_CONTENT=$(cat "$SPEC_FILE")

    SYSPROMPT_FILE=$(mktemp "${TMPDIR:-/tmp}/ralph-sys.XXXXXX")
    PROMPT_FILE=$(mktemp "${TMPDIR:-/tmp}/ralph-prompt.XXXXXX")

    cat > "$SYSPROMPT_FILE" << SYSEOF
Ralph iteration $iteration. Constitution: $SPEC_FILE

$SPEC_CONTENT
SYSEOF

    cat > "$PROMPT_FILE" << 'PROMPTEOF'
You are inside a ralph loop — meditative iteration toward a desired state. Activate the ralph skill and follow its Loop protocol against the constitution above. The workdir's CLAUDE.md auto-loads; read it on entry.
PROMPTEOF

    PROMPT=$(cat "$PROMPT_FILE")

    if [[ "$BACKEND" == "codex" ]]; then
        codex --dangerously-bypass-approvals-and-sandbox \
            --config "developer_instructions=$(cat "$SYSPROMPT_FILE")" \
            $EXTRA_FLAGS \
            "$PROMPT"
    else
        claude --dangerously-skip-permissions \
            $EXTRA_FLAGS \
            --append-system-prompt "$(cat "$SYSPROMPT_FILE")" \
            <<< "$PROMPT"
    fi

    rm -f "$SYSPROMPT_FILE" "$PROMPT_FILE"

    echo "--- Iteration complete ---"
    sleep 2
done

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Ralph complete — $iteration iterations"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Session kept open for inspection. Type exit to close."
exec bash -l
LOOP

chmod +x "$LOOP_SCRIPT"

echo "Starting ralph on $SPEC_FILE"
echo "  Backend:  $BACKEND"
echo "  Work dir: $WORK_DIR"
[[ -n "$EXTRA_FLAGS" ]] && echo "  Flags:    $EXTRA_FLAGS"

# Launch tmux with a login shell running the loop script
tmux new-session -d -s "$SESSION" -c "$WORK_DIR" \
    bash -l "$LOOP_SCRIPT" "$SPEC_FILE" "$WORK_DIR" "$BACKEND" "$EXTRA_FLAGS"

echo "  Session:  $SESSION"
echo "  Attach:   tmux attach -t $SESSION"
