Files
GLM-Tools-Skills-Agents/hooks/community/jat/user-prompt-signal.sh
uroma b60638f0a3 Add community skills, agents, system prompts from 22+ sources
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
2026-02-13 10:58:17 +00:00

140 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# user-prompt-signal.sh - UserPromptSubmit hook for tracking user messages
#
# Fires when user submits a prompt to Claude Code.
# Writes user_input event to timeline for IDE visibility.
#
# Input: JSON via stdin with format: {"session_id": "...", "prompt": "...", ...}
# Output: Appends to /tmp/jat-timeline-{tmux-session}.jsonl
set -euo pipefail
# Read JSON input from stdin
HOOK_INPUT=$(cat)
# Skip empty input
if [[ -z "$HOOK_INPUT" ]]; then
exit 0
fi
# Parse session_id and prompt from the JSON input
SESSION_ID=$(echo "$HOOK_INPUT" | jq -r '.session_id // ""' 2>/dev/null || echo "")
USER_PROMPT=$(echo "$HOOK_INPUT" | jq -r '.prompt // ""' 2>/dev/null || echo "")
# Skip empty prompts or missing session_id
if [[ -z "$USER_PROMPT" ]] || [[ -z "$SESSION_ID" ]]; then
exit 0
fi
# Skip /jat:start commands - these cause a race condition where the event gets
# written to the OLD agent's timeline before /jat:start updates the agent file.
# The /jat:start command emits its own "starting" signal which is the proper
# event for the new session.
if [[ "$USER_PROMPT" =~ ^/jat:start ]]; then
exit 0
fi
# Get tmux session name by looking up agent file from session_id
# (Cannot use tmux display-message in subprocess - no TMUX env var)
TMUX_SESSION=""
# Build list of directories to search: current dir + configured projects
SEARCH_DIRS="."
JAT_CONFIG="$HOME/.config/jat/projects.json"
if [[ -f "$JAT_CONFIG" ]]; then
PROJECT_PATHS=$(jq -r '.projects[].path // empty' "$JAT_CONFIG" 2>/dev/null | sed "s|^~|$HOME|g")
for PROJECT_PATH in $PROJECT_PATHS; do
if [[ -d "${PROJECT_PATH}/.claude" ]]; then
SEARCH_DIRS="$SEARCH_DIRS $PROJECT_PATH"
fi
done
fi
for BASE_DIR in $SEARCH_DIRS; do
for SUBDIR in "sessions" ""; do
if [[ -n "$SUBDIR" ]]; then
AGENT_FILE="${BASE_DIR}/.claude/${SUBDIR}/agent-${SESSION_ID}.txt"
else
AGENT_FILE="${BASE_DIR}/.claude/agent-${SESSION_ID}.txt"
fi
if [[ -f "$AGENT_FILE" ]]; then
AGENT_NAME=$(cat "$AGENT_FILE" 2>/dev/null | tr -d '\n')
if [[ -n "$AGENT_NAME" ]]; then
TMUX_SESSION="jat-${AGENT_NAME}"
break 2
fi
fi
done
done
if [[ -z "$TMUX_SESSION" ]]; then
exit 0
fi
# Detect if the prompt contains an image (by checking for common image paths/patterns)
# Image paths typically match: /path/to/file.(png|jpg|jpeg|gif|webp|svg)
# Also check for task-images directory and upload patterns
HAS_IMAGE="false"
if [[ "$USER_PROMPT" =~ \.(png|jpg|jpeg|gif|webp|svg|PNG|JPG|JPEG|GIF|WEBP|SVG)($|[[:space:]]) ]] || \
[[ "$USER_PROMPT" =~ task-images/ ]] || \
[[ "$USER_PROMPT" =~ upload-.*\.(png|jpg|jpeg|gif|webp|svg) ]] || \
[[ "$USER_PROMPT" =~ /tmp/.*\.(png|jpg|jpeg|gif|webp|svg) ]]; then
HAS_IMAGE="true"
fi
# Truncate long prompts for timeline display (keep first 500 chars)
PROMPT_PREVIEW="${USER_PROMPT:0:500}"
if [[ ${#USER_PROMPT} -gt 500 ]]; then
PROMPT_PREVIEW="${PROMPT_PREVIEW}..."
fi
# REMOVED: Task ID lookup from signal file
# Previously we read task_id from /tmp/jat-signal-tmux-{session}.json, but this caused
# signal leaking when a user started a new task - the user_input event would inherit
# the OLD task_id from the previous signal file.
#
# User input events should not be associated with a specific task since they represent
# what the user typed, which may be switching to a new task entirely (e.g., /jat:start).
# The task context is better represented by subsequent agent signals that actually
# emit the new task ID.
TASK_ID=""
# Build event JSON
EVENT_JSON=$(jq -c -n \
--arg type "user_input" \
--arg session "$SESSION_ID" \
--arg tmux "$TMUX_SESSION" \
--arg task "$TASK_ID" \
--arg prompt "$PROMPT_PREVIEW" \
--argjson hasImage "$HAS_IMAGE" \
'{
type: $type,
session_id: $session,
tmux_session: $tmux,
task_id: $task,
timestamp: (now | todate),
data: {
prompt: $prompt,
hasImage: $hasImage
}
}' 2>/dev/null || echo "{}")
# Append to timeline log (JSONL format - preserves history)
TIMELINE_FILE="/tmp/jat-timeline-${TMUX_SESSION}.jsonl"
echo "$EVENT_JSON" >> "$TIMELINE_FILE" 2>/dev/null || true
# Start output monitor for real-time activity detection (shimmer effect)
# Kill any existing monitor for this session first
PID_FILE="/tmp/jat-monitor-${TMUX_SESSION}.pid"
if [[ -f "$PID_FILE" ]]; then
kill "$(cat "$PID_FILE")" 2>/dev/null || true
rm -f "$PID_FILE"
fi
# Start new monitor in background
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
nohup "$SCRIPT_DIR/monitor-output.sh" "$TMUX_SESSION" &>/dev/null &
exit 0