62 lines
2.6 KiB
Bash
Executable File
62 lines
2.6 KiB
Bash
Executable File
#!/bin/sh
|
||
# Хук Claude Code для панели «Claude» в iTerm2.
|
||
# Пишет события сессий и субагентов в ~/.cache/claude-agents/<session_id>.jsonl
|
||
# вместе с тем, где запущена сессия: PID процесса claude, вкладка iTerm2 или панель tmux.
|
||
# Нужен jq (в macOS 15+ встроен, иначе: brew install jq).
|
||
# Никогда не мешает Claude Code: ничего не выводит и всегда выходит с кодом 0.
|
||
|
||
dir="$HOME/.cache/claude-agents"
|
||
input=$(cat)
|
||
|
||
sid=$(printf '%s' "$input" | jq -r '.session_id // empty' 2>/dev/null | tr -cd 'A-Za-z0-9_-')
|
||
[ -n "$sid" ] || exit 0
|
||
mkdir -p "$dir" 2>/dev/null || exit 0
|
||
|
||
# PID самого claude: идём вверх по родителям, пропуская оболочки, которыми запущен хук
|
||
pid=$PPID
|
||
comm=""
|
||
i=0
|
||
while [ "$i" -lt 4 ] && [ "${pid:-1}" -gt 1 ]; do
|
||
comm=$(ps -o comm= -p "$pid" 2>/dev/null | sed 's#.*/##; s/^-//')
|
||
case "$comm" in
|
||
sh|bash|zsh|dash|fish) pid=$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' ') ;;
|
||
*) break ;;
|
||
esac
|
||
i=$((i + 1))
|
||
done
|
||
|
||
# Внутри tmux ITERM_SESSION_ID унаследован от сервера tmux и указывает не туда — не пишем его
|
||
iterm="${ITERM_SESSION_ID:-}"
|
||
tmux_socket=""
|
||
tmux_pane=""
|
||
if [ -n "${TMUX:-}" ] && [ -n "${TMUX_PANE:-}" ]; then
|
||
iterm=""
|
||
tmux_socket="${TMUX%%,*}"
|
||
tmux_pane="$TMUX_PANE"
|
||
fi
|
||
|
||
printf '%s' "$input" | jq -c --arg iterm "$iterm" --arg pid "${pid:-}" --arg pid_comm "$comm" \
|
||
--arg tmux_socket "$tmux_socket" --arg tmux_pane "$tmux_pane" '
|
||
def cut: if type == "string" then .[0:300] else . end;
|
||
{
|
||
hook_event_name, session_id, transcript_path, cwd, agent_id, agent_type,
|
||
model, session_title, source, from_model, to_model, tool_name, tool_use_id,
|
||
notification_type, agent_transcript_path, reason,
|
||
message: (.message | cut),
|
||
description: (.description | cut),
|
||
last_assistant_message: (.last_assistant_message | cut),
|
||
tool_input: (if (.tool_input | type) == "object"
|
||
then .tool_input | {subagent_type, description, model, name}
|
||
| map_values(cut) | with_entries(select(.value != null))
|
||
else null end),
|
||
t: now,
|
||
iterm: $iterm,
|
||
pid: ($pid | tonumber? // null),
|
||
pid_comm: (if $pid_comm == "" then null else $pid_comm end),
|
||
tmux_socket: (if $tmux_socket == "" then null else $tmux_socket end),
|
||
tmux_pane: (if $tmux_pane == "" then null else $tmux_pane end)
|
||
} | with_entries(select(.value != null))
|
||
' >> "$dir/$sid.jsonl" 2>/dev/null
|
||
|
||
exit 0
|