首页 › tutorials › Claude Code自动化:从-p模式到Hooks全攻略

Claude Code自动化:从-p模式到Hooks全攻略

概述:本教程系统讲解Claude Code的三大自动化能力——Headless模式(-p标志)、Hooks生命周期钩子、以及Agent SDK编程式调用。学完本教程,你将能把Claude Code嵌入CI/CD流水线、构建批量代码审查工具、实现自动格式化和安全检查。适合有半年以上Claude Code使用经验的开发者,以及需要将AI编码能力产品化的工程团队。

前置条件: - Claude Code CLI已安装并完成认证(claude --version ≥ 1.0.36) - 熟悉命令行操作和shell脚本 - 了解JSON格式和基本的Node.js/Python知识 - 一个可用的项目目录作为实验环境


一、Headless模式:让Claude Code脱离终端

1.1 什么是Headless模式

Headless模式是Claude Code的非交互式运行方式。通过添加-p(或--print)标志,Claude Code不再启动交互式TUI界面,而是直接在标准输出中打印结果。这使得它可以在脚本、CI管道、定时任务中无人值守地运行。

图表1

图表 1

1.2 基础用法

最简单的headless调用只需要一个提示词:

# 单次问答,直接输出到终端
claude -p "解释一下这个项目的目录结构"

# 管道输入——将文件内容作为上下文
cat src/main.ts | claude -p "这段代码有什么问题?请用JSON格式返回问题列表"

# 指定工作目录
claude -p --cwd /path/to/project "运行所有测试并报告失败原因"

1.3 控制输出格式

--output-format标志决定了Claude Code如何返回结果,这在编程集成中至关重要:

# 纯文本输出(默认)
claude -p "列出所有TODO注释" --output-format text

# JSON输出——适合程序解析
claude -p "分析代码质量" --output-format json

# 流式JSON——逐条输出,适合实时处理
claude -p "重构这个模块" --output-format stream-json

# 获取JSON格式的完整对话记录
claude -p "解释架构设计" --output-format json --verbose

JSON输出格式的典型结构:

{
  "type": "result",
  "subtype": "success",
  "cost_usd": 0.042,
  "duration_ms": 12340,
  "duration_api_ms": 8920,
  "is_error": false,
  "num_turns": 3,
  "result": "项目采用分层架构...",
  "session_id": "abc123"
}

1.4 限制工具权限

在自动化场景中,安全是第一要务。--allowedTools标志控制Claude Code可以使用哪些工具:

# 只允许读取——最安全的只读模式
claude -p "审查代码风格" \
  --allowedTools "Read,Glob,Grep"

# 允许读取和编辑——用于代码修改
claude -p "修复所有lint错误" \
  --allowedTools "Read,Edit,Glob,Grep"

# 允许执行bash命令——用于测试运行
claude -p "运行测试套件并修复失败用例" \
  --allowedTools "Read,Edit,Bash,Glob,Grep"

# 禁用网络访问工具——防止信息泄露
claude -p "分析代码逻辑" \
  --disallowedTools "WebSearch,WebFetch"

1.5 限制交互轮次

--max-turns防止Agent陷入无限循环,这在批量任务中尤其重要:

# 最多执行5轮工具调用
claude -p "修复所有TypeScript类型错误" \
  --max-turns 5 \
  --allowedTools "Read,Edit,Bash"

1.6 实战:批量代码审查脚本

下面是一个完整的shell脚本,用headless模式批量审查Git仓库中的变更文件:

#!/bin/bash
# batch-review.sh — 批量代码审查脚本

set -euo pipefail

# 获取main分支到当前HEAD之间变更的文件列表
CHANGED_FILES=$(git diff --name-only main...HEAD -- '*.ts' '*.tsx' '*.py')

if [ -z "$CHANGED_FILES" ]; then
  echo "没有发现变更文件"
  exit 0
fi

echo "=== 批量代码审查开始 ==="
echo "待审查文件:"
echo "$CHANGED_FILES"
echo ""

# 逐文件审查
while IFS= read -r file; do
  echo "--- 审查: $file ---"

  # 使用-p模式进行非交互式审查
  claude -p "$(cat <<'PROMPT'
请审查以下文件的最新git diff,重点关注:
1. 潜在的安全漏洞
2. 性能问题
3. 代码可维护性
请用简洁的中文输出审查结果,如果没有问题就说"无问题"。
PROMPT
  )" \
    --allowedTools "Read,Bash" \
    --max-turns 3 \
    --cwd "$(git rev-parse --show-toplevel)"

  echo ""
done <<< "$CHANGED_FILES"

echo "=== 批量代码审查完成 ==="

运行方式:

chmod +x batch-review.sh
./batch-review.sh

1.7 常见问题

问题 原因 解决方案
Error: No API key 未设置认证 运行 claude login 或设置 ANTHROPIC_API_KEY
输出包含ANSI转义码 终端检测到TTY 设置 NO_COLOR=1 环境变量
脚本卡住不返回 Agent轮次过多 添加 --max-turns 限制
权限被拒绝 工具不在白名单 检查 --allowedTools 配置
JSON解析失败 混合了文本和JSON 使用 --output-format json

二、Hooks:Claude Code的生命周期钩子

2.1 Hooks机制概述

Hooks是Claude Code中一个强大的自动化层,允许你在Agent执行的关键节点注入自定义逻辑。每个Hook本质上是一个shell命令,在特定事件触发时自动执行。

图表2

图表 2

2.2 Hook事件类型

Claude Code支持以下生命周期事件:

事件 触发时机 典型用途
PreToolUse 工具调用之前 权限检查、参数验证、安全审计
PostToolUse 工具调用之后 自动格式化、通知推送、日志记录
Notification Agent发送通知时 Slack/邮件通知、状态同步
Stop Agent停止时 清理临时文件、汇总报告
SessionStart 会话开始时 加载环境变量、初始化上下文

2.3 配置Hooks

Hooks在settings.json中配置。配置文件位于:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/pre-bash-guard.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write $CLAUDE_FILE_PATH"
          }
        ]
      }
    ],
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' '$CLAUDE_NOTIFICATION'"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/session-summary.sh"
          }
        ]
      }
    ]
  }
}

2.4 Hook输入输出协议

每个Hook通过标准输入接收JSON格式的上下文信息,通过退出码控制Claude Code的行为。

输入JSON结构(PreToolUse):

{
  "session_id": "sess_abc123",
  "tool_name": "Bash",
  "tool_input": {
    "command": "rm -rf node_modules"
  }
}

退出码含义:

退出码 含义 效果
0 通过 继续执行工具调用
2 阻止 取消本次工具调用,向Agent反馈阻止原因
其他 错误 Hook执行出错,工具调用被取消

通过stdout返回阻止原因:

#!/bin/bash
# pre-bash-guard.sh — 阻止危险的bash命令

read -r INPUT
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

# 检查危险命令模式
DANGEROUS_PATTERNS=("rm -rf /" "rm -rf ~" "DROP TABLE" "format c:" "> /dev/sda")

for pattern in "${DANGEROUS_PATTERNS[@]}"; do
  if [[ "$COMMAND" == *"$pattern"* ]]; then
    echo "已阻止危险命令:检测到 '$pattern' 模式。如果确认需要执行,请手动操作。"
    exit 2
  fi
done

exit 0

2.5 实战:五层防护Hooks配置

以下是一套生产级别的Hooks配置,覆盖代码质量、安全防护、通知和日志四大维度:

第一层:PreToolUse — 安全守卫

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/guard-bash.sh"
          }
        ]
      },
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/guard-edit.sh"
          }
        ]
      }
    ]
  }
}

guard-bash.sh:

#!/bin/bash
# guard-bash.sh — Bash命令安全守卫
set -euo pipefail

INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command')

# 规则1:阻止强制推送
if echo "$CMD" | grep -qE 'git\s+push\s+.*--force|git\s+push\s+.*-f\b'; then
  echo "已阻止:禁止使用 --force 推送。如需覆盖远程历史,请使用 --force-with-lease。"
  exit 2
fi

# 规则2:阻止删除受保护分支
if echo "$CMD" | grep -qE 'git\s+branch\s+-[dD]\s+(main|master|release|develop)'; then
  echo "已阻止:禁止删除受保护分支 (main/master/release/develop)。"
  exit 2
fi

# 规则3:阻止操作生产环境文件
if echo "$CMD" | grep -qE '/etc/|/var/www/production|/usr/local/bin/deploy'; then
  echo "已阻止:检测到生产环境路径,请确认后再手动执行。"
  exit 2
fi

exit 0

guard-edit.sh:

#!/bin/bash
# guard-edit.sh — 文件编辑守卫
set -euo pipefail

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path')

# 阻止编辑敏感文件
PROTECTED_FILES=(".env" ".env.production" "credentials.json" "secrets.yaml" ".ssh/config")
for protected in "${PROTECTED_FILES[@]}"; do
  if [[ "$FILE_PATH" == *"$protected"* ]]; then
    echo "已阻止:禁止编辑敏感文件 $FILE_PATH。如需修改,请手动操作。"
    exit 2
  fi
done

exit 0

第二层:PostToolUse — 自动格式化

{
  "PostToolUse": [
    {
      "matcher": "Edit|Write",
      "hooks": [
        {
          "type": "command",
          "command": "bash ~/.claude/hooks/auto-format.sh"
        }
      ]
    }
  ]
}

auto-format.sh:

#!/bin/bash
# auto-format.sh — 编辑后自动格式化
set -euo pipefail

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.file_path')

# 根据文件扩展名选择格式化工具
case "$FILE_PATH" in
  *.ts|*.tsx|*.js|*.jsx)
    npx prettier --write "$FILE_PATH" 2>/dev/null || true
    npx eslint --fix "$FILE_PATH" 2>/dev/null || true
    ;;
  *.py)
    python -m black "$FILE_PATH" 2>/dev/null || true
    python -m isort "$FILE_PATH" 2>/dev/null || true
    ;;
  *.go)
    gofmt -w "$FILE_PATH" 2>/dev/null || true
    ;;
  *.rs)
    rustfmt "$FILE_PATH" 2>/dev/null || true
    ;;
esac

第三层:PostToolUse — 测试自动运行

{
  "PostToolUse": [
    {
      "matcher": "Edit",
      "hooks": [
        {
          "type": "command",
          "command": "bash ~/.claude/hooks/auto-test.sh"
        }
      ]
    }
  ]
}

auto-test.sh:

#!/bin/bash
# auto-test.sh — 编辑后自动运行相关测试
set -euo pipefail

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path')

# 查找对应的测试文件
TEST_FILE=""
case "$FILE_PATH" in
  src/**/*.ts)
    # src/utils/helper.ts → src/utils/helper.test.ts
    TEST_FILE="${FILE_PATH%.ts}.test.ts"
    ;;
  **/*.py)
    # app/models/user.py → tests/test_user.py
    BASENAME=$(basename "${FILE_PATH%.py}")
    TEST_FILE="tests/test_${BASENAME}.py"
    ;;
esac

# 如果测试文件存在,运行测试
if [ -n "$TEST_FILE" ] && [ -f "$TEST_FILE" ]; then
  echo "检测到变更:$FILE_PATH"
  echo "运行关联测试:$TEST_FILE"

  case "$TEST_FILE" in
    *.test.ts) npx vitest run "$TEST_FILE" --reporter=verbose ;;
    *.test.py) python -m pytest "$TEST_FILE" -v ;;
  esac
fi

第四层:Notification — 即时通知

{
  "Notification": [
    {
      "matcher": "",
      "hooks": [
        {
          "type": "command",
          "command": "bash ~/.claude/hooks/notify.sh"
        }
      ]
    }
  ]
}

notify.sh:

#!/bin/bash
# notify.sh — 多渠道通知
set -euo pipefail

INPUT=$(cat)
MESSAGE=$(echo "$INPUT" | jq -r '.message // .notification // empty')

# macOS系统通知
if [[ "$(uname)" == "Darwin" ]]; then
  osascript -e "display notification \"$MESSAGE\" with title \"Claude Code\""
fi

# Linux桌面通知
if [[ "$(uname)" == "Linux" ]]; then
  notify-send "Claude Code" "$MESSAGE" 2>/dev/null || true
fi

# 可选:Slack通知
# curl -s -X POST "$SLACK_WEBHOOK_URL" \
#   -H 'Content-Type: application/json' \
#   -d "{\"text\": \"🤖 Claude Code: $MESSAGE\"}"

第五层:Stop — 会话日志

{
  "Stop": [
    {
      "matcher": "",
      "hooks": [
        {
          "type": "command",
          "command": "bash ~/.claude/hooks/log-session.sh"
        }
      ]
    }
  ]
}

log-session.sh:

#!/bin/bash
# log-session.sh — 记录会话摘要
set -euo pipefail

INPUT=$(cat)
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
TIMESTAMP=$(date '+%Y-%m-%d_%H%M%S')
LOG_DIR="$HOME/.claude/logs"

mkdir -p "$LOG_DIR"

# 将会话信息追加到日志文件
echo "$INPUT" | jq '.' >> "$LOG_DIR/session_${TIMESTAMP}.jsonl"

# 输出摘要
echo "会话日志已保存到 $LOG_DIR/session_${TIMESTAMP}.jsonl"

2.6 Matcher匹配规则

matcher字段支持精确匹配和正则表达式两种模式:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{"type": "command", "command": "echo 'Bash工具将被调用'"}]
      },
      {
        "matcher": "Edit|Write",
        "hooks": [{"type": "command", "command": "echo '文件将被修改'"}]
      },
      {
        "matcher": "",
        "hooks": [{"type": "command", "command": "echo '任意工具将被调用'"}]
      }
    ]
  }
}

三、Agent SDK:编程式调用Claude Code

3.1 从CLI到SDK

如果说-p模式是"远程遥控",那么Agent SDK就是"嵌入式控制"。Agent SDK允许你在TypeScript或Python代码中直接调用Claude Code的全部能力——包括工具调用、上下文管理、Agent循环。

3.2 安装Agent SDK

# TypeScript SDK
npm install @anthropic-ai/claude-code-sdk

# Python SDK
pip install claude-code-sdk

3.3 TypeScript基础用法

import { claude } from '@anthropic-ai/claude-code-sdk';

async function main() {
  // 基础调用
  const result = await claude({
    prompt: '分析这个项目的依赖关系,找出过时的包',
    options: {
      maxTurns: 5,
      allowedTools: ['Read', 'Glob', 'Grep', 'Bash'],
      cwd: '/path/to/project',
    },
  });

  console.log('结果:', result.result);
  console.log('成本:', result.cost_usd, 'USD');
  console.log('耗时:', result.duration_ms, 'ms');
}

main();

3.4 流式输出处理

import { claude } from '@anthropic-ai/claude-code-sdk';

async function streamExample() {
  const stream = claude({
    prompt: '重构认证模块',
    options: {
      maxTurns: 10,
      allowedTools: ['Read', 'Edit', 'Bash'],
    },
  });

  for await (const event of stream) {
    switch (event.type) {
      case 'assistant':
        // Agent的文本输出
        process.stdout.write(event.content);
        break;
      case 'tool_use':
        // 工具调用事件
        console.log(`\n[工具调用] ${event.tool_name}`);
        break;
      case 'tool_result':
        // 工具返回结果
        console.log(`[工具结果] ${event.tool_name} 完成`);
        break;
      case 'result':
        // 最终结果
        console.log('\n=== 完成 ===');
        console.log(`成本: $${event.cost_usd.toFixed(4)}`);
        console.log(`轮次: ${event.num_turns}`);
        break;
    }
  }
}

streamExample();

3.5 Subagent模式:并行任务分发

Subagent是Agent SDK中最重要的模式之一。它允许你同时启动多个Agent实例,各自独立完成任务,最终汇总结果。

图表3

图表 3

TypeScript实现并行Subagent:

import { claude } from '@anthropic-ai/claude-code-sdk';

interface ReviewResult {
  category: string;
  issues: string[];
  score: number;
}

async function parallelCodeReview(projectPath: string): Promise<void> {
  const reviewTasks = [
    {
      category: '代码质量',
      prompt: `审查 ${projectPath} 中的所有TypeScript源文件,找出代码质量问题:命名不规范、重复代码、过长函数。返回JSON格式的结果。`,
      allowedTools: ['Read', 'Glob', 'Grep'],
    },
    {
      category: '安全审计',
      prompt: `检查 ${projectPath} 中的安全漏洞:SQL注入、XSS、硬编码密钥、不安全的依赖。返回JSON格式的结果。`,
      allowedTools: ['Read', 'Glob', 'Grep', 'Bash'],
    },
    {
      category: '性能瓶颈',
      prompt: `分析 ${projectPath} 中的性能问题:N+1查询、内存泄漏风险、不必要的同步操作。返回JSON格式的结果。`,
      allowedTools: ['Read', 'Glob', 'Grep'],
    },
    {
      category: '依赖健康',
      prompt: `检查 ${projectPath} 的 package.json 和 package-lock.json,找出过时的、有已知漏洞的、不再维护的依赖。返回JSON格式的结果。`,
      allowedTools: ['Read', 'Bash'],
    },
  ];

  // 并行启动所有审查任务
  const results = await Promise.all(
    reviewTasks.map(async (task) => {
      const result = await claude({
        prompt: task.prompt,
        options: {
          maxTurns: 5,
          allowedTools: task.allowedTools,
          cwd: projectPath,
        },
      });

      return {
        category: task.category,
        content: result.result,
        cost: result.cost_usd,
      };
    })
  );

  // 汇总结果
  console.log('\n========================================');
  console.log('       并行代码审查综合报告');
  console.log('========================================\n');

  let totalCost = 0;
  for (const r of results) {
    totalCost += r.cost;
    console.log(`## ${r.category}`);
    console.log(r.content);
    console.log(`(成本: $${r.cost.toFixed(4)})\n`);
  }

  console.log(`\n总成本: $${totalCost.toFixed(4)}`);
}

// 运行
parallelCodeReview(process.argv[2] || process.cwd());

3.6 Python版本

import asyncio
from claude_code_sdk import claude

async def batch_analyze(repos: list[str]):
    """并行分析多个仓库"""
    tasks = [
        claude(
            prompt=f"分析 {repo} 的架构,输出技术栈和模块依赖关系",
            options={
                "max_turns": 3,
                "allowed_tools": ["Read", "Glob", "Grep"],
                "cwd": repo,
            },
        )
        for repo in repos
    ]

    results = await asyncio.gather(*tasks)

    for repo, result in zip(repos, results):
        print(f"\n{'='*50}")
        print(f"仓库: {repo}")
        print(f"{'='*50}")
        print(result.result)

if __name__ == "__main__":
    repos = [
        "/projects/frontend",
        "/projects/backend",
        "/projects/shared-libs",
    ]
    asyncio.run(batch_analyze(repos))

四、/loop与定时任务

4.1 /loop命令

/loop是Claude Code内置的循环执行命令(v2.1.71+引入),用于在会话中周期性地执行任务:

# 在Claude Code交互界面中使用
> /loop 每30秒检查一次测试状态,如果全部通过则停止

# 典型场景:监控部署状态
> /loop 每60秒检查一次 kubectl get pods 的状态,当所有pod都为Running时通知我

4.2 桌面定时任务

通过/schedule命令可以创建持久化的定时任务,即使关闭Claude Code终端也会按计划执行:

# 每天早上9点执行
> /schedule "每天早上9点总结昨天的git commits,生成日报" --cron "0 9 * * *"

# 每周一运行
> /schedule "运行完整的测试套件并报告覆盖率变化" --cron "0 10 * * 1"

4.3 cron表达式参考

┌──────── 分钟 (0-59)
│ ┌────── 小时 (0-23)
│ │ ┌──── 日 (1-31)
│ │ │ ┌── 月 (1-12)
│ │ │ │ ┌ 星期 (0-7, 0和7都是周日)
│ │ │ │ │
* * * * *

常用表达式:

表达式 含义
*/5 * * * * 每5分钟
0 * * * * 每小时整点
0 9 * * * 每天上午9点
0 9 * * 1-5 工作日上午9点
0 0 1 * * 每月1号零点

五、实战项目:全自动CI代码审查机器人

将前面学到的所有技术整合为一个完整的CI/CD代码审查机器人。

5.1 项目结构

claude-review-bot/
├── package.json
├── tsconfig.json
├── src/
│   ├── index.ts            # 主入口
│   ├── reviewer.ts         # 代码审查逻辑
│   ├── hooks/
│   │   ├── guard-bash.sh   # Bash命令守卫
│   │   ├── guard-edit.sh   # 文件编辑守卫
│   │   └── auto-format.sh  # 自动格式化
│   └── reporters/
│       ├── console.ts      # 控制台报告
│       └── github.ts       # GitHub PR评论
├── .claude/
│   └── settings.json       # Hooks配置
└── config.json             # 审查规则配置

5.2 审查规则配置

{
  "rules": {
    "security": {
      "enabled": true,
      "severity": "critical",
      "patterns": [
        "硬编码API密钥",
        "SQL拼接",
        "未验证的用户输入",
        "不安全的正则表达式"
      ]
    },
    "quality": {
      "enabled": true,
      "severity": "warning",
      "patterns": [
        "重复代码",
        "过长函数(>50行)",
        "过深嵌套(>4层)",
        "魔法数字"
      ]
    },
    "performance": {
      "enabled": true,
      "severity": "info",
      "patterns": [
        "N+1查询",
        "不必要的同步操作",
        "大循环内的内存分配"
      ]
    }
  },
  "parallel": true,
  "max_turns": 5,
  "output": {
    "format": "markdown",
    "post_to_github": true
  }
}

5.3 主入口

// src/index.ts
import { claude } from '@anthropic-ai/claude-code-sdk';
import * as fs from 'fs';
import * as path from 'path';

interface ReviewConfig {
  rules: Record<string, {
    enabled: boolean;
    severity: string;
    patterns: string[];
  }>;
  parallel: boolean;
  max_turns: number;
}

async function main() {
  const config: ReviewConfig = JSON.parse(
    fs.readFileSync('config.json', 'utf-8')
  );

  const projectPath = process.argv[2] || process.cwd();
  const changedFiles = getChangedFiles();

  if (changedFiles.length === 0) {
    console.log('没有检测到变更文件,跳过审查。');
    return;
  }

  console.log(`📋 检测到 ${changedFiles.length} 个变更文件,开始审查...\n`);

  // 根据配置构建审查任务
  const tasks = Object.entries(config.rules)
    .filter(([_, rule]) => rule.enabled)
    .map(([category, rule]) => ({
      category,
      severity: rule.severity,
      prompt: buildPrompt(category, rule.patterns, changedFiles),
    }));

  // 并行执行
  if (config.parallel) {
    const results = await Promise.all(
      tasks.map(task => claude({
        prompt: task.prompt,
        options: {
          maxTurns: config.max_turns,
          allowedTools: ['Read', 'Glob', 'Grep'],
          cwd: projectPath,
        },
      }))
    );

    // 按严重级别排序输出
    const severityOrder = { critical: 0, warning: 1, info: 2 };
    const combined = tasks.map((t, i) => ({
      ...t,
      result: results[i].result,
      cost: results[i].cost_usd,
    }));
    combined.sort((a, b) =>
      severityOrder[a.severity] - severityOrder[b.severity]
    );

    printReport(combined);
  }
}

function getChangedFiles(): string[] {
  // 在CI环境中从git获取变更文件
  const { execSync } = require('child_process');
  try {
    const baseBranch = process.env.GITHUB_BASE_REF || 'main';
    return execSync(
      `git diff --name-only origin/${baseBranch}...HEAD`
    ).toString().trim().split('\n').filter(Boolean);
  } catch {
    return [];
  }
}

function buildPrompt(
  category: string,
  patterns: string[],
  files: string[]
): string {
  return `你是代码审查专家。请审查以下变更文件中是否存在 ${category} 相关问题。

重点关注:${patterns.join('、')}

变更文件列表:
${files.map(f => `- ${f}`).join('\n')}

请用以下JSON格式返回结果:
{
  "issues": [
    {
      "file": "文件路径",
      "line": 行号,
      "severity": "critical/warning/info",
      "message": "问题描述",
      "suggestion": "修复建议"
    }
  ]
}`;
}

function printReport(results: any[]): void {
  console.log('\n' + '='.repeat(60));
  console.log('          🔍 Claude Code 审查报告');
  console.log('='.repeat(60));

  let totalCost = 0;
  let totalIssues = 0;

  for (const r of results) {
    totalCost += r.cost;
    console.log(`\n### ${r.category} (${r.severity})`);
    console.log(r.result);
    totalIssues++;
  }

  console.log('\n' + '='.repeat(60));
  console.log(`📊 审查维度: ${results.length} | 总成本: $${totalCost.toFixed(4)}`);
  console.log('='.repeat(60) + '\n');
}

main().catch(console.error);

5.4 GitHub Actions集成

# .github/workflows/claude-review.yml
name: Claude Code Review

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Run Claude Code Review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GITHUB_BASE_REF: ${{ github.base_ref }}
        run: npx tsx src/index.ts ${{ github.workspace }}

      - name: Post review comment
        if: always()
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const report = fs.readFileSync('review-report.md', 'utf-8');
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: report
            });

六、完整工作流架构

图表4

图表 4


七、进阶模式与最佳实践

7.1 渐进式权限模型

在自动化场景中,建议采用分层权限策略:

# 第一级:纯只读(报告生成)
claude -p "生成项目架构文档" \
  --allowedTools "Read,Glob,Grep"

# 第二级:读写+受限Bash(代码修复)
claude -p "修复lint错误" \
  --allowedTools "Read,Edit,Glob,Grep" \
  --max-turns 10

# 第三级:完全权限(仅限CI环境)
if [ "$CI" = "true" ]; then
  claude -p "执行完整的代码质量检查流程" \
    --allowedTools "Read,Edit,Bash,Glob,Grep"
fi

7.2 成本控制策略

# 使用 --max-turns 控制单次成本上限
claude -p "快速检查" --max-turns 2

# 使用 --model 选择更经济的模型
claude -p "简单的文本总结" --model haiku

# 在SDK中实现成本预算
const result = await claude({
  prompt: '分析代码',
  options: {
    maxTurns: 5,
    maxCostUsd: 0.50, // 成本上限50美分
  },
});

7.3 错误处理与重试

async function resilientClaudeCall(
  prompt: string,
  maxRetries = 3
): Promise<any> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const result = await claude({
        prompt,
        options: {
          maxTurns: 5,
          allowedTools: ['Read', 'Edit', 'Bash'],
        },
      });

      if (result.is_error) {
        throw new Error(`Agent返回错误: ${result.result}`);
      }
      return result;
    } catch (error) {
      console.error(`第${attempt}次尝试失败:`, error);
      if (attempt === maxRetries) throw error;

      // 指数退避
      await new Promise(r =>
        setTimeout(r, Math.pow(2, attempt) * 1000)
      );
    }
  }
}

7.4 多仓库批量操作

#!/bin/bash
# multi-repo-sync.sh — 多仓库批量同步操作

REPOS=(
  "/projects/frontend"
  "/projects/backend"
  "/projects/mobile"
  "/projects/shared-libs"
)

PROMPT="检查并升级所有过时的npm依赖到最新稳定版本,运行测试确保没有破坏性变更"

for repo in "${REPOS[@]}"; do
  echo "=== 处理: $repo ==="

  claude -p "$PROMPT" \
    --cwd "$repo" \
    --allowedTools "Read,Edit,Bash,Glob,Grep" \
    --max-turns 8 \
    --output-format json \
    > "${repo##*/}-result.json" &
done

# 等待所有后台任务完成
wait

echo "=== 所有仓库处理完成 ==="

# 汇总结果
for repo in "${REPOS[@]}"; do
  RESULT_FILE="${repo##*/}-result.json"
  if [ -f "$RESULT_FILE" ]; then
    COST=$(jq -r '.cost_usd // 0' "$RESULT_FILE")
    echo "$repo: 成本 \$${COST}"
  fi
done

八、调试与排错

8.1 开启调试日志

# 环境变量方式
CLAUDE_CODE_DEBUG=1 claude -p "测试"

# 查看详细工具调用
claude -p "分析代码" --verbose --output-format stream-json 2>&1 | tee debug.log

8.2 常见问题排查清单

症状 可能原因 排查步骤
Hook未触发 配置路径错误 检查 ~/.claude/settings.json 中 hooks 字段JSON格式
Hook脚本报错 权限不足 chmod +x 添加执行权限
-p模式超时 max-turns太小或提示词太模糊 增大 --max-turns,优化提示词
JSON输出损坏 混合了警告和JSON 使用 --output-format json 并设置 NO_COLOR=1
成本异常高 Agent陷入循环 检查 --max-turns 和提示词的明确性
SDK连接失败 API Key问题 检查 ANTHROPIC_API_KEY 环境变量

8.3 监控Hook执行

# 在每个Hook脚本中添加日志
exec >> ~/.claude/hooks.log 2>&1
echo "[$(date)] Hook executed: $0"
echo "[$(date)] Input: $(cat)"

延伸阅读

训练营适用性评估:本教程适合中级训练营(第3-4天),学员需具备CLI和基本编程基础。预计教学时长4-5小时,其中Headless模式讲解1小时、Hands实战配置2小时、Agent SDK编程练习2小时。建议学员提前准备好一个真实的代码仓库作为实验环境。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入