关于 resolve-fixed-pr-comments
resolve-fixed-pr-comments 是一项根据当前文件检查未解决的 PR 评审讨论串,并仅处理要求已完全满足或已失效项的技能。它只允许解决讨论串,禁止修改代码、运行测试及其他 GitHub 操作。
主要功能
- 01仅加载未解决的评审讨论串
- 02根据当前文件核对评论要求
- 03不处理存疑或未完全修复项
- 04仅允许解决讨论串这一写入操作
- 05禁止改代码和运行测试
适用场景
- 01核实修复后关闭评审讨论串
- 02对照反馈检查本地未提交改动
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ neolabhq/ context-engineering-kit --skill resolve-fixed-pr-comments安装后在 Claude Code 中输入/resolve-fixed-pr-comments确认已加载。
详细介绍
解决已修复的 PR 审查评论
仅加载未解决的 PR 审查讨论串,逐条根据代码库的当前状态进行核实(修复可以已提交/推送,也可以仅存在于未提交的本地更改中——两者都算),并且只解决确实已修复或已不再相关的讨论串。唯一允许的写入操作是解决讨论串。不做其他任何改动。
关键准则
违反这些规则的字面要求即表示任务失败。 如果任务失败,你会被杀掉!
- 不确定时,保留讨论串为未解决状态。宁可让已修复的评论仍未解决,也不要错误地解决尚未修复的评论。
- 你必须仅加载
isResolved/is_resolved为 false 的讨论串。跳过已解决的讨论串。 - 你必须只观察代码库的当前状态。读取文件当前的内容。不要根据代码过去的状态、某次提交改动了什么,或 Git 历史来推断——只有当前文件是否满足要求才算依据。
- 修复有效与否,不取决于是否已提交/推送。仅存在于未提交的本地更改中也可以接受。检查当前工作树即可。
- 你不得修改代码、创建/编辑/删除任何文件,也不得运行测试、代码检查工具、格式化工具或构建。
- 你不得推送、拉取、提交、暂存、检出、切换、重置、还原、变基、合并、拣选提交,或执行任何会修改 Git 状态的操作。只允许只读检查(
git status、git diff、git log、git branch),且仅用于观察当前状态。 - 你不得在 PR 中添加评论、回复讨论串、提交审查、批准或请求更改。对 GitHub 唯一允许的写入操作,是解决确实已修复的讨论串。
- 你必须审慎且严谨。只有当评论的所有要求都已在当前代码库中完全满足时,才算“已修复”。部分处理、未处理的细枝末节,以及“差不多”的改动,都必须保持未解决状态。
- 未根据实际文件核实的讨论串,绝不能解决。未核实 → 不解决。
危险信号——停止并保持未解决
如果你的判断符合以下任一情况,请勿解决讨论串:
- “修复大概已经在了,我就解决吧。”→ 不行。核实当前文件,否则保持未解决。
- “提交说明说已经修复了。”→ 提交说明和历史记录都不是证据。读取当前文件。
- “大部分要求都处理了。”→ 部分处理 ≠ 已修复。保持未解决。
- “只是个小问题,解决掉能让 PR 更整洁。”→ 未处理的细枝末节必须保持未解决。
- “代码位置变了,所以评论已不再相关。”→ 只有当要求在当前代码中确实已满足或确实已过时,才可以解决;不能因为核实起来不方便就解决。
- “我自己快速修一下,然后解决。”→ 禁止。不得修改代码。如果还没修复,就保持未解决。
- “我会回复说明为什么解决了。”→ 禁止。不得回复或评论。静默解决,或保持未解决。
- “这个分支看起来完成了,我把所有讨论串都解决。”→ 必须逐条处理,并根据各自核实到的证据决定。
合理化借口一览
| 借口 | 实际情况 |
|---|---|
| “修复已经提交了,所以事情完成了。” | 阅读当前文件并确认要求已满足。已提交 ≠ 已验证。 |
| “Git diff 显示了更改。” | diff 记录的是过去的变更。请确认当前文件内容满足要求,而不是仅确认发生过更改。 |
| “它还没提交,所以现在不算。” | 未提交的本地更改也是有效证据。请按当前工作树状态进行检查。 |
| “我只要做个小修复就可以解决了。” | 严禁编辑代码。未修复 → 未解决。 |
| “回复一下比较礼貌。” | 不要回复或发表评论。唯一允许的写入操作是解决评论。 |
| “这是个无关紧要的小问题,解决掉整理一下吧。” | 未处理 = 未解决,不论问题多么微不足道。 |
| “评审者肯定会接受这个。” | 你不是评审者。只有要求已满足时才解决,不要根据对方可能会接受来判断。 |
| “不确定 100%,但可能已经修好了。” | 不确定 = 保持未解决。 |
使用方法
一次处理一个评论线程:(1)加载未解决的评论线程及其 GraphQL 节点 id;(2)逐个阅读其引用的当前文件,并根据现有内容检查每项要求;(3)只有在要求全部满足或已不适用时才解决,否则跳过。报告已解决的内容,以及仍未解决的内容和原因。
步骤 0:确认可用工具
-
检查是否已安装并通过身份验证的 GitHub CLI:
gh auth status -
检查 GitHub MCP 服务是否可用:
mcp__MCP_DOCKER__pull_request_read如果是直接安装的,也可以使用不带
MCP_DOCKER前缀的类似命令。
- 如果两者都可用,使用任何一个具备足够仓库访问权限的工具。
- 如果 GitHub MCP 服务可用,但结构不同,请进行调整以符合预期结构。
- 如果两者都不可用,请尝试通过 curl 直接加载(以防仓库是公开的)。如果仓库是私有的,请让用户安装 GitHub CLI 或 GitHub MCP 服务。
- 如果未安装 MCP 服务,但已安装 GitHub CLI 且尚未通过身份验证,请让用户运行
gh auth login进行身份验证。
步骤 1:确定目标 PR
- 明确指定的 PR 参数始终优先于当前分支解析。如果传入了 PR 编号或 URL,请使用该参数(例如,URL
https://github.com/{owner}/{repo}/pull/{n}→ 编号{n}),不要查询当前分支。 - 否则,默认使用当前分支对应的 PR:
gh pr view --json number,url,headRefName # current branch's PR
- 解析仓库所有者/名称:
gh repo view --json owner,name。 - 如果该分支没有 PR,
gh pr view会报错“no pull requests found”——停止操作,并报告该分支没有关联的 PR(请用户提供 PR 编号/URL)。
步骤 2:获取未解决的评论
已解决/未解决是 GraphQL reviewThreads { isResolved } 的概念——REST /pulls/{n}/comments 端点不会提供此信息。使用以下两种方法之一;如果首选方法不可用,则使用另一种方法。
首选:gh CLI(GraphQL)
直接在 jq 中按 isResolved == false 进行筛选:
gh api graphql -f query='
query($owner:String!,$repo:String!,$pr:Int!){
repository(owner:$owner,name:$repo){
pullRequest(number:$pr){
reviewThreads(first:100){
nodes {
id
isResolved
isOutdated
path
line
startLine
originalLine
comments(first:50){
nodes { author{login} body diffHunk url }
}
}
}
}
}
}' -F owner=OWNER -F repo=REPO -F pr=PR_NUMBER \
--jq '[.data.repository.pullRequest.reviewThreads.nodes[]
| select(.isResolved==false)
| {id, path, isOutdated,
line: (.line // .startLine // .originalLine),
comments: [.comments.nodes[]
| {author: .author.login, url, body, diffHunk}]}]'
这会返回每个未解决评论线程的 GraphQL 节点 id(步骤 4 中解决评论时需要)、文件 path、isOutdated 标志、可用的 line,以及按顺序排列的评论(作者、正文、永久链接 url、diffHunk)。
重要:对于已过时的评论线程,line 为 null(diff 已移动)。上面的 jq 已回退到 line // startLine // originalLine,因此只要存在任何锚点,line 就不会为 null。如果这三者全都为 null,请在模板中省略 :<line> 片段——绝不要输出 path:null。
回退方案:GitHub MCP
如果 GitHub MCP 服务(MCP_DOCKER)可用,请使用 mcp__MCP_DOCKER__pull_request_read 工具,并设置 method: "get_review_comments":
mcp__MCP_DOCKER__pull_request_read
method: "get_review_comments"
owner: "OWNER"
repo: "REPO"
pullNumber: PR_NUMBER
perPage: 100
它会返回 review_threads[],每个线程都包含 is_resolved、is_outdated、is_collapsed(均为 snake_case——已根据此工具的响应确认)以及 comments[](body、path、author、html_url)。仅保留 is_resolved 为 false 的线程。请注意,MCP 评论对象包含 path,但不包含行号,因此应使用 html_url 作为位置锚点。当 pageInfo.hasNextPage 为 true 时,使用 after: <endCursor> 翻页。
MCP review-thread 对象还包含线程节点
id(PRRT_...节点 ID)。请按线程记录该 ID——第 4 步中,mcp__MCP_DOCKER__pull_request_review_write的method: "resolve_thread"需要用到它。
第 3 步:对照当前代码库验证每个线程
对于每个未解决的线程,收集具体要求,并对照当前文件内容进行验证。严格遵循关键指南。
- 确认评论的实际要求是什么。如果 HUMAN 审阅者提供了反馈,要求就是该反馈。如果只有机器人/AI 建议(Claude、CodeRabbit、Copilot 等),要求就是建议的修复。一个线程可能包含多项要求——必须全部满足,才能算已修复。
- 打开
path指定的文件并阅读当前内容(使用 Read 工具/无需使用git show :<path>——只需读取工作树文件)。可选运行git diff -- <path>或git status,仅用于查看当前未提交的更改;绝不能用来推断历史或作为证明。 - 判定处理结果:
| 处理结果 | 条件 | 操作 |
|---|---|---|
| FIXED(已修复) | 当前文件内容已完全满足线程中的每项要求(无论更改是否已提交)。 | 标记为在第 4 步解决。 |
| OBSOLETE(已过时) | 评论所指的代码确实已不存在/相关问题在当前代码中确实已不复存在。 | 标记为在第 4 步解决。 |
| NOT FIXED(未修复) | 任一要求未满足、仅部分满足,或无法从当前文件确认。 | 保持未解决。不做任何操作。 |
| UNSURE(无法确定) | 无法有把握地验证要求是否已满足。 | 保持未解决。不做任何操作。 |
不要编辑代码来让线程通过。不要运行测试/构建/代码检查来“验证”。验证时只需阅读当前源代码,并判断是否满足要求。
第 4 步:解决确实已修复的线程
对于标记为 FIXED 或 OBSOLETE 的每个线程,使用第 2 步记录的线程节点 id 进行解决。使用可用的任一方式(优先使用加载评论时所用的方式)。解决已经解决的线程不会产生影响。
首选:gh CLI(GraphQL resolveReviewThread mutation)
resolveReviewThread mutation 接受一个 ResolveReviewThreadInput,其必需字段为 threadId(即第 2 步中 reviewThreads.nodes[].id 的 GraphQL 节点 id)。已通过内省 GitHub 的 GraphQL schema 确认(ResolveReviewThreadInput.threadId: ID!)。
gh api graphql -f query='
mutation($threadId:ID!){
resolveReviewThread(input:{threadId:$threadId}){
thread { id isResolved }
}
}' -F threadId='PRRT_kwDOxxxxxxxxxxxxxxxx'
成功时,响应为 {"data":{"resolveReviewThread":{"thread":{"id":"PRRT_...","isResolved":true}}}}。请确认 isResolved 为 true。
备用方案:GitHub MCP(pull_request_review_write → resolve_thread)
GitHub MCP 服务可以通过 mcp__MCP_DOCKER__pull_request_review_write 和 method: "resolve_thread" 来解决线程。只需要 threadId(线程节点 ID,例如 PRRT_kwDOxxx)。根据该工具自身的文档,此方法不会使用 owner/repo/pullNumber,但工具架构将它们标记为必填项——请传入 PR 的 owner/repo/pullNumber 以满足验证要求;解决操作会忽略这些参数。
mcp__MCP_DOCKER__pull_request_review_write
method: "resolve_thread"
threadId: "PRRT_kwDOxxxxxxxxxxxxxxxx"
owner: "OWNER"
repo: "REPO"
pullNumber: PR_NUMBER
如果 MCP 服务不可用,或者其 pull_request_review_write 不支持 resolve_thread,则回退到上面的 gh CLI GraphQL mutation。
仅允许使用
resolve_thread。不要使用unresolve_thread、create、submit_pending、delete_pending或任何event(APPROVE/REQUEST_CHANGES/COMMENT)——此技能禁止这些写入操作。
参数说明
| 参数 | 路径 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
threadId | gh CLI 和 MCP | 字符串(ID!) | 是 | 审查线程的 GraphQL 节点 ID(reviewThreads.nodes[].id,例如 PRRT_kwDO...)。这是线程 ID,不是评论 ID,也不是数字 REST ID。 |
method | MCP | 字符串 | 是(MCP) | 必须为 "resolve_thread"。 |
owner | MCP | 字符串 | 是(MCP 架构) | 仓库所有者。resolve_thread 会忽略此参数,但工具架构要求必须提供。 |
repo | MCP | 字符串 | 是(MCP 架构) | 仓库名称。resolve_thread 会忽略此参数,但工具架构要求必须提供。 |
pullNumber | MCP | 数字 | 是(MCP 架构) | PR 编号。resolve_thread 会忽略此参数,但工具架构要求必须提供。 |
clientMutationId | gh CLI | 字符串 | 否 | GraphQL 输入中的可选去重令牌。通常省略。 |
步骤 5:报告
总结结果,不要采取任何进一步操作:
- 目标 PR(编号 + URL)。
- 已加载的未解决线程数量。
- 已解决的线程,每个线程注明其
path:line(如果位置已过时,则注明path),以及一行原因(FIXED / OBSOLETE)和当前代码中的证据。 - 未解决的线程,每个线程注明一行原因(NOT FIXED / partial / UNSURE)。
- 遇到的任何限制(例如 MCP 不可用、所有线程均已解决)。
示例
输入: resolve-fixed-pr-comments(无参数,当前分支有 PR #42)
处理: 加载 PR #42 的未解决线程(步骤 2)。线程 A 位于 src/auth.ts:30,要求“为无效令牌添加错误处理”。阅读当前的 src/auth.ts——现在令牌检查外有一个 try/catch(未提交的本地更改)。判定为 FIXED → 通过 resolveReviewThread(threadId: "PRRT_...") 解决。线程 B 位于 README.md:10,是一个小问题:“修正拼写错误 'teh'”。阅读当前的 README.md——仍然写着“teh”。判定为 NOT FIXED → 保持未解决。
输出:“PR #42:已加载 2 个未解决线程。已解决 1 个——src/auth.ts:30(FIXED:工作树中的令牌验证代码外新增了 try/catch)。保持未解决 1 个——README.md:10(NOT FIXED:仍有 'teh' 拼写错误)。”
输入: resolve-fixed-pr-comments https://github.com/acme/app/pull/7
处理: 参数优先于当前分支。PR #7。有一个线程要求将 getUser 重命名为 fetchUser,并更新其调用方。当前代码已重命名函数,但有一个调用方仍在使用 getUser。要求只部分满足 → 判定为 NOT FIXED → 保持未解决。
输出:“PR #7:已加载 1 个未解决线程。已解决 0 个。保持未解决 1 个——src/user.ts:12(NOT FIXED:函数已重命名,但 src/page.ts:5 中的调用方仍调用 getUser)。”
故障排除 / 常见问题
| 情况 | 处理方式 |
|---|---|
| 当前分支没有 PR | gh pr view 报错 → 报告此情况,并请求提供 PR 编号/URL。 |
| 参数是 URL | 提取 /pull/ 后面的数字。 |
| 未解决的讨论串数量为零 | 无需解决任何内容;报告“没有未解决的评论”。 |
| 讨论串超过 100 条 | 在验证前进行分页(GraphQL after 游标 / MCP after)。 |
| MCP 不可用 | 使用 gh GraphQL 加载并解决讨论串;如果两者都不可用,则报告限制。 |
MCP resolve_thread 因缺少 owner/repo/pullNumber 而拒绝请求 | 工具架构要求提供这些参数,尽管该方法会忽略它们——请传入 PR 的 owner/repo/pullNumber。 |
Could not resolve to a node with the global id | ID 有误——请确保传入讨论串节点 id(PRRT_...),该 ID 来自 reviewThreads.nodes[].id,而不是评论 ID 或数字型 REST ID。 |
对于你无意处理的讨论串,解决变更返回 isResolved: true | 你解决了错误的讨论串——此技能不允许安全地自动撤销(取消解决属于禁止的写入操作);请向用户报告。 |
| 修复仅存在于未提交的更改中 | 这是有效证据——检查工作树中的文件,如果要求已满足,则解决该讨论串。 |
| 无法根据当前文件确认某项要求 | 保持讨论串为未解决状态。切勿根据假设进行解决。 |
| 想通过修改代码来满足讨论串要求 | 禁止。不得修改代码。未修复的问题保持未解决。 |