sync: HP_BOWEI 2026-10-20

This commit is contained in:
Myfro9
2026-10-20 17:39:07 +08:00
parent 798e92717a
commit 7ace9b332b
3 changed files with 147 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
#!/usr/bin/env bash
# claude-brain 巡检:列出本会话每个子 agent 的最近活动时间、空闲时长与最后动作,
# 标出空闲超过阈值的 worker,供调度员每 30 分钟打印并决定是否唤醒。
#
# 原理:Claude Code 把每个 subagent 的转录写在
# ~/.claude/projects/<项目slug>/<会话ID>/subagents/agent-<id>.jsonl
# 旁边的 agent-<id>.meta.json 带 description(派出时的 description 参数)与 model。
# 转录文件的 mtime 就是该 agent 最近一次活动;最后几 KB 能看出它停在什么动作上。
#
# 用法(在 claude-brain 运行时所在的工程根目录执行):
# check_agents.sh [运行目录] [--threshold 30] [--hours 24] [--session <会话ID>] [--ids id1,id2]
# 运行目录给出时,末尾顺带打印其中的 agents.md 名册。
# --ids 只看这些 agent(前缀即可,逗号分隔);不给则列出时间窗内所有有转录的 agent。
# 输出:先一行 "巡检 HH:MM",然后 markdown 表。判定列:
# 正常 / 空闲超限 / 正常(大脑等待不计) / 已结束?(回合结束且空闲超限,需对照名册)
threshold=30
hours=24
session=""
ids=""
rundir=""
while [ $# -gt 0 ]; do
case "$1" in
--threshold) threshold="$2"; shift 2 ;;
--hours) hours="$2"; shift 2 ;;
--session) session="$2"; shift 2 ;;
--ids) ids="$2"; shift 2 ;;
*) rundir="$1"; shift ;;
esac
done
cwd="$(pwd -W 2>/dev/null || pwd)"
slug="$(printf '%s' "$cwd" | sed -e 's#[:/\\_]#-#g')"
proj="$HOME/.claude/projects/$slug"
if [ ! -d "$proj" ]; then
echo "找不到项目转录目录: $proj" >&2
echo "请在 claude-brain 运行时所在的工程根目录执行本脚本。" >&2
exit 1
fi
mins=$((hours * 60))
if [ -n "$session" ]; then
files=$(find "$proj/$session/subagents" -name 'agent-*.jsonl' 2>/dev/null)
else
files=$(find "$proj" -path '*/subagents/agent-*.jsonl' -mmin "-$mins" 2>/dev/null)
fi
now=$(date +%s)
echo "巡检 $(date +%H:%M)(阈值 ${threshold} min,时间窗 ${hours} h)"
echo
echo "| agent | 角色/任务 | 模型 | 最近活动 | 空闲 | 最后动作 | 判定 |"
echo "|---|---|---|---|---|---|---|"
over=0
# 按 mtime 新→旧排序
for f in $(ls -t $files 2>/dev/null); do
id=$(basename "$f" .jsonl | sed 's/^agent-//')
if [ -n "$ids" ]; then
hit=0
for p in $(printf '%s' "$ids" | tr ',' ' '); do
case "$id" in "$p"*) hit=1 ;; esac
done
[ $hit -eq 1 ] || continue
fi
meta="${f%.jsonl}.meta.json"
desc="?"; model="?"
if [ -f "$meta" ]; then
desc=$(grep -o '"description":"[^"]*"' "$meta" | head -n1 | sed 's/"description":"//;s/"$//')
model=$(grep -o '"model":"[^"]*"' "$meta" | head -n1 | sed 's/"model":"//;s/"$//')
fi
mt=$(stat -c %Y "$f")
idle=$(( (now - mt) / 60 ))
last=$(date -d "@$mt" +%H:%M)
tailtxt=$(tail -c 6000 "$f")
if printf '%s' "$tailtxt" | grep -q '"name":"Monitor"'; then
act="等待 Monitor"
elif printf '%s' "$tailtxt" | grep -q '"run_in_background":true'; then
act="等待后台命令"
elif printf '%s' "$tailtxt" | grep -q 'Monitor expired\|Monitor event'; then
act="收到 Monitor 事件后停住"
elif printf '%s' "$tailtxt" | tail -c 1500 | grep -q '"stop_reason":"end_turn"'; then
act="回合结束"
elif printf '%s' "$tailtxt" | grep -q '"type":"tool_use"'; then
act="工具调用中"
else
act="活动中"
fi
isbrain=0
case "$desc" in *大脑*|*brain*|*Brain*) isbrain=1 ;; esac
if [ $isbrain -eq 1 ]; then
verdict="正常(大脑等待不计)"
elif [ "$idle" -ge "$threshold" ]; then
if [ "$act" = "回合结束" ]; then verdict="已结束?(对照名册;运行中则为空闲超限)"; else verdict="**空闲超限**"; fi
over=$((over + 1))
else
verdict="正常"
fi
printf '| %s… | %s | %s | %s | %s min | %s | %s |\n' "${id:0:5}" "$desc" "$model" "$last" "$idle" "$act" "$verdict"
done
echo
if [ "$over" -gt 0 ]; then
echo "有 $over 个 agent 空闲 ≥ ${threshold} min。对照 agents.md:状态为「运行中」且报告文件不存在的,按 SKILL.md「30 分钟巡检」第 4 步介入。"
else
echo "无空闲超限的 agent。"
fi
if [ -n "$rundir" ] && [ -f "$rundir/agents.md" ]; then
echo
cat "$rundir/agents.md"
fi