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: 1 addition & 1 deletion .claude/commands/pr-loop-self.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Prompt to use (the tick logic, with adaptive STEP 0):
>
> Then, in order:
> 1. POLL: run `bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/notify-poll.sh`; summarize new issues / PR comments / reviews and the open-PR status section.
> 2. MERGE: run `bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/merge-ready.sh`; report each PR merged or why skipped. (It only merges PRs the owner APPROVED that are CI-green & mergeable; never approves.)
> 2. MERGE: run `bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/merge-ready.sh`; report each PR merged or why skipped. (It only merges PRs the owner APPROVED that are CI-green & mergeable; never approves.) After merging, it fast-forwards the LOCAL checkout to `main` when it is clean and already on `main` — so your terminal/IDE shows the latest without a manual pull. It never switches branches or clobbers uncommitted work; anything else is skipped (`local_sync` line reports the reason).
> 3. ADDRESS FEEDBACK: run `bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/pr-feedback.sh`; for each PR it lists (bot-authored, with unaddressed CHANGES_REQUESTED), run orchestrator→worktree implementer→reviewer-lenses (self adapter: `GATES_FILE=.claude/self/gates.json`, lenses `correctness`/`tests`, consensus `all`) on the SAME branch, push to update the PR in place, and post the `<!-- claude-addressed -->` marker comment via bot-gh.sh. Do NOT merge here.
> 4. ADVANCE: ONLY when there are ZERO open PRs — pick the lowest-numbered open self `module:*` issue (`module:docs`, `module:harness`, `module:examples`, `module:ci`) with no feat/issue-<n>-* branch; drive it through the orchestrator using `.claude/self/gates.json` as the adapter (scope → worktree implementer → `GATES_FILE=.claude/self/gates.json gate.sh` gates → reviewer lenses `correctness`/`tests` consensus `all` → bot PR). One issue in flight at a time.
> 5. If nothing actionable, reply exactly one line: "No actionable activity."
Expand Down
2 changes: 1 addition & 1 deletion .claude/commands/pr-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Prompt to use (the tick logic, with adaptive STEP 0):
>
> Then, in order:
> 1. POLL: run `bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/notify-poll.sh`; summarize new issues / PR comments / reviews and the open-PR status section.
> 2. MERGE: run `bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/merge-ready.sh`; report each PR merged or why skipped. (It only merges PRs the owner APPROVED that are CI-green & mergeable; never approves.)
> 2. MERGE: run `bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/merge-ready.sh`; report each PR merged or why skipped. (It only merges PRs the owner APPROVED that are CI-green & mergeable; never approves.) After merging, it fast-forwards the LOCAL checkout to `main` when it is clean and already on `main` — so your terminal/IDE shows the latest without a manual pull. It never switches branches or clobbers uncommitted work; anything else is skipped (`local_sync` line reports the reason).
> 3. ADDRESS FEEDBACK: run `bash ${CLAUDE_PLUGIN_ROOT:-.claude}/scripts/pr-feedback.sh`; for each PR it lists (bot-authored, with unaddressed CHANGES_REQUESTED), run orchestrator→worktree implementer→reviewer-lenses on the SAME branch, push to update the PR in place, and post the `<!-- claude-addressed -->` marker comment via bot-gh.sh. Do NOT merge here.
> 4. ADVANCE: ONLY when there are ZERO open PRs — pick the lowest-numbered open module:* issue with no feat/issue-<n>-* branch; drive it through the orchestrator (scope → worktree implementer → gate.sh gates → reviewer lenses → bot PR). One issue in flight at a time.
> 5. If nothing actionable, reply exactly one line: "No actionable activity."
Expand Down
23 changes: 23 additions & 0 deletions .claude/scripts/merge-ready.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,27 @@ for n in $(gh pr list -R "$repo" --base "$base" --state open --json number -q '.
echo "{\"pr\":$n,\"action\":\"skip\",\"reason\":\"${verdict#SKIP:}\",\"title\":\"$title\"}"; skipped=$((skipped+1))
fi
done

# Post-merge: fast-forward the LOCAL checkout to the freshly-merged base so the
# owner's terminal/IDE shows the latest code without a manual pull. Strictly safe:
# acts ONLY when the checkout is on the base branch with a clean tree, and only
# fast-forwards (never a merge commit, never a branch switch, never clobbers
# uncommitted work). Untracked sandbox device-node masks don't count as changes.
# Any obstacle -> skip with a reason; never force. See docs/HARDENING.md.
if [ "$merged" -gt 0 ]; then
wt="$(git rev-parse --show-toplevel 2>/dev/null || true)"
cur="$(git -C "${wt:-.}" symbolic-ref --quiet --short HEAD 2>/dev/null || echo DETACHED)"
if [ -z "$wt" ]; then
:
elif [ "$cur" != "$base" ]; then
echo "{\"local_sync\":\"skip\",\"reason\":\"checkout on '$cur', not '$base'\"}"
elif ! git -C "$wt" diff --quiet || ! git -C "$wt" diff --cached --quiet; then
echo "{\"local_sync\":\"skip\",\"reason\":\"working tree has tracked changes\"}"
elif git -C "$wt" fetch --quiet origin "$base" 2>/dev/null \
&& git -C "$wt" merge --ff-only -q "origin/$base" 2>/dev/null; then
echo "{\"local_sync\":\"ok\",\"branch\":\"$base\",\"head\":\"$(git -C "$wt" rev-parse --short HEAD)\"}"
else
echo "{\"local_sync\":\"skip\",\"reason\":\"fetch or fast-forward failed (diverged/offline?)\"}"
fi
fi
echo "=== merge-ready: merged=$merged skipped=$skipped ==="
Loading