Files
PolyGateway/.claude/scripts/hooks/post-edit-quality.sh
T
iomgaa 3058f4c744 chore: bootstrap project scaffolding
Add architecture doc (research-wiki/ARCHITECTURE.md), CLAUDE.md with
tiered SOP for Fable 5, adapted .claude skills/hooks/settings, package
skeleton (src/polygateway), pyproject with import-linter contracts,
Makefile, .env.example and smoke test.
2026-07-20 00:49:10 -04:00

84 lines
2.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.
#!/usr/bin/env bash
# ============================================================
# post-edit-quality.sh
# Claude Code PostToolUse hook — 每次编辑 .py 文件后自动检查
#
# 触发时机: Claude 每次执行 Write/Edit 后
# 作用: 对被修改的文件执行复杂度和风格检查(确定性质量守卫)
# 退出码: 0 = 通过, 非0 = 报告问题(Claude 会看到 stderr 反馈)
#
# 注册: 见 .claude/settings.json → hooks.PostToolUse
# ============================================================
set -euo pipefail
# PolyGateway conda 环境(存在则优先其工具链)
PROJ_ENV="$HOME/miniconda3/envs/PolyGateway/bin"
[[ -d "$PROJ_ENV" ]] && export PATH="$PROJ_ENV:$PATH"
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
# 只检查 .py 文件
if [[ ! "$FILE_PATH" == *.py ]]; then
exit 0
fi
# reference/ 只读区、外部路径不检查(写入本身由 pre-tool-guard 拦截)
case "$FILE_PATH" in
*/reference/*|reference/*) exit 0 ;;
esac
# 只检查存在的文件
if [[ ! -f "$FILE_PATH" ]]; then
exit 0
fi
ERRORS=""
WARNINGS=""
# ── 1. Ruff 格式 + lint 检查 ──
if command -v ruff &> /dev/null; then
RUFF_OUTPUT=$(ruff check "$FILE_PATH" 2>&1 || true)
if [[ -n "$RUFF_OUTPUT" ]]; then
ERRORS+="[ruff] 风格/lint 问题:\n$RUFF_OUTPUT\n\n"
fi
fi
# ── 2. Radon 圈复杂度(只报告 C 级及以下) ──
if command -v radon &> /dev/null; then
RADON_OUTPUT=$(radon cc "$FILE_PATH" -n C -s 2>&1 || true)
if echo "$RADON_OUTPUT" | grep -qE '^\s+[FMC]\s'; then
ERRORS+="[radon] 圈复杂度过高(≥C):\n$RADON_OUTPUT\n\n"
fi
fi
# ── 3. 文件行数检查(warning,不阻塞)──
LINE_COUNT=$(wc -l < "$FILE_PATH")
if [[ "$LINE_COUNT" -gt 200 ]]; then
WARNINGS+="[行数] $FILE_PATH${LINE_COUNT} 行,超过 200 行建议上限。\n\n"
fi
# ── 4. 禁止裸 except ──
if grep -nE '^\s*except\s*:\s*$|^\s*except\s+Exception\s*:\s*pass' "$FILE_PATH" 2>/dev/null; then
ERRORS+="[安全] 检测到裸 except 或 except Exception: pass,请捕获具体异常类型(CLAUDE.md P5)。\n\n"
fi
# ── 5. 禁止硬编码敏感信息 ──
if grep -nEi "(api_key|secret|password|token)\s*=\s*[\"'][^\"']+[\"']" "$FILE_PATH" 2>/dev/null; then
ERRORS+="[安全] 疑似硬编码敏感信息,请使用环境变量或 .env 文件。\n\n"
fi
# ── 输出结果 ──
if [[ -n "$WARNINGS" ]]; then
echo -e "⚠️ Warnings$FILE_PATH,不阻塞):\n" >&2
echo -e "$WARNINGS" >&2
fi
if [[ -n "$ERRORS" ]]; then
echo -e "❌ 代码质量检查发现问题($FILE_PATH):\n" >&2
echo -e "$ERRORS" >&2
exit 1
fi
exit 0