#!/usr/bin/env bash # # fleet-logs.sh — quickly inspect a fleet factory job's logs (agent-queue). # # The factory (learning_ai_devops_tools/agent-queue) writes two artifacts per job # under queue/logs/: # • .log — sparse runner lifecycle (launch, PR open, verify, errors) # • .devin-export.json — the live Devin transcript (steps[]: source + message) # where looks like 20260602-003202__fleet-. # # Usage: # scripts/fleet-logs.sh [command] [job] # # Commands: # status [job] steps count + slot (building/review/...) + latest step (default) # tail [job] follow the runner .log (-f) # steps [job] [N] last N transcript steps (default 12) # watch [job] [N] live-refresh the last N steps every few seconds # full [job] all agent messages through your pager ($PAGER/less) # path [job] print the resolved log file paths # ls list known jobs (newest first) with slot + step count # # `job` is a full or PARTIAL job id (e.g. `3c0586ce`). Omit it to use the most # recent job. Override the factory location with AQ=/path/to/agent-queue. # set -euo pipefail # ── Locate the agent-queue checkout ─────────────────────────────────────────── resolve_aq() { if [[ -n "${AQ:-}" ]]; then printf '%s' "$AQ"; return; fi local here parent here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" parent="$(cd "$here/../.." 2>/dev/null && pwd || true)" # …/ for cand in \ "$parent/learning_ai_devops_tools/agent-queue" \ "$HOME/code/mygh/learning_ai_devops_tools/agent-queue" \ "$HOME/code/learning_ai_devops_tools/agent-queue"; do [[ -d "$cand/queue/logs" ]] && { printf '%s' "$cand"; return; } done return 1 } AQ_DIR="$(resolve_aq || true)" if [[ -z "$AQ_DIR" || ! -d "$AQ_DIR/queue/logs" ]]; then echo "error: agent-queue logs dir not found. Set AQ=/path/to/agent-queue." >&2 exit 1 fi LOGDIR="$AQ_DIR/queue/logs" QUEUE="$AQ_DIR/queue" have_jq() { command -v jq >/dev/null 2>&1; } need_jq() { have_jq || { echo "error: 'jq' is required for this command (brew install jq)." >&2; exit 1; }; } # ── Resolve a job's export file by (optional) substring; default = newest ────── resolve_export() { local pat="${1:-}" f if [[ -z "$pat" ]]; then f="$(ls -t "$LOGDIR"/*.devin-export.json 2>/dev/null | head -1 || true)" else f="$(ls -t "$LOGDIR"/*"$pat"*.devin-export.json 2>/dev/null | head -1 || true)" fi [[ -n "$f" ]] || { echo "error: no transcript matching '${pat:-}' in $LOGDIR" >&2; return 1; } printf '%s' "$f" } base_of() { basename "$1" .devin-export.json; } # 20260602-…__fleet- runner_log() { printf '%s/%s.log' "$LOGDIR" "$(base_of "$1")"; } slot_of() { local base="$1" d for d in building review testing shipped failed inbox; do [[ -e "$QUEUE/$d/$base.md" ]] && { printf '%s' "$d"; return; } done printf 'unknown' } steps_count() { have_jq && jq '.steps|length' "$1" 2>/dev/null || echo '?'; } print_steps() { local exp="$1" n="${2:-12}" need_jq jq -r --argjson n "$n" '.steps[-$n:][] | "[\(.source)] \(.message[0:300])"' "$exp" 2>/dev/null \ || echo "(transcript mid-write — re-run)" } cmd="${1:-status}"; shift || true case "$cmd" in ls) printf '%-40s %-10s %-7s %s\n' "JOB (base)" "SLOT" "STEPS" "FILE" ls -t "$LOGDIR"/*.devin-export.json 2>/dev/null | while read -r f; do b="$(base_of "$f")" printf '%-40s %-10s %-7s %s\n' "$b" "$(slot_of "$b")" "$(steps_count "$f")" "$f" done ;; path) exp="$(resolve_export "${1:-}")" echo "transcript: $exp" echo "runner log: $(runner_log "$exp")" ;; status) exp="$(resolve_export "${1:-}")"; base="$(base_of "$exp")" echo "job: $base" echo "slot: $(slot_of "$base")" echo "steps: $(steps_count "$exp")" echo "transcript: $exp" echo "--- latest step ---" print_steps "$exp" 3 ;; tail) exp="$(resolve_export "${1:-}")"; log="$(runner_log "$exp")" echo "==> tail -f $log (Ctrl-C to stop)" tail -n +1 -f "$log" ;; steps) exp="$(resolve_export "${1:-}")" print_steps "$exp" "${2:-12}" ;; watch) exp="$(resolve_export "${1:-}")"; n="${2:-8}" echo "==> live last $n steps of $(base_of "$exp") (Ctrl-C to stop)" while true; do clear 2>/dev/null || true printf '== %s | slot=%s | steps=%s | %s ==\n\n' \ "$(base_of "$exp")" "$(slot_of "$(base_of "$exp")")" "$(steps_count "$exp")" "$(date +%T)" print_steps "$exp" "$n" sleep 3 done ;; full) exp="$(resolve_export "${1:-}")"; need_jq jq -r '.steps[] | "== \(.source) ==\n\(.message)\n"' "$exp" | "${PAGER:-less}" ;; -h|--help|help) sed -n '2,33p' "$0" | sed 's/^# \{0,1\}//' ;; *) echo "unknown command '$cmd' (try: status|tail|steps|watch|full|path|ls; -h for help)" >&2 exit 1 ;; esac