Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/agent/followups.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@
- [ ] FU-10 · C · src=PR#45 第八轮 [Low] · 2026-08-06 · **注释与文档漂移(收口时未清)**:safe-cleanup.sh 里若干注释仍在引用已删掉的东西 —— :150-151 / :247 / :317 提到 `update-ref` 的 expected-old-value(那个函数已删)、:501 附近说 §3「deletes on the SERVER」(已改成完全不处理)。另外 run.md:76 写「不加 --delete-branch,远程分支删除统一交给 safe-cleanup」,但 safe-cleanup 已不处理远程、git-guard 又硬拒 --delete-branch,于是**远程 head 分支的清理在文档流程里没有主人**,只剩 GitHub 的 auto-delete-on-merge,而 skill 既不检查该设置是否打开、也没在任何地方教人去开。改法:清一遍过时注释;在 doctor 里加一条只读检查「本仓库是否开了 auto-delete-on-merge」并在关闭时提示
- [ ] FU-11 · C · src=PR#45 第八轮 [Low] · 2026-08-06 · §1b 现在是个纯报告,但计价没变:每个候选分支一次 gh API 调用(本仓库约 25 次 / 20.6 秒),而 status.md 让它在**每次** `pilot status` 都跑。改法二选一:① 按 tip sha 做本地缓存(tip 没动就不重查);② 在 status.md 里把 `--squash-merged` 改成显式 opt-in,默认不带
- [ ] FU-12 · C · src=PR#45 第八轮 [Low] · 2026-08-06 · §1b 会把「某个活着的 worktree 正在 rebase/bisect 的分支」当成游离分支列出来并打印 `git branch -D <b>`,而同一次运行里 §2 对那个 worktree 打的是 KEEP —— **同一份输出自相矛盾**。已验证无害(git 2.50 会拒绝 `cannot delete branch 'x' used by worktree`,分支完好,rebase --continue 正常),所以只是输出问题。顺带记一句:这也说明删掉 `ref_in_use_by_worktree` 是对的 —— `git branch -D` 自带那个拒绝,而 `update-ref -d` 没有
- [ ] FU-13 · C · src=PR#45 第九轮 APPROVE 附带 [Low] · 2026-08-06 · **`--remote` / `--remote-name` 已成摆设**:两个 flag 仍被解析、仍出现在 `--help` 的 Usage 和未知参数提示里,但 `--remote-name` 现在只喂给 `## Remote branches ($remote_name)` 这个标题,`--remote` 只开关一段说明文字。而且那段说明文字**从文档流程里已经不可达** —— status.md/run.md 都不再传 `--remote`,所以它只会对「传了一个文档已不再提及的 flag」的调用者打印。改法:把「去开 GitHub auto-delete-on-merge」这句折进默认输出或 doctor(FU-10 已记 doctor 那半),然后把两个 flag 连同 `.pilot.yml` 的 `remote:` 键一起考虑是否移除
- [ ] FU-14 · C · src=PR#45 第九轮 APPROVE 附带 [Low] · 2026-08-06 · `--integration X` 只决定**候选列表**,而真正执行的 `git branch -d` 判的是「合进 **HEAD**」。站在非 integration 分支上时,每一个真正已合并的候选都会打印 `SKIP (not safely merged)`。方向是 fail-safe(只会漏删,不会误删),但 status.md 要求模型把输出**原样**转达给用户,于是它会如实转达一个**假的「未合并」**。改法:执行前切到 integration,或改用 `git branch -d` 之外的等价判断,或在这一行的输出里说明「判据是 HEAD,不是 --integration」

1 change: 0 additions & 1 deletion plugins/pilot/skills/pilot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ base_branch: main
integration_branch: preview # PR 合并进这里,不是主干
protect_patterns: [release, hotfix]
remote: origin
allow_remote_cleanup: false
docs_dir: docs/agent
```

Expand Down
2 changes: 1 addition & 1 deletion plugins/pilot/skills/pilot/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ base_branch: main # 主干,受保护,禁止直推
integration_branch: preview # PR 合并进这里;不存在则回退到 base_branch
protect_patterns: [release, hotfix] # 额外保护的分支前缀
remote: origin
allow_remote_cleanup: false # 删除远程已合并分支需显式置 true
# allow_remote_cleanup 已废弃:脚本不再删远程分支,没有任何代码读这个键(用 GitHub auto-delete-on-merge)
docs_dir: docs/agent # 规划/运行态文档目录
planning_source: docs # docs(默认)=查上面那七个文件 | external=规划在别处,门禁不查(见下)
```
Expand Down
7 changes: 5 additions & 2 deletions plugins/pilot/skills/pilot/phases/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@
```
bash <skill>/scripts/safe-cleanup.sh --integration <integration_branch> [--squash-merged] --apply
```
- 要连带删远程已合并分支:仅当 `.pilot.yml` 的 `allow_remote_cleanup: true`,且用户明确同意,才加 `--remote`。
- 无人值守模式(由 /loop 调用且用户已预先授权清理):可直接 `--apply`,但**永远不加 `--remote`** 除非配置显式开启。
- **远程分支脚本不处理**(`--remote` 只会打印一段说明)。让用户去仓库设置里开 GitHub 的
**auto-delete-on-merge** —— 它在合并真正发生的那一侧判定,而从 clone 里判断要靠可能过期的
remote-tracking ref,且 bare 仓库不留 reflog。
- 无人值守模式(由 /loop 调用且用户已预先授权清理):可直接 `--apply`。脚本此时唯一会执行的
删除仍是 `git branch -d`,其余照样只列。

6. **建议下一步**:基于 progress.md 指出「下一个该做的 READY task」;若没有规划文档,建议 `pilot plan`。

Expand Down
23 changes: 21 additions & 2 deletions plugins/pilot/skills/pilot/scripts/safe-cleanup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,16 @@ echo

# ---- 2. Worktrees: clean + merged only --------------------------------------
echo "## Worktrees (clean + merged only)"
main_root="$(git rev-parse --show-toplevel)"
# The PRIMARY worktree, not "whichever worktree you are standing in". `--show-toplevel` returns
# the CURRENT worktree, so running from a linked one — which this skill's own doctrine (one task =
# one worktree) makes the normal case, and status.md runs on every `pilot status` — made §2 skip
# the linked worktree it was standing in and instead print a command to remove the MAIN checkout:
# remove with: git worktree remove /path/to/repo && git branch -d primaryfeat
# Harmless as printed output (git refuses both halves), but it is a wrong command handed to a human
# to paste, and on the parent commit — where §2 still executed the removal — it was an attempt to
# delete the main checkout. The first block of `git worktree list --porcelain` is always primary.
main_root="$(git worktree list --porcelain 2>/dev/null | sed -n 's/^worktree //p' | head -1)"
[ -n "$main_root" ] || main_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
# `git worktree list --porcelain` emits blocks separated by blank lines.
wt_path=""; wt_branch=""
handle_wt() {
Expand Down Expand Up @@ -489,7 +498,17 @@ handle_wt() {
# This also disposes of the mid-bisect case (`git bisect start` with HEAD still on a branch reports
# porcelain-clean, and removing the worktree takes BISECT_LOG/BISECT_START with it).
printf ' %s [%s] (%s)\n' "$path" "$short" "$via"
printf ' remove with: git worktree remove %q && git branch -d %q\n' "$path" "$short"
# `-d` for git-native evidence, `-D` for squash evidence — the same split §1b uses, and for the
# same reason: after a squash the original tip is not an ancestor, so `git branch -d` CANNOT
# succeed. Printing `-d` for a squash-merged worktree produced a half-completed paste — the
# directory removed, then `error: the branch 'x' is not fully merged` — leaving an orphan branch.
# In a squash repo that was every single line of this section, i.e. the only repo shape this
# feature exists for.
if [ "$via" = "git" ]; then
printf ' remove with: git worktree remove %q && git branch -d %q\n' "$path" "$short"
else
printf ' remove with: git worktree remove %q && git branch -D %q\n' "$path" "$short"
fi
printf ' (check for ignored files first — `git worktree remove` deletes the directory:\n'
printf ' git -C %q status --porcelain --ignored=matching)\n' "$path"
}
Expand Down
5 changes: 4 additions & 1 deletion plugins/pilot/skills/pilot/templates/pilot.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ protect_patterns: # 额外保护的分支前缀(如 release/1.2 会
- release
- hotfix
remote: origin
allow_remote_cleanup: false # 删除远程已合并分支需显式置 true(无人值守默认不删远程)
# allow_remote_cleanup 已废弃 —— 脚本不再删远程分支,没有任何代码读这个键。
# 远程 head 分支请用 GitHub 的 auto-delete-on-merge(仓库设置里开),它在合并真正
# 发生的那一侧判定;从 clone 里判断要靠可能过期的 remote-tracking ref,而且 bare
# 仓库不留 reflog,是所有删除里唯一完全没有后悔药的。
docs_dir: docs/agent # 规划/运行态文档目录

# 规划在哪里。docs(默认)= 起跑门禁检查 docs_dir 下那七个文件;
Expand Down
Loading