agent-orchestrator/scripts/claude-status

213 lines
9.8 KiB
Bash
Executable File

#!/bin/bash
# Claude Unified Status
# Shows all sessions across all projects with summary stats
# Helper function to get Claude session info directly from Claude's data
get_claude_info() {
local TMUX_SESSION="$1"
# Get the TTY for this tmux session
local TTY=$(tmux list-panes -t "$TMUX_SESSION" -F '#{pane_tty}' 2>/dev/null | head -1)
[ -z "$TTY" ] && return 1
# Find the Claude PID running on that TTY
local TTY_SHORT="${TTY#/dev/}"
local CLAUDE_PID=$(ps -eo pid,tty,comm 2>/dev/null | awk -v tty="$TTY_SHORT" '$2 == tty && $3 == "claude" {print $1; exit}')
[ -z "$CLAUDE_PID" ] && return 1
# Get the working directory of that process
local CWD=$(lsof -p "$CLAUDE_PID" 2>/dev/null | awk '$4 == "cwd" {print $NF}')
[ -z "$CWD" ] && return 1
# Get current git branch from that directory
local BRANCH=$(git -C "$CWD" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
# Convert to Claude's project path format and find active session
local PROJECT_PATH=$(echo "$CWD" | tr '/_' '--')
local PROJECT_DIR="$HOME/.claude/projects/$PROJECT_PATH"
local SESSION_ID=""
local SUMMARY=""
if [ -d "$PROJECT_DIR" ]; then
# Find the most recently modified session file (exclude agent- files)
local ACTIVE_SESSION_FILE=$(ls -t "$PROJECT_DIR"/*.jsonl 2>/dev/null | grep -v "agent-" | head -1)
if [ -n "$ACTIVE_SESSION_FILE" ]; then
SESSION_ID=$(basename "$ACTIVE_SESSION_FILE" .jsonl)
# Extract the most recent summary from the session file
SUMMARY=$(grep '"type":"summary"' "$ACTIVE_SESSION_FILE" 2>/dev/null | tail -1 | jq -r '.summary // empty' 2>/dev/null)
fi
fi
# Output as key=value pairs (properly quoted for eval)
printf 'claude_branch=%q\n' "$BRANCH"
printf 'claude_session_id=%q\n' "$SESSION_ID"
printf 'claude_summary=%q\n' "$SUMMARY"
}
echo "╔══════════════════════════════════════════════════════════════════════════════╗"
echo "║ CLAUDE ORCHESTRATOR STATUS ║"
echo "╚══════════════════════════════════════════════════════════════════════════════╝"
echo ""
# Count sessions
INTEGRATOR_COUNT=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -c "^integrator-" || echo 0)
SPLITLY_COUNT=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -c "^splitly-" || echo 0)
TOTAL=$((INTEGRATOR_COUNT + SPLITLY_COUNT))
# Count empty checkouts
INTEGRATOR_EMPTY=0
for i in {0..9}; do
count=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -c "^integrator-${i}-" 2>/dev/null || true)
count=${count:-0}
count=$(echo "$count" | tr -d '[:space:]')
[ "$count" -eq 0 ] 2>/dev/null && ((INTEGRATOR_EMPTY++))
done
SPLITLY_EMPTY=0
for i in {0..12}; do
count=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -c "^splitly-${i}-" 2>/dev/null || true)
count=${count:-0}
count=$(echo "$count" | tr -d '[:space:]')
[ "$count" -eq 0 ] 2>/dev/null && ((SPLITLY_EMPTY++))
done
echo "📊 SUMMARY: $TOTAL active sessions"
echo " Integrator: $INTEGRATOR_COUNT sessions, $INTEGRATOR_EMPTY empty checkouts"
echo " Splitly: $SPLITLY_COUNT sessions, $SPLITLY_EMPTY empty checkouts"
echo ""
# Show integrator sessions
echo "┌──────────────────────────────────────────────────────────────────────────────┐"
echo "│ INTEGRATOR │"
echo "└──────────────────────────────────────────────────────────────────────────────┘"
if [ "$INTEGRATOR_COUNT" -eq 0 ]; then
echo " (no active sessions)"
else
# Get session details from the session data files
for session in $(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep "^integrator-" | sort); do
activity=$(tmux display-message -t "$session" -p '#{session_activity}' 2>/dev/null)
now=$(date +%s)
if [ -n "$activity" ]; then
diff=$((now - activity))
if [ $diff -lt 60 ]; then
last_active="${diff}s ago"
elif [ $diff -lt 3600 ]; then
last_active="$((diff / 60))m ago"
elif [ $diff -lt 86400 ]; then
last_active="$((diff / 3600))h ago"
else
last_active="$((diff / 86400))d ago"
fi
else
last_active="-"
fi
data_file="$HOME/.integrator-sessions/$session"
meta_branch=$(grep "^branch=" "$data_file" 2>/dev/null | cut -d'=' -f2-)
meta_status=$(grep "^status=" "$data_file" 2>/dev/null | cut -d'=' -f2-)
meta_summary=$(grep "^summary=" "$data_file" 2>/dev/null | cut -d'=' -f2- | cut -c1-60)
# Get live Claude session info
eval "$(get_claude_info "$session" 2>/dev/null)"
echo " 📍 $session ($last_active)"
# Show branch - prefer live, show if different from metadata
if [ -n "$claude_branch" ]; then
if [ -n "$meta_branch" ] && [ "$claude_branch" != "$meta_branch" ]; then
echo " Branch: $claude_branch (meta: $meta_branch)"
else
echo " Branch: $claude_branch"
fi
elif [ -n "$meta_branch" ]; then
echo " Branch: $meta_branch (stale)"
fi
# Show summary - prefer Claude's auto-generated, fall back to metadata
if [ -n "$claude_summary" ]; then
echo " Claude: ${claude_summary:0:65}"
fi
if [ -n "$meta_summary" ]; then
echo " Status: ${meta_summary}..."
fi
# Show session ID if available (useful for resuming)
[ -n "$claude_session_id" ] && echo " Session: ${claude_session_id:0:8}..."
done
fi
echo ""
# Show splitly sessions
echo "┌──────────────────────────────────────────────────────────────────────────────┐"
echo "│ SPLITLY / SAFESPLIT │"
echo "└──────────────────────────────────────────────────────────────────────────────┘"
if [ "$SPLITLY_COUNT" -eq 0 ]; then
echo " (no active sessions)"
else
for session in $(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep "^splitly-" | sort); do
activity=$(tmux display-message -t "$session" -p '#{session_activity}' 2>/dev/null)
now=$(date +%s)
if [ -n "$activity" ]; then
diff=$((now - activity))
if [ $diff -lt 60 ]; then
last_active="${diff}s ago"
elif [ $diff -lt 3600 ]; then
last_active="$((diff / 60))m ago"
elif [ $diff -lt 86400 ]; then
last_active="$((diff / 3600))h ago"
else
last_active="$((diff / 86400))d ago"
fi
else
last_active="-"
fi
data_file="$HOME/.splitly-sessions/$session"
meta_branch=$(grep "^branch=" "$data_file" 2>/dev/null | cut -d'=' -f2-)
meta_status=$(grep "^status=" "$data_file" 2>/dev/null | cut -d'=' -f2-)
meta_summary=$(grep "^summary=" "$data_file" 2>/dev/null | cut -d'=' -f2- | cut -c1-60)
# Get live Claude session info
eval "$(get_claude_info "$session" 2>/dev/null)"
echo " 📍 $session ($last_active)"
# Show branch - prefer live, show if different from metadata
if [ -n "$claude_branch" ]; then
if [ -n "$meta_branch" ] && [ "$claude_branch" != "$meta_branch" ]; then
echo " Branch: $claude_branch (meta: $meta_branch)"
else
echo " Branch: $claude_branch"
fi
elif [ -n "$meta_branch" ]; then
echo " Branch: $meta_branch (stale)"
fi
# Show summary - prefer Claude's auto-generated, fall back to metadata
if [ -n "$claude_summary" ]; then
echo " Claude: ${claude_summary:0:65}"
fi
if [ -n "$meta_summary" ]; then
echo " Status: ${meta_summary}..."
fi
# Show session ID if available (useful for resuming)
[ -n "$claude_session_id" ] && echo " Session: ${claude_session_id:0:8}..."
done
fi
echo ""
echo "┌──────────────────────────────────────────────────────────────────────────────┐"
echo "│ QUICK ACTIONS │"
echo "└──────────────────────────────────────────────────────────────────────────────┘"
echo " ~/claude-spawn i [linear-url] - New integrator session in new iTerm2 tab"
echo " ~/claude-spawn s [issue-num] - New splitly session in new iTerm2 tab"
echo " ~/claude-integrator-session cleanup"
echo " ~/claude-splitly-session cleanup"
echo ""