mcpField
P
pr-comment-triage

pr-comment-triage

github.com/bonkey测试与质量042 次安装3 周前更新
代码仓库

关于 pr-comment-triage

pr-comment-triage 用于处理当前分支 PR 上的反馈。它会结合代码和讨论核实每项主张,再判断是否修改代码、回复或解决审查线程。

主要功能

  1. 01获取当前 PR 的反馈
  2. 02追踪分页评论和审查线程
  3. 03依据代码核实评论主张
  4. 04区分 Agent 与人工反馈
  5. 05解决线程前先回复说明

适用场景

  1. 01整理进行中的 PR 反馈
  2. 02核实审查意见是否成立
  3. 03确认修复后解决审查线程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bonkey/skills --skill pr-comment-triage

安装后在 Claude Code 中输入/pr-comment-triage确认已加载。

详细介绍

PR 评论分诊

审查当前 PR 上的每条评论,并谨慎决定如何处理:在代码中修复、回复以请求澄清,或在问题已处理时将其解决。解决每个已确认处理完毕的审查讨论串,并在解决时始终附上一条简短的说明回复。

评论是对代码的判断,并非关于代码的事实。每位作者的评论都如此,而 AI 审查 Agent 的评论尤其如此,因为它们只根据单个差异片段作出判断,缺少人类审查者掌握的上下文。在根据任何判断修改代码之前,都要先对照代码确认。

范围

当用户希望获得有关当前 PR 反馈的帮助时,使用此技能,包括以下请求:

  • “检查 PR 上的评论”
  • “分诊审查反馈”
  • “检查这些 PR 评论是否仍需处理”
  • “解决已处理的审查评论”

此技能适用于当前分支上的当前 PR。

规则

  • 对线程是否已处理应保持谨慎,但一旦确认已处理,就要解决它——不要让已确认处理完毕的线程继续处于未解决状态。
  • 在解决线程之前,始终在该线程中附上一条简短的说明回复,无论解决的原因是什么(代码已修复、评论无效、问题已过时或讨论已达成一致)。
  • 在你发布到 PR 的每条评论(包括线程回复和顶层评论)末尾都添加署名行:🤖 Generated with Claude Code。将其单独放在评论正文的最后一行。
  • 报告你发布的每条评论。发布时从 API 响应中获取每条评论的 URL——绝不要重建或猜测链接——并在本次运行结束时全部列出,每条内容缩写为一两句话。
  • 读取每个 API 响应的所有分页。GitHub 每页最多返回 100 项,因此未分页的请求无法完整列出内容——请参阅识别当前 PR中的分页命令。
  • 此技能可重复运行。假设它可能会在同一 PR 上多次运行,每次运行都要重新获取实时状态——绝不要依赖上次运行时的清单。每次运行都要收集上次之后新增的评论,并重新检查代码可能已处理或已使其过时的未解决线程。
  • 区分审查线程和顶层 PR 评论:
    • 审查线程可以解决。
    • GitHub 上的顶层 PR 对话评论不能标记为已解决;只能回复或保持原样。
  • 绝不要盲目地批量解决所有评论。
  • 作出决定前,先阅读当前代码和相关讨论。
  • 如果评论含糊不清、与其他反馈冲突,或需要产品/架构决策,应询问用户,而不是自行猜测。
  • **将 AI 撰写的每条评论都视为未经验证的判断。**审查 Agent——Copilot、CodeRabbit、Devin、Greptile、Graphite、任何 [bot] 账号,以及仓库运行的任何内部审查 Agent——只能看到差异,无法了解仓库的历史、约定、调用方或测试。它们可能会报告周边代码已避免的缺陷、引用项目中不存在的符号和 API,或要求进行项目已决定不做的改动。措辞再肯定也不是证据。请参阅对 AI 撰写的评论提高验证标准。
  • **绝不要为了满足未经确认的 Agent 评论而修改代码。**未经确认的判断应视为驳回,而不是可以顺手采取的预防措施。回复中要说明代码实际的行为。
  • 保持怀疑不等于一概否定。Agent 的判断也可能正确;确认属实的评论应像其他评论一样处理。改变的是举证标准,而不是采取行动的意愿。

工作流

1. 识别当前 PR

获取当前检出分支对应的 PR。

推荐命令:

gh pr view --json number,title,url,headRepositoryOwner

使用 gh api graphql 获取审查线程,因为 gh pr view 可能无法提供所需的完整线程清单。

获取以下内容:

  • PR 编号、标题、URL
  • 审查线程,包含:
    • 线程 ID
    • 已解决状态
    • 文件路径/行号(如有)
    • 线程中的所有评论
  • PR 对话中的顶层 issue 评论
读取每一页

GitHub 会将每次响应限制为 100 项,而 gh pr view --json comments,reviews 只返回第一页。截断的获取结果会隐藏评论,且不会报错,因此每次调用列表时都要传入 --paginate,并持续跟进游标,直到 hasNextPage 为 false。

REST 端点——--paginate 会沿着 Link 标头一直跟进到最后一页:

gh api --paginate repos/OWNER/REPO/issues/PR_NUMBER/comments   # top-level conversation
gh api --paginate repos/OWNER/REPO/pulls/PR_NUMBER/comments    # review thread comments
gh api --paginate repos/OWNER/REPO/pulls/PR_NUMBER/reviews     # review summaries

GraphQL——查询必须声明 $endCursor 变量并请求 pageInfo { hasNextPage endCursor },否则 --paginate 无法继续翻页:

gh api graphql --paginate -F owner='OWNER' -F repo='REPO' -F pr=PR_NUMBER -f query='
query($owner:String!, $repo:String!, $pr:Int!, $endCursor:String) {
  repository(owner: $owner, name: $repo) {
    pullRequest(number: $pr) {
      reviewThreads(first: 100, after: $endCursor) {
        pageInfo { hasNextPage endCursor }
        nodes {
          id
          isResolved
          isOutdated
          path
          line
          comments(first: 100) {
            pageInfo { hasNextPage endCursor }
            nodes { id author { login __typename } createdAt body url }
          }
        }
      }
    }
  }
}'

--paginate 每次查询只会跟进一个连接——此处为 reviewThreads。嵌套连接仍有各自的限制,因此,如果某个线程的 comments 报告 hasNextPage: true,就需要单独再查询一次该线程剩余的评论。

记录每条评论的作者

对于 Copilot 或 CodeRabbit 等 GitHub App 账号,author.__typename 的值为 Bot;REST 中对应的字段是 user.type。通过普通用户账号发布评论的 Agent 会显示为 User,因此还要将登录名与此仓库运行的评审 Agent 进行匹配;仅凭类型无法区分内部 Agent 和真人。在清单中将每条评论标记为 human 或 agent。这项标记决定了在依据评论修改代码前需要多少证据。

如果当前分支没有 PR,请停止并告知用户。

2. 建立完整的评论清单

收集所有可能需要采取行动的反馈,包括真人和 Agent 的反馈。每次运行时都要重新建立清单,以便反复运行时始终与当前 PR 保持同步:

  • 尚未解决的评审线程——包括上次运行后新增的线程
  • 关注点可能已被当前代码解决的未结线程(应将其标记为已解决),或已失效的未结线程(引用的代码已更改、移动或删除)
  • 可能被错误标记为已解决的已解决评审线程
  • 对话中的顶层 PR 评论
  • 包含可执行请求的评审摘要

在评估任何内容之前,先确认清单完整:每次列表调用都使用了 --paginate,每个游标都已跟进至 hasNextPage 为 false,且线程数和评论数与 PR 页面显示的数量一致。如果数量不一致,请重新获取,而不要对不完整的列表进行分类处理。

对于每项,记录:

  • 评论/线程标识符
  • 作者,以及作者是真人还是 AI Agent
  • 时间戳
  • 适用时记录代码位置
  • 评论原文
  • 回复/线程上下文
  • 当前是否已解决

忽略明显的机器人噪声——吹毛求疵的刷屏、重复的评审摘要、覆盖率相关闲聊——除非用户要求纳入。AI Agent 的实质性评论不是噪声:将其保留在清单中并进行核实。无法判断是噪声还是实质内容时,将其保留。

3. 仔细评估每条评论

将每条评论归入以下类别之一:

  1. 在代码中处理

    • 反馈有效且尚未处理。
    • 仍需修改代码/配置/文档。
  2. 已处理,可安全标记为已解决

    • 所要求的更改已存在于当前分支中。
    • 或线程已被更好的实现取代,原有关注点已不再适用。
  3. 需要讨论/由用户决定

    • 评论含义不明确。
    • 请求与其他要求冲突。
    • 建议的修复有风险、涉及架构或带有主观性。
  4. 无需采取行动,但无法自动标记为已解决

    • 通常适用于顶层 PR 评论,因为 GitHub 不支持将其标记为已解决。
    • 可酌情起草回复,说明为何无需进一步修改。
  5. 缺乏依据

    • 代码与说法相矛盾:前提错误、所指符号不存在、调用方已保证该不变量,或所述情况不可能发生。
    • 说明代码的实际行为,然后标记为已解决。被驳回的 AI 撰写评论归入此类。
4. 对照当前代码进行核实

在判定问题已解决之前:

  • 阅读相关文件。
  • 检查请求的行为是否确实已实现。
  • 检查后续提交或回复是否已经处理了相关问题。
  • 优先依据代码库中的证据,而非臆测。

不要仅凭“我觉得没问题”就解决讨论串。

对 AI 撰写的意见采取更严格的标准

AI 审查 Agent 看到的是差异,而不是整个项目。它无法知道调用方强制执行了哪些不变量、哪个分支不可达、代码库有意采用了哪种模式、哪个测试已经覆盖了该情况,或依赖项固定在哪个版本。因此,它的意见虽然流畅、具体,却恰好缺少决定其是否成立的上下文。

对于 Agent 提出的每条意见,在编写任何代码之前都要完成以下事项:

  1. 重新表述主张,使其可以被证伪。 “parseConfig 在 path 为空时会发生 panic”可以核实。“错误处理可以改进”则不行——请对方指出具体情况,否则驳回。
  2. 在代码中查证主张。 阅读相关函数、调用方和测试。没有读过哪些内容会到达该代码行之前,针对某一行的意见就毫无意义。
  3. 验证该意见所依赖的前提。 Agent 经常会臆测本代码库中不存在的 nil、类型、竞态、配置键或 API。请搜索该意见提到的符号。
  4. 依据证据作出判断。 已确认——处理该问题。已证伪——驳回,并指出与之矛盾的代码。两者皆非——即未确认:驳回或询问用户,并保持代码不变。

两条意见一致,不代表有两份证据;Agent 会相互重复彼此的猜测。某条意见阻止了必需检查,也不代表它就是正确的——检查未通过只能说明检查本身的情况,不能说明代码的情况。

不要为 Agent 扩大差异。重构、新增抽象、额外的防御性检查、新依赖或更广泛的重命名,都必须先得到人工请求。

建议修改代码块只是提议,不是补丁。请阅读周围代码并自行编写修复;切勿未经阅读就提交建议代码块。

5. 操作前先提供分类摘要

按决策类别提供简洁摘要:

  • 处理
  • 解决
  • 缺乏依据——指出与各项主张矛盾的代码
  • 需要用户提供信息
  • 顶层评论,无需进一步操作

每项都要包括:

  • 作者
  • 简短引述或转述
  • 决策
  • 一句话说明理由

如果用户要求你采取行动,除非某项决策存在歧义或风险,否则请在摘要之后继续操作。

根据决策采取行动

当评论需要处理时
  • 以最小且正确的改动解决根本问题。
  • 将修复限制在反馈范围内。
  • 修改代码后,依据新代码重新核查讨论串,然后解决该讨论串,并简短说明所做修复(见下文)。
何时应解决审查讨论串

只解决审查讨论串,不解决顶层 PR 评论。

无论因何原因解决讨论串,都必须先发布一条简短的解释回复。 一两句话即可;回复应告知审查者发生了什么:

  • 已在代码中修复 — 说明所做的更改;适当时提供提交或 file:line
  • 不成立 — 说明为何该问题不适用于实际实现;如果是 Agent 提出的主张,指出与其矛盾的 file:line
  • 已过时 — 相关代码已被移除或替换
  • 已通过讨论解决 — 指向解决问题的回复或决定

每条回复正文末尾都必须单独一行写上归属标记 🤖 Generated with Claude Code。

必须按以下顺序执行这两步:

  1. 在讨论串中发布解释回复。
  2. 通过 GitHub GraphQL 解决讨论串。

示例形式:

# 1. Reply with a short explanation (end the body with the attribution line).
#    Request `url` back and keep it — it is the direct link for the posted-comments list.
gh api graphql -f query='mutation($threadId:ID!,$body:String!) { addPullRequestReviewThreadReply(input:{pullRequestReviewThreadId:$threadId, body:$body}) { comment { id url } } }' -F threadId='THREAD_ID' -F body='Fixed in <commit> — extracted the helper as requested.

🤖 Generated with Claude Code'

# 2. Resolve the thread
gh api graphql -f query='mutation($threadId:ID!) { resolveReviewThread(input:{threadId:$threadId}) { thread { isResolved } } }' -F threadId='THREAD_ID'

如果讨论串已经解决,除非你发现其解决有误,否则不要处理;如果确实有误,请告知用户,不要悄悄改动历史记录。

当条目是顶层 PR 评论时

顶层 PR 评论无法解决。应改为:

  • 判断是否需要更改代码
  • 可以起草或发布一条简短回复
  • 在摘要中将其报告为已处理/无需操作

gh pr comment 会输出其创建的评论 URL — 将该 URL 保留在已发布评论列表中:

gh pr comment PR_NUMBER --body 'Confirmed — the rate limit is enforced by the gateway, so no change here.

🤖 Generated with Claude Code'

不要声称解决了 GitHub 不允许解决的内容。

输出格式

使用简洁的清单或表格,列名可包括:

  • kind(thread、top-level、review-summary)
  • author
  • author kind(human、agent)
  • location
  • decision
  • reason
  • action
已发布的评论

每次运行结束时,都要按发布顺序列出本次运行中发布的评论。每条评论使用一个项目符号:用一两句话概述评论内容,然后附上可直接访问的链接。

## Comments posted

- Extracted the retry helper into `client.go:88` as requested, then resolved the thread — [reply](https://github.com/owner/repo/pull/123#discussion_r456789)
- Explained that the nil check is unreachable because the caller validates the input — [reply](https://github.com/owner/repo/pull/123#discussion_r456790)
- Confirmed the rate limit is enforced by the gateway, so no change is needed — [comment](https://github.com/owner/repo/pull/123#issuecomment-99887766)

发布评论时,请使用 API 返回的 URL。如果本次运行没有发布评论,请明确说明,不要省略该列表。

决策标准

仅当以下至少一项成立时,才可以安全地解决讨论串:

  • 所要求的更改已在代码中实现
  • 根据实际实现,该问题不成立
  • 后续讨论已明确解决该问题
  • 相关代码已被移除或替换,因此讨论串已过时

如果无法明确确认其中任何一项,就不要解决。

代码更改还有另一道门槛。只有在你亲自发现代码中的缺陷后,AI 撰写的意见才足以触发代码更改。建议的差异、笃定的语气和红色审查状态都不能作为证据。如果无法确认该主张是否成立,应驳回或交由用户处理 — 绝不能为了保险而实施更改。

故障排除

  • 如果 gh 未通过身份验证,请告知用户运行 gh auth login。
  • 如果 GraphQL 字段因 GitHub 版本或 API 结构而不同,请改用自定义的 gh api graphql 查询。
  • 如果你确定存在的评论没有出现在清单中,说明获取结果被截断了。请使用 --paginate 重新获取,并检查嵌套连接(例如讨论串的 comments)是否有自己的 hasNextPage。
  • 如果当前分支没有 PR,请停止并告知用户。
  • 如果仅凭代码无法判断评论是否已处理,请询问用户,不要猜测。
  • 如果 AI 撰写的意见引用了你无法找到的函数、标志、字段或 API,请将该意见视为与此代码库不符,而不是认为自己的搜索不完整。在回复中说明这一点,并指出代码中实际存在的内容。
  • 如果 Agent 重复发布你已经驳回的意见,请链接到你之前的回复,而不是再次争辩,并告知用户该 Agent 正在循环重复。

评论

支持 Markdown