#!/usr/bin/env bash
#
# capture-resume.sh  -  one line at session start when a run was left unfinished.
#
# Runs from the SessionStart hook. Its whole job is to say what is pending and
# then get out of the way, so it is bound by three rules:
#
#   1. It never blocks. Exit 0 always, whatever it finds.
#   2. It never calls a model, and it never reads a transcript.
#   3. It prints at most a few lines. A session banner that scrolls is a banner
#      the user learns to skip, which costs more than it saves.
#
# It answers two questions:
#   - Is there a pipeline run that stopped before Phase 5? Name it and the resume
#     command, because that run's work is recoverable and its findings are not
#     yet in the durable stores until it flushes.
#   - Is the pipeline's own observation queue stale? (>= REVIEW_DAYS since the
#     last review, with at least one open observation.) Offer one line. The
#     user's own work is never made to wait on it.
#
# Usage: ./capture-resume.sh [--json]

set -uo pipefail

JSON=0
[ "${1:-}" = "--json" ] && JSON=1

_MA_CR_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
if [ -f "$_MA_CR_HERE/../lib/user-facing.sh" ]; then . "$_MA_CR_HERE/../lib/user-facing.sh"; else . "$HOME/.claude/lib/user-facing.sh"; fi

LOGS="${LOGS_ROOT:-$HOME/.claude/logs/multi-agent}"
PIPELINE_MEM="$HOME/.claude/memory/multi-agent/_pipeline"
REVIEW_DAYS=7

# Unfinished runs are sorted into three buckets because each needs a different
# action: waiting on the user (an open PR, or a pause for the channel answer),
# left at a Phase 0 question (nothing built), and stopped mid-development.
AWAITING_N=0; AWAITING_TASK=""; AWAITING_PHASE=""
DIED_N=0;     DIED_TASK="";     DIED_PHASE=""
UNSTARTED_N=0; UNSTARTED_TASK=""
STALE_TASK=""
STALE_PHASE=""

if [ -d "$LOGS" ] && command -v jq >/dev/null 2>&1; then
  # Oldest first, so the first hit in each bucket is the one the banner calls
  # the oldest. Both layouts are walked: state is written flat as <task-id>/ by
  # phase-tracker.sh and nested as <project>/<task-id>/ by Phase 0, and a
  # reader that knows only one of them under-reports by the size of the other.
  # artifacts/ holds the copy gc-abandoned takes before it marks a run failed,
  # so it keeps the status the run had while it was alive.
  while IFS= read -r f; do
    [ -f "$f" ] || continue
    STATUS=$(jq -r '.status // ""' "$f" 2>/dev/null)
    # Only runs that claim to be running are bucketed. A file with no status is
    # unknown, and reporting unknown as "stopped mid-development" would be a
    # false claim. The fix for a hidden run is for its writer to record a status.
    # `complete` is the schema spelling and `completed` is in the wild too, so
    # both are excluded; a reader that knows one calls finished runs stale.
    case "$STATUS" in in_progress | paused | awaiting_input) ;; *) continue ;; esac
    # `phase` is the field name a state written before currentPhase carries.
    PHASE=$(jq -r '.currentPhase // .phase // "?" | tostring' "$f" 2>/dev/null)
    TASK=$(jq -r '.taskId // .jiraId // ""' "$f" 2>/dev/null)
    [ -n "$TASK" ] || continue
    # `.pr` is an object in the schema and a bare URL string in older state
    # files. `jq '.pr.url'` on a string errors, and with stderr suppressed that
    # reads as "no PR", so the shape is read rather than assumed.
    PR=$(jq -r 'if (.pr|type)=="string" then .pr elif (.pr|type)=="object" then (.pr.url // .pr.number // "") else "" end | tostring' "$f" 2>/dev/null)

    # Waiting for you, not broken: an open PR means the work landed, and
    # Phase 5 pauses for channel selection by design (modes.md). 6 and 7 are
    # the same pause in a state written before the six-phase numbering.
    if [ "$STATUS" = "awaiting_input" ] || [ -n "$PR" ] ||
      [ "$PHASE" = "5" ] || [ "$PHASE" = "6" ] || [ "$PHASE" = "7" ]; then
      AWAITING_N=$((AWAITING_N + 1))
      [ -z "$AWAITING_TASK" ] && { AWAITING_TASK="$TASK"; AWAITING_PHASE="$PHASE"; }
    elif [ "$PHASE" = "0" ]; then
      # Phase 0 is almost all questions. Nothing was built, so there is nothing
      # to resume and nothing to lose.
      UNSTARTED_N=$((UNSTARTED_N + 1))
      [ -z "$UNSTARTED_TASK" ] && UNSTARTED_TASK="$TASK"
    else
      DIED_N=$((DIED_N + 1))
      [ -z "$DIED_TASK" ] && { DIED_TASK="$TASK"; DIED_PHASE="$PHASE"; }
    fi
  done <<EOF
$(find "$LOGS" -maxdepth 4 -name agent-state.json -type f -not -path '*/artifacts/*' -print0 2>/dev/null | xargs -0 ls -tr 2>/dev/null)
EOF
  # Kept for the JSON consumers that read staleTask/stalePhase.
  if [ -n "$AWAITING_TASK" ]; then
    STALE_TASK="$AWAITING_TASK"; STALE_PHASE="$AWAITING_PHASE"
  elif [ -n "$DIED_TASK" ]; then
    STALE_TASK="$DIED_TASK"; STALE_PHASE="$DIED_PHASE"
  fi
fi

REVIEW_DUE=0
OPEN_OBS=0
if [ -d "$PIPELINE_MEM/observations" ]; then
  OPEN_OBS=$(grep -l '^status: open' "$PIPELINE_MEM/observations"/*.md 2>/dev/null | wc -l | tr -d ' ')
  LAST_REVIEW_FILE="$PIPELINE_MEM/last-review-date.txt"
  LAST=$(cat "$LAST_REVIEW_FILE" 2>/dev/null || echo "never")
  if [ "${OPEN_OBS:-0}" -gt 0 ]; then
    if [ "$LAST" = "never" ] || [ -z "$LAST" ]; then
      REVIEW_DUE=1
    else
      # Date arithmetic without GNU date: compare epoch seconds, and treat an
      # unparseable stamp as "due" rather than silently never reviewing again.
      LAST_EPOCH=$(date -j -f "%Y-%m-%d" "$LAST" +%s 2>/dev/null \
                || date -d "$LAST" +%s 2>/dev/null || echo "")
      if [ -z "$LAST_EPOCH" ]; then
        REVIEW_DUE=1
      else
        AGE_DAYS=$(( ( $(date +%s) - LAST_EPOCH ) / 86400 ))
        [ "$AGE_DAYS" -ge "$REVIEW_DAYS" ] && REVIEW_DUE=1
      fi
    fi
  fi
fi

if [ "$JSON" -eq 1 ]; then
  printf '{"staleTask":"%s","stalePhase":"%s","awaiting":%s,"died":%s,"unstarted":%s,"openObservations":%s,"reviewDue":%s}\n' \
    "$STALE_TASK" "$STALE_PHASE" "$AWAITING_N" "$DIED_N" "$UNSTARTED_N" "${OPEN_OBS:-0}" "$REVIEW_DUE"
  exit 0
fi

# One line per bucket, each naming its own next action. Counts are printed
# even when they are 1, because "1 run" and "13 runs" call for different
# reactions.
LANG_CODE=$(ma_output_lang 2>/dev/null || echo en)
if [ "$AWAITING_N" -gt 0 ]; then
  if [ "$LANG_CODE" = "tr" ]; then
    printf 'multi-agent: %s çalışma seni bekliyor, en eskisi %s (Phase %s). Bitirmek için `%s`.\n' \
      "$AWAITING_N" "$AWAITING_TASK" "$AWAITING_PHASE" "$(ma_command resume)"
  else
    printf 'multi-agent: %s run(s) waiting on you, oldest %s at Phase %s - `%s` to finish.\n' \
      "$AWAITING_N" "$AWAITING_TASK" "$AWAITING_PHASE" "$(ma_command resume)"
  fi
fi
if [ "$DIED_N" -gt 0 ]; then
  if [ "$LANG_CODE" = "tr" ]; then
    printf 'multi-agent: %s çalışma geliştirme sırasında durdu, en eskisi %s (Phase %s). Devam için `%s`, silmek için `%s`.\n' \
      "$DIED_N" "$DIED_TASK" "$DIED_PHASE" "$(ma_command resume)" "$(ma_command kill)"
  else
    printf 'multi-agent: %s run(s) stopped mid-development, oldest %s at Phase %s - `%s` or `%s`.\n' \
      "$DIED_N" "$DIED_TASK" "$DIED_PHASE" "$(ma_command resume)" "$(ma_command kill)"
  fi
fi
if [ "$UNSTARTED_N" -gt 0 ]; then
  if [ "$LANG_CODE" = "tr" ]; then
    printf 'multi-agent: %s çalışma Phase 0 sorusunda kaldı, hiçbir şey üretilmedi. Temizlemek için `%s --abandoned`.\n' \
      "$UNSTARTED_N" "$(ma_command garbage-collect)"
  else
    printf 'multi-agent: %s run(s) left at a Phase 0 question, nothing built - `%s --abandoned` to clear.\n' \
      "$UNSTARTED_N" "$(ma_command garbage-collect)"
  fi
fi
if [ "$REVIEW_DUE" -eq 1 ]; then
  if [ "$LANG_CODE" = "tr" ]; then
    printf 'multi-agent: %s açık pipeline gözlemi var, son inceleme %s+ gün önce. Uygun olduğunda `%s backlog`.\n' \
      "$OPEN_OBS" "$REVIEW_DAYS" "$(ma_command refactor)"
  else
    printf 'multi-agent: %s open pipeline observation(s), last review %s+ days ago - `%s backlog` when convenient.\n' \
      "$OPEN_OBS" "$REVIEW_DAYS" "$(ma_command refactor)"
  fi
fi
exit 0
