Community Skills (32): - jat: jat-start, jat-verify, jat-complete - pi-mono: codex-cli, codex-5.3-prompting, interactive-shell - picoclaw: github, weather, tmux, summarize, skill-creator - dyad: 18 skills (swarm-to-plan, multi-pr-review, fix-issue, lint, etc.) - dexter: dcf valuation skill Agents (23): - pi-mono subagents: scout, planner, reviewer, worker - toad: 19 agent configs (Claude, Codex, Gemini, Copilot, OpenCode, etc.) System Prompts (91): - Anthropic: 15 Claude prompts (opus-4.6, code, cowork, etc.) - OpenAI: 49 GPT prompts (gpt-5 series, o3, o4-mini, tools) - Google: 13 Gemini prompts (2.5-pro, 3-pro, workspace, cli) - xAI: 5 Grok prompts - Other: 9 misc prompts (Notion, Raycast, Warp, Kagi, etc.) Hooks (9): - JAT hooks for session management, signal tracking, activity logging Prompts (6): - pi-mono templates for PR review, issue analysis, changelog audit Sources analyzed: jat, ralph-desktop, toad, pi-mono, cmux, pi-interactive-shell, craft-agents-oss, dexter, picoclaw, dyad, system_prompts_leaks, Prometheus, zed, clawdbot, OS-Copilot, and more
114 lines
5.2 KiB
Bash
Executable File
114 lines
5.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# Pre-compact hook: Save current agent identity, workflow state, and terminal scrollback before compaction
|
|
# This ensures we can restore identity, workflow context, AND terminal history after compaction
|
|
#
|
|
# Uses WINDOWID-based file - stable across /clear (unlike PPID which changes)
|
|
# Each terminal window has unique WINDOWID, avoiding race conditions
|
|
|
|
PROJECT_DIR="$(pwd)"
|
|
CLAUDE_DIR="$PROJECT_DIR/.claude"
|
|
JAT_LOGS_DIR="$PROJECT_DIR/.jat/logs"
|
|
|
|
# Use WINDOWID for persistence (stable across /clear, unique per terminal)
|
|
# Falls back to PPID if WINDOWID not available
|
|
WINDOW_KEY="${WINDOWID:-$PPID}"
|
|
PERSISTENT_AGENT_FILE="$CLAUDE_DIR/.agent-identity-${WINDOW_KEY}"
|
|
PERSISTENT_STATE_FILE="$CLAUDE_DIR/.agent-workflow-state-${WINDOW_KEY}.json"
|
|
|
|
# Find the current session's agent file
|
|
SESSION_ID=$(cat /tmp/claude-session-${PPID}.txt 2>/dev/null | tr -d '\n')
|
|
# Use sessions/ subdirectory to keep .claude/ clean
|
|
AGENT_FILE="$CLAUDE_DIR/sessions/agent-${SESSION_ID}.txt"
|
|
|
|
# Get tmux session name for signal file lookup and scrollback capture
|
|
TMUX_SESSION=""
|
|
if [[ -n "${TMUX:-}" ]]; then
|
|
TMUX_SESSION=$(tmux display-message -p '#S' 2>/dev/null)
|
|
fi
|
|
|
|
# ============================================================================
|
|
# CAPTURE TERMINAL SCROLLBACK BEFORE COMPACTION
|
|
# This preserves the pre-compaction terminal history that would otherwise be lost
|
|
# Uses unified session log: .jat/logs/session-{sessionName}.log
|
|
# ============================================================================
|
|
if [[ -n "$TMUX_SESSION" ]]; then
|
|
# Use the unified capture script
|
|
CAPTURE_SCRIPT="$HOME/.local/bin/capture-session-log.sh"
|
|
if [[ -x "$CAPTURE_SCRIPT" ]]; then
|
|
PROJECT_DIR="$PROJECT_DIR" "$CAPTURE_SCRIPT" "$TMUX_SESSION" "compacted" 2>/dev/null || true
|
|
echo "[PreCompact] Captured scrollback for $TMUX_SESSION (compacted)" >> "$CLAUDE_DIR/.agent-activity.log"
|
|
else
|
|
# Fallback: inline capture if script not found
|
|
mkdir -p "$JAT_LOGS_DIR" 2>/dev/null
|
|
LOG_FILE="$JAT_LOGS_DIR/session-${TMUX_SESSION}.log"
|
|
TIMESTAMP=$(date -Iseconds)
|
|
|
|
SCROLLBACK=$(tmux capture-pane -t "$TMUX_SESSION" -p -S - -E - 2>/dev/null || true)
|
|
if [[ -n "$SCROLLBACK" ]]; then
|
|
# Add header if new file
|
|
if [[ ! -f "$LOG_FILE" ]]; then
|
|
echo "# Session Log: $TMUX_SESSION" > "$LOG_FILE"
|
|
echo "# Created: $TIMESTAMP" >> "$LOG_FILE"
|
|
echo "================================================================================" >> "$LOG_FILE"
|
|
echo "" >> "$LOG_FILE"
|
|
fi
|
|
# Append scrollback with separator
|
|
echo "$SCROLLBACK" >> "$LOG_FILE"
|
|
echo "" >> "$LOG_FILE"
|
|
echo "════════════════════════════════════════════════════════════════════════════════" >> "$LOG_FILE"
|
|
echo "📦 CONTEXT COMPACTED at $TIMESTAMP" >> "$LOG_FILE"
|
|
echo "════════════════════════════════════════════════════════════════════════════════" >> "$LOG_FILE"
|
|
echo "" >> "$LOG_FILE"
|
|
|
|
echo "[PreCompact] Captured scrollback to: $LOG_FILE" >> "$CLAUDE_DIR/.agent-activity.log"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [[ -f "$AGENT_FILE" ]]; then
|
|
AGENT_NAME=$(cat "$AGENT_FILE" | tr -d '\n')
|
|
|
|
# Save agent name to window-specific location
|
|
echo "$AGENT_NAME" > "$PERSISTENT_AGENT_FILE"
|
|
|
|
# Build workflow state JSON
|
|
SIGNAL_STATE="unknown"
|
|
TASK_ID=""
|
|
TASK_TITLE=""
|
|
|
|
# Try to get last signal state from signal file
|
|
SIGNAL_FILE="/tmp/jat-signal-tmux-${TMUX_SESSION}.json"
|
|
if [[ -f "$SIGNAL_FILE" ]]; then
|
|
# Signal file may have .state or .signalType depending on source
|
|
SIGNAL_STATE=$(jq -r '.state // .signalType // .type // "unknown"' "$SIGNAL_FILE" 2>/dev/null)
|
|
# Task ID may be in .task_id or .data.taskId
|
|
TASK_ID=$(jq -r '.task_id // .data.taskId // .taskId // ""' "$SIGNAL_FILE" 2>/dev/null)
|
|
TASK_TITLE=$(jq -r '.data.taskTitle // .taskTitle // ""' "$SIGNAL_FILE" 2>/dev/null)
|
|
fi
|
|
|
|
# If no signal file, try to get task from JAT Tasks
|
|
if [[ -z "$TASK_ID" ]] && command -v jt &>/dev/null; then
|
|
TASK_ID=$(jt list --json 2>/dev/null | jq -r --arg a "$AGENT_NAME" '.[] | select(.assignee == $a and .status == "in_progress") | .id' 2>/dev/null | head -1)
|
|
if [[ -n "$TASK_ID" ]]; then
|
|
TASK_TITLE=$(jt show "$TASK_ID" --json 2>/dev/null | jq -r '.[0].title // ""' 2>/dev/null)
|
|
fi
|
|
fi
|
|
|
|
# Save workflow state
|
|
cat > "$PERSISTENT_STATE_FILE" << EOF
|
|
{
|
|
"agentName": "$AGENT_NAME",
|
|
"signalState": "$SIGNAL_STATE",
|
|
"taskId": "$TASK_ID",
|
|
"taskTitle": "$TASK_TITLE",
|
|
"savedAt": "$(date -Iseconds)"
|
|
}
|
|
EOF
|
|
|
|
# Output marker for IDE state detection
|
|
echo "[JAT:COMPACTING]"
|
|
|
|
# Log for debugging
|
|
echo "[PreCompact] Saved agent: $AGENT_NAME, state: $SIGNAL_STATE, task: $TASK_ID (WINDOWID=$WINDOW_KEY)" >> "$CLAUDE_DIR/.agent-activity.log"
|
|
fi
|