gh-issues自动修复GitHub问题 gh-issues

自动化处理GitHub问题,使用并行子代理修复问题并创建PR,监控并处理PR评论。关键词:自动化、GitHub、问题修复、PR创建、评论处理。

DevOps 0 次安装 0 次浏览 更新于 2/24/2026

gh-issues — Auto-fix GitHub Issues with Parallel Sub-agents

你是一个指挥者。严格按照这6个阶段执行。不要跳过阶段。

重要 — 不要使用 gh CLI依赖。这个技能只使用curl + GitHub REST API。GH_TOKEN环境变量已经由OpenClaw注入。在所有API调用中将其作为Bearer token传递:

curl -s -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" ...

阶段1 — 解析参数

解析/gh-issues之后提供的参数字符串。

位置参数:

  • owner/repo — 可选。这是要获取问题的源仓库。如果省略,从当前git远程检测: git remote get-url origin 从URL中提取owner/repo(处理HTTPS和SSH格式)。

标志(全部可选):

标志 默认 描述
–label (无) 按标签过滤(例如bug, enhancement
–limit 10 每次轮询获取的最大问题数
–milestone (无) 按里程碑标题过滤
–assignee (无) 按被分配人过滤(@me为自己)
–state open 问题状态:open, closed, all
–fork (无) 你的fork(user/repo)来推送分支和打开PR。从源仓库获取问题;代码推送到fork;从fork到源仓库打开PR。
–watch false 在每批之后继续轮询新问题和PR评论
–interval 5 轮询间隔(分钟)(只有在 --watch
–dry-run false 仅获取和显示 —— 不生成子代理
–yes false 跳过确认并自动处理所有过滤后的问题
–reviews-only false 跳过问题处理(阶段2-5)。仅运行阶段6 —— 检查打开的PR是否有评论并处理它们。
–cron false Cron安全模式:获取问题并生成子代理,不等待结果退出。
–model (无) 子代理使用的模型(例如glm-5, zai/glm-5)。如果没有指定,使用代理的默认模型。
–notify-channel (无) Telegram频道ID,用于发送最终PR摘要(例如-1002381931352)。仅发送最终结果和PR链接,不发送状态更新。

存储解析后的值以供后续阶段使用。

派生值:

  • SOURCE_REPO = 位置参数owner/repo(问题所在的位置)
  • PUSH_REPO = 如果提供了–fork值,则为该值,否则与SOURCE_REPO相同
  • FORK_MODE = 如果提供了–fork,则为true,否则为false

如果设置了 --reviews-only 直接跳到阶段6。首先运行令牌解析(阶段2),然后跳到阶段6。

如果设置了 --cron

  • 强制 --yes(跳过确认)
  • 如果也设置了 --reviews-only,运行令牌解析然后跳到阶段6(cron评论模式)
  • 否则,正常通过阶段2-5运行,激活cron模式行为

阶段2 — 获取问题

令牌解析: 首先,确保GH_TOKEN可用。检查环境:

echo $GH_TOKEN

如果为空,从配置中读取:

cat ~/.openclaw/openclaw.json | jq -r '.skills.entries["gh-issues"].apiKey // empty'

如果仍然为空,检查 /data/.clawdbot/openclaw.json

cat /data/.clawdbot/openclaw.json | jq -r '.skills.entries["gh-issues"].apiKey // empty'

将其导出为GH_TOKEN以供后续命令使用:

export GH_TOKEN="<token>"

构建并运行一个curl请求到GitHub问题API:

curl -s -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/{SOURCE_REPO}/issues?per_page={limit}&state={state}&{query_params}"

其中{query_params}是从以下构建的:

  • labels={label}如果提供了–label
  • milestone={milestone}如果提供了–milestone(注意:API期望里程碑_number_,因此如果用户提供了标题,首先通过GET /repos/{SOURCE_REPO}/milestones并按标题匹配解决)
  • assignee={assignee}如果提供了–assignee(如果是@me,首先通过 GET /user 解决你的用户名)

重要:GitHub问题API还返回拉取请求。过滤掉它们 —— 排除响应对象中存在pull_request键的任何项目。

如果在监视模式下:还过滤掉PROCESSED_ISSUES集合中已有的任何问题号码。

错误处理:

  • 如果curl返回HTTP 401或403 → 停止并告诉用户:

    “GitHub身份验证失败。请检查OpenClaw仪表板中的apiKey,或在~/.openclaw/openclaw.json中的skills.entries.gh-issues下。”

  • 如果响应是一个空数组(过滤后)→ 报告"没有找到匹配过滤器的问题"并停止(如果在监视模式下则循环回来)。
  • 如果curl失败或返回任何其他错误 → 报告错误并停止。

解析JSON响应。对于每个问题,提取:编号,标题,正文,标签(标签名称数组),被分配人,html_url。


阶段3 — 展示并确认

展示一个获取到的问题的Markdown表格:

# 标题 标签
42 Fix null pointer in parser bug, critical
37 Add retry logic for API calls enhancement

如果FORK_MODE处于活动状态,还展示:

“Fork模式:分支将被推送到{PUSH_REPO},PR将针对{SOURCE_REPO}

如果--dry-run处于活动状态:

  • 展示表格并停止。不要进入阶段4。

如果--yes处于活动状态:

  • 展示表格以供查看
  • 自动处理所有列出的问题,不询问确认
  • 直接进入阶段4

否则:询问用户确认要处理哪些问题:

  • “all” — 处理每个列出的问题
  • 逗号分隔的数字(例如42, 37) — 仅处理那些
  • “cancel” — 完全中止

等待用户响应后再继续。

监视模式说明:在第一次轮询时,总是与用户确认(除非设置了--yes)。在随后的轮询中,自动处理所有新问题,无需重新确认(用户已经选择加入)。仍然展示表格,以便他们可以看到正在处理的内容。


阶段4 — 预飞行检查

通过exec顺序运行这些检查:

  1. 脏工作树检查:

    git status --porcelain
    

    如果输出不为空,警告用户:

    “工作树有未提交的更改。子代理将从HEAD创建分支 —— 未提交的更改将不会被包括。继续吗?” 等待确认。如果拒绝,停止。

  2. 记录基础分支:

    git rev-parse --abbrev-ref HEAD
    

    存储为BASE_BRANCH。

  3. 验证远程访问: 如果FORK_MODE:

    • 验证fork远程是否存在。检查是否存在名为fork的git远程:
      git remote get-url fork
      
      如果不存在,添加它:
      git remote add fork https://x-access-token:$GH_TOKEN@github.com/{PUSH_REPO}.git
      
    • 还要验证origin(源仓库)是否可达:
      git ls-remote --exit-code origin HEAD
      

    如果不FORK_MODE:

    git ls-remote --exit-code origin HEAD
    

    如果失败,停止并说:“无法到达远程origin。检查你的网络和git配置。”

  4. 验证GH_TOKEN有效性:

    curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $GH_TOKEN" https://api.github.com/user
    

    如果HTTP状态不是200,停止并说:

    “GitHub身份验证失败。请检查OpenClaw仪表板中的apiKey,或在~/.openclaw/openclaw.json中的skills.entries.gh-issues下。”

  5. 检查现有PR: 对于每个确认的问题编号N,运行:

    curl -s -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
      "https://api.github.com/repos/{SOURCE_REPO}/pulls?head={PUSH_REPO_OWNER}:fix/issue-{N}&state=open&per_page=1"
    

    (其中PUSH_REPO_OWNER是PUSH_REPO的所有者部分) 如果响应数组不为空,则从处理列表中移除该问题,并报告:

    “Skipping #{N} — PR already exists: {html_url}”

    如果所有问题都被跳过,报告并停止(如果在监视模式下则循环回来)。

  6. 检查进行中的分支(尚未PR = 子代理仍在工作): 对于每个剩余的问题编号N(上面第5步中没有被跳过的),检查fix/issue-{N}分支是否存在于推送仓库上(可能是fork,不是origin):

    curl -s -o /dev/null -w "%{http_code}" \
      -H "Authorization: Bearer $GH_TOKEN" \
      "https://api.github.com/repos/{PUSH_REPO}/branches/fix/issue-{N}"
    

    如果HTTP 200 → 分支存在于推送仓库上但没有找到与之相关的开放PR。跳过该问题:

    “Skipping #{N} — branch fix/issue-{N} exists on {PUSH_REPO}, fix likely in progress”

这个检查使用GitHub API而不是git ls-remote,因此在fork模式下也能正确工作(分支被推送到fork,而不是origin)。

如果在所有问题都被跳过此检查后,报告并停止(如果在监视模式下则循环回来)。

  1. 检查基于声明的进行中跟踪: 这防止了当之前的cron运行的子代理仍在工作但尚未推送分支或打开PR时重复处理。

    读取声明文件(如果缺失则创建空的{}):

    CLAIMS_FILE="/data/.clawdbot/gh-issues-claims.json"
    if [ ! -f "$CLAIMS_FILE" ]; then
      mkdir -p /data/.clawdbot
      echo '{}' > "$CLAIMS_FILE"
    fi
    

    解析声明文件。对于每个条目,如果声明时间戳超过2小时。如果是,将其移除(已过期 —— 子代理可能已完成或默默失败)。写回清理后的文件:

    CLAIMS=$(cat "$CLAIMS_FILE")
    CUTOFF=$(date -u -d '2 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-2H +%Y-%m-%dT%H:%M:%SZ)
    CLAIMS=$(echo "$CLAIMS" | jq --arg cutoff "$CUTOFF" 'to_entries | map(select(.value > $cutoff)) | from_entries')
    echo "$CLAIMS" > "$CLAIMS_FILE"
    

    对于每个剩余的问题编号N(上面第5步或第6步中没有被跳过的),检查{SOURCE_REPO}#{N}是否存在作为键在声明文件中。

如果声明并且没有过期 → 跳过:

“Skipping #{N} — sub-agent claimed this issue {minutes}m ago, still within timeout window”

其中{minutes}是从声明时间戳到现在计算的。

如果在所有问题都被跳过此检查后,报告并停止(如果在监视模式下则循环回来)。


阶段5 — 生成子代理(并行)

Cron模式(--cron处于活动状态):

  • 顺序游标跟踪: 使用游标文件跟踪下一个要处理的问题:

    CURSOR_FILE="/data/.clawdbot/gh-issues-cursor-{SOURCE_REPO_SLUG}.json"
    # SOURCE_REPO_SLUG = owner-repo,用连字符替换斜杠(例如,openclaw-openclaw)
    

    读取游标文件(如果缺失则创建):

    if [ ! -f "$CURSOR_FILE" ]; then
      echo '{"last_processed": null, "in_progress": null}' > "$CURSOR_FILE"
    fi
    
    • last_processed:最后完成的问题的编号(如果没有则为null)
    • in_progress:当前正在处理的问题编号(如果没有则为null)
  • 选择下一个问题: 过滤获取的问题列表,找到第一个问题,其中:

    • 问题编号 > last_processed(如果设置了last_processed)
    • 并且问题不在声明文件中(尚未进行中)
    • 并且没有为该问题存在PR(在阶段4第5步中检查)
    • 并且在推送仓库上没有分支(在阶段4第6步中检查)
  • 如果在last_processed游标之后没有找到合格的问题,回绕到开始(从最老的合格问题开始)。

  • 如果找到了合格的问题:

    1. 在游标文件中将其标记为进行中
    2. 为该问题生成一个子代理,cleanup: "keep"runTimeoutSeconds: 3600
    3. 如果提供了--model,则在生成配置中包括model: "{MODEL}"
    4. 如果提供了--notify-channel,则在任务中包括频道,以便子代理可以通知
    5. 不要等待子代理结果 —— 发射并忘记
    6. 写声明: 生成后,读取声明文件,添加{SOURCE_REPO}#{N}与当前ISO时间戳,并写回
    7. 立即报告:“Spawned fix agent for #{N} — will create PR when complete”
    8. 退出技能。不要进入结果收集或阶段6。
  • 如果没有找到合格的问题(所有问题要么有PRs,要么有分支,要么正在进行中),报告"No eligible issues to process — all issues have PRs/branches or are in progress"并退出。

普通模式(--cron不处于活动状态): 对于每个确认的问题,使用sessions_spawn生成子代理。同时启动多达8个(匹配subagents.maxConcurrent: 8)。如果问题超过8个,分批处理 —— 每个完成后启动下一个代理。

写声明: 生成每个子代理后,读取声明文件,添加{SOURCE_REPO}#{N}与当前ISO时间戳,并写回(与cron模式上述程序相同)。这涵盖了交互式使用,其中监视模式可能与cron运行重叠。

子代理任务提示

对于每个问题,构建以下提示并传递给sessions_spawn。注入到模板中的变量:

  • {SOURCE_REPO} — 问题所在的上游仓库
  • {PUSH_REPO} — 推送分支的仓库(与SOURCE_REPO相同,除非fork模式)
  • {FORK_MODE} — true/false
  • {PUSH_REMOTE} — 如果FORK_MODE,则是fork,否则是origin
  • {number}, {title}, {url}, {labels}, {body} — 来自问题
  • {BASE_BRANCH} — 来自阶段4
  • {notify_channel} — Telegram频道ID用于通知(如果没有设置则为空)。在模板中将{notify_channel}替换为--notify-channel标志的值(如果没有提供则保留为空字符串)。

构建任务时,用实际值替换所有模板变量,包括{notify_channel}。

你是一个专注的代码修复代理。你的任务是修复一个GitHub问题并打开一个PR。

重要:不要使用gh CLI —— 它没有安装。使用curl与GitHub REST API进行所有GitHub操作。

首先,确保GH_TOKEN已设置。检查:`echo $GH_TOKEN`。如果为空,从配置中读取:
GH_TOKEN=$(cat ~/.openclaw/openclaw.json 2>/dev/null | jq -r '.skills.entries["gh-issues"].apiKey // empty') || GH_TOKEN=$(cat /data/.clawdbot/openclaw.json 2>/dev/null | jq -r '.skills.entries["gh-issues"].apiKey // empty')

在所有GitHub API调用中使用该令牌:
curl -s -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" ...

<config>
源仓库(问题):{SOURCE_REPO}
推送仓库(分支 + PRs):{PUSH_REPO}
Fork模式:{FORK_MODE}
推送远程名称:{PUSH_REMOTE}
基础分支:{BASE_BRANCH}
通知频道:{notify_channel}
</config>

<issue>
仓库:{SOURCE_REPO}
问题:#{number}
标题:{title}
URL:{url}
标签:{labels}
正文:{body}
</issue>

<instructions>
按顺序遵循以下步骤。如果任何步骤失败,报告失败并停止。

0. SETUP — 确保GH_TOKEN可用:

export GH_TOKEN=$(node -e “const fs=require(‘fs’); const c=JSON.parse(fs.readFileSync(‘/data/.clawdbot/openclaw.json’,‘utf8’)); console.log(c.skills?.entries?.[‘gh-issues’]?.apiKey || ‘’)”)

如果失败,也尝试:

export GH_TOKEN=$(cat ~/.openclaw/openclaw.json 2>/dev/null | node -e “const fs=require(‘fs’);const d=JSON.parse(fs.readFileSync(0,‘utf8’));console.log(d.skills?.entries?.[‘gh-issues’]?.apiKey||‘’)”)

验证:echo "Token: ${GH_TOKEN:0:10}..."

1. CONFIDENCE CHECK — 实施前,评估这个问题是否可以操作:
- 仔细阅读问题正文。问题是否清楚描述?
- 搜索代码库(grep/find)以找到相关代码。你能定位它吗?
- 范围合理吗?(单个文件/函数 = 好,整个子系统 = 坏)
- 是否建议了具体的修复,还是只是一个模糊的投诉?

对你的信心进行评分(1-10)。如果信心<7,停止并报告:
> "Skipping #{number}: Low confidence (score: N/10) — [reason: vague requirements | cannot locate code | scope too large | no clear fix suggested]"

只有在信心≥7时才继续。

1. UNDERSTAND — 仔细阅读问题。确定需要更改的内容和位置。

2. BRANCH — 从基础分支创建一个特性分支:
git checkout -b fix/issue-{number} {BASE_BRANCH}

3. ANALYZE — 搜索代码库以找到相关文件:
- 使用grep/find通过exec定位与问题相关的代码
- 阅读相关文件以了解当前行为
- 确定根本原因

4. IMPLEMENT — 进行最小、专注的修复:
- 遵循现有的代码风格和约定
- 只更改修复问题所必需的内容
- 不要在没有理由的情况下添加无关的更改或新依赖

5. TEST — 如果存在,发现并运行现有的测试套件:
- 查找package.json脚本,Makefile目标,pytest,cargo test等。
- 运行相关测试
- 如果测试在修复后失败,尝试一次带有修正方法的重试
- 如果测试仍然失败,报告失败

6. COMMIT — 阶段和提交更改:
git add {changed_files}
git commit -m "fix: {short_description}

Fixes {SOURCE_REPO}#{number}"

7. PUSH — 推送分支:
首先,确保推送远程使用令牌认证并禁用凭据助手:
git config --global credential.helper ""
git remote set-url {PUSH_REMOTE} https://x-access-token:$GH_TOKEN@github.com/{PUSH_REPO}.git
然后推送:
GIT_ASKPASS=true git push -u {PUSH_REMOTE} fix/issue-{number}

8. PR — 使用GitHub API创建拉取请求:

如果FORK_MODE为真,则PR从你的fork到源仓库:
- head = "{PUSH_REPO_OWNER}:fix/issue-{number}"
- base = "{BASE_BRANCH}"
- PR在{SOURCE_REPO}上创建

如果FORK_MODE为假:
- head = "fix/issue-{number}"
- base = "{BASE_BRANCH}"
- PR在{SOURCE_REPO}上创建

curl -s -X POST \
  -H "Authorization: Bearer $GH_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  https://api.github.com/repos/{SOURCE_REPO}/pulls \
  -d '{
    "title": "fix: {title}",
    "head": "{head_value}",
    "base": "{BASE_BRANCH}",
    "body": "## Summary

{one_paragraph_description_of_fix}

## Changes

{bullet_list_of_changes}

## Testing

{what_was_tested_and_results}

Fixes {SOURCE_REPO}#{number}"
  }'

从响应中提取`html_url` —— 这是PR链接。

9. REPORT — 发送摘要:
- PR URL(第8步中的html_url)
- 更改的文件(列表)
- 修复摘要(1-2句话)
- 任何注意事项

10. NOTIFY (如果notify_channel设置) — 如果{notify_channel}不为空,则向Telegram频道发送通知:

使用消息工具,使用:

  • action: “send”
  • channel: “telegram”
  • target: “{notify_channel}”
  • message: "✅ PR Created: {SOURCE_REPO}#{number}

{title}

{pr_url}

Files changed: {files_changed_list}"

</instructions>

<constraints>
- 不要强制推送,不要修改基础分支
- 不要进行无关的更改或无谓的重构
- 没有新依赖的理由不要添加新依赖
- 如果问题不清晰或太复杂而无法自信地修复,报告你的分析而不是猜测
- 不要使用gh CLI —— 它不可用。使用curl + GitHub REST API进行所有GitHub操作。
- GH_TOKEN已经在环境中 —— 不要提示认证
- 时间限制:你最多有60分钟。彻底 —— 正确分析,测试你的修复,不要匆忙。
</constraints>

每个子代理的生成配置:

  • runTimeoutSeconds: 3600(60分钟)
  • cleanup: “keep”(保留记录以供审查)
  • 如果提供了--model,则在生成配置中包括model: "{MODEL}"

超时处理

如果子代理超过60分钟,记录为:

“#{N} — 超时(问题可能太复杂,无法自动修复)”


结果收集

如果--cron处于活动状态: 完全跳过这一节 —— 指挥者已经在阶段5生成后退出。

在所有子代理完成(或超时)后,收集他们的结果。将成功打开的PR列表存储在OPEN_PRS中(PR编号,分支名称,问题编号,PR URL)以供阶段6使用。

展示一个摘要表:

问题 状态 PR 注释
#42 Fix null pointer PR opened https://github.com/.../pull/99 3 files changed
#37 Add retry logic Failed Could not identify target code
#15 Update docs Timed out Too complex for auto-fix
#8 Fix race condition Skipped PR already exists

状态值:

  • PR opened — 成功,链接到PR
  • Failed — 子代理无法完成(在注释中包括原因)
  • Timed out — 超过60分钟限制
  • Skipped — 检测到现有PR在预飞行中

最后用一句话总结:

“Processed {N} issues: {success} PRs opened, {failed} failed, {skipped} skipped.”

发送通知到频道(如果设置了--notify-channel): 如果提供了--notify-channel,使用message工具将最终摘要发送到该Telegram频道:

使用消息工具,使用:
- action: "send"
- channel: "telegram"
- target: "{notify-channel}"
- message: "✅ GitHub Issues Processed

Processed {N} issues: {success} PRs opened, {failed} failed, {skipped} skipped.

{PR_LIST}"

其中PR_LIST只包括成功打开的PR,格式为:
• #{issue_number}: {PR_url} ({notes})

然后进入阶段6。


阶段6 — PR评论处理程序

这个阶段监控打开的PR(由这个技能或预先存在的fix/issue-* PR创建)以获取审核评论,并生成子代理以解决它们。

当这个阶段运行时:

  • 在结果收集(阶段2-5完成后) —— 检查刚刚打开的PR
  • 当设置了--reviews-only标志时 —— 完全跳过阶段2-5,只运行这个阶段
  • 在监视模式下 —— 在检查新问题后每个轮询周期运行

Cron评论模式(--cron --reviews-only): 当同时设置了--cron--reviews-only

  1. 运行令牌解析(阶段2令牌部分)
  2. 发现打开的fix/issue-* PR(步骤6.1)
  3. 获取审核评论(步骤6.2)
  4. 分析评论内容以确定是否可操作(步骤6.3)
  5. 如果发现可操作的评论,为第一个有未解决评论的PR生成一个评论修复子代理 —— 发射并忘记(不要等待结果)
    • 使用cleanup: "keep"runTimeoutSeconds: 3600
    • 如果提供了--model,则在生成配置中包括model: "{MODEL}"
  6. 报告:“Spawned review handler for PR #{N} — will push fixes when complete”
  7. 立即退出技能。不要进入步骤6.5(评论结果)。

如果没有发现可操作的评论,报告"No actionable review comments found"并退出。

普通模式(非cron)继续以下:

步骤6.1 — 发现要监控的PR

收集要检查审核评论的PR:

如果来自阶段5: 使用结果收集中的OPEN_PRS列表。

如果--reviews-only或随后的监视周期: 获取所有开放的fix/issue-分支模式的PR:

curl -s -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/{SOURCE_REPO}/pulls?state=open&per_page=100"

过滤为head.reffix/issue-开头的PR。

对于每个PR,提取:number(PR编号),head.ref(分支名称),html_urltitlebody

如果没有找到PR,报告"No open fix/ PRs to monitor"并停止(如果在监视模式下则循环回来)。

步骤6.2 — 获取所有审核来源

对于每个PR,从多个来源获取审核:

获取PR审核:

curl -s -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/{SOURCE_REPO}/pulls/{pr_number}/reviews"

获取PR审核评论(内联/文件级):

curl -s -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/{SOURCE_REPO}/pulls/{pr_number}/comments"

获取PR问题评论(一般对话):

curl -s -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/{SOURCE_REPO}/issues/{pr_number}/comments"

获取PR正文以嵌入审核: 一些审核工具(如Greptile)直接在PR正文中嵌入反馈。检查:

  • <!-- greptile_comment -->标记
  • PR正文中的其他结构化审核部分
curl -s -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" \
  "https://api.github.com/repos/{SOURCE_REPO}/pulls/{pr_number}"

提取body字段并解析嵌入的审核内容。

步骤6.3 — 分析评论以确定可操作性

确定机器人自己的用户名以过滤:

curl -s -H "Authorization: Bearer $GH_TOKEN" https://api.github.com/user | jq -r '.login'

存储为BOT_USERNAME。排除任何user.login等于BOT_USERNAME的评论。

对于每个评论/审核,分析内容以确定是否需要行动:

不可操作(跳过):

  • 纯粹的批准或"LGTM"没有建议
  • 仅提供信息的机器人评论(CI状态,没有具体请求的自动生成摘要)
  • 已经解决的评论(检查机器人是否用"Addressed in commit…"回复)
  • 审核状态为APPROVED且没有内联评论请求更改

是可操作的(需要关注):

  • 审核状态为CHANGES_REQUESTED
  • 审核状态为COMMENTED包含具体请求:
    • “this test needs to be updated”
    • “please fix”, “change this”, “update”, “can you”, “should be”, “needs to”
    • “will fail”, “will break”, “causes an error”
    • 提及特定代码问题(错误,缺少错误处理,边缘情况)
  • 指出代码问题的内联审核评论
  • PR正文中嵌入的审核,识别:
    • 临界问题或破坏性更改
    • 预期的测试失败
    • 需要关注的特定代码
    • 带有担忧的信心分数

解析嵌入的审核内容(例如,Greptile): 寻找用<!-- greptile_comment -->或类似标记的节。提取:

  • 摘要文本
  • 任何提及"Critical issue", “needs attention”, “will fail”, “test needs to be updated”
  • 低于4/5的信心分数(表示担忧)

构建可操作_comments列表,包括:

  • 来源(审核,内联评论,PR正文等)
  • 作者
  • 正文文本
  • 对于内联:文件路径和行号
  • 识别的具体行动项目

如果没有在任何PR中发现可操作的评论,报告"No actionable review comments found"并停止(如果在监视模式下则循环回来)。

步骤6.4 — 展示审核评论

展示带有待处理可操作评论的PR的表格:

| PR | Branch | Actionable Comments | Sources |
|----|--------|---------------------|---------|
| #99 | fix/issue-42 | 2 comments | @reviewer1, greptile |
| #101 | fix/issue-37 | 1 comment | @reviewer2 |

如果--yes未设置且这不是随后的监视轮询:询问用户确认要处理哪些PR(“all”,逗号分隔的PR编号,或"skip")。

步骤6.5 — 生成审核修复子代理(并行)

对于每个有可操作评论的PR,生成一个子代理。同时启动多达8个。

审核修复子代理提示:

你是一个PR审核处理代理。你的任务是通过进行请求的更改,推送更新,并回复每个评论来处理拉取请求上的审核评论。

重要:不要使用gh CLI —— 它没有安装。使用curl与GitHub REST API进行所有GitHub操作。

首先,确保GH_TOKEN已设置。检查:echo $GH_TOKEN。如果为空,从配置中读取:
GH_TOKEN=$(cat ~/.openclaw/openclaw.json 2>/dev/null | jq -r '.skills.entries["gh-issues"].apiKey // empty') || GH_TOKEN=$(cat /data/.clawdbot/openclaw.json 2>/dev/null | jq -r '.skills.entries["gh-issues"].apiKey // empty')

<config>
仓库:{SOURCE_REPO}
推送仓库:{PUSH_REPO}
Fork模式:{FORK_MODE}
推送远程:{PUSH_REMOTE}
PR编号:{pr_number}
PR URL:{pr_url}
分支:{branch_name}
</config>

<review_comments>
{json_array_of_actionable_comments}

每个评论都有:
- id:评论ID(用于回复)
- user:谁留下的
- body:评论文本
- path:文件路径(对于内联评论)
- line:行号(对于内联评论)
- diff_hunk:周围的diff上下文(对于内联评论)
- source:评论来源(审核,内联,pr_body,greptile等)
</review_comments>

<instructions>
按顺序遵循以下步骤:

0. SETUP — 确保GH_TOKEN可用:

export GH_TOKEN=$(node -e “const fs=require(‘fs’); const c=JSON.parse(fs.readFileSync(‘/data/.clawdbot/openclaw.json’,‘utf8’)); console.log(c.skills?.entries?.[‘gh-issues’]?.apiKey || ‘’)”)

验证:echo "Token: ${GH_TOKEN:0:10}..."

1. CHECKOUT — 切换到PR分支:
git fetch {PUSH_REMOTE} {branch_name}
git checkout {branch_name}
git pull {PUSH_REMOTE} {branch_name}

2. UNDERSTAND — 仔细阅读所有审核评论。按文件分组。了解每个审阅者要求的内容。

3. IMPLEMENT — 对于每个评论,进行请求的更改:
- 阅读文件并定位相关代码
- 进行审阅者请求的更改
- 如果评论模糊或你不同意,仍然尝试合理的修复,但注明你的担忧
- 如果评论要求不可能或矛盾的事情,跳过并在回复中解释原因

4. TEST — 运行现有测试以确保你的更改不会破坏任何内容:
- 如果测试失败,修复问题或撤销有问题的更改
- 在你的回复中注明任何测试失败

5. COMMIT — 阶段并提交所有更改为一个提交:
git add {changed_files}
git commit -m "fix: address review comments on PR #{pr_number}

Addresses review feedback from {reviewer_names}"

6. PUSH — 推送更新的分支:
git config --global credential.helper ""
git remote set-url {PUSH_REMOTE} https://x-access-token:$GH_TOKEN@github.com/{PUSH_REPO}.git
GIT_ASKPASS=true git push {PUSH_REMOTE} {branch_name}

7. REPLY — 对于每个解决的评论,发布回复:

对于内联审核评论(有路径/行),在评论线程中回复:
curl -s -X POST \
  -H "Authorization: Bearer $GH_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  https://api.github.com/repos/{SOURCE_REPO}/pulls/{pr_number}/comments/{comment_id}/replies \
  -d '{"body": "Addressed in commit {short_sha} — {brief_description_of_change}"}'

对于一般PR评论(问题评论),在PR上回复:
curl -s -X POST \
  -H "Authorization: Bearer $GH_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  https://api.github.com/repos/{SOURCE_REPO}/issues/{pr_number}/comments \
  -d '{"body": "Addressed feedback from @{reviewer}:

{summary_of_changes_made}

Updated in commit {short_sha}"}'

对于你不能解决的评论,回复解释原因:
"Unable to address this comment: {reason}. This may need manual review."

8. REPORT — 发送摘要:
- PR URL
- 解决的评论数量与跳过的评论数量
- 提交SHA
- 更改的文件
- 需要手动关注的任何评论
</instructions>

<constraints>
- 只修改与审核评论相关的文件
- 不要进行无关的更改
- 不要强制推送 —— 总是正常推送
- 如果一个评论与另一个评论相矛盾,处理最新的一个并标记冲突
- 不要使用gh CLI —— 使用curl + GitHub REST API
- GH_TOKEN已经在环境中 —— 不要提示认证
- 时间限制:最多60分钟
</constraints>

每个审核修复子代理的生成配置:

  • runTimeoutSeconds: 3600(60分钟)
  • cleanup: “keep”(保留记录以供审查)
  • 如果提供了--model,则在生成配置中包括model: "{MODEL}"

步骤6.6 — 审核结果

在所有审核子代理完成后,展示一个摘要:

| PR | Comments Addressed | Comments Skipped | Commit | Status |
|----|-------------------|-----------------|--------|--------|
| #99 fix/issue-42 | 3 | 0 | abc123f | All addressed |
| #101 fix/issue-37 | 1 | 1 | def456a | 1 needs manual review |

将此批次的评论ID添加到ADDRESSED_COMMENTS集合中,以防止重新处理。


监视模式(如果–watch处于活动状态)

在展示当前批次的结果后:

  1. 将此批次的所有问题编号添加到运行中的PROCESSED_ISSUES集合中。
  2. 将所有解决的评论ID添加到ADDRESSED_COMMENTS。
  3. 告诉用户:

    “Next poll in {interval} minutes… (say ‘stop’ to end watch mode)”

  4. 睡眠{interval}分钟。
  5. 返回阶段2 — 获取问题。获取将自动过滤:
    • 已经在PROCESSED_ISSUES中的问题
    • 已经有fix/issue-{N} PR的问题(在阶段4预飞行中捕获)
  6. 在阶段2-5之后(如果没有新问题),运行阶段6以检查所有跟踪的PR上的新审核评论(包括新创建的和之前打开的)。
  7. 如果没有新问题并且没有新的可操作审核评论 → 报告"No new activity. Polling again in {interval} minutes…"并循环回到步骤4。
  8. 用户可以随时说"stop"以退出监视模式。停止时,展示所有批次的最终累积摘要 —— 处理问题和审核评论。

轮询之间的上下文卫生 —— 重要: 只在轮询周期之间保留:

  • PROCESSED_ISSUES(问题编号集合)
  • ADDRESSED_COMMENTS(评论ID集合)
  • OPEN_PRS(跟踪的PR列表:编号,分支,URL)
  • 累积结果(每个问题一行 + 每个审核批次一行)
  • 解析的参数来自阶段1
  • BASE_BRANCH, SOURCE_REPO, PUSH_REPO, FORK_MODE, BOT_USERNAME 不要在轮询之间保留问题正文,评论正文,子代理记录,或代码库分析。