xtrm-tools 0.5.29 → 0.5.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +19 -3
  3. package/README.md +13 -37
  4. package/cli/dist/index.cjs +311 -161
  5. package/cli/dist/index.cjs.map +1 -1
  6. package/cli/package.json +1 -1
  7. package/config/instructions/agents-top.md +1 -1
  8. package/config/instructions/claude-top.md +1 -1
  9. package/config/pi/extensions/beads/index.ts +68 -7
  10. package/config/pi/extensions/core/guard-rules.ts +0 -2
  11. package/config/pi/extensions/custom-footer/index.ts +5 -6
  12. package/hooks/beads-claim-sync.mjs +18 -6
  13. package/hooks/beads-gate-messages.mjs +5 -2
  14. package/hooks/beads-memory-gate.mjs +20 -7
  15. package/hooks/statusline.mjs +44 -8
  16. package/package.json +3 -2
  17. package/plugins/xtrm-tools/.claude-plugin/plugin.json +1 -1
  18. package/plugins/xtrm-tools/hooks/beads-claim-sync.mjs +18 -6
  19. package/plugins/xtrm-tools/hooks/beads-gate-messages.mjs +5 -2
  20. package/plugins/xtrm-tools/hooks/beads-memory-gate.mjs +20 -7
  21. package/plugins/xtrm-tools/hooks/statusline.mjs +44 -8
  22. package/plugins/xtrm-tools/skills/sync-docs/SKILL.md +57 -2
  23. package/plugins/xtrm-tools/skills/sync-docs/scripts/drift_detector.py +1 -1
  24. package/plugins/xtrm-tools/skills/sync-docs/scripts/validate_metadata.py +1 -1
  25. package/plugins/xtrm-tools/skills/xt-end/SKILL.md +4 -4
  26. package/plugins/xtrm-tools/skills/xt-merge/SKILL.md +190 -0
  27. package/skills/sync-docs/SKILL.md +57 -2
  28. package/skills/sync-docs/scripts/drift_detector.py +1 -1
  29. package/skills/sync-docs/scripts/validate_metadata.py +1 -1
  30. package/skills/xt-end/SKILL.md +4 -4
  31. package/skills/xt-merge/SKILL.md +190 -0
@@ -8,7 +8,7 @@ description: >-
8
8
  docs-only drift detection on README.md, CHANGELOG.md, and docs/ — creating
9
9
  missing focused files instead of a monolithic README.
10
10
  gemini-command: sync-docs
11
- version: 1.1.0
11
+ version: 1.2.0
12
12
  ---
13
13
 
14
14
  # sync-docs
@@ -33,7 +33,7 @@ Phase 5: Validate — schema-check all docs/
33
33
 
34
34
  ```bash
35
35
  # Global install
36
- python3 "$HOME/.claude/skills/sync-docs/scripts/context_gatherer.py" [--since=30]
36
+ python3 "$HOME/.agents/skills/sync-docs/scripts/context_gatherer.py" [--since=30]
37
37
 
38
38
  # From repository
39
39
  python3 "skills/sync-docs/scripts/context_gatherer.py" [--since=30]
@@ -149,7 +149,62 @@ python3 "skills/sync-docs/scripts/drift_detector.py" scan --since 30
149
149
 
150
150
  ---
151
151
 
152
+ ## Frontmatter Schema
153
+
154
+ All `docs/*.md` files require valid YAML frontmatter. Scripts only validate `docs/*.md` (not subdirectories).
155
+
156
+ ### Required Fields
157
+
158
+ | Field | Format | Example |
159
+ |-------|--------|---------|
160
+ | `title` | string (quote if contains colon) | `"Session-Flow: Pi Parity"` |
161
+ | `scope` | string | `hooks` |
162
+ | `category` | enum (see below) | `reference` |
163
+ | `version` | semver | `1.0.0` |
164
+ | `updated` | date | `2026-03-22` |
165
+
166
+ ### Valid Categories
167
+
168
+ Only these values pass validation:
169
+
170
+ | Category | Use for |
171
+ |----------|---------|
172
+ | `api` | API documentation |
173
+ | `architecture` | System design, architecture decisions |
174
+ | `guide` | How-to guides, tutorials |
175
+ | `overview` | High-level introductions |
176
+ | `plan` | Planning documents, roadmaps |
177
+ | `reference` | Reference documentation |
178
+
179
+ **Invalid**: `roadmap`, `deprecated`, `complete` — will fail validation.
180
+
181
+ ### YAML Quoting
182
+
183
+ Titles with special characters (colons, quotes) must be quoted:
184
+
185
+ ```yaml
186
+ # ✅ Correct
187
+ title: "Session-Flow: Pi Parity"
188
+ title: "What's New in v2.0"
189
+
190
+ # ❌ Incorrect — YAML parse error
191
+ title: Session-Flow: Pi Parity
192
+ title: What's New in v2.0
193
+ ```
194
+
195
+ ### Optional Fields
196
+
197
+ | Field | Format | Use |
198
+ |-------|--------|-----|
199
+ | `description` | string (quoted) | Brief summary |
200
+ | `source_of_truth_for` | list of globs | Link to code areas |
201
+ | `synced_at` | git hash | Drift checkpoint |
202
+ | `domain` | list of tags | Categorization |
203
+
204
+ ---
205
+
152
206
  ## docs/ as SSOT
153
207
 
154
208
  `docs/` is the only source of truth for project documentation in this workflow.
209
+ Scripts validate `docs/*.md` only — subdirectories (`docs/plans/`, `docs/reference/`) are ignored.
155
210
  Use frontmatter (`source_of_truth_for`) to link docs pages to code areas and detect drift.
@@ -42,7 +42,7 @@ def get_docs_files(project_root: Path) -> list[Path]:
42
42
  docs_dir = project_root / "docs"
43
43
  if not docs_dir.exists():
44
44
  return []
45
- return sorted(docs_dir.rglob("*.md"))
45
+ return sorted(docs_dir.glob("*.md"))
46
46
 
47
47
 
48
48
  def extract_frontmatter(content: str) -> dict[str, Any]:
@@ -158,7 +158,7 @@ def validate_metadata_file(path: Path) -> bool:
158
158
 
159
159
  def iter_targets(target: Path) -> list[Path]:
160
160
  if target.is_dir():
161
- return sorted(target.rglob("*.md"))
161
+ return sorted(target.glob("*.md"))
162
162
  return [target]
163
163
 
164
164
 
@@ -60,7 +60,7 @@ xt end
60
60
 
61
61
  ### If it succeeds
62
62
  You'll see:
63
- - ✓ Rebased onto origin/main
63
+ - ✓ Rebased onto origin/<default-branch>
64
64
  - ✓ Pushed branch
65
65
  - ✓ PR created: <url>
66
66
  - ✓ Linked PR to N issue(s)
@@ -84,7 +84,7 @@ Then re-run `xt end`. If the conflicts are complex, explain what each file confl
84
84
 
85
85
  Usually a stale remote ref. Try:
86
86
  ```bash
87
- git fetch origin main
87
+ git fetch origin
88
88
  xt end
89
89
  ```
90
90
 
@@ -117,9 +117,9 @@ If the worktree was removed: confirm that too.
117
117
 
118
118
  ## Edge cases
119
119
 
120
- **Already on main branch**: `xt end` will error — you're not in an xt session. Don't run it from main.
120
+ **Already on main/master branch**: `xt end` will error — you're not in an xt session. Don't run it from the default branch.
121
121
 
122
- **No commits yet on branch**: The PR will have no changes. This usually means something went wrong earlier. Verify with `git log origin/main..HEAD`.
122
+ **No commits yet on branch**: The PR will have no changes. This usually means something went wrong earlier. Verify with `git log origin/<default-branch>..HEAD` (where default-branch is main or master).
123
123
 
124
124
  **`gh` CLI not authenticated**: `gh pr create` will fail. Fix: `gh auth login`, then re-run `xt end`.
125
125
 
@@ -0,0 +1,190 @@
1
+ ---
2
+ name: xt-merge
3
+ description: |
4
+ Merges queued PRs from xt worktree sessions in the correct order (FIFO), maintaining linear
5
+ history by rebasing remaining PRs after each merge. Use this skill whenever the user has
6
+ multiple open PRs from xt worktrees, asks to "merge my PRs", "process the PR queue",
7
+ "drain the queue", "merge worktree branches", or says "what PRs do I have open".
8
+ Also activate after any xt-end completion when other PRs are already open, or when the
9
+ user asks "can I merge yet" or "is CI green". Handles the full sequence: list → sort →
10
+ CI check → merge oldest → rebase cascade → repeat until queue is empty.
11
+ ---
12
+
13
+ # merge-prs — Worktree PR Merge Workflow
14
+
15
+ You are draining a queue of PRs created by `xt end` from multiple worktree sessions.
16
+ The key constraint is **ordering**: merge in FIFO order and rebase the remaining PRs
17
+ after each merge. Work through the stages below in sequence.
18
+
19
+ ---
20
+
21
+ ## Why FIFO and why the rebase cascade matters
22
+
23
+ When `xt end` runs, it rebases the worktree branch onto `origin/main` at that moment
24
+ and pushes. If you ran three sessions in sequence:
25
+
26
+ ```
27
+ Session A finishes at t=1 → xt/feature-a rebased onto main@sha1
28
+ Session B finishes at t=2 → xt/feature-b rebased onto main@sha2 (sha2 >= sha1)
29
+ Session C finishes at t=3 → xt/feature-c rebased onto main@sha3 (sha3 >= sha2)
30
+ ```
31
+
32
+ After merging A, main advances to sha4. Branch B is now based on sha2 — it still
33
+ compiles and CI passes, but it doesn't include A's changes. You must rebase B onto
34
+ sha4 before merging, so the history stays linear and B's CI reflects the real state
35
+ of main + B.
36
+
37
+ **FIFO = merge the oldest-created PR first.** The older the PR, the smaller the
38
+ rebase cascade it triggers in subsequent branches. Merging out of order means
39
+ you're rebasing more than necessary and risk conflicts that wouldn't have existed.
40
+
41
+ ---
42
+
43
+ ## Stage 1 — Build the queue
44
+
45
+ List all open PRs from xt worktree branches:
46
+
47
+ ```bash
48
+ gh pr list --state open --json number,title,headRefName,createdAt,isDraft \
49
+ --jq '.[] | select(.headRefName | startswith("xt/")) | [.number, .createdAt, .headRefName, .title] | @tsv' \
50
+ | sort -k2
51
+ ```
52
+
53
+ This sorts by creation time. The top row is the **head of the queue** — merge it first.
54
+
55
+ If there are draft PRs in the list, skip them. Drafts are not ready to merge.
56
+
57
+ Present the sorted queue to the user before proceeding:
58
+ ```
59
+ Queue (oldest → newest):
60
+ #42 xt/fix-auth-gate "Fix beads edit gate claim check" 2026-03-21 10:14
61
+ #45 xt/add-release-script "Add release script for npm publish" 2026-03-21 14:32
62
+ #47 xt/default-branch "Detect default branch in xt end" 2026-03-22 09:11
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Stage 2 — Check CI on the head PR
68
+
69
+ ```bash
70
+ gh pr checks <number>
71
+ ```
72
+
73
+ Wait for all checks to pass. If CI is still running, tell the user and pause — don't
74
+ merge a PR with pending or failing checks.
75
+
76
+ If CI is failing:
77
+ - Show the failing check names and link to the run
78
+ - Do NOT proceed with the merge
79
+ - Let the user decide: fix the issue in the worktree (may already be deleted), push a
80
+ fixup commit directly to the branch, or close the PR
81
+
82
+ ---
83
+
84
+ ## Stage 3 — Merge the head PR
85
+
86
+ ```bash
87
+ gh pr merge <number> --rebase --delete-branch
88
+ ```
89
+
90
+ Use `--rebase` (not `--squash` or `--merge`) to keep linear history and preserve
91
+ individual commits from the session. Use `--delete-branch` to clean up the remote branch.
92
+
93
+ After merge, confirm main advanced:
94
+ ```bash
95
+ git fetch origin
96
+ git log origin/main --oneline -3
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Stage 4 — Rebase cascade (all remaining PRs)
102
+
103
+ For every remaining PR in the queue, rebase its branch onto the new main:
104
+
105
+ ```bash
106
+ git fetch origin main
107
+ git checkout xt/<branch>
108
+ git rebase origin/main
109
+ git push origin xt/<branch> --force-with-lease
110
+ ```
111
+
112
+ Repeat for each remaining branch. Do them in queue order (oldest next).
113
+
114
+ After pushing, GitHub will re-trigger CI on each rebased PR. You don't need to wait
115
+ for CI here — the rebase just gets the branches current. CI will run in parallel.
116
+
117
+ ### If rebase conflicts occur
118
+
119
+ ```bash
120
+ git status # shows conflicted files
121
+ # edit each file to resolve <<<< ==== >>>> markers
122
+ git add <resolved-files>
123
+ git rebase --continue
124
+ ```
125
+
126
+ Conflicts mean two sessions touched the same file. Resolve carefully:
127
+ - Keep both changes if they're in different parts of the file
128
+ - If they overlap, understand what each session was doing and merge the intent
129
+ - When unsure, call the user in to review before continuing
130
+
131
+ After resolving, push with `--force-with-lease` and move to the next branch.
132
+
133
+ ---
134
+
135
+ ## Stage 5 — Repeat
136
+
137
+ Go back to Stage 2 with the new head of the queue. Check CI, merge, rebase cascade,
138
+ repeat until the queue is empty.
139
+
140
+ The full loop:
141
+ ```
142
+ while queue not empty:
143
+ wait for CI green on head PR
144
+ merge head PR (--rebase --delete-branch)
145
+ rebase all remaining PRs onto new main
146
+ push each (--force-with-lease)
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Stage 6 — Done
152
+
153
+ When the queue is empty:
154
+ ```bash
155
+ gh pr list --state open
156
+ git log origin/main --oneline -5
157
+ ```
158
+
159
+ Confirm no open xt/ PRs remain and show the user the final state of main.
160
+
161
+ ---
162
+
163
+ ## Edge cases
164
+
165
+ **PR was already merged**: `gh pr merge` will error. Skip it and continue.
166
+
167
+ **Branch was deleted** (worktree cleaned up by `xt end --keep`): The remote branch
168
+ still exists (pushed by `xt end`). The local branch may not. Check out from remote:
169
+ ```bash
170
+ git fetch origin
171
+ git checkout -b xt/<branch> origin/xt/<branch>
172
+ ```
173
+
174
+ **CI never triggers after rebase push**: GitHub sometimes needs a nudge. Close and
175
+ re-open the PR, or push an empty commit:
176
+ ```bash
177
+ git commit --allow-empty -m "trigger CI"
178
+ git push origin xt/<branch>
179
+ ```
180
+
181
+ **Dependent sessions** (B was intentionally built on A's work): If session B was
182
+ started from inside session A's worktree rather than from main, B's branch already
183
+ contains A's commits. In this case B will rebase cleanly onto main after A merges —
184
+ its commits are a superset. No special handling needed; the rebase just eliminates
185
+ the duplicate commits.
186
+
187
+ **Multiple conflicts across many PRs**: If the cascade produces conflicts in several
188
+ branches, tackle them one at a time in queue order. Don't try to resolve all of them
189
+ before pushing any — push each one as you resolve it so CI starts running in parallel
190
+ while you work on the next.
@@ -8,7 +8,7 @@ description: >-
8
8
  docs-only drift detection on README.md, CHANGELOG.md, and docs/ — creating
9
9
  missing focused files instead of a monolithic README.
10
10
  gemini-command: sync-docs
11
- version: 1.1.0
11
+ version: 1.2.0
12
12
  ---
13
13
 
14
14
  # sync-docs
@@ -33,7 +33,7 @@ Phase 5: Validate — schema-check all docs/
33
33
 
34
34
  ```bash
35
35
  # Global install
36
- python3 "$HOME/.claude/skills/sync-docs/scripts/context_gatherer.py" [--since=30]
36
+ python3 "$HOME/.agents/skills/sync-docs/scripts/context_gatherer.py" [--since=30]
37
37
 
38
38
  # From repository
39
39
  python3 "skills/sync-docs/scripts/context_gatherer.py" [--since=30]
@@ -149,7 +149,62 @@ python3 "skills/sync-docs/scripts/drift_detector.py" scan --since 30
149
149
 
150
150
  ---
151
151
 
152
+ ## Frontmatter Schema
153
+
154
+ All `docs/*.md` files require valid YAML frontmatter. Scripts only validate `docs/*.md` (not subdirectories).
155
+
156
+ ### Required Fields
157
+
158
+ | Field | Format | Example |
159
+ |-------|--------|---------|
160
+ | `title` | string (quote if contains colon) | `"Session-Flow: Pi Parity"` |
161
+ | `scope` | string | `hooks` |
162
+ | `category` | enum (see below) | `reference` |
163
+ | `version` | semver | `1.0.0` |
164
+ | `updated` | date | `2026-03-22` |
165
+
166
+ ### Valid Categories
167
+
168
+ Only these values pass validation:
169
+
170
+ | Category | Use for |
171
+ |----------|---------|
172
+ | `api` | API documentation |
173
+ | `architecture` | System design, architecture decisions |
174
+ | `guide` | How-to guides, tutorials |
175
+ | `overview` | High-level introductions |
176
+ | `plan` | Planning documents, roadmaps |
177
+ | `reference` | Reference documentation |
178
+
179
+ **Invalid**: `roadmap`, `deprecated`, `complete` — will fail validation.
180
+
181
+ ### YAML Quoting
182
+
183
+ Titles with special characters (colons, quotes) must be quoted:
184
+
185
+ ```yaml
186
+ # ✅ Correct
187
+ title: "Session-Flow: Pi Parity"
188
+ title: "What's New in v2.0"
189
+
190
+ # ❌ Incorrect — YAML parse error
191
+ title: Session-Flow: Pi Parity
192
+ title: What's New in v2.0
193
+ ```
194
+
195
+ ### Optional Fields
196
+
197
+ | Field | Format | Use |
198
+ |-------|--------|-----|
199
+ | `description` | string (quoted) | Brief summary |
200
+ | `source_of_truth_for` | list of globs | Link to code areas |
201
+ | `synced_at` | git hash | Drift checkpoint |
202
+ | `domain` | list of tags | Categorization |
203
+
204
+ ---
205
+
152
206
  ## docs/ as SSOT
153
207
 
154
208
  `docs/` is the only source of truth for project documentation in this workflow.
209
+ Scripts validate `docs/*.md` only — subdirectories (`docs/plans/`, `docs/reference/`) are ignored.
155
210
  Use frontmatter (`source_of_truth_for`) to link docs pages to code areas and detect drift.
@@ -42,7 +42,7 @@ def get_docs_files(project_root: Path) -> list[Path]:
42
42
  docs_dir = project_root / "docs"
43
43
  if not docs_dir.exists():
44
44
  return []
45
- return sorted(docs_dir.rglob("*.md"))
45
+ return sorted(docs_dir.glob("*.md"))
46
46
 
47
47
 
48
48
  def extract_frontmatter(content: str) -> dict[str, Any]:
@@ -158,7 +158,7 @@ def validate_metadata_file(path: Path) -> bool:
158
158
 
159
159
  def iter_targets(target: Path) -> list[Path]:
160
160
  if target.is_dir():
161
- return sorted(target.rglob("*.md"))
161
+ return sorted(target.glob("*.md"))
162
162
  return [target]
163
163
 
164
164
 
@@ -60,7 +60,7 @@ xt end
60
60
 
61
61
  ### If it succeeds
62
62
  You'll see:
63
- - ✓ Rebased onto origin/main
63
+ - ✓ Rebased onto origin/<default-branch>
64
64
  - ✓ Pushed branch
65
65
  - ✓ PR created: <url>
66
66
  - ✓ Linked PR to N issue(s)
@@ -84,7 +84,7 @@ Then re-run `xt end`. If the conflicts are complex, explain what each file confl
84
84
 
85
85
  Usually a stale remote ref. Try:
86
86
  ```bash
87
- git fetch origin main
87
+ git fetch origin
88
88
  xt end
89
89
  ```
90
90
 
@@ -117,9 +117,9 @@ If the worktree was removed: confirm that too.
117
117
 
118
118
  ## Edge cases
119
119
 
120
- **Already on main branch**: `xt end` will error — you're not in an xt session. Don't run it from main.
120
+ **Already on main/master branch**: `xt end` will error — you're not in an xt session. Don't run it from the default branch.
121
121
 
122
- **No commits yet on branch**: The PR will have no changes. This usually means something went wrong earlier. Verify with `git log origin/main..HEAD`.
122
+ **No commits yet on branch**: The PR will have no changes. This usually means something went wrong earlier. Verify with `git log origin/<default-branch>..HEAD` (where default-branch is main or master).
123
123
 
124
124
  **`gh` CLI not authenticated**: `gh pr create` will fail. Fix: `gh auth login`, then re-run `xt end`.
125
125
 
@@ -0,0 +1,190 @@
1
+ ---
2
+ name: xt-merge
3
+ description: |
4
+ Merges queued PRs from xt worktree sessions in the correct order (FIFO), maintaining linear
5
+ history by rebasing remaining PRs after each merge. Use this skill whenever the user has
6
+ multiple open PRs from xt worktrees, asks to "merge my PRs", "process the PR queue",
7
+ "drain the queue", "merge worktree branches", or says "what PRs do I have open".
8
+ Also activate after any xt-end completion when other PRs are already open, or when the
9
+ user asks "can I merge yet" or "is CI green". Handles the full sequence: list → sort →
10
+ CI check → merge oldest → rebase cascade → repeat until queue is empty.
11
+ ---
12
+
13
+ # merge-prs — Worktree PR Merge Workflow
14
+
15
+ You are draining a queue of PRs created by `xt end` from multiple worktree sessions.
16
+ The key constraint is **ordering**: merge in FIFO order and rebase the remaining PRs
17
+ after each merge. Work through the stages below in sequence.
18
+
19
+ ---
20
+
21
+ ## Why FIFO and why the rebase cascade matters
22
+
23
+ When `xt end` runs, it rebases the worktree branch onto `origin/main` at that moment
24
+ and pushes. If you ran three sessions in sequence:
25
+
26
+ ```
27
+ Session A finishes at t=1 → xt/feature-a rebased onto main@sha1
28
+ Session B finishes at t=2 → xt/feature-b rebased onto main@sha2 (sha2 >= sha1)
29
+ Session C finishes at t=3 → xt/feature-c rebased onto main@sha3 (sha3 >= sha2)
30
+ ```
31
+
32
+ After merging A, main advances to sha4. Branch B is now based on sha2 — it still
33
+ compiles and CI passes, but it doesn't include A's changes. You must rebase B onto
34
+ sha4 before merging, so the history stays linear and B's CI reflects the real state
35
+ of main + B.
36
+
37
+ **FIFO = merge the oldest-created PR first.** The older the PR, the smaller the
38
+ rebase cascade it triggers in subsequent branches. Merging out of order means
39
+ you're rebasing more than necessary and risk conflicts that wouldn't have existed.
40
+
41
+ ---
42
+
43
+ ## Stage 1 — Build the queue
44
+
45
+ List all open PRs from xt worktree branches:
46
+
47
+ ```bash
48
+ gh pr list --state open --json number,title,headRefName,createdAt,isDraft \
49
+ --jq '.[] | select(.headRefName | startswith("xt/")) | [.number, .createdAt, .headRefName, .title] | @tsv' \
50
+ | sort -k2
51
+ ```
52
+
53
+ This sorts by creation time. The top row is the **head of the queue** — merge it first.
54
+
55
+ If there are draft PRs in the list, skip them. Drafts are not ready to merge.
56
+
57
+ Present the sorted queue to the user before proceeding:
58
+ ```
59
+ Queue (oldest → newest):
60
+ #42 xt/fix-auth-gate "Fix beads edit gate claim check" 2026-03-21 10:14
61
+ #45 xt/add-release-script "Add release script for npm publish" 2026-03-21 14:32
62
+ #47 xt/default-branch "Detect default branch in xt end" 2026-03-22 09:11
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Stage 2 — Check CI on the head PR
68
+
69
+ ```bash
70
+ gh pr checks <number>
71
+ ```
72
+
73
+ Wait for all checks to pass. If CI is still running, tell the user and pause — don't
74
+ merge a PR with pending or failing checks.
75
+
76
+ If CI is failing:
77
+ - Show the failing check names and link to the run
78
+ - Do NOT proceed with the merge
79
+ - Let the user decide: fix the issue in the worktree (may already be deleted), push a
80
+ fixup commit directly to the branch, or close the PR
81
+
82
+ ---
83
+
84
+ ## Stage 3 — Merge the head PR
85
+
86
+ ```bash
87
+ gh pr merge <number> --rebase --delete-branch
88
+ ```
89
+
90
+ Use `--rebase` (not `--squash` or `--merge`) to keep linear history and preserve
91
+ individual commits from the session. Use `--delete-branch` to clean up the remote branch.
92
+
93
+ After merge, confirm main advanced:
94
+ ```bash
95
+ git fetch origin
96
+ git log origin/main --oneline -3
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Stage 4 — Rebase cascade (all remaining PRs)
102
+
103
+ For every remaining PR in the queue, rebase its branch onto the new main:
104
+
105
+ ```bash
106
+ git fetch origin main
107
+ git checkout xt/<branch>
108
+ git rebase origin/main
109
+ git push origin xt/<branch> --force-with-lease
110
+ ```
111
+
112
+ Repeat for each remaining branch. Do them in queue order (oldest next).
113
+
114
+ After pushing, GitHub will re-trigger CI on each rebased PR. You don't need to wait
115
+ for CI here — the rebase just gets the branches current. CI will run in parallel.
116
+
117
+ ### If rebase conflicts occur
118
+
119
+ ```bash
120
+ git status # shows conflicted files
121
+ # edit each file to resolve <<<< ==== >>>> markers
122
+ git add <resolved-files>
123
+ git rebase --continue
124
+ ```
125
+
126
+ Conflicts mean two sessions touched the same file. Resolve carefully:
127
+ - Keep both changes if they're in different parts of the file
128
+ - If they overlap, understand what each session was doing and merge the intent
129
+ - When unsure, call the user in to review before continuing
130
+
131
+ After resolving, push with `--force-with-lease` and move to the next branch.
132
+
133
+ ---
134
+
135
+ ## Stage 5 — Repeat
136
+
137
+ Go back to Stage 2 with the new head of the queue. Check CI, merge, rebase cascade,
138
+ repeat until the queue is empty.
139
+
140
+ The full loop:
141
+ ```
142
+ while queue not empty:
143
+ wait for CI green on head PR
144
+ merge head PR (--rebase --delete-branch)
145
+ rebase all remaining PRs onto new main
146
+ push each (--force-with-lease)
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Stage 6 — Done
152
+
153
+ When the queue is empty:
154
+ ```bash
155
+ gh pr list --state open
156
+ git log origin/main --oneline -5
157
+ ```
158
+
159
+ Confirm no open xt/ PRs remain and show the user the final state of main.
160
+
161
+ ---
162
+
163
+ ## Edge cases
164
+
165
+ **PR was already merged**: `gh pr merge` will error. Skip it and continue.
166
+
167
+ **Branch was deleted** (worktree cleaned up by `xt end --keep`): The remote branch
168
+ still exists (pushed by `xt end`). The local branch may not. Check out from remote:
169
+ ```bash
170
+ git fetch origin
171
+ git checkout -b xt/<branch> origin/xt/<branch>
172
+ ```
173
+
174
+ **CI never triggers after rebase push**: GitHub sometimes needs a nudge. Close and
175
+ re-open the PR, or push an empty commit:
176
+ ```bash
177
+ git commit --allow-empty -m "trigger CI"
178
+ git push origin xt/<branch>
179
+ ```
180
+
181
+ **Dependent sessions** (B was intentionally built on A's work): If session B was
182
+ started from inside session A's worktree rather than from main, B's branch already
183
+ contains A's commits. In this case B will rebase cleanly onto main after A merges —
184
+ its commits are a superset. No special handling needed; the rebase just eliminates
185
+ the duplicate commits.
186
+
187
+ **Multiple conflicts across many PRs**: If the cascade produces conflicts in several
188
+ branches, tackle them one at a time in queue order. Don't try to resolve all of them
189
+ before pushing any — push each one as you resolve it so CI starts running in parallel
190
+ while you work on the next.