关于 dg
dg 是一项代码审查 skill,让 Gilfoyle 和 Dinesh 通过两个 Agent 展开对抗式讨论,发现并评估问题。它可检查 git diff 或指定文件,最终生成含可执行建议和趣味对话的总结。
主要功能
- 01审查已暂存和未暂存的差异
- 02审查指定文件或目录
- 03双 Agent 多轮对抗审查
- 04纳入依赖漏洞相关背景
- 05生成结构化审查及可选漫画
适用场景
- 01发现待提交代码变更中的问题
- 02审查指定源文件或目录
- 03在代码审查中评估依赖风险
- 04将审查对话制作为漫画
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ v1r3n/ dinesh-gilfoyle --skill dg安装后在 Claude Code 中输入/dg确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
comic-template.htmldinesh-agent.mdgilfoyle-agent.md详细介绍
Dinesh 与 Gilfoyle 代码审查
这是一场受 HBO 的《硅谷》启发的双 Agent 对抗式代码审查。Gilfoyle 以刻薄而精准的技术分析攻击代码,Dinesh 则以慌乱却专业的态度为代码辩护。两人的斗嘴令人捧腹,而来回交锋也确实能让审查结果更完善。
调用方式
/dg— 审查 git diff(已暂存 + 未暂存)/dg 3— 审查 git diff,最多 3 轮/dg src/auth.ts— 审查指定文件/dg src/auth.ts 3— 审查指定文件,最多 3 轮
解析参数
- 无参数 → 目标 = git diff,轮数上限 = 5
- 仅数字 → 目标 = git diff,轮数上限 = 指定数字
- 仅路径 → 目标 = 指定路径,轮数上限 = 5
- 路径 + 数字 → 目标 = 指定路径,轮数上限 = 指定数字
编排流程
第 1 步:收集代码
如果是 git diff:
git diff HEAD
git diff --staged
合并两份 diff。如果两者都为空,告知用户没有需要审查的内容。
如果是文件/路径: 读取目标文件。如果路径是目录,则读取其中所有源文件。
始终执行:收集依赖上下文。 在项目根目录中查找依赖文件,并将它们纳入发送给 Agent 的上下文:
package.json、package-lock.json、yarn.lock、pnpm-lock.yaml(Node.js)requirements.txt、pyproject.toml、Pipfile.lock(Python)go.mod、go.sum(Go)pom.xml、build.gradle(Java)Gemfile、Gemfile.lock(Ruby)Cargo.toml、Cargo.lock(Rust)composer.json、composer.lock(PHP)
Gilfoyle 进行依赖漏洞扫描时需要这些文件。
第 2 步:展开辩论
初始化:round = 0,debate_history = []
digraph debate {
"Gather code" [shape=box];
"Dispatch Gilfoyle" [shape=box];
"New issues found?" [shape=diamond];
"Dispatch Dinesh" [shape=box];
"All conceded, no pushback?" [shape=diamond];
"Round >= cap?" [shape=diamond];
"Ask user: continue?" [shape=diamond];
"Synthesize final review" [shape=doublecircle];
"Gather code" -> "Dispatch Gilfoyle";
"Dispatch Gilfoyle" -> "New issues found?";
"New issues found?" -> "Synthesize final review" [label="no — converged"];
"New issues found?" -> "Dispatch Dinesh" [label="yes"];
"Dispatch Dinesh" -> "All conceded, no pushback?";
"All conceded, no pushback?" -> "Synthesize final review" [label="yes — converged"];
"All conceded, no pushback?" -> "Round >= cap?";
"Round >= cap?" -> "Dispatch Gilfoyle" [label="no — next round"];
"Round >= cap?" -> "Ask user: continue?" [label="yes"];
"Ask user: continue?" -> "Dispatch Gilfoyle" [label="yes — extend cap"];
"Ask user: continue?" -> "Synthesize final review" [label="no"];
}
每一轮:
-
调度 Gilfoyle Agent(Agent 工具,通用)并提供:
- 此技能目录中
gilfoyle-agent.md的完整内容 - 待审查的代码
- 完整辩论历史
- 轮数
- 指令:“你只负责研究——阅读代码并给出审查意见。不要编辑任何文件。”
- 此技能目录中
-
向用户展示 Gilfoyle 的斗嘴内容。
-
**检查是否收敛:**解析 Gilfoyle 的 FINDINGS 部分。如果所有发现都在之前的轮次中重复出现,则视为收敛。
-
调度 Dinesh Agent(Agent 工具,通用)并提供:
- 此技能目录中
dinesh-agent.md的完整内容 - 待审查的代码
- Gilfoyle 最近一次回复的完整内容
- 完整辩论历史
- 轮数
- 指令:“你只负责研究——阅读代码并给出辩护。不要编辑任何文件。”
- 此技能目录中
-
向用户展示 Dinesh 的斗嘴内容。
-
**检查是否收敛:**解析 Dinesh 的 FINDINGS 部分。如果每一点都是
[concede],且没有[defend]或[dismiss],则视为收敛。 -
将双方的回复追加到 debate_history,并将轮数加一。
-
**如果轮数 >= 上限:**询问用户:“这两位可以争论到天亮。要继续进行更多轮吗?(y/N)”
- 是 → 按原轮数上限增加轮数上限,并继续循环
- 否 → 进入总结
收敛提示(选择合适的一条):
- “Gilfoyle 已经找不到可恨之处了。前所未有。”
- “Dinesh 认输了。不出所料。”
- “这两位在原地打转。趁还没动手,先把他们分开。”
第 3 步:汇总最终审查结果
辩论结束后,根据完整辩论记录生成结构化摘要。
显示格式:
## Dinesh vs Gilfoyle Review — [target]
### [N] rounds of mass destruction
---
### Best of the Banter
[2-4 of the funniest or most insightful exchanges from the debate]
---
### Verdict
#### Critical (Gilfoyle won, Dinesh conceded)
[Issues where Dinesh couldn't mount a defense — these are real and need fixing]
- `file:line` — issue — fix
#### Important (Gilfoyle won after debate)
[Issues Dinesh tried to defend but Gilfoyle's argument was stronger]
- `file:line` — issue — fix
#### Contested (Dinesh held his ground)
[Issues where Dinesh's defense was valid — code is likely fine]
- `file:line` — what was raised — why the defense holds
#### Dismissed (Gilfoyle was nitpicking)
[Issues both sides agree don't matter]
- `file:line` — what was raised — why it's a non-issue
### Strengths
[Things even Gilfoyle grudgingly acknowledged were good]
### Score
Gilfoyle: X | Dinesh: Y
[Tongue-in-cheek tally of who won more arguments]
### Recommended Changes
[Clean checklist — no banter, no context, just what to do]
- [ ] `file:line` — what to change
- [ ] `file:line` — what to change
- [ ] ...
If no changes needed: "Nothing to fix. Gilfoyle is furious."
步骤 4:提供漫画
显示最终评审后,询问用户:
“想要一组精彩瞬间的漫画吗?(y/N/pr)”
- y — 生成并在浏览器中打开
- pr — 生成、转换为 PNG,并作为评论附加到当前 PR
- N — 跳过
如果选择 y 或 pr,请生成一组 HTML 漫画:
- 从此技能目录中的
comic-template.html读取漫画模板。 - 填写模板占位符:
{{REVIEW_TARGET}}— 评审的目标(例如,“UI 代码库”、“git diff”或文件路径){{ROUND_COUNT}}— 辩论轮数{{GILFOYLE_SCORE}}/{{DINESH_SCORE}}— 最终分数{{DATE}}— 当前日期{{PANELS}}— 根据最精彩的交锋生成 4–8 格漫画。每格使用以下 HTML 结构:
<div class="panel gilfoyle">
<span class="panel-number">1</span>
<div class="panel-header">
<div class="avatar"><svg><use href="#gilfoyle-avatar"/></svg></div>
GILFOYLE
</div>
<div class="panel-body">
<div class="speech">The quote goes here. Use <code>inline code</code> for technical references.</div>
</div>
</div>
<div class="panel dinesh">
<span class="panel-number">2</span>
<div class="panel-header">
<div class="avatar"><svg><use href="#dinesh-avatar"/></svg></div>
DINESH
</div>
<div class="panel-body">
<div class="speech">The response goes here.</div>
</div>
</div>
<div class="panel gilfoyle full-width">
<span class="panel-number">3</span>
<div class="panel-header">
<div class="avatar"><svg><use href="#gilfoyle-avatar"/></svg></div>
GILFOYLE
</div>
<div class="panel-body">
<div class="speech">A particularly devastating line that deserves the full width.</div>
</div>
</div>
{{VERDICT_ITEMS}}— 根据最终评审生成结论条目:
<div class="verdict-item">
<span class="tag tag-fixed">FIXED</span> CSP nonce replaced with deploy-time placeholder
</div>
<div class="verdict-item">
<span class="tag tag-contested">CONTESTED</span> MutationObserver lifetime — Dinesh held ground
</div>
<div class="verdict-item">
<span class="tag tag-dismissed">DISMISSED</span> prop-types — tree-shakes out
</div>
-
挑选最精彩的瞬间作为漫画格。 优先选择:
- 最有趣的交锋(你来我往的对话效果最好)
- Gilfoyle 认输的时刻(罕见且戏剧性十足)
- Dinesh 最犀利的吐槽
- 技术上最具杀伤力的台词
- 引语要简洁——每个对话气泡裁剪为 1–3 句话
-
将填好的 HTML 写入带时间戳的文件:
/tmp/dg-comic-{timestamp}.html
如果选择 y:
5. 在浏览器中打开:open /tmp/dg-comic-{timestamp}.html
6. 告诉用户文件的保存位置。
如果选择 pr:
5. 使用无头浏览器转换为 PNG:
# Try puppeteer/chromium first, fall back to wkhtmltoimage, then to Safari
npx --yes puppeteer-screenshot /tmp/dg-comic-{timestamp}.html /tmp/dg-comic-{timestamp}.png 2>/dev/null \
|| wkhtmltoimage --quality 90 /tmp/dg-comic-{timestamp}.html /tmp/dg-comic-{timestamp}.png 2>/dev/null \
|| /usr/bin/osascript -e 'tell application "Safari" to open POSIX file "/tmp/dg-comic-{timestamp}.html"'
如果没有可用的截图工具,请告知用户手动在浏览器中截图。 6. 检测当前 PR:
gh pr view --json number,url --jq '.number'
- 上传图片并在 PR 上发表评论:
注意:如果gh pr comment {PR_NUMBER} --body "$(cat <<'EOF' ## /dg Review Comic Strip  _Generated by [/dg](https://github.com/v1r3n/dinesh-gilfoyle)_ EOF )"gh pr comment不支持上传本地图片,请建议将图片拖放到 PR 正文中,或转换为 base64 后嵌入。 - 告诉用户评论已发布,并附上 PR 链接。
核心原则
- 斗嘴就是亮点,而非装饰——它让评审既有趣又全面
- Dinesh 认输是最有力的信号——当他无从辩护时,说明确实存在问题
- 成功的辩护能验证代码——如果 Dinesh 能在 Gilfoyle 的猛烈质疑下证明其合理性,代码就站得住脚
- 始终以可执行的总结收尾——外表有趣,内里实用
- 确保技术上正确——只有技术内容经得起推敲,幽默才有效