brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
code-review对代码变更做审查:识别 bug、安全漏洞、性能问题。P0 必须修复写评论,P1 建议性评论,P2 只在总结里一句带过。用户要求 review、审查、发评论、打评论时都必须先用 skill_read 读全文。
Independent GitHub snapshot · Automated classification · Original documentation governs
对 PR/MR diff 做审查,发现问题并发布行内评论。
本技能有两种模式,默认走快速模式:
| 模式 | 触发 | 流程文档 | 特点 |
|---|---|---|---|
| 快速模式(默认) | 用户说 review / 审查 / 看看代码,但没强调深度 | 本文件下方「硬约束 + 6 步流程」 | 只看 diff,快 |
| 深度模式 | 用户明确说「深度 review / deep review / thorough review / 严格审查 / 彻底 review / 仔细审查 / deep code review」 | references/deep-review.md | 读 diff 外上下文 + task_fanout 并行扇出 + 对抗式验证,比快速模式慢 2-3 倍(子 agent 并行,不串行累加) |
不确定 → 走快速模式。 别自作主张进深度模式(它更慢,且会读 diff 外文件)。
深度模式与下方硬约束的关系:
gh api contents 拉取,按 head sha),用于补封闭上下文。下方「只看 diff / 禁止 clone」对深度模式放宽为「禁止 git clone/git checkout,但允许按需拉单个文件 + search/code 找调用方」。其余硬约束深度模式同样遵守。下面从「⚠️ 硬约束」开始的内容是快速模式的流程;深度模式见 references/deep-review.md。
只看 diff:不 clone 仓库、不拉完整源文件、不读 diff 之外的文件。
只读不写:不编译、不运行代码、不跑测试。
禁止写脚本:绝不写 python/shell 脚本去解析 diff。不写 python3 -c "...",不写 sed -n。读 diff 只能用 file_read(支持 offset + max_lines 分段读)。
跳过噪音文件(见下方完整列表)。
按文件数分档预算,分批 review(不设固定总轮次,但每文件只读 1 轮):
| 值得 review 的文件数 | 策略 | 预算 |
|---|---|---|
| 1-2 个 | 一次性读完发评论 | ~6 轮 |
| 3-6 个 | 分批,每批 2-3 文件,每批走完「拉 diff → 读 → 发评论」 | ~10-15 轮 |
| 7+ 个 | 走 references/large-diff.md 方法论,只看实质改动 | 按需 |
失败信号(不是轮次硬上限,是行为红线):
GitHub 链接必须先用 gh:看到 github.com / PR / issue 链接,第一反应用 gh CLI,不许先 web_fetch。gh 不可用(未装/未认证)才降级。禁止用 web_search 搜 GitHub PR/issue——搜索引擎搜不到 PR 内容,404 也不许搜。
绝不 clone 仓库。绝不 git checkout PR 分支。绝不读 diff 之外的源文件。
diff 已经包含所有判断所需的信息——@@ +start,len @@ 标注新文件行号,diff --git a/PATH b/PATH 给出文件路径。看不到上下文不是 clone 的理由,是「跳过这个 finding」的理由。
| ❌ 禁止 | 为什么 |
|---|---|
git clone https://github.com/owner/repo.git /tmp/... | 第 1 条硬约束,且会拉一堆无关文件 |
git fetch origin pull/N/head && git checkout pr-N | 同上,等价于 clone |
file_read(path=/tmp/clone-repo/scripts/foo.py) | 读 diff 之外的源文件,违反第 1 条 |
cd /tmp/clone-repo && git diff origin/main pr-N -- foo.py | 用 git diff 代替 file_read 读 diff,违反第 3 条 |
| 「上下文不够,clone 一下看看」 | 上下文不够 → 跳过这个 finding,不 clone |
rg_search(pattern=^@@.*@@, path=/tmp/pr_<N>.diff) 列出所有 hunk 起止gh api search/code -f q='OldName repo:owner/repo'(这是搜索,不是 clone)优先级:gh CLI > web_fetch(.diff) > 停止并提示用户
从用户给的 GitHub 链接解析出 owner/repo 和 PR 号:
https://github.com/<owner>/<repo>/pull/<N> → owner/repo + Nhttps://github.com/<owner>/<repo>/pull/<N>/files → 同上然后检查 gh 是否可用:
gh auth status 2>&1 | head -5
gh 可用(正常路径,99% 的情况)直接进入「流程 第 1 步」,用 gh pr diff / gh api 拉 diff。不要碰 web_fetch。
gh 未装或未认证(降级路径)gh,或降级 web_fetch(见下)。gh auth status 报错):先提示用户 gh auth login。私有仓库 web_fetch 必 404,别浪费时间。web_fetch 只能抓公开仓库的 diff 原始文本:
web_fetch(url=https://github.com/<owner>/<repo>/pull/<N>.diff)
/tmp/pr_<N>.diff,后续流程同 gh 路径。web_fetch 404 = 私有仓库或 PR 不存在 → 停止,告诉用户:「这个 PR 可能是私有仓库,需要先 gh auth login 认证。」不许 web_search。| ❌ 禁止 | ✅ 应该 |
|---|---|
web_fetch 抓 github.com/.../pull/16 页面 HTML | gh pr diff 16 --repo owner/repo |
web_search 搜 site:github.com owner repo pull 16 | gh api repos/owner/repo/pulls/16 |
web_fetch 抓 .diff 之前不试 gh | 先 gh auth status,可用就走 gh |
404 后 web_search 找「PR 信息」 | 404 → 告诉用户需要 gh auth login |
数据/生成文件:.jsonl .csv .json .lock .snap .txt .md .rst .yaml .yml .toml .ini .cfg .conf .env .svg .png .jpg .jpeg .gif .ico .webp .mp4 .mp3 .wav .pdf .zip .tar .gz .bz2 .7z .bin .dat .db .sqlite .parquet .arrow .pkl .pickle .npy .npz .h5 .pt .pth .onnx .model
lockfile:pnpm-lock.yaml package-lock.json yarn.lock go.sum poetry.lock Cargo.lock Gemfile.lock Pipfile.lock composer.lock uv.lock
二进制/构建产物:.so .o .a .dll .dylib .exe .class .jar .war .pyc .pyo .wasm .min.js .min.css .map
vendored/生成代码:vendor/ node_modules/ dist/ build/ target/ __pycache__/ .next/ .nuxt/
测试文件:*_test.go *_test.py test_*.py *.test.ts *.test.tsx *.test.js *.spec.ts *.spec.tsx *.spec.js 以及 tests/ test/ __tests__/ spec/ e2e/ 目录下的文件。测试代码不做 review——它们是被测对象的验证,不承载业务逻辑,评审 ROI 低。例外:如果本次改动只改了测试文件(没有任何业务代码变更),才读测试看有没有明显写错的断言。
纯格式化:import 排序、空白变更、行尾符变更
gh api repos/<owner/repo>/pulls/<N>/files > /tmp/pr_<N>_files.json
gh api repos/<owner/repo>/pulls/<N> --jq '.head.sha' > /tmp/pr_<N>_sha.txt
不要 clone。不要 gh pr checkout。先不拉全量 diff——先看清单值不值得拉。
# 值得 review 的文件(排除 deleted + 噪音扩展名)
# 用 jq 提取 + grep -v 管道过滤,避免 jq 内嵌长正则的转义问题
jq -r '.[] | select(.status != "removed") | "\(.status)\t\(.additions)+\(.deletions)-\t\(.filename)"' /tmp/pr_<N>_files.json \
| grep -vE '\.(jsonl|csv|json|lock|snap|txt|md|rst|yaml|yml|toml|ini|cfg|conf|env|svg|png|jpg|jpeg|gif|ico|webp|mp4|mp3|wav|pdf|zip|tar|gz|bz2|7z|bin|dat|db|sqlite|parquet|arrow|pkl|pickle|npy|npz|h5|pt|pth|onnx|model|so|o|a|dll|dylib|exe|class|jar|war|pyc|pyo|wasm|min\.js|min\.css|map)#x27; \
| grep -vE '(pnpm-lock|package-lock|yarn\.lock|go\.sum|poetry\.lock|Cargo\.lock|uv\.lock|vendor/|node_modules/|dist/|build/|__pycache__/|\.next/)' \
| grep -vE '(_test\.(go|py)$|test_[^/]*\.py$|\.(test|spec)\.(ts|tsx|js|jsx)$|(^|/)(tests?|__tests__|spec|e2e)/)'
# 被删除的文件(不读 diff,但删了函数/类要查残留引用)
jq -r '.[] | select(.status == "removed") | "deleted\t\(.filename)"' /tmp/pr_<N>_files.json
⚠️ 禁止在 jq 内写长正则——shell 转义极易出错导致反复重试浪费轮次。用管道
| grep -vE做后置过滤。
看清单后决定:
| 清单状态 | 动作 |
|---|---|
| 值得 review 的清单为空 + 无 deleted | 回「无可 review 的源码改动」,结束 |
| 值得 review 的清单为空 + 有 deleted | 只查残留引用(见 references/large-diff.md #8),不读 diff |
| 1-2 个值得 review | 一次性走第 3-6 步,全部读完发评论 |
| 3-6 个值得 review | 分批:按改动量排序,每批 2-3 个文件,每批走完第 3-6 步(拉 diff → 读 → 发评论),发完一批继续下一批 |
| 7+ 个值得 review | 读 references/large-diff.md 方法论,只看实质改动,机械改动(重命名/签名变更)只抽查 2-3 个调用点 |
被删除的文件里如果有函数/类被删,review 完后搜一下旧符号有没有残留引用(
gh api search/code或本地 grep)。这步可选,P1 级别。
gh pr diff <N> --repo <owner/repo> > /tmp/pr_<N>.diff
rg_search(pattern=^diff --git, path=/tmp/pr_<N>.diff)
rg_search 输出每个文件在 diff 中的起始行号。 交叉比对第 2 步选出的本批文件,记住它们的 diff 起始行号。
rg_search必须传path参数,不传会全盘扫描导致超时。
用 file_read 的 offset(1-based 行号,与 rg_search 输出对齐)和 max_lines 读指定文件的 diff 块。
⚠️ max_lines 必须设为 500 起步。 100 行太碎片化,会浪费大量轮次。单文件改动超过 500 行时按 500 分段,否则一次读完。绝不使用 max_lines=100。
# 文件 1 在 diff 第 1 行,改动约 380 行 → 一次读完
file_read(path=/tmp/pr_59.diff, offset=1, max_lines=500)
# 文件 2 在 diff 第 432 行,改动约 167 行 → 一次读完
file_read(path=/tmp/pr_59.diff, offset=432, max_lines=500)
# 大文件在 diff 第 900 行,改动约 720 行 → 分两段
file_read(path=/tmp/pr_59.diff, offset=900, max_lines=500)
file_read(path=/tmp/pr_59.diff, offset=1400, max_lines=300)
读完立即在脑子里找问题,不要多读一轮。本批所有文件读完进入第 5 步。
P0 — 必须修复(写行内评论)
P1 — 建议修复(写行内评论)
P2 — 不写评论,总结里一句带过
每条 finding 必须能说出:「什么输入 → 走哪条路径 → 什么错误」。说不出来就删掉。P0 必须是 CONFIRMED。
关键:必须用单条评论 API(/pulls/{n}/comments),不能用批量 review API 的 comments 字段。 批量 review API 不支持 line/side,会变成文件级评论。
每条评论单独 POST:
SHA=$(cat /tmp/pr_<N>_sha.txt)
# 评论 1
gh api repos/<owner/repo>/pulls/<N>/comments --method POST \
-f body="问题描述
触发场景
建议修复" \
-f commit_id="$SHA" \
-f path="ethan/core/agent.py" \
-F line=155 \
-f side="RIGHT"
# 评论 2(如有更多,同样格式)
gh api repos/<owner/repo>/pulls/<N>/comments --method POST \
-f body="..." -f commit_id="$SHA" -f path="..." -F line=... -f side="RIGHT"
发完所有行内评论后,再发一条 review 总结(不带 comments):
gh api repos/<owner/repo>/pulls/<N>/reviews --method POST \
-f body="整体看完了,详见行内评论。" \
-f event="COMMENT"
path是文件在仓库中的相对路径(从 diff headerdiff --git a/PATH b/PATH读取)。line是新文件中的行号(从@@ +start,len @@读取,对应+开头的行),必须是整数。side固定为"RIGHT"(评论新文件侧)。 如果用批量 review API 的comments字段,line/side会被丢弃变成文件级评论,这是错误的。
聊天里只回一条简短总结:
看完了 PR N,发现 X 个 P0(已评论到行):① 问题一 ② 问题二。其余没大问题,建议改完再合。
没有 P0 就说"没发现阻塞性问题,可以合并"。
核心原则:简洁、口语化、直击要害。 像同事在旁边跟你说话,不像 AI 生成的报告。
`teardownDeviceModule()` 是异步的,但 `before-quit` 里没拦退出,Electron 不等它跑完就直接杀进程了。
感觉这里应该先 `preventDefault()` 拦住,等 `prepareAppQuit()` resolve 之后再手动 `app.quit()`,不然清理逻辑可能跑一半就被掐了。
⚠️ 潜在的阻塞退出风险。在 before-quit 钩子中,当 isUpdateDownloaded() 为 false 且非 isUpdateInstallQuitting() 时,代码执行了 event.preventDefault() 的隐式等价逻辑吗?虽然这里没有直接调用 event.preventDefault(),但由于 prepareAppQuit() 内部调用了 setAppQuitting(true) 并异步执行 teardownDeviceModule()……(后面还有一大段)
问题:标题式开头、长句绕来绕去、一段到底不分段、像论文不像对话。
先 gh auth status 确认当前账号身份。多账号时用 gh auth switch --user <账号> 切换,用完切回。
跟仓库语言一致:代码注释/commit 用中文 → 评论用中文;用英文 → 用英文。
不发布评论,在对话里按 📍 文件:行号 格式输出评论列表。