feat: 融合 devflow-claude P0 批机制 (REQ-20260416-0017)

P0-1: SessionStart Hook — hooks/session-context.sh
  从分支名解析 REQ-ID,调 MCP API 查询需求详情注入 system-reminder

P0-2: PreToolUse Hook — hooks/pre-tool-confirm.sh
  拦截生产推送、force push、docker prod 容器操作、git reset --hard 等

P0-3: Release Draft 闸门设计文档 — docs/design/release-draft-gate.md
  完整架构 + 渐进式落地路径(拆 7 个子任务延后)
  附最小可用脚本 hooks/release-draft.sh 创建 Gitea draft release

P0-4: Memory 隔离规则 — 写入 req-prd / req-design / req-workflow
  禁止 auto-memory 污染模板产出物(章节结构、字段定义、文档结构)

P0-5: CLAUDE.md 架构检查 + 架构片段库
  dev-coding skill 执行前检查架构关键词
  新增 templates/claude-md-snippets/ 含 Go+Gin / React+AntD / Vue+Element /
  MCP+TS / generic 五套骨架

P0-6: /commit 分支保护自动化 — 新 skill dev-commit-plugin
  保护分支自动建功能分支 + Conventional Commits + REQ-XXX 自动关联

安装:
  bash hooks/install.sh

后续:
  P0-3 完整实现拆 7 个子任务(P0-3.1 ~ P0-3.7)
  建议先部署 hooks 跑 1-2 周观察,再推进 Release 机制落地
This commit is contained in:
2026-04-16 21:02:29 +09:30
parent bfe3815626
commit 23ea8fdca5
18 changed files with 1433 additions and 0 deletions

94
hooks/pre-tool-confirm.sh Executable file
View File

@@ -0,0 +1,94 @@
#!/bin/bash
# pre-tool-confirm.sh
# PreToolUse Hook: 拦截危险操作,强制原生确认对话框
#
# 输入格式stdin JSON
# { "tool_name": "Bash", "tool_input": { "command": "..." } }
#
# 输出格式stdout JSON
# { "hookSpecificOutput": { "hookEventName": "PreToolUse",
# "permissionDecision": "ask",
# "permissionDecisionReason": "..." } }
#
# 安装方式:在 ~/.claude/settings.json 配置
# hooks.PreToolUse:
# - matcher: "Bash"
# hooks:
# - type: command
# command: "<path>/hooks/pre-tool-confirm.sh"
# timeout: 30
#
# 参考devflow-claude confirm-before-commit.sh + ai-proj memory 规则
# REQ-20260416-0017 P0-2
set -e
INPUT=$(cat)
if ! command -v jq >/dev/null 2>&1; then
# 没有 jq 就不处理
exit 0
fi
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
if [ -z "$COMMAND" ]; then
exit 0
fi
REASON=""
# ============ 1. 生产分支推送 ============
if echo "$COMMAND" | grep -qE '\bgit\s+push\b.*\b(origin\s+)?(main|master)\b'; then
REASON="⚠️ 即将推送到 main/master 生产分支。确认已过 PR 评审?"
# ============ 2. 强制推送 ============
elif echo "$COMMAND" | grep -qE '\bgit\s+push\b.*(--force|--force-with-lease|-f\b)'; then
REASON="⛔ 危险force push 会覆盖远程历史,可能丢失他人提交。确认继续?"
# ============ 3. tea pr merge --base main ============
elif echo "$COMMAND" | grep -qE '\btea\s+pr\s+merge\b.*--base\s+main\b'; then
REASON="⚠️ 即将合并 PR 到 main 分支,合并后将触发生产部署。确认 PR 已测试?"
# ============ 4. docker rm/stop 生产容器 ============
elif echo "$COMMAND" | grep -qE '\bdocker\s+(rm|stop|kill)\b.*\b(ai_postgres_prod|ai_backend_prod|ai_frontend_prod|ai_redis_prod)\b'; then
REASON="⛔ 危险:即将停止/删除生产容器2026-04-05 曾因此宕机 15 分钟。确认是灾难恢复?"
# ============ 5. docker rm/stop 其他 prod 相关 ============
elif echo "$COMMAND" | grep -qE '\bdocker\s+(rm|stop|kill)\b.*_prod\b'; then
REASON="⚠️ 即将停止/删除含 _prod 的容器。确认是生产环境?"
# ============ 6. git reset --hard / clean -fd ============
elif echo "$COMMAND" | grep -qE '\bgit\s+reset\s+--hard\b'; then
REASON="⚠️ git reset --hard 会丢弃所有未提交改动。确认继续?"
elif echo "$COMMAND" | grep -qE '\bgit\s+clean\s+.*-f'; then
REASON="⚠️ git clean -f 会删除未跟踪文件。确认继续?"
# ============ 7. rm -rf / 系统路径 ============
elif echo "$COMMAND" | grep -qE '\brm\s+.*-[rf]+.*\s+(/|/\*|~|\$HOME)'; then
REASON="⛔ 危险rm -rf 指向系统根或家目录。确认继续?"
# ============ 8. ssh 生产服务器 + 破坏性命令 ============
elif echo "$COMMAND" | grep -qE 'ssh\s+\S*prod\S*.*\b(rm|drop|truncate|delete)\b'; then
REASON="⛔ 危险:在生产服务器执行破坏性命令。确认继续?"
# ============ 9. psql/mysql 生产数据库 + DROP/TRUNCATE/DELETE ============
elif echo "$COMMAND" | grep -qiE '(psql|mysql).*prod.*\b(DROP|TRUNCATE|DELETE FROM)\b'; then
REASON="⛔ 危险:生产数据库 DROP/TRUNCATE/DELETE。确认已备份"
# ============ 10. MCP advance_delivery_stage force=true ============
# 这种会走 MCP 而不是 Bash本 hook 不好拦,留给另一个 matcher 处理
fi
if [ -n "$REASON" ]; then
jq -n --arg reason "$REASON" '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "ask",
permissionDecisionReason: $reason
}
}'
else
exit 0
fi