mcpField
P
pr-review-canvas

pr-review-canvas

github.com/cursor测试与质量14.5k2.3k 次安装今天更新
代码仓库

关于 pr-review-canvas

用于生成 GitHub pull request 交互式 HTML 评审页面的技能。它通过摘要、文件注释、差异展示和可选图示,帮助评审者理解变更。

主要功能

  1. 01获取 PR 元数据与文件
  2. 02汇总变更内容
  3. 03展示带注释的文件区块
  4. 04渲染并分类差异
  5. 05支持图示与检查清单

适用场景

  1. 01准备引导式 PR 评审
  2. 02解释复杂代码改动
  3. 03标示移动代码或样板代码
  4. 04分享本地交互式评审页

安装

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

$npx skills add https://github.com/cursor/plugins --skill pr-review-canvas

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

renderer.js
styles.css
template.html

详细介绍

PR 评审画布

生成一份交互式 HTML,评审 GitHub PR,仿佛有位同事正带你了解其中的重点。

工作流

1. 获取 PR 数据

并行运行以下 gh api 调用:

gh api repos/{owner}/{repo}/pulls/{number} --jq '{title, body, user: .user.login, state, additions, deletions, changed_files, base: .base.ref, head: .head.ref}'
gh api repos/{owner}/{repo}/pulls/{number}/files --paginate --jq '.[] | {filename, status, additions, deletions, patch}'
gh api repos/{owner}/{repo}/pulls/{number}/comments --jq '.[] | {user: .user.login, body, path, line}'
2. 分析 PR 并编写正文 HTML

阅读差异,理解 PR,并直接以 HTML 编写 <body> 内容。你可以充分发挥创意——目标是向评审者清楚地说明这个 PR。选择最适合该 PR 的结构。

常见结构(按需调整):

  • 包含标题、PR 编号、作者和统计数据的页眉
  • 用通俗语言说明 PR 内容的摘要框
  • 带注释和差异内容的核心文件分区
  • 默认折叠的机械性或样板文件
  • 底部的评审清单

你也可以添加:

  • 伪代码摘要,用于冗长代码——用通俗语言或简短伪代码展示算法,并在下方折叠显示实际差异(使用标注为“显示完整实现”的 .bp-section 卡片)。如果 150 行重试、退避和错误处理代码实际上只是“使用指数退避和熔断器进行请求”,这种方式就很有帮助。
  • 图表(内联 SVG、通过 CDN 引入的 mermaid、<pre> 中的 ASCII 图)
  • 展示前后控制流的流程图
  • 对比新旧行为的表格
  • 用于提示警告、问题或注意事项的提示框
  • 有助于理解的交互式小部件
  • 任何其他能让评审更清晰的内容

伪代码模式示例:

<div class="file-card">
  <div class="file-hdr" onclick="toggle(this)">
    <span class="fname">retryClient.ts</span>
    <div class="fstats"><span class="pill add">+173</span><span class="pill del">&minus;11</span><span class="chev open">&#9654;</span></div>
  </div>
  <div class="file-body open">
    <div class="file-note">
      <strong>What this does in plain English:</strong>
      <pre style="margin-top:8px;color:var(--text);font-size:12px;line-height:1.6;">
fetch(url):
  if circuit breaker is open → fail fast
  retry up to N times:
    try fetch with timeout
    on success → close circuit breaker, return
    on retryable error → wait (exponential backoff + jitter)
    on non-retryable error → throw
  circuit breaker records failure</pre>
    </div>
    <div class="bp-section" style="margin:0;border:0;border-radius:0;">
      <div class="bp-hdr" onclick="toggleBP(this)">
        <span>Show full implementation (+173 lines)</span><span class="chev">&#9654;</span>
      </div>
      <div class="bp-body"><div data-diff="retryClient"></div></div>
    </div>
  </div>
</div>
3. 可用的 CSS 类和 JS 实用工具

阅读此技能目录中的 styles.css 和 renderer.js。它们提供了一套预先构建的暗色主题工具。将它们原样注入 template.html。

可使用的 CSS 类:

类用途
.header、.header h1、.header-meta页面页眉
.pill.add、.pill.del、.pill.files统计徽标(+N、-N、N 个文件)
.content居中内容容器(最大宽度 900px)
.summary摘要/TL;DR 框
.section-title带底部边框的章节标题
.ic行内代码引用(等宽字体、蓝色、深色背景)
.file-card、.file-hdr、.file-body可折叠文件卡片(在 .file-hdr 上使用 onclick="toggle(this)")
.file-note文件卡片内的固定审阅注释
.bp-section、.bp-hdr、.bp-body折叠式样板代码卡片(使用 onclick="toggleBP(this)")
.bp-note样板代码卡片内的注释
.verdict审阅检查清单框

可用的 JS 函数:

函数用法
toggle(hdrElement)展开/折叠 .file-body
toggleBP(hdrElement)展开/折叠 .bp-body
renderDiff(target, diffInput)渲染统一差异。target 可以是 DOM 元素、字符串 ID 或 CSS 选择器。diffInput 可以是原始补丁字符串或行数组,两者均可。会自动过滤导入语句、折叠纯空白变更,并检测移动的代码(蓝色/紫色着色)。
esc(string)对字符串进行 HTML 转义

渲染差异 — 使用 data-diff 属性自动发现。 在正文 HTML 中需要渲染差异的位置放置 <div data-diff="KEY"></div> 占位元素。页面加载后,渲染器会自动查找这些元素,并从 template.html 中的 <script id="pr-diffs-json" type="application/json"> 元素填充内容。

重要:补丁字符串除了包含换行符、反斜杠和引号外,还可能包含 </script>。 即使使用 json.dumps(...),如果将原始输出粘贴到可执行的 <script> 中也不够安全,因为 HTML 解析可能会提前结束标签。切勿手动将补丁字符串嵌入 JS/JSON。请改用以下安全方法:

  1. 在获取步骤中,使用 jq 将补丁保存到 JSON 文件(它能正确处理转义):
gh api repos/{owner}/{repo}/pulls/{number}/files --paginate \
  --jq '[.[] | {key: (.filename | gsub("[^a-zA-Z0-9]"; "_")), value: (.patch // "")}] | from_entries' \
  > /tmp/pr-patches-{number}.json
  1. 在组装时,使用 Python 将 JSON 安全地注入 template.html:
python3 <<'PY'
import json
from pathlib import Path

patches = json.loads(Path('/tmp/pr-patches-{number}.json').read_text())
html = Path('/tmp/pr-review-{number}-body.html').read_text()
css = Path('styles.css').read_text()
js = Path('renderer.js').read_text()
tmpl = Path('template.html').read_text()

# Prevent literal </script> from terminating HTML script tags early.
safe_json = json.dumps(patches).replace('<', '\\u003c').replace('>', '\\u003e').replace('&', '\\u0026')

out = (
  tmpl.replace('/* INJECT_CSS */', css)
      .replace('/* INJECT_JS */', js)
      .replace('', html)
      .replace('{"__PR_DIFFS_PLACEHOLDER__":true}', safe_json)
)

Path('/tmp/pr-review-{number}.html').write_text(out)
PY

这样可以确保 JSON 有效,并安全地将内容嵌入 HTML 脚本中。Agent 会将正文 HTML 写入临时文件,然后由 Python 安全地组装所有内容。

差异数据的键应与 HTML 中 data-diff 属性的值匹配:

<div data-diff="path_to_file_ts"></div>

由于 renderer.js 在 <head> 中加载,如果需要用于自定义场景,也可以直接从行内 <script> 标签调用 renderDiff(target, lines)。该函数接受 DOM 元素、ID 字符串或 CSS 选择器作为 target,并接受字符串或数组作为 lines。

你不必局限于这些内容。 可以添加自己的行内 <style> 块、<script> 块、SVG、图表或其他任何内容。预先构建的组件能节省时间,但不会限制你。

4. 组装并提供服务
  1. 将正文 HTML(即所有放在 <body> 内的内容)写入 /tmp/pr-review-{number}-body.html

  2. 使用上面第 3 步中的 jq 命令,将补丁保存到 /tmp/pr-patches-{number}.json

  3. 运行上面第 3 步中的 Python 组装脚本(从此技能目录读取 styles.css、renderer.js、template.html,安全注入正文和补丁,并写入最终 HTML)

  4. 在固定端口上启动本地服务:

    cd /tmp && python3 -m http.server 8432 --bind 127.0.0.1
    

    在后台运行此命令,然后在应用内浏览器中打开 http://127.0.0.1:8432/pr-review-{number}.html。

    为何使用固定端口并执行 cd /tmp: 后台 Shell 没有 TTY,因此 Python 会无限期缓冲其启动消息(“Serving HTTP on...”);使用端口 0 就永远无法得知分配了哪个端口。并且,虽然 --directory /tmp 可用,但 cd /tmp 在不同 Python 版本中更可靠。如果端口 8432 已被占用,请尝试 8433、8434 等。

Diff 功能(由 renderer.js 自动处理)
  • 过滤仅包含导入语句的行
  • 将仅有空白字符的更改折叠为上下文行
  • 检测移动的代码块(在一处连续删除 3 行或更多,并在其他位置原样添加)——以蓝色/紫色而非红色/绿色呈现
  • 近似匹配项(移动后有少量编辑)会使用不同的紫色色调
样式说明
  • 深色主题:背景为 #1a1a1a,正文使用 Inter 字体,代码使用 IBM Plex Mono 字体
  • 橙色使用 var(--warning),绿色使用 var(--success),红色使用 var(--danger),蓝色使用 var(--accent)
  • 文件标题栏(position: sticky; top: 0)和注释(top: 35px)会在滚动时固定
  • 核心文件默认展开(.file-body.open),机械生成的文件默认折叠

评论

支持 Markdown