mcpField
D
dg

dg

github.com/v1r3n测试与质量19744 次安装30 周前更新
代码仓库

关于 dg

dg 是一项代码审查 skill,让 Gilfoyle 和 Dinesh 通过两个 Agent 展开对抗式讨论,发现并评估问题。它可检查 git diff 或指定文件,最终生成含可执行建议和趣味对话的总结。

主要功能

  1. 01审查已暂存和未暂存的差异
  2. 02审查指定文件或目录
  3. 03双 Agent 多轮对抗审查
  4. 04纳入依赖漏洞相关背景
  5. 05生成结构化审查及可选漫画

适用场景

  1. 01发现待提交代码变更中的问题
  2. 02审查指定源文件或目录
  3. 03在代码审查中评估依赖风险
  4. 04将审查对话制作为漫画

安装

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

$npx skills add https://github.com/v1r3n/dinesh-gilfoyle --skill dg

安装后在 Claude Code 中输入/dg确认已加载。

包含的文件

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

comic-template.html
dinesh-agent.md
gilfoyle-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 轮

解析参数

  1. 无参数 → 目标 = git diff,轮数上限 = 5
  2. 仅数字 → 目标 = git diff,轮数上限 = 指定数字
  3. 仅路径 → 目标 = 指定路径,轮数上限 = 5
  4. 路径 + 数字 → 目标 = 指定路径,轮数上限 = 指定数字

编排流程

第 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"];
}

每一轮:

  1. 调度 Gilfoyle Agent(Agent 工具,通用)并提供:

    • 此技能目录中 gilfoyle-agent.md 的完整内容
    • 待审查的代码
    • 完整辩论历史
    • 轮数
    • 指令:“你只负责研究——阅读代码并给出审查意见。不要编辑任何文件。”
  2. 向用户展示 Gilfoyle 的斗嘴内容。

  3. **检查是否收敛:**解析 Gilfoyle 的 FINDINGS 部分。如果所有发现都在之前的轮次中重复出现,则视为收敛。

  4. 调度 Dinesh Agent(Agent 工具,通用)并提供:

    • 此技能目录中 dinesh-agent.md 的完整内容
    • 待审查的代码
    • Gilfoyle 最近一次回复的完整内容
    • 完整辩论历史
    • 轮数
    • 指令:“你只负责研究——阅读代码并给出辩护。不要编辑任何文件。”
  5. 向用户展示 Dinesh 的斗嘴内容。

  6. **检查是否收敛:**解析 Dinesh 的 FINDINGS 部分。如果每一点都是 [concede],且没有 [defend] 或 [dismiss],则视为收敛。

  7. 将双方的回复追加到 debate_history,并将轮数加一。

  8. **如果轮数 >= 上限:**询问用户:“这两位可以争论到天亮。要继续进行更多轮吗?(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 漫画:

  1. 从此技能目录中的 comic-template.html 读取漫画模板。
  2. 填写模板占位符:
    • {{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>
  1. 挑选最精彩的瞬间作为漫画格。 优先选择:

    • 最有趣的交锋(你来我往的对话效果最好)
    • Gilfoyle 认输的时刻(罕见且戏剧性十足)
    • Dinesh 最犀利的吐槽
    • 技术上最具杀伤力的台词
    • 引语要简洁——每个对话气泡裁剪为 1–3 句话
  2. 将填好的 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'
  1. 上传图片并在 PR 上发表评论:
    gh pr comment {PR_NUMBER} --body "$(cat <<'EOF'
    ## /dg Review Comic Strip
    
    ![Dinesh vs Gilfoyle](/tmp/dg-comic-{timestamp}.png)
    
    _Generated by [/dg](https://github.com/v1r3n/dinesh-gilfoyle)_
    EOF
    )"
    
    注意:如果 gh pr comment 不支持上传本地图片,请建议将图片拖放到 PR 正文中,或转换为 base64 后嵌入。
  2. 告诉用户评论已发布,并附上 PR 链接。

核心原则

  • 斗嘴就是亮点,而非装饰——它让评审既有趣又全面
  • Dinesh 认输是最有力的信号——当他无从辩护时,说明确实存在问题
  • 成功的辩护能验证代码——如果 Dinesh 能在 Gilfoyle 的猛烈质疑下证明其合理性,代码就站得住脚
  • 始终以可执行的总结收尾——外表有趣,内里实用
  • 确保技术上正确——只有技术内容经得起推敲,幽默才有效

评论

支持 Markdown