#!/bin/bash
#
# codevibe-codex - Wrapper to run Codex CLI inside tmux for mobile control
#
# This script launches Codex CLI inside a tmux session, enabling:
# - Mobile prompts when screen is locked (via tmux send-keys)
# - Same user experience as regular codex command
# - Automatic sync with iOS app via session log watching
#
# Usage:
#   codevibe-codex [codex-args...]
#   codevibe-codex login              # Sign in via browser
#   codevibe-codex logout             # Sign out
#   codevibe-codex status             # Show auth status
#
# Environment:
#   ENVIRONMENT                        # Set to 'production' (default) or 'development'
#
# Examples:
#   codevibe-codex                    # Start new session
#   codevibe-codex "fix the bug"      # Start with prompt
#   ENVIRONMENT=development codevibe-codex login  # Login to development
#

set -e

# Default to production environment if not specified
export ENVIRONMENT="${ENVIRONMENT:-production}"

# Use TMPDIR if set (macOS sets this to user-specific temp), otherwise /tmp
CODEVIBE_TMPDIR="${TMPDIR:-/tmp}"

# Get the directory where this script is located (resolving symlinks)
# This is needed because npm global installs symlink bin scripts to /usr/local/bin/
SOURCE="${BASH_SOURCE[0]}"
while [ -L "$SOURCE" ]; do
  DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
PLUGIN_DIR="$(dirname "$SCRIPT_DIR")"

# ─── PATH augmentation ───────────────────────────────────────────────
# When the install one-liner runs in a fresh terminal, Homebrew's
# installer writes the shellenv eval into ~/.zprofile (and similar)
# but the user's current shell hasn't sourced it yet. Subsequent
# codevibe-* runs in that same terminal then fail tmux discovery
# because /opt/homebrew/bin isn't on PATH. Prepend common locations
# so the wrapper recovers without forcing the user to open a new
# terminal. Prepend (not append) is deliberate: the Homebrew binary
# install.sh just laid down should win over any older system binary
# (e.g. a stale /usr/bin/node on Linux) at the same name. To preserve
# the relative ordering of augmented dirs, build a single prefix
# string and prepend it once — iterating prepend-per-dir would
# reverse intended order. ${PATH:+:$PATH} keeps an empty starting
# PATH from producing a trailing colon (which makes cwd searchable).
_CV_NEW_PATHS=""
for _CV_DIR in /opt/homebrew/bin /opt/homebrew/sbin /usr/local/bin /usr/local/sbin /opt/local/bin /usr/bin /bin; do
  case ":$PATH:" in
    *":$_CV_DIR:"*) ;;
    *) [ -d "$_CV_DIR" ] && _CV_NEW_PATHS="$_CV_NEW_PATHS:$_CV_DIR" ;;
  esac
done
[ -n "$_CV_NEW_PATHS" ] && export PATH="${_CV_NEW_PATHS#:}${PATH:+:$PATH}"
unset _CV_DIR _CV_NEW_PATHS

# ─── Wrapper telemetry (GA4 Measurement Protocol) ─────────────────────
# Diagnoses agent CLI failures: pre-flight bailouts, fast-die patterns,
# whether SessionStart hook fired, exit code. Background curl, fail
# silently, no PII (hashed hostname + per-run random id only). Honors
# CODEVIBE_TELEMETRY_SOURCE=test for internal testing.
_CV_MID="G-GS74YEQTB8"
_CV_SEC="lAfOF6OxRzSQ-NsLBRjhAg"
_CV_CID="$(echo "$(uname -n)-$(id -u)" | (sha256sum 2>/dev/null || shasum -a 256 2>/dev/null || echo "anonymous-fallback ") | cut -c1-36)"
_CV_RUN_ID="$(head -c 16 /dev/urandom 2>/dev/null | od -An -tx1 | tr -d ' \n' | cut -c1-32)"
[ -z "$_CV_RUN_ID" ] && _CV_RUN_ID="fallback-$(date +%s)-$$"
_CV_AGENT="codex"
_CV_SOURCE="${CODEVIBE_TELEMETRY_SOURCE:-production}"
_CV_STARTED_AT="$(date +%s)"
_CV_EXITED=""    # set by terminal events; suppresses trap double-fire
_CV_PLUGIN_VERSION="$(node -p "require('$PLUGIN_DIR/package.json').version" 2>/dev/null || echo unknown)"
_CV_MCP_LOG="${CODEVIBE_TMPDIR}/codevibe-codex-mcp.log"
_CV_MCP_LOG_BASELINE=0
if [ -f "$_CV_MCP_LOG" ]; then
  _CV_MCP_LOG_BASELINE=$(wc -l < "$_CV_MCP_LOG" 2>/dev/null | tr -d ' ')
  [ -z "$_CV_MCP_LOG_BASELINE" ] && _CV_MCP_LOG_BASELINE=0
fi
_CV_TMUX_STARTED="false"
_CV_AGENT_INVOKED="false"
_CV_AGENT_STARTED_AT=0
_CV_CODEX_EXIT_FILE="${CODEVIBE_TMPDIR}/codevibe-codex-exit-$$"

# Strip an arbitrary string down to a JSON-safe identifier alphabet.
# Removes anything that could break the hand-built JSON payload below
# (quotes, backslashes, ANSI escapes, control bytes, tabs, newlines).
# Truncates to 40 chars to bound the impact of pathological CLI version
# output. Caller is responsible for emptiness check after sanitize.
cv_sanitize() {
  printf '%s' "$1" | LC_ALL=C tr -cd 'A-Za-z0-9._\- ' | cut -c1-40
}

# Sanitize trusted-but-still-string values that go into the payload
# (plugin version, source label) so future schema additions can't
# accidentally reintroduce a JSON-injection path.
_CV_PLUGIN_VERSION="$(cv_sanitize "$_CV_PLUGIN_VERSION")"
[ -z "$_CV_PLUGIN_VERSION" ] && _CV_PLUGIN_VERSION="unknown"
_CV_SOURCE="$(cv_sanitize "$_CV_SOURCE")"
[ -z "$_CV_SOURCE" ] && _CV_SOURCE="production"

cv_telem() {
  local event="$1"; shift
  local params="$*"
  curl -s -X POST \
    "https://www.google-analytics.com/mp/collect?measurement_id=${_CV_MID}&api_secret=${_CV_SEC}" \
    -H "Content-Type: application/json" \
    -d "{\"client_id\":\"${_CV_CID}\",\"events\":[{\"name\":\"${event}\",\"params\":{\"agent\":\"${_CV_AGENT}\",\"plugin_version\":\"${_CV_PLUGIN_VERSION}\",\"source\":\"${_CV_SOURCE}\",\"run_id\":\"${_CV_RUN_ID}\"${params:+,$params}}}]}" \
    </dev/null >/dev/null 2>&1 &
}

cv_failed() {
  [ -n "$_CV_EXITED" ] && return 0
  _CV_EXITED="failed"
  cv_telem "wrapper_failed" "\"reason\":\"$1\",\"lifetime_seconds\":$(( $(date +%s) - _CV_STARTED_AT ))"
}

# Handle auth commands (login, logout, status, reset-device)
# Delegate to codevibe-core CLI (shared auth across all plugins)
case "$1" in
    login|logout|status|reset-device)
        CORE_CLI="$PLUGIN_DIR/node_modules/@quantiya/codevibe-core/bin/codevibe.js"
        # Also check hoisted location (when installed via @quantiya/codevibe meta-package)
        if [ ! -f "$CORE_CLI" ]; then
            CORE_CLI="$PLUGIN_DIR/../codevibe-core/bin/codevibe.js"
        fi
        if [ -f "$CORE_CLI" ]; then
            cv_telem "wrapper_started" "\"invocation\":\"auth_$1\",\"os\":\"$(uname -s | cv_sanitize)\",\"arch\":\"$(uname -m | cv_sanitize)\""
            exec node "$CORE_CLI" "$1"
        else
            echo "Error: codevibe-core not found. Try reinstalling: npm install -g @quantiya/codevibe"
            cv_failed "core_not_found"
            sleep 1
            exit 1
        fi
        ;;
esac

# Capture environment facts for the session-flow wrapper_started event.
# Each probe is non-fatal — if a CLI is missing we record "missing" rather
# than aborting; pre-flight checks below still gate execution. Every
# string that lands in the JSON payload goes through cv_sanitize so an
# agent CLI emitting ANSI escapes or quotes in `--version` can't break
# the hand-built payload.
_CV_CODEX_VER="missing"
command -v codex >/dev/null 2>&1 && _CV_CODEX_VER="$(codex --version 2>/dev/null | cv_sanitize)"
[ -z "$_CV_CODEX_VER" ] && _CV_CODEX_VER="unknown"
_CV_NODE_VER="missing"
command -v node >/dev/null 2>&1 && _CV_NODE_VER="$(node -v 2>/dev/null | cv_sanitize)"
[ -z "$_CV_NODE_VER" ] && _CV_NODE_VER="unknown"
_CV_TMUX_VER="missing"
command -v tmux >/dev/null 2>&1 && _CV_TMUX_VER="$(tmux -V 2>/dev/null | cv_sanitize)"
[ -z "$_CV_TMUX_VER" ] && _CV_TMUX_VER="unknown"
_CV_OS_VER="$(uname -s | cv_sanitize)"
[ -z "$_CV_OS_VER" ] && _CV_OS_VER="unknown"
_CV_ARCH_VER="$(uname -m | cv_sanitize)"
[ -z "$_CV_ARCH_VER" ] && _CV_ARCH_VER="unknown"
_CV_CODEX_AUTH="false"; [ -f "$HOME/.codex/auth.json" ] && _CV_CODEX_AUTH="true"
_CV_CODEX_CONFIG="false"; [ -f "$HOME/.codex/config.toml" ] && _CV_CODEX_CONFIG="true"
_CV_INSIDE_TMUX="false"; [ -n "$TMUX" ] && _CV_INSIDE_TMUX="true"
_CV_IS_TTY="false"; { [ -t 0 ] && [ -t 1 ]; } && _CV_IS_TTY="true"
cv_telem "wrapper_started" "\"invocation\":\"session\",\"os\":\"$_CV_OS_VER\",\"arch\":\"$_CV_ARCH_VER\",\"codex_version\":\"$_CV_CODEX_VER\",\"node_version\":\"$_CV_NODE_VER\",\"tmux_version\":\"$_CV_TMUX_VER\",\"codex_auth_present\":$_CV_CODEX_AUTH,\"codex_config_present\":$_CV_CODEX_CONFIG,\"inside_tmux\":$_CV_INSIDE_TMUX,\"is_terminal\":$_CV_IS_TTY"

# Configuration
TMUX_SESSION_PREFIX="codevibe-codex"
LOG_FILE="${CODEVIBE_TMPDIR}/codevibe-codex-wrapper.log"
MCP_LOG_FILE="${CODEVIBE_TMPDIR}/codevibe-codex-mcp.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}

# Cleanup function to kill server when wrapper exits
cleanup() {
    local wrapper_exit_code=$?
    log "Cleanup triggered"

    # Fire wrapper_exited telemetry BEFORE killing the server so the MCP
    # log is intact when we grep for SessionStart. cv_failed sets
    # _CV_EXITED on pre-flight failures so this block won't double-fire.
    if [ -z "$_CV_EXITED" ]; then
        _CV_EXITED="exited"
        local codex_exit="unknown"
        if [ -f "$_CV_CODEX_EXIT_FILE" ]; then
            codex_exit="$(cat "$_CV_CODEX_EXIT_FILE" 2>/dev/null | head -c 10 | tr -d '\n\r ')"
            [ -z "$codex_exit" ] && codex_exit="unknown"
        fi
        local lifetime=$(( $(date +%s) - _CV_STARTED_AT ))
        local codex_lifetime=0
        if [ "$_CV_AGENT_STARTED_AT" -gt 0 ] 2>/dev/null; then
            codex_lifetime=$(( $(date +%s) - _CV_AGENT_STARTED_AT ))
        fi
        local hook_fired="false"
        if [ -f "$_CV_MCP_LOG" ]; then
            if tail -n "+$((_CV_MCP_LOG_BASELINE + 1))" "$_CV_MCP_LOG" 2>/dev/null \
                | grep -q "SessionStart" 2>/dev/null; then
                hook_fired="true"
            fi
        fi
        # Outcome priority: SIGINT/SIGTERM beats everything (user intent).
        # Then "we never got far enough to invoke codex" — distinct from
        # "we invoked codex via passthrough but never started a tmux of
        # our own" (the latter is a normal direct-run, not an abort).
        local outcome
        if [ "$wrapper_exit_code" = "130" ] || [ "$wrapper_exit_code" = "143" ]; then
            outcome="interrupted"
        elif [ "$_CV_AGENT_INVOKED" = "false" ]; then
            outcome="pre_invoke_abort"
        elif [ "$codex_exit" != "unknown" ] && [ "$codex_exit" != "0" ]; then
            outcome="error_exit"
        elif [ "$codex_lifetime" -lt 5 ] 2>/dev/null; then
            outcome="early_exit"
        elif [ "$codex_lifetime" -lt 60 ] 2>/dev/null; then
            outcome="clean_short"
        else
            outcome="clean_long"
        fi
        cv_telem "wrapper_exited" "\"exit_code\":$wrapper_exit_code,\"lifetime_seconds\":$lifetime,\"codex_exit_code\":\"$codex_exit\",\"codex_lifetime_seconds\":$codex_lifetime,\"tmux_session_started\":$_CV_TMUX_STARTED,\"agent_invoked\":$_CV_AGENT_INVOKED,\"session_start_hook_fired\":$hook_fired,\"terminal_outcome\":\"$outcome\""
    fi

    if [ -n "$SERVER_PID" ] && kill -0 "$SERVER_PID" 2>/dev/null; then
        log "Stopping server (PID: $SERVER_PID)"
        kill "$SERVER_PID" 2>/dev/null || true
        wait "$SERVER_PID" 2>/dev/null || true
    fi
    # Remove PID file and port file
    rm -f "${CODEVIBE_TMPDIR}/codevibe-codex-server-$$.pid"
    rm -f "${CODEVIBE_TMPDIR}/codevibe-codex-${SESSION_NAME}.port"
    rm -f "$_CV_CODEX_EXIT_FILE"

    # Remove our hooks from ~/.codex/hooks.json (idempotent, concurrent-safe)
    if command -v jq &> /dev/null && [ -f "$HOME/.codex/hooks.json" ]; then
        # Only remove if no other codevibe-codex sessions are running
        if [ "$(pgrep -f 'codevibe-codex' | wc -l)" -le 1 ]; then
            log "Removing CodeVibe hooks from $HOME/.codex/hooks.json"
            jq 'del(.hooks[] | .[] | select(.hooks[]?.command | contains("codevibe-codex")))' \
                "$HOME/.codex/hooks.json" > "$HOME/.codex/hooks.json.tmp" 2>/dev/null && \
                mv "$HOME/.codex/hooks.json.tmp" "$HOME/.codex/hooks.json" || true
        else
            log "Other codevibe-codex sessions active, keeping hooks"
        fi
    fi
}

# Set up trap for cleanup
trap cleanup EXIT INT TERM

# Check if tmux is installed
if ! command -v tmux &> /dev/null; then
    echo "Error: tmux is required but not installed."
    echo "Install with: brew install tmux"
    cv_failed "tmux_missing"
    sleep 1
    exit 1
fi

# Check if codex is installed
if ! command -v codex &> /dev/null; then
    echo "Error: codex CLI is not installed."
    echo "Install with: npm install -g @openai/codex"
    cv_failed "codex_missing"
    sleep 1
    exit 1
fi

# Check if node is installed
if ! command -v node &> /dev/null; then
    echo "Error: Node.js is required but not installed."
    cv_failed "node_missing"
    sleep 1
    exit 1
fi

# Check if server is built
if [ ! -f "$PLUGIN_DIR/dist/server.js" ]; then
    echo "Error: Server not built. Run 'npm run build' in the plugin directory first."
    cv_failed "server_not_built"
    sleep 1
    exit 1
fi

# Generate a unique session name
SESSION_NAME="${TMUX_SESSION_PREFIX}-$$"
WORKING_DIR="$(pwd)"

log "Starting codevibe-codex with session: $SESSION_NAME"
log "Working directory: $WORKING_DIR"
log "Arguments: $*"

# Check if we're already inside tmux.
# We deliberately do NOT `exec` here — running codex as a child process
# lets the EXIT trap fire after it returns so wrapper_exited still gets
# emitted on these direct-run paths. Behaviorally identical for the user
# (codex remains the foreground process for the duration).
if [ -n "$TMUX" ]; then
    log "Already inside tmux, running codex directly"
    _CV_AGENT_INVOKED="true"
    _CV_AGENT_STARTED_AT="$(date +%s)"
    # `|| _CV_RC=$?` is load-bearing: with `set -e`, a non-zero exit from
    # codex would abort the wrapper before we capture the exit code,
    # leaving wrapper_exited with codex_exit_code="unknown". The `||`
    # form catches non-zero without triggering set -e, while exit 0
    # leaves _CV_RC at its 0 default. printf's `|| true` keeps a
    # disk-full failure from clobbering diagnostics.
    _CV_RC=0
    codex "$@" || _CV_RC=$?
    printf '%s' "$_CV_RC" > "$_CV_CODEX_EXIT_FILE" 2>/dev/null || true
    exit "$_CV_RC"
fi

# Check if running in a terminal — same direct-run treatment as above.
if [ ! -t 0 ] || [ ! -t 1 ]; then
    log "Not running in a terminal, running codex directly"
    _CV_AGENT_INVOKED="true"
    _CV_AGENT_STARTED_AT="$(date +%s)"
    _CV_RC=0
    codex "$@" || _CV_RC=$?
    printf '%s' "$_CV_RC" > "$_CV_CODEX_EXIT_FILE" 2>/dev/null || true
    exit "$_CV_RC"
fi

# Start the session log watcher server in background
log "Starting session log watcher server..."
export CODEX_WORKING_DIRECTORY="$WORKING_DIR"
export CODEVIBE_CODEX_TMUX_SESSION="$SESSION_NAME"
export CODEVIBE_CODEX_PLUGIN_DIR="$PLUGIN_DIR"

# Install hooks.json for Codex CLI with absolute paths (idempotent)
# Codex CLI does NOT expand env vars in hook commands, so we must
# write absolute paths at runtime.
CODEX_HOOKS_FILE="$HOME/.codex/hooks.json"
HOOKS_DIR="$PLUGIN_DIR/hooks"

generate_hooks_json() {
  cat <<HOOKEOF
{
  "hooks": {
    "SessionStart": [{"matcher": "*", "hooks": [{"type": "command", "command": "bash ${HOOKS_DIR}/session-start.sh"}]}],
    "UserPromptSubmit": [{"matcher": "*", "hooks": [{"type": "command", "command": "bash ${HOOKS_DIR}/user-prompt.sh"}]}],
    "PreToolUse": [{"matcher": "*", "hooks": [{"type": "command", "command": "bash ${HOOKS_DIR}/pre-tool-use.sh"}]}],
    "PostToolUse": [{"matcher": "*", "hooks": [{"type": "command", "command": "bash ${HOOKS_DIR}/post-tool-use.sh"}]}],
    "Stop": [{"matcher": "*", "hooks": [{"type": "command", "command": "bash ${HOOKS_DIR}/stop.sh"}]}]
  }
}
HOOKEOF
}

# Ensure hooks feature flag is enabled in Codex config
CODEX_CONFIG="$HOME/.codex/config.toml"
if [ -f "$CODEX_CONFIG" ]; then
  if ! grep -q "codex_hooks" "$CODEX_CONFIG" 2>/dev/null; then
    echo -e '\n[features]\ncodex_hooks = true' >> "$CODEX_CONFIG"
    log "Enabled codex_hooks feature flag in config.toml"
  fi
else
  mkdir -p "$HOME/.codex"
  echo -e '[features]\ncodex_hooks = true' > "$CODEX_CONFIG"
  log "Created config.toml with codex_hooks feature flag"
fi

mkdir -p "$HOME/.codex"
if [ -f "$CODEX_HOOKS_FILE" ]; then
  if grep -q "codevibe-codex" "$CODEX_HOOKS_FILE" 2>/dev/null; then
    log "CodeVibe hooks already installed in $CODEX_HOOKS_FILE"
  elif command -v jq &> /dev/null; then
    log "Merging CodeVibe hooks into existing $CODEX_HOOKS_FILE"
    GENERATED=$(generate_hooks_json)
    jq -s '.[0] as $existing | .[1] as $new |
      $existing | .hooks = (
        ($existing.hooks // {}) as $eh |
        ($new.hooks // {}) as $nh |
        ($eh | keys) + ($nh | keys) | unique | map(
          { (.) : (($eh[.] // []) + ($nh[.] // [])) }
        ) | add // {}
      )' "$CODEX_HOOKS_FILE" <(echo "$GENERATED") > "${CODEX_HOOKS_FILE}.tmp" && \
      mv "${CODEX_HOOKS_FILE}.tmp" "$CODEX_HOOKS_FILE"
  else
    log "WARN: jq not found and existing hooks.json exists — cannot merge safely"
  fi
else
  log "Installing CodeVibe hooks to $CODEX_HOOKS_FILE"
  generate_hooks_json > "$CODEX_HOOKS_FILE"
fi

# Start server and capture its PID
node "$PLUGIN_DIR/dist/server.js" >> "$MCP_LOG_FILE" 2>&1 &
SERVER_PID=$!
echo "$SERVER_PID" > "${CODEVIBE_TMPDIR}/codevibe-codex-server-$$.pid"

log "Server started with PID: $SERVER_PID"

# Wait a moment for server to initialize
sleep 1

# Check if server is still running (exits if auth failed)
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
    log "ERROR: Server failed to start"
    # Show the last few lines of the log for context (e.g., auth error)
    echo ""
    tail -3 "$MCP_LOG_FILE" 2>/dev/null | grep -v '^\[' | head -1
    echo ""
    echo "Server failed to start. Check $MCP_LOG_FILE for details."
    cv_failed "server_died_on_startup"
    sleep 1
    exit 1
fi

# Create tmux session and run codex
log "Creating tmux session: $SESSION_NAME"

# Build the codex command with proper escaping
CODEX_CMD="codex"
for arg in "$@"; do
    # Escape single quotes in arguments
    escaped_arg=$(printf '%s' "$arg" | sed "s/'/'\\\\''/g")
    CODEX_CMD="$CODEX_CMD '$escaped_arg'"
done

# Create the session running codex.
# The inner shell writes codex's exit code to $_CV_CODEX_EXIT_FILE so the
# wrapper's cleanup trap can report it via `wrapper_exited` telemetry —
# tmux's own attach exit code is independent of the inner process exit.
tmux new-session -d -s "$SESSION_NAME" -x "$(tput cols)" -y "$(tput lines)" \
    "export CODEVIBE_CODEX_TMUX_SESSION='$SESSION_NAME'; export ENVIRONMENT='$ENVIRONMENT'; $CODEX_CMD; printf '%s' \"\$?\" > '$_CV_CODEX_EXIT_FILE'; exit"
_CV_TMUX_STARTED="true"
_CV_AGENT_INVOKED="true"
_CV_AGENT_STARTED_AT="$(date +%s)"

# Enable mouse support for scrolling
tmux set-option -t "$SESSION_NAME" -g mouse on

# Enable copy/paste with system clipboard
tmux set-option -t "$SESSION_NAME" set-clipboard on
tmux set-window-option -t "$SESSION_NAME" mode-keys vi
if command -v pbcopy >/dev/null 2>&1; then
  CLIP_CMD="pbcopy"
elif grep -qi microsoft /proc/sys/kernel/osrelease 2>/dev/null && command -v clip.exe >/dev/null 2>&1; then
  CLIP_CMD="clip.exe"
elif command -v wl-copy >/dev/null 2>&1; then
  CLIP_CMD="wl-copy"
elif command -v xclip >/dev/null 2>&1; then
  CLIP_CMD="xclip -selection clipboard"
fi
if [ -n "${CLIP_CMD:-}" ]; then
  tmux bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "$CLIP_CMD"
  tmux bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "$CLIP_CMD"
fi

# Store session mapping for mobile prompts
echo "$SESSION_NAME" > "${CODEVIBE_TMPDIR}/codevibe-codex-tmux-session-$$"

log "Attaching to tmux session: $SESSION_NAME"

# Attach to the session
tmux attach-session -t "$SESSION_NAME"

# After tmux exits, cleanup is handled by trap
log "Tmux session ended"
