auto-continue.sh 2.42 KB
#!/usr/bin/env bash
# Stop 钩子:让 ERP workflow 在回合中途结束时自动续跑,除非命中「终止标记」或「防循环上限」。
# 终止标记 [ERP-HALT] 只认 transcript 中 assistant 行内的出现——钩子自己的 reason、
# 窗口取最近 200 行:兜住「横幅在前、诊断在后」的回合(横幅后每个诊断动作约 2-3 行)。
# Skill 加载文本都不在 assistant 行,避免自匹配误放行(曾导致钩子实际只能续跑一次)。
# 防循环:连续「无工具调用」的空转停止计数达上限放行;有工具调用即由 PostToolUse 的
# reset-stall-counter.sh 清零(唯一可靠的进展信号;不再用 transcript 字节增长启发式——
# 纯文字空转一轮也会增长数 KB,按字节判进展会让上限永远到不了)。
# 注意:不按 stop_hook_active 提前退出——本钩子就是要多次续跑,防循环靠空转计数
# (Claude Code 自身另有连续 block 的硬上限兜底)。
set -u

INPUT="$(cat)"

SENTINEL='[ERP-HALT]'
MAX_STALL=8

get_str() {
  printf '%s' "$INPUT" \
    | sed -n "s/.*\"$1\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" \
    | head -n1
}
TRANSCRIPT="$(get_str transcript_path)"
TRANSCRIPT="${TRANSCRIPT//\\\\//}"
TRANSCRIPT="${TRANSCRIPT//\\//}"

KEY="$(printf '%s' "$TRANSCRIPT" | tr -cd 'A-Za-z0-9' | tail -c 40)"
[ -z "$KEY" ] && KEY="default"
CNT_FILE="${TMPDIR:-/tmp}/erp-autocont-$KEY"

allow_stop() { rm -f "$CNT_FILE" 2>/dev/null; exit 0; }

# 1) 终止标记出现在最近的 assistant 行 → 放行停下
if [ -n "$TRANSCRIPT" ] && [ -f "$TRANSCRIPT" ]; then
  if tail -n 200 "$TRANSCRIPT" 2>/dev/null | grep '"type":"assistant"' | grep -qF "$SENTINEL"; then
    allow_stop
  fi
fi

# 2) 防循环:连续空转停止达到上限 → 放行停下(计数由 PostToolUse 在有工具调用时清零)
CNT=0
[ -f "$CNT_FILE" ] && CNT="$(cat "$CNT_FILE" 2>/dev/null || echo 0)"
case "$CNT" in (''|*[!0-9]*) CNT=0 ;; esac
if [ "$CNT" -ge "$MAX_STALL" ]; then
  allow_stop
fi
echo $((CNT + 1)) > "$CNT_FILE"

# 3) 拦下停止 → 续跑
printf '%s' '{"decision":"block","reason":"继续推进 ERP 编码流程,不要输出收尾叙述、不要停下问用户是否继续。若 coding Workflow 正在后台运行或刚返回通知,按其结果继续诊断/续跑;只有打印了终止标记的硬护栏点(全部完成、测试闸持续红、缺值阻塞、Workflow 已转后台等待)才应停下。"}'
exit 0