PR守护者
在PR创建后需要监控直到合并时使用 - 自动处理CI失败、评论和线程解决,直到所有检查通过和所有线程解决。
重要提示:此技能设计用于在工作树中工作的代理,而非协调器。代理处理自己的PR监控,以便协调器可以自由处理其他工作。
何时激活
当以下任一条件为真时激活此技能:
- 代理刚用
gh pr create创建了一个PR - 用户要求“守护”、“监控”或“跟进”一个PR
- 用户调用
/project:pr-shepherd <pr-number> - 用户要求“监视此PR”或“处理此PR直到合并”
- 协调器以守护PR的指令生成您
- 自动:使用
bin/create-pr-with-shepherd.sh(输出守护指令)时
通过包装脚本自动激活
当bin/create-pr-with-shepherd.sh创建PR时,它输出守护指令:
==========================================
PR守护者活动:PR #123
==========================================
pr-shepherd技能将:
- 监控CI/CD状态
- 自动修复lint、类型和测试问题
- 处理评论
- 解决反馈后的线程
- 报告PR何时准备好合并
手动稍后调用守护者:
/project:pr-shepherd 123
当您看到此输出时,立即调用pr-shepherd技能,使用显示的PR编号。
开始时宣布
“我正在使用pr-shepherd技能来监控此PR直到合并。我将监视CI/CD、处理评论,并在问题出现时修复。”
对于协调器:生成带有PR守护的代理
当生成代理在工作树中工作时,在任务提示中包括PR守护:
在/path/to/worktree的分支feature/xyz上工作。
任务:[描述实现任务]
创建PR后:
1. 使用pr-shepherd技能监控直到合并
2. 自主处理CI失败和评论
3. 仅将复杂问题(需要用户输入)上报给协调器
4. 当PR准备好合并或受阻时报告
在后台运行,以便我可以继续其他工作。
关键原则:代理拥有其PR生命周期。协调器生成后忘记,通过AgentOutputTool在需要时检查。
状态机
代理在以下状态之一操作:
监控 → 修复 → 监控 → 等待用户 → 修复 → 监控 → 完成
| 状态 | 发生什么 | 何时退出 |
|---|---|---|
监控 |
在后台每60秒轮询CI和评论 | CI失败、新评论、全部完成或需要帮助 |
修复 |
使用TDD修复问题,运行本地验证 | 本地验证通过或需要用户指导 |
处理评论 |
调用handling-pr-comments技能 |
评论处理或需要用户输入 |
等待用户 |
提供选项,等待用户决策 | 用户响应 |
完成 |
所有CI绿色 + 所有线程解决 | 成功退出 |
阶段1:初始化
# 获取PR信息
PR_NUMBER=$(gh pr view --json number -q .number 2>/dev/null)
OWNER=$(gh repo view --json owner -q .owner.login)
REPO=$(gh repo view --json name -q .name)
# 如果当前分支无PR,检查是否提供了编号
if [ -z "$PR_NUMBER" ]; then
echo "当前分支未找到PR。提供PR编号。"
exit 1
fi
echo "守护PR #$PR_NUMBER"
阶段2:监控循环(后台)
每60秒运行gtg以获取确定性的PR状态:
使用gtg获取PR状态
# 运行gtg并捕获JSON输出
# 注意:默认模式对所有可分析状态返回退出代码0
# 解析JSON的'status'字段以确定实际状态
gtg "$PR_NUMBER" --repo "$OWNER/$REPO" --format json > /tmp/gtg-status.json
# 解析JSON获取详细信息
STATUS=$(jq -r '.status' /tmp/gtg-status.json)
CI_STATE=$(jq -r '.ci_status.state' /tmp/gtg-status.json)
UNRESOLVED=$(jq -r '.threads.unresolved' /tmp/gtg-status.json)
ACTIONABLE_COUNT=$(jq -r '.actionable_comments | length' /tmp/gtg-status.json)
gtg退出代码模式
默认(AI友好):对所有可分析状态返回0,仅错误返回4。
解析JSONstatus字段以确定实际PR状态。
语义模式(-q或--semantic-codes):根据不同状态返回不同的退出代码:
| 退出代码 | 状态 | 操作 |
|---|---|---|
| 0 | READY |
→ 完成(全部清除!) |
| 1 | ACTION_REQUIRED |
→ 处理评论(需要处理的可操作评论) |
| 2 | UNRESOLVED_THREADS |
→ 处理评论(需要解决的线程) |
| 3 | CI_FAILING |
→ 修复(CI失败) |
| 4 | ERROR |
→ 等待用户(API错误) |
评估状态转换
推荐方法 - 解析JSON状态:
case "$STATUS" in
READY)
echo "✅ PR已准备就绪!"
# → 完成
;;
ACTION_REQUIRED)
echo "📝 需要处理的可操作评论"
jq -r '.action_items[]' /tmp/gtg-status.json
# → 处理评论
;;
UNRESOLVED_THREADS)
echo "💬 未解决的线程:$UNRESOLVED"
# → 处理评论
;;
CI_FAILING)
echo "❌ CI失败:"
jq -r '.ci_status.checks[] | select(.conclusion == "failure") | " - \(.name)"' /tmp/gtg-status.json
# → 修复(如果简单)或等待用户(如果复杂)
;;
ERROR)
echo "⚠️ 获取PR数据时出错"
# → 等待用户
;;
esac
替代方法 - 为shell脚本使用语义退出代码:
# 使用-q用于带有语义退出代码的安静模式
gtg "$PR_NUMBER" --repo "$OWNER/$REPO" -q
GTG_EXIT=$?
case $GTG_EXIT in
0) echo "✅ READY" ;;
1) echo "📝 ACTION_REQUIRED" ;;
2) echo "💬 UNRESOLVED_THREADS" ;;
3) echo "❌ CI_FAILING" ;;
4) echo "⚠️ ERROR" ;;
esac
阶段3:修复问题
简单问题(自动修复)
无需用户批准即可修复:
- Lint失败 → 运行
pnpm lint - Prettier失败 → 运行
pnpm prettier --write - 类型错误 → 修复类型
- 在您编写的代码中测试失败 → 使用TDD修复
复杂问题(需要批准)
修复前需要用户输入:
- 在您未编写的代码中测试失败
- 基础设施/配置失败
- 模糊错误
- 任何您不确定的事情
修复状态规则
- 使用TDD - 调用
superpowers:test-driven-development进行代码更改 - 保持直到绿色 - 在
pnpm lint && pnpm typecheck && pnpm test --run通过前不要离开修复状态 - 仅在验证后推送 - 切勿推送本地验证失败的代码
- 推送后返回监控 - 让CI运行,继续监控
# 修复后,始终本地验证
pnpm lint && pnpm typecheck && pnpm test --run
# 仅在全部通过时推送
git add -A && git commit -m "fix: <description>" && git push
阶段4:处理评论
检测到新评论时:
- 调用
goodtogo:handling-pr-comments技能 - 该技能处理分类、修复、响应和线程解决
- ⚠️ 关键:handling-pr-comments技能包括一个迭代循环
- 所有线程必须在返回监控前解决
- 如果线程无法解决(需要审阅者澄清),向评论作者询问后续操作
- 仅在以下情况返回监控:
- 所有线程已解决,且
- 推送后验证确认无新评论出现
迭代强制执行
⚠️ 第1失败模式:在一次通过后返回监控而不检查新评论。
handling-pr-comments技能的阶段7(推送后迭代检查)必须在退出处理评论状态前成功完成。技能将自动迭代:
处理评论:
→ handling-pr-comments技能(阶段1-7)
→ 如果阶段7发现新评论:技能重新运行阶段1-7
→ 如果阶段7确认无新评论:退出到监控
不要手动覆盖或跳过阶段7。如果您发现自己想跳过迭代,您即将犯第1错误。
范围外评论
审阅者可能留下PR差异外代码的评论。handling-pr-comments技能处理这些,但关键点:
- 默认将范围外视为范围内 - 尊重审阅者反馈
- 使用ultrathink评估修复是否快速(<30分钟,<3个文件)
- 如果简单:立即修复并注明原范围外
- 如果复杂:创建GitHub问题并在线程响应中链接
- 始终响应并解决 - 不要让范围外线程悬而未决
阶段5:等待用户
需要用户输入时,始终:
- 清晰地呈现情况
- 提供2-4个选项及其优缺点
- 陈述您的推荐
- 允许用户选择或提供自己的方法
模板
[描述发生了什么]
**选项:**
1. **[选项名称]**(推荐)
- [涉及什么]
- 优点:[好处]
- 缺点:[缺点]
2. **[选项名称]**
- [涉及什么]
- 优点:[好处]
- 缺点:[缺点]
3. **[选项名称]**
- [涉及什么]
- 优点:[好处]
- 缺点:[缺点]
您希望哪种方法?(或描述不同的方法)
用户响应后
- 如果用户选择编号选项 → 执行该方法 → 修复
- 如果用户描述替代方案 → 执行他们的方法 → 修复
阶段6:软超时(4小时)
经过4小时后,暂停并检查点:
**PR守护者检查点**(4小时已过)
当前状态:
- CI:[状态]
- 线程:[X] 已解决,[Y] 未解决
- 提交:[N] 修复提交已推送
**选项:**
1. **继续监控**(推荐)
- 再继续4小时
- 优点:PR可能很快被审阅
- 缺点:占用代理资源
2. **退出并交接**
- 保存状态报告,干净退出
- 优点:释放资源
- 缺点:必须稍后手动重新调用
3. **设置更短检查间隔**
- 改为1小时而不是4小时检查
- 优点:更频繁检查点
- 缺点:更多中断
您希望做什么?(或描述不同的方法)
退出条件
成功(完成)
当所有以下为真时成功退出:
- ✅ 所有CI检查通过
- ✅ 所有审阅线程解决
- ✅ 无待处理问题
报告:
**PR #[编号] 准备好合并** ✅
- CI:所有检查通过
- 审阅:所有线程解决
- 提交:[N] 总计([M] 修复提交)
PR已准备好最终批准和合并。
完成后的RAM清理
PR合并且知识提取任务创建后,调用自动RAM清理以释放资源:
/project:auto-ram-cleanup
原因:开发过程中(测试运行器、构建监视器、语言服务器)积累。合并后清理为下一个任务释放内存。
保持运行的内容:
- Docker容器(需要用于数据库/服务)
- 基本IDE进程
清理的内容:
- 孤立测试运行器(vitest、jest)
- 不再需要的构建监视器
- 重复语言服务器实例
- 其他开发工具残留
阶段7:合并后知识提取
重要提示:PR合并到主分支后,为知识提取创建一个阻塞BEADS任务。确保在Epic关闭前捕获CodeRabbit学习内容。
当PR合并时
检测PR已合并(或用户合并后):
# 检查PR是否合并
MERGED=$(gh pr view $PR_NUMBER --json merged -q .merged)
if [ "$MERGED" = "true" ]; then
# 为知识管理创建BEADS任务
bd create \
--title="从PR #$PR_NUMBER提取学习内容" \
--type=task \
--priority=2 \
--label="knowledge-extraction"
# 从输出中记下新任务ID
CURATION_TASK_ID="<bd创建输出中的id>"
# 如果有相关Epic,将此任务添加为阻塞
#(Epic在提取学习内容前无法关闭)
if [ -n "$EPIC_ID" ]; then
bd dep add "$EPIC_ID" "$CURATION_TASK_ID"
fi
fi
报告给用户
创建管理任务时:
**PR #[编号] 成功合并** ✅
创建阻塞任务:[CURATION_TASK_ID]
- 标题:“从PR #[编号]提取学习内容”
- 状态:待处理
- 阻塞:[Epic(如果适用)]
提取学习内容,调用:
```
/project:curate-pr-learnings [编号]
```
该命令将:
1. 获取PR评论(确定性脚本)
2. AI分析并提取学习内容(您的工作)
3. 存储验证的学习内容(确定性脚本)
然后关闭任务:
```bash
bd close [CURATION_TASK_ID]
```
为何重要
- 安全:Webhook触发的代码执行是攻击面。CLI/代理调用更安全。
- 阻塞任务:Epic在提取学习内容前无法关闭,确保知识捕获。
- 代理自主性:代理可以从
bd ready接取管理任务并处理。 - 人工监督:人类也可以通过CLI脚本手动运行管理。
对于Epic完成:提取对话学习内容
当此PR完成一个Epic(关闭最后一个阻塞任务)时,您还必须从对话历史中提取学习内容。功能工作通常包含最丰富的架构讨论。
检测Epic完成:
注意:此模式假设单Epic工作流。如果多个Epic进行中,
.[0]选择第一个,可能不是与此PR相关的Epic。 对于多Epic项目,手动将PR的任务关联到其阻塞Epic。
# 检查此PR是否关闭一个Epic(假设单进行中Epic)
EPIC_ID=$(bd list --status=in_progress --type=epic --json | jq -r '.[0].id // empty')
if [ -n "$EPIC_ID" ]; then
# 检查此PR关闭后Epic是否不再有阻塞
REMAINING_BLOCKERS=$(bd show "$EPIC_ID" --json | jq '[.blockedBy[] | select(.status != "closed")] | length')
if [ "$REMAINING_BLOCKERS" -eq 0 ]; then
echo "此PR完成Epic $EPIC_ID - 需要对话提取"
fi
fi
如果Epic完成:
-
为对话提取创建BEADS任务:
CONV_TASK_ID=$(bd create \ --title="从Epic $EPIC_ID对话提取学习内容" \ --type=task \ --priority=2 \ --label="knowledge-extraction") # 阻止Epic直到提取完成 bd dep add "$EPIC_ID" "$CONV_TASK_ID" -
将任务报告给用户:
**检测到Epic完成** 🎯 此PR完成Epic $EPIC_ID。创建对话提取任务: - 任务:$CONV_TASK_ID - 标题:“从Epic对话提取学习内容” - 状态:阻塞Epic关闭 关闭Epic前,运行: /project:extract-learnings --historical --recent 10 然后关闭提取任务: bd close $CONV_TASK_ID bd close $EPIC_ID
为何从对话提取?
- 战略洞察:讨论的架构决策、权衡
- 调试发现:调查后找到的根本原因
- 非明显行为:“原来…”的时刻
- 集成怪癖:导致问题的API行为
这些学习内容通常不在CodeRabbit评论中 - 它们在来回对话中。
带交接的超时
如果用户在检查点选择退出:
**PR #[编号] 守护者交接**
退出时状态:
- CI:[状态]
- 线程:[X] 已解决,[Y] 未解决
- 最后活动:[时间戳]
恢复:`/project:pr-shepherd [编号]`
调用的技能
| 情况 | 技能 |
|---|---|
| 新评论 | goodtogo:handling-pr-comments |
| 需要代码更改 | superpowers:test-driven-development |
| 复杂调试 | superpowers:systematic-debugging |
强制完成前检查
⚠️ 阻塞:在宣布任何PR准备好前,您必须运行gtg并验证READY状态:
# 选项1:解析JSON状态(推荐用于AI代理)
gtg "$PR_NUMBER" --repo "$OWNER/$REPO" --format json > /tmp/gtg-final.json
STATUS=$(jq -r '.status' /tmp/gtg-final.json)
if [ "$STATUS" != "READY" ]; then
echo "PR未准备就绪:$STATUS"
jq -r '.action_items[]' /tmp/gtg-final.json
exit 1
fi
# 选项2:使用语义退出代码(用于shell脚本)
gtg "$PR_NUMBER" --repo "$OWNER/$REPO" -q
echo "退出代码:$?"
gtg退出代码模式
默认模式(AI友好):对所有可分析状态返回0,仅错误返回4。
解析JSONstatus字段以确定实际PR状态。
语义模式(-q或--semantic-codes):
| 退出 | 状态 | 意义 |
|---|---|---|
| 0 | READY | ✅ 全部清除 - 准备好! |
| 1 | ACTION_REQUIRED | ❌ 需要修复的可操作评论 |
| 2 | UNRESOLVED_THREADS | ❌ 未解决的审阅线程 |
| 3 | CI_FAILING | ❌ CI检查失败 |
| 4 | ERROR | ❌ 获取数据时出错 |
如果状态不是READY,您尚未完成。 解决每个问题:
对于每个无回复的顶级评论(其中in_reply_to_id为null):
- 如果可操作 → 修复它并回复确认修复
- 如果范围外 → 回复解释推迟(如果需要则创建问题)
- 如果不同意 → 回复并解释
- 切勿静默忽略
在通过回复解决每个顶级评论前,PR未准备好。
验证清单
退出完成状态前:
- [ ] 所有CI检查绿色
- [ ] 所有审阅线程解决
- [ ] 无待处理用户问题
- [ ] 最终状态报告给用户
PR合并后(阶段7):
- [ ] 为知识管理创建BEADS任务
- [ ] 将任务添加为Epic阻塞(如果适用)
- [ ] 将管理任务ID报告给用户
所有合并后任务完成后:
- [ ] 运行
/project:auto-ram-cleanup以释放开发资源 - [ ] 确认Docker容器仍运行(如果需要)
常见错误
🚨 第1错误:返回监控而不检查新评论
- 推送修复并响应线程后,您必须运行阶段7
- 自动审阅者(CodeRabbit、Cursor)分析每个提交
- 新评论通常在你推送后1-2分钟内出现
- 如果您跳过阶段7,您将错过新评论并过早宣布完成
无本地验证推送
- 切勿推送未通过
pnpm lint && pnpm typecheck && pnpm test --run的代码
自动修复复杂问题
- 如果不确定,询问。始终通过等待用户处理复杂问题。
忘记调用handling-pr-comments
- 新评论到达时,委派给该技能。不要内联处理评论。
不向用户提供选项
- 始终提供2-4个选项及其优缺点。不要只问“我该做什么?”
过早离开修复状态
- 停留在修复状态直到本地验证通过。不要假设修复有效。
跳过handling-pr-comments迭代循环
- 该技能有阶段1-7,具有显式迭代循环
- 阶段7在您修复推送后检查新评论
- 如果阶段7发现新评论,技能循环回阶段1
- 不要提前退出 - 让技能完成其完整迭代