Files
team/.claude/hooks/team-pane-cleanup.sh
T
2026-04-19 21:47:08 +08:00

128 lines
3.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ============================================================================
# team-pane-cleanup.sh — Agent Team tmux Pane 清理 Hook
#
# 用于 PostToolUse(TeamDelete) 事件
# 读取 .claude/team-panes.json,关闭所有记录的 agent pane
# 跳过 PM pane,仅关闭 agent pane
#
# 清理策略:
# 1. Ctrl+C 终止前台进程
# 2. 等待 3 秒让 Claude Code 优雅退出
# 3. 无条件 kill-pane 强制关闭
# 4. 验证 pane 确实已关闭
# ============================================================================
set -euo pipefail
# 项目根目录
PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
STATE_FILE="${PROJECT_ROOT}/.claude/team-panes.json"
LOG_FILE="${PROJECT_ROOT}/.claude/team-panes.log"
# 日志函数
log() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] team-pane-cleanup: $*"
echo "${msg}" >&2
echo "${msg}" >> "${LOG_FILE}" 2>/dev/null || true
}
# 读取 stdin(必须读取,但不使用)
timeout 3 cat >/dev/null 2>&1 || true
# 状态文件不存在 → 无需清理
if [ ! -f "${STATE_FILE}" ]; then
log "状态文件不存在,无需清理"
exit 0
fi
log "开始清理流程"
# 读取 agent_pane_ids
AGENT_PANES=$(jq -r '.agent_pane_ids[]?' "${STATE_FILE}" 2>/dev/null || true)
PM_PANE=$(jq -r '.pm_pane_id // empty' "${STATE_FILE}" 2>/dev/null || true)
TEAM_NAME=$(jq -r '.team_name // empty' "${STATE_FILE}" 2>/dev/null || true)
log "team=${TEAM_NAME}, PM=${PM_PANE}, agent_panes=[${AGENT_PANES//$'\n'/, }]"
if [ -z "${AGENT_PANES}" ]; then
log "无 agent pane 需要清理"
rm -f "${STATE_FILE}"
rm -f /tmp/claude-pane-snapshot-* 2>/dev/null || true
exit 0
fi
# 关闭单个 pane 的函数
# 参数: $1 = pane_id
# 返回: 0=成功关闭, 1=关闭失败
close_pane() {
local pane_id="$1"
# 安全检查:确保不是 PM pane
if [ "${pane_id}" == "${PM_PANE}" ]; then
log "跳过 PM pane ${pane_id}"
return 1
fi
# 检查 pane 是否仍存在
if ! tmux list-panes -t "${pane_id}" 2>/dev/null | head -1 | grep -q .; then
log "pane ${pane_id} 已不存在"
return 0
fi
log "关闭 pane ${pane_id} ..."
# 第 1 步: 发送 Ctrl+C 终止运行中的进程
tmux send-keys -t "${pane_id}" C-c 2>/dev/null || true
sleep 1
# 第 2 步: 再次发送 Ctrl+CClaude Code 可能需要两次中断才退出)
tmux send-keys -t "${pane_id}" C-c 2>/dev/null || true
sleep 2
# 第 3 步: 如果进程已退出到 bash,发送 exit
tmux send-keys -t "${pane_id}" 'exit' Enter 2>/dev/null || true
sleep 1
# 第 4 步: 无条件 kill-pane(不管 pane 是否仍在)
tmux kill-pane -t "${pane_id}" 2>/dev/null || true
# 第 5 步: 验证 pane 确实已关闭
sleep 0.5
if tmux list-panes -t "${pane_id}" 2>/dev/null | head -1 | grep -q .; then
log "警告: pane ${pane_id} 仍在,尝试二次 kill-pane"
tmux kill-pane -t "${pane_id}" 2>/dev/null || true
sleep 0.5
if tmux list-panes -t "${pane_id}" 2>/dev/null | head -1 | grep -q .; then
log "错误: pane ${pane_id} 无法关闭"
return 1
fi
fi
log "pane ${pane_id} 已成功关闭"
return 0
}
# 关闭每个 agent pane
CLOSED_COUNT=0
FAILED_COUNT=0
while IFS= read -r pane_id; do
[ -z "${pane_id}" ] && continue
if close_pane "${pane_id}"; then
CLOSED_COUNT=$((CLOSED_COUNT + 1))
else
FAILED_COUNT=$((FAILED_COUNT + 1))
fi
done <<< "${AGENT_PANES}"
log "清理完成: 成功=${CLOSED_COUNT}, 失败=${FAILED_COUNT}"
# 清理状态文件
rm -f "${STATE_FILE}"
# 清理所有关联的快照文件
rm -f /tmp/claude-pane-snapshot-* 2>/dev/null || true
exit 0