@caddis/cli 0.4.56 → 0.4.57
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.
- package/bundles/antigravity-plugin/guard_agy.py +700 -68
- package/bundles/antigravity-plugin/hooks.json +2 -1
- package/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/scripts/caddis_checkout_guard.py +63 -12
- package/bundles/antigravity-plugin/scripts/caddis_gate.py +21 -0
- package/bundles/antigravity-plugin/scripts/caddis_lanes.py +35 -0
- package/bundles/antigravity-plugin/scripts/caddis_merge_chain.py +67 -22
- package/bundles/antigravity-plugin/scripts/caddis_review.py +59 -9
- package/bundles/antigravity-plugin/scripts/caddis_roadmap.py +120 -24
- package/bundles/antigravity-plugin/scripts/caddis_roadmap_page.py +80 -7
- package/bundles/antigravity-plugin/scripts/oss_review.py +300 -79
- package/bundles/antigravity-plugin/scripts/setup_project_ai.py +4 -0
- package/bundles/antigravity-plugin/session_end_agy.py +13 -10
- package/bundles/antigravity-plugin/skills/cloud-phases/SKILL.md +53 -8
- package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +11 -8
- package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/gh-cli/SKILL.md +9 -5
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +18 -11
- package/bundles/antigravity-plugin/skills/mmr/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/pr-merge/SKILL.md +44 -4
- package/bundles/antigravity-plugin/skills/review-pr/SKILL.md +13 -4
- package/bundles/antigravity-plugin/skills/ship/SKILL.md +26 -7
- package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +31 -0
- package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +42 -4
- package/bundles/antigravity-plugin/warm_start_agy.py +26 -15
- package/bundles/antigravity-plugin-extras/plugin.json +1 -1
- package/bundles/antigravity-plugin-extras/skills/agent-orchestration/SKILL.md +5 -5
- package/bundles/antigravity-plugin-extras/skills/cross-review/SKILL.md +1 -1
- package/bundles/codex/.codex/skills/devops/gh-cli/SKILL.md +9 -5
- package/bundles/manifest.json +3 -3
- package/package.json +1 -1
|
@@ -61,7 +61,8 @@ def _repo_root(path: str):
|
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
def _user_artifact_root() -> str:
|
|
64
|
-
"""Where usage goes when the workspace is in no repository: the user's own folder, never the cwd.
|
|
64
|
+
"""Where usage goes when the workspace is in no repository: the user's own folder, never the cwd.
|
|
65
|
+
The caller writes there only when it already exists."""
|
|
65
66
|
return _artifact_root(os.path.expanduser("~"))
|
|
66
67
|
|
|
67
68
|
|
|
@@ -121,21 +122,24 @@ def main() -> None:
|
|
|
121
122
|
try:
|
|
122
123
|
roots = _workspace_roots(data) or [os.getcwd()]
|
|
123
124
|
# A workspace folder may sit inside a repo: the artifact dir is the REPO ROOT's, not the sub-folder's.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
#
|
|
127
|
-
# repo that participates in it, and creating .caddis in a repo that never opted in
|
|
125
|
+
# A folder in no repository is skipped: it has no project, and its cwd is never a fallback.
|
|
126
|
+
resolved = [top for top in (_repo_root(r) for r in roots) if top]
|
|
127
|
+
# Write the record only to roots that ALREADY have a .caddis dir. A multi-root session's usage
|
|
128
|
+
# belongs to each repo that participates in it, and creating .caddis in a repo that never opted in
|
|
128
129
|
# would be caddis littering someone else's tree.
|
|
129
130
|
targets = []
|
|
130
131
|
for root in resolved:
|
|
131
132
|
art = _artifact_root(root)
|
|
132
133
|
if os.path.isdir(art) and art not in targets:
|
|
133
134
|
targets.append(art)
|
|
135
|
+
if not resolved:
|
|
136
|
+
# No workspace is in a repository. Usage goes to the user's own folder, and only when
|
|
137
|
+
# that folder already exists. It is never created and never the cwd.
|
|
138
|
+
user_art = _user_artifact_root()
|
|
139
|
+
if os.path.isdir(user_art):
|
|
140
|
+
targets = [user_art]
|
|
134
141
|
if not targets:
|
|
135
|
-
#
|
|
136
|
-
# repo there is no project to attach usage to, so it goes to the user's folder, not the cwd.
|
|
137
|
-
first_repo = _repo_root(roots[0])
|
|
138
|
-
targets = [_artifact_root(first_repo) if first_repo else _user_artifact_root()]
|
|
142
|
+
return # nothing has opted in: write nothing
|
|
139
143
|
record = {
|
|
140
144
|
"ts": datetime.now(timezone.utc).isoformat(),
|
|
141
145
|
"event": "session_end",
|
|
@@ -146,7 +150,6 @@ def main() -> None:
|
|
|
146
150
|
"model": data.get("modelName"),
|
|
147
151
|
}
|
|
148
152
|
for art in targets:
|
|
149
|
-
os.makedirs(art, exist_ok=True)
|
|
150
153
|
with open(os.path.join(art, "usage-log.jsonl"), "a", encoding="utf-8") as fh:
|
|
151
154
|
fh.write(json.dumps(record) + "\n")
|
|
152
155
|
except Exception as _exc:
|
|
@@ -23,6 +23,35 @@ Two modes:
|
|
|
23
23
|
With no plan argument, use the active plan (`python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_todo.py" active-plan`,
|
|
24
24
|
or the one `status: current` plan in `.caddis/plans/`). If there is none, or more than one, ask.
|
|
25
25
|
|
|
26
|
+
## Step 0 — Is this checkout safe to move?
|
|
27
|
+
|
|
28
|
+
<!-- checkout-safety: keep byte-identical in pr-merge, ship-pr, ship-merge and cloud-phases; a test pins it -->
|
|
29
|
+
Some steps below move the files of this checkout (`git rebase`, `switch`, `checkout <branch>`, `pull`, `merge`,
|
|
30
|
+
`stash`, `reset --hard`). Before the first of them, run:
|
|
31
|
+
```
|
|
32
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_checkout_guard.py" shared --root .
|
|
33
|
+
```
|
|
34
|
+
It prints `SHARED: yes <reason>` or `SHARED: no` and exits 0. It says yes when the repo's `AGENTS.md` has a line
|
|
35
|
+
`Shared checkout: yes` (a dev service serves from this checkout), or when `git status` lists a change. With no
|
|
36
|
+
`--own-files`, every change counts as another session's. A linked worktree is never shared.
|
|
37
|
+
|
|
38
|
+
- **On `SHARED: no`,** do the steps as written, in this checkout.
|
|
39
|
+
- **On `SHARED: yes`,** never move this checkout. Leave its changes as they are, and report them. Instead:
|
|
40
|
+
- **Rebase:** `git worktree add --detach "$TEMP/<repo>-rebase" <branch>`, then
|
|
41
|
+
`git -C <worktree> rebase origin/<default>` and `git -C <worktree> push --force-with-lease origin HEAD:<branch>`.
|
|
42
|
+
- **Pull a branch to test it:** `git fetch origin`, then
|
|
43
|
+
`git worktree add --detach "$TEMP/<repo>-<branch>" origin/<branch>` (for the default branch,
|
|
44
|
+
`origin/<default>`), and run the gates there. Install dependencies fresh; never link `node_modules` or a venv.
|
|
45
|
+
- **Clean up after a merge:** do not switch or pull. Run `git fetch --prune`, then
|
|
46
|
+
`git fetch origin <default>:<default>`: it fast-forwards the default branch with no checkout. Git refuses when a
|
|
47
|
+
checkout has the default branch out; then leave it and report it. Delete the local feature branch only when no
|
|
48
|
+
checkout has it out.
|
|
49
|
+
- Remove each worktree you made when its step ends: `git worktree remove <worktree>`.
|
|
50
|
+
|
|
51
|
+
`$TEMP` is `%TEMP%` (`$env:TEMP` in PowerShell). The caddis guard checks only the `Shared checkout: yes` line in
|
|
52
|
+
`AGENTS.md`, not a dirty tree: with that line, it asks before a tree move, and denies it in a headless session.
|
|
53
|
+
<!-- /checkout-safety -->
|
|
54
|
+
|
|
26
55
|
## Step 1 — check the preconditions (stop on any failure)
|
|
27
56
|
|
|
28
57
|
```
|
|
@@ -35,7 +64,11 @@ gh auth status
|
|
|
35
64
|
- `origin` must be a GitHub repository. Cloud sessions clone from GitHub; a repo with no GitHub
|
|
36
65
|
remote cannot use this command. Say so and stop.
|
|
37
66
|
- The current branch must be the plan's feature branch, never the default branch. The cloud PRs
|
|
38
|
-
target this branch, and it goes to
|
|
67
|
+
target this branch, and it goes to the default branch later through the normal `/caddis:ship-pr`.
|
|
68
|
+
Read the default branch as a bare name: `git rev-parse --abbrev-ref origin/HEAD` prints
|
|
69
|
+
`origin/<default>`, so strip the `origin/` prefix before you compare
|
|
70
|
+
(`d=$(git rev-parse --abbrev-ref origin/HEAD) && d=${d#origin/}`; when origin/HEAD is not set,
|
|
71
|
+
`gh repo view --json defaultBranchRef -q .defaultBranchRef.name`).
|
|
39
72
|
- Tracked changes must be committed. A cloud session cannot see uncommitted work.
|
|
40
73
|
- `gh` must be signed in as an account that can push to the repository and open PRs.
|
|
41
74
|
|
|
@@ -152,14 +185,26 @@ gh pr list --base <feature branch> --state open --json number,title,headRefName,
|
|
|
152
185
|
For each PR from a `<prefix>/phase-<NN>` branch, one at a time:
|
|
153
186
|
1. Read the whole diff (`gh pr diff <N>`). Check it against the phase's Design and Touches. A file
|
|
154
187
|
outside Touches is a finding.
|
|
155
|
-
2. Wait for CI
|
|
188
|
+
2. Wait for CI outside the session:
|
|
189
|
+
`python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_lanes.py" ci-watch --pr <N>`. Only `RESULT: pass`
|
|
190
|
+
counts; `HEAD:` names the watched head. A `gh pr checks` table is not proof: it can show an older
|
|
191
|
+
head's checks.
|
|
156
192
|
3. Review under the three rules (rule 3, review by tier): stop at the first CLEAN; after 3 rounds,
|
|
157
|
-
ask the owner. A fix goes back to the same cloud session or is made locally on the PR branch.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
`
|
|
161
|
-
|
|
162
|
-
|
|
193
|
+
ask the owner. A fix goes back to the same cloud session or is made locally on the PR branch. A
|
|
194
|
+
fix pushes a new head: run ci-watch again.
|
|
195
|
+
4. Just before merging, check all three, then merge that head only:
|
|
196
|
+
- the last ci-watch printed `RESULT: pass`, and its `HEAD:` is the head you reviewed;
|
|
197
|
+
- `gh pr view <N> --json headRefOid,mergeStateStatus` still shows that head;
|
|
198
|
+
- no CI run on the default branch is in progress:
|
|
199
|
+
`gh run list --branch <default branch> --json status` lists no `in_progress` or `queued` run
|
|
200
|
+
(wait, then check again).
|
|
201
|
+
|
|
202
|
+
`gh pr merge <N> --squash --delete-branch --match-head-commit <watched head>` (the full SHA).
|
|
203
|
+
GitHub refuses the merge if the head moved. A merge on a head match alone merged a red PR (#34).
|
|
204
|
+
5. Pull: `git pull --ff-only origin <feature branch>`. In a shared checkout (Step 0 says `SHARED: yes`), never
|
|
205
|
+
pull here: make a detached worktree of `origin/<feature branch>`, as Step 0 says, and run point 6 there.
|
|
206
|
+
6. Run the phase's exit gate locally: the tests of the touched files, in the foreground, each command under
|
|
207
|
+
10 minutes. Do not start the full suite in the background. CI runs it on every PR.
|
|
163
208
|
7. Update the phase's Tracker row: status, PR number, merge commit, review result. Set the prompt's
|
|
164
209
|
frontmatter `status: done` so `/caddis:handoff` tidies it.
|
|
165
210
|
|
|
@@ -86,23 +86,26 @@ now means the narrower case — a **single file** too big to split, or more batc
|
|
|
86
86
|
see it, the fix is usually to review that one file separately, not to narrow `--range`; don't raise
|
|
87
87
|
`--max-diff-chars` blind.
|
|
88
88
|
|
|
89
|
-
**Do not alternate providers on a schedule.**
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
**Do not alternate providers on a schedule.** The order is the owner policy: **DeepSeek, then agy Argon,
|
|
90
|
+
then GLM** (`REVIEW_ORDER` in `oss_review.py`). A named `--provider` goes first; on a provider failure
|
|
91
|
+
(HTTP 429, any 5xx, a timeout, a connection error, an empty reply) the tool moves to the next one in
|
|
92
|
+
that order and prints which provider gave the verdict. A provider with no key is skipped. agy runs
|
|
93
|
+
through `caddis_spend.py run` (the spend cap); if the cap refuses, agy is skipped. On a 429 the tool
|
|
94
|
+
waits for `Retry-After` once (at most 60 s); it never splits the diff because of a 429 or an empty
|
|
95
|
+
reply. A custom endpoint (`--base-url`/`--model`) never falls back. Name a provider only when you have
|
|
96
|
+
a reason.
|
|
95
97
|
|
|
96
98
|
## Interpret the exit code
|
|
97
99
|
- **0 — REVIEW: CLEAN** → no blocking issues. Proceed.
|
|
98
100
|
- **1 — REVIEW: BLOCKING** → read the printed findings, then **FIX each blocking item** (or explicitly
|
|
99
101
|
justify why one is a false positive). Fix it, then re-review only the fix diff. After 3 rounds, ask the owner (rule 3).
|
|
100
102
|
- **4 — error** → no verdict parsed, or a git/endpoint failure. Read stderr; do NOT treat as clean.
|
|
101
|
-
- **3 —
|
|
103
|
+
- **3 — could not run** → no key (see Prerequisite), the secret filter refused, or every provider
|
|
104
|
+
failed (429, 5xx, timeout, empty reply). Read stderr. A provider failure is not a verdict: re-run later.
|
|
102
105
|
|
|
103
106
|
## Three rules: one attempt, one review
|
|
104
107
|
1. **Think before you send.** Before a task goes to any coder, write its edge cases and check the facts it depends on (one query or one file read).
|
|
105
|
-
2. **Run it before review.** The coder runs the
|
|
108
|
+
2. **Run it before review.** The coder runs only the tests of the files it touched, in the foreground, each command under 10 minutes (split into parts if needed). Name the exact commands in the task. Never start the full suite in the background and never wait on a monitor for it: CI runs the full suite on every PR. Then run the change once on real data.
|
|
106
109
|
3. **Review by tier.** Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <base>...HEAD` (add `--plan <plan> --phase <N>` inside a plan; no `TIER:` line means tier 2).
|
|
107
110
|
Tier 0: gates only. Tier 1-small: your self-check only. Tier 1: one review by another vendor; stop at
|
|
108
111
|
the first CLEAN. Tier 2: two reviewers of two other vendors, in one round. Fix blocking findings only;
|
|
@@ -270,7 +270,7 @@ yourself (relay + Tracker) before stopping — do not hand back "run `/caddis:ha
|
|
|
270
270
|
## Execution protocol (standing rules — this plan is the memory, not anyone's head)
|
|
271
271
|
Three rules: one attempt, one review.
|
|
272
272
|
1. **Think before you send.** Before a task goes to any coder, write its edge cases and check the facts it depends on (one query or one file read).
|
|
273
|
-
2. **Run it before review.** The coder runs the
|
|
273
|
+
2. **Run it before review.** The coder runs only the tests of the files it touched, in the foreground, each command under 10 minutes (split into parts if needed). Name the exact commands in the task. Never start the full suite in the background and never wait on a monitor for it: CI runs the full suite on every PR. Then run the change once on real data.
|
|
274
274
|
3. **Review by tier.** Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <base>...HEAD` (add `--plan <plan> --phase <N>` inside a plan; no `TIER:` line means tier 2).
|
|
275
275
|
Tier 0: gates only. Tier 1-small: your self-check only. Tier 1: one review by another vendor; stop at
|
|
276
276
|
the first CLEAN. Tier 2: two reviewers of two other vendors, in one round. Fix blocking findings only;
|
|
@@ -73,7 +73,10 @@ gh pr diff 55
|
|
|
73
73
|
gh pr checkout 55
|
|
74
74
|
gh pr review 55 --approve --body "LGTM!"
|
|
75
75
|
gh pr review 55 --request-changes --body "Please fix error handling"
|
|
76
|
-
|
|
76
|
+
# merge only on ci-watch RESULT: pass, only its HEAD:, with no default-branch run in progress
|
|
77
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_lanes.py" ci-watch --pr 55
|
|
78
|
+
gh run list --branch main --json status # no in_progress or queued run (main = the default branch)
|
|
79
|
+
gh pr merge 55 --squash --delete-branch --match-head-commit <watched head>
|
|
77
80
|
|
|
78
81
|
# Manage
|
|
79
82
|
gh pr ready 55 # Mark draft as ready
|
|
@@ -170,8 +173,9 @@ gh issue develop 42 --branch fix/issue-42
|
|
|
170
173
|
git add src/auth/login.py tests/test_login.py # named files only, never `git add .`
|
|
171
174
|
git commit -m "fix: resolve login bug" -- src/auth/login.py tests/test_login.py && git push -u origin HEAD
|
|
172
175
|
gh pr create --title "fix: resolve login bug" --body "Closes #42"
|
|
173
|
-
|
|
174
|
-
gh
|
|
176
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_lanes.py" ci-watch --pr <n> # RESULT: pass, HEAD: <watched head>
|
|
177
|
+
gh run list --branch main --json status # wait while a default-branch run is in progress
|
|
178
|
+
gh pr merge <n> --squash --delete-branch --match-head-commit <watched head>
|
|
175
179
|
```
|
|
176
180
|
|
|
177
181
|
### Release Workflow
|
|
@@ -189,8 +193,8 @@ gh release upload v1.3.0 ./dist/*.tar.gz
|
|
|
189
193
|
| Create repo | `gh repo create name --public` |
|
|
190
194
|
| Create issue | `gh issue create --title "..." --labels bug` |
|
|
191
195
|
| Create PR | `gh pr create --title "..." --reviewer user` |
|
|
192
|
-
| Merge PR | `gh pr merge 55 --squash --delete-branch`
|
|
196
|
+
| Merge PR | `gh pr merge 55 --squash --delete-branch --match-head-commit <watched head>`, only after ci-watch `RESULT: pass` |
|
|
193
197
|
| Create release | `gh release create v1.0.0 --generate-notes` |
|
|
194
|
-
| Watch CI | `gh run watch`
|
|
198
|
+
| Watch CI | `caddis_lanes.py ci-watch --pr 55` (fallback: `gh run watch`) |
|
|
195
199
|
| Set secret | `echo "val" \| gh secret set KEY` |
|
|
196
200
|
| API call | `gh api /repos/o/r --jq '.description'` |
|
|
@@ -32,8 +32,8 @@ These override everything below. They exist because branch isolation and the run
|
|
|
32
32
|
depend on them:
|
|
33
33
|
|
|
34
34
|
- **Work ONLY on the current branch.** You are already on the feature branch (the current branch,
|
|
35
|
-
`git branch --show-current`; that read is the only `git branch` form allowed).
|
|
36
|
-
`git checkout`, `git switch`, `git branch <name>`, `git switch -c`, or any command that changes,
|
|
35
|
+
`git branch --show-current`; that read is the only `git branch` form allowed).
|
|
36
|
+
**NEVER** run `git checkout`, `git switch`, `git branch <name>`, `git switch -c`, or any command that changes,
|
|
37
37
|
creates, or leaves the current branch. Read the default branch with
|
|
38
38
|
`git symbolic-ref --short refs/remotes/origin/HEAD`, which prints `origin/<default>`: remove the
|
|
39
39
|
`origin/` prefix before you compare. If that command fails (origin/HEAD is not set), the default
|
|
@@ -57,7 +57,7 @@ depend on them:
|
|
|
57
57
|
|
|
58
58
|
## Three rules: one attempt, one review
|
|
59
59
|
1. **Think before you send.** Before a task goes to any coder, write its edge cases and check the facts it depends on (one query or one file read).
|
|
60
|
-
2. **Run it before review.** The coder runs the
|
|
60
|
+
2. **Run it before review.** The coder runs only the tests of the files it touched, in the foreground, each command under 10 minutes (split into parts if needed). Name the exact commands in the task. Never start the full suite in the background and never wait on a monitor for it: CI runs the full suite on every PR. Then run the change once on real data.
|
|
61
61
|
3. **Review by tier.** Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <base>...HEAD` (add `--plan <plan> --phase <N>` inside a plan; no `TIER:` line means tier 2).
|
|
62
62
|
Tier 0: gates only. Tier 1-small: your self-check only. Tier 1: one review by another vendor; stop at
|
|
63
63
|
the first CLEAN. Tier 2: two reviewers of two other vendors, in one round. Fix blocking findings only;
|
|
@@ -185,12 +185,17 @@ row, visible to any later reader without anyone having to catch it live.
|
|
|
185
185
|
this wording without `--allow-load`. Only the owner gives that flag.
|
|
186
186
|
7b. **Write test economy into every agent brief, not only the lane prompt.** The script already adds it
|
|
187
187
|
to its lane prompts. A brief you write yourself (an Agent-tool subagent, a peer session) needs the same
|
|
188
|
-
five lines: after each step run only the tests for the file or module you changed
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
188
|
+
five lines: after each step run only the tests for the file or module you changed, in the foreground, each
|
|
189
|
+
command under 10 minutes; never start the full suite, and never wait on a monitor for it (CI runs it on every PR);
|
|
190
|
+
run no review loop inside the agent (you review); report progress
|
|
191
|
+
every 20 minutes; never start a second heavy test run while one is still running. **Agents never run
|
|
192
|
+
the full suite.** Measured 2026-10-02 on one shared box: a 2,063-test suite took 2.7 min
|
|
192
193
|
alone and 6.7 min beside a second test-heavy agent, and one agent's brief (baseline, tests after each of 9
|
|
193
194
|
module switches, full gates, in-agent review) cost 30-40 of its 59 minutes.
|
|
195
|
+
On 18-19 Oct 2026 agents started the full suite (about 40 min) in the background and waited through
|
|
196
|
+
monitors with their own timeouts. One missed the finish and sat "Waiting" for over 1 h. Four parallel
|
|
197
|
+
suites also slowed the box. The orchestrator checks a stalled agent by process (pytest alive, CPU moving),
|
|
198
|
+
not by its monitor.
|
|
194
199
|
8. Record these Tracker values:
|
|
195
200
|
- `Model` = the packet's `model`.
|
|
196
201
|
- `Lane` = the lanes tried, joined with ` -> ` and followed by the reason. For example,
|
|
@@ -288,10 +293,12 @@ You: /clear, then paste ↓
|
|
|
288
293
|
**In headless/runner mode, never ask — halt, write the block, and exit.** The block is how a
|
|
289
294
|
non-interactive run tells a human what it needs; asking is still forbidden.
|
|
290
295
|
|
|
291
|
-
**4. Run the tests yourself.** After the last phase you complete, run the
|
|
292
|
-
more
|
|
293
|
-
|
|
294
|
-
suite
|
|
296
|
+
**4. Run the tests yourself.** After the last phase you complete, run the tests of the files you touched
|
|
297
|
+
once more, in the foreground, each command under 10 minutes (split into parts if needed), and record the
|
|
298
|
+
real result. Never start the full suite in the background and never wait on a monitor for it. CI runs the
|
|
299
|
+
full suite on every PR and is the gate before merge. The runner re-runs its own gate independently and
|
|
300
|
+
that decides success — but you run your tests too so your reported `"tests"` value is truthful, not
|
|
301
|
+
assumed. Never report `"passed"` on tests you did not see go green.
|
|
295
302
|
|
|
296
303
|
**4b. If every phase is now done, tidy the plan into `done/` IN THE SAME COMMIT.** Only when the
|
|
297
304
|
whole plan is finished (every `## Tracker` row is `done`, no halt, no blocker) — a mid-plan halt is
|
|
@@ -22,7 +22,7 @@ The exit codes follow `caddis_exit.py`: 0 clean, 1 blocked, 2 advisory, 3 could
|
|
|
22
22
|
|
|
23
23
|
## Three rules: one attempt, one review
|
|
24
24
|
1. **Think before you send.** Before a task goes to any coder, write its edge cases and check the facts it depends on (one query or one file read).
|
|
25
|
-
2. **Run it before review.** The coder runs the
|
|
25
|
+
2. **Run it before review.** The coder runs only the tests of the files it touched, in the foreground, each command under 10 minutes (split into parts if needed). Name the exact commands in the task. Never start the full suite in the background and never wait on a monitor for it: CI runs the full suite on every PR. Then run the change once on real data.
|
|
26
26
|
3. **Review by tier.** Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <base>...HEAD` (add `--plan <plan> --phase <N>` inside a plan; no `TIER:` line means tier 2).
|
|
27
27
|
Tier 0: gates only. Tier 1-small: your self-check only. Tier 1: one review by another vendor; stop at
|
|
28
28
|
the first CLEAN. Tier 2: two reviewers of two other vendors, in one round. Fix blocking findings only;
|
|
@@ -9,7 +9,7 @@ End-to-end delivery of feature-branch work through the reviewed lane in one shot
|
|
|
9
9
|
push safely, create or update the Pull Request, monitor CI checks to green, merge into the default
|
|
10
10
|
branch, validate the deployment, and clean up the feature branch.
|
|
11
11
|
|
|
12
|
-
For a
|
|
12
|
+
For a quick commit and push of a feature branch, use `/ship` (the express lane). It never pushes the default branch.
|
|
13
13
|
To open a PR and stop at green for human review without merging, use `/ship-pr`.
|
|
14
14
|
To merge an already-opened PR, use `/ship-merge`.
|
|
15
15
|
|
|
@@ -29,11 +29,47 @@ can be provided.
|
|
|
29
29
|
Read `AGENTS.md` + the detected workflow file(s) first for the repo's real gate names, default
|
|
30
30
|
branch, and merge conventions — never assume `main`, never assume job names.
|
|
31
31
|
|
|
32
|
+
## Step 0b — Is this checkout safe to move?
|
|
33
|
+
|
|
34
|
+
<!-- checkout-safety: keep byte-identical in pr-merge, ship-pr, ship-merge and cloud-phases; a test pins it -->
|
|
35
|
+
Some steps below move the files of this checkout (`git rebase`, `switch`, `checkout <branch>`, `pull`, `merge`,
|
|
36
|
+
`stash`, `reset --hard`). Before the first of them, run:
|
|
37
|
+
```
|
|
38
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_checkout_guard.py" shared --root .
|
|
39
|
+
```
|
|
40
|
+
It prints `SHARED: yes <reason>` or `SHARED: no` and exits 0. It says yes when the repo's `AGENTS.md` has a line
|
|
41
|
+
`Shared checkout: yes` (a dev service serves from this checkout), or when `git status` lists a change. With no
|
|
42
|
+
`--own-files`, every change counts as another session's. A linked worktree is never shared.
|
|
43
|
+
|
|
44
|
+
- **On `SHARED: no`,** do the steps as written, in this checkout.
|
|
45
|
+
- **On `SHARED: yes`,** never move this checkout. Leave its changes as they are, and report them. Instead:
|
|
46
|
+
- **Rebase:** `git worktree add --detach "$TEMP/<repo>-rebase" <branch>`, then
|
|
47
|
+
`git -C <worktree> rebase origin/<default>` and `git -C <worktree> push --force-with-lease origin HEAD:<branch>`.
|
|
48
|
+
- **Pull a branch to test it:** `git fetch origin`, then
|
|
49
|
+
`git worktree add --detach "$TEMP/<repo>-<branch>" origin/<branch>` (for the default branch,
|
|
50
|
+
`origin/<default>`), and run the gates there. Install dependencies fresh; never link `node_modules` or a venv.
|
|
51
|
+
- **Clean up after a merge:** do not switch or pull. Run `git fetch --prune`, then
|
|
52
|
+
`git fetch origin <default>:<default>`: it fast-forwards the default branch with no checkout. Git refuses when a
|
|
53
|
+
checkout has the default branch out; then leave it and report it. Delete the local feature branch only when no
|
|
54
|
+
checkout has it out.
|
|
55
|
+
- Remove each worktree you made when its step ends: `git worktree remove <worktree>`.
|
|
56
|
+
|
|
57
|
+
`$TEMP` is `%TEMP%` (`$env:TEMP` in PowerShell). The caddis guard checks only the `Shared checkout: yes` line in
|
|
58
|
+
`AGENTS.md`, not a dirty tree: with that line, it asks before a tree move, and denies it in a headless session.
|
|
59
|
+
<!-- /checkout-safety -->
|
|
60
|
+
|
|
32
61
|
## Step 1 — Refuse on the default branch
|
|
33
62
|
|
|
34
|
-
A PR is *branch → default*.
|
|
35
|
-
|
|
36
|
-
|
|
63
|
+
A PR is *branch → default*. Read the default branch as a bare name: `git rev-parse --abbrev-ref
|
|
64
|
+
origin/HEAD` prints `origin/<default>`, so strip the `origin/` prefix before you compare.
|
|
65
|
+
```bash
|
|
66
|
+
d=$(git rev-parse --abbrev-ref origin/HEAD 2>/dev/null) && d=${d#origin/} # prints origin/<default>: strip origin/
|
|
67
|
+
[ -n "$d" ] || d=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name) # origin/HEAD not set
|
|
68
|
+
git branch --show-current # compare with "$d"
|
|
69
|
+
```
|
|
70
|
+
If HEAD **is** the default branch, stop: there is nothing to open a PR from. Offer to move the
|
|
71
|
+
uncommitted work to a feature branch (`git switch -c <branch>`), or run `/ship`, which does that and
|
|
72
|
+
hands back here.
|
|
37
73
|
|
|
38
74
|
## Step 2 — Preflight (local gates mirroring CI)
|
|
39
75
|
|
|
@@ -69,6 +105,8 @@ Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <
|
|
|
69
105
|
git rebase <default-branch>
|
|
70
106
|
git push --force-with-lease origin <branch> # never bare --force
|
|
71
107
|
```
|
|
108
|
+
- In a shared checkout (Step 0b says `SHARED: yes`), never rebase here: rebase in a detached worktree, as
|
|
109
|
+
Step 0b says.
|
|
72
110
|
|
|
73
111
|
## Step 5 — Push + create or update the PR
|
|
74
112
|
|
|
@@ -141,6 +179,8 @@ If the default branch triggers an automated deployment pipeline:
|
|
|
141
179
|
**Only after** the merge is complete and deployment (if any) is validated green:
|
|
142
180
|
- Run `git status --short`. If it shows changes you did not make, do not switch, stash, reset or commit:
|
|
143
181
|
leave them, report them, and stop cleanup here (a shared checkout often holds a peer's edits).
|
|
182
|
+
- In a shared checkout (Step 0b says `SHARED: yes`), skip the switch and the pull below. Clean up as Step 0b
|
|
183
|
+
says: `git fetch --prune`, `git fetch origin <default-branch>:<default-branch>`, then delete the branches.
|
|
144
184
|
- Fetch and prune: `git fetch --prune`.
|
|
145
185
|
- Switch to the default branch: `git switch <default-branch>`.
|
|
146
186
|
- Fast-forward to the merge commit: `git pull --ff-only origin <default-branch>`.
|
|
@@ -34,8 +34,11 @@ gh pr view <n> --repo <owner/repo> --json number,title,author,state,isDraft,merg
|
|
|
34
34
|
- the PR is **merged or closed** — there is nothing to decide;
|
|
35
35
|
- it is a **draft** — say so and ask whether to continue;
|
|
36
36
|
- **the operator is the author.** GitHub does not allow approving your own PR. Say it plainly, and
|
|
37
|
-
say the alternatives: have someone else approve it, or merge with an admin bypass
|
|
38
|
-
|
|
37
|
+
say the alternatives: have someone else approve it, or merge with an admin bypass. An admin
|
|
38
|
+
bypass skips the approval only, never the CI rule: merge only after `caddis_lanes.py ci-watch
|
|
39
|
+
--pr <n>` prints `RESULT: pass`, with no default-branch run in progress (section 4)
|
|
40
|
+
(`gh pr merge <n> --squash --admin --match-head-commit <watched head>`). Do not silently produce a
|
|
41
|
+
review they cannot submit.
|
|
39
42
|
|
|
40
43
|
## 2. Gather what the decision needs
|
|
41
44
|
|
|
@@ -85,12 +88,18 @@ Lead with the verdict. Keep it short enough to read before deciding:
|
|
|
85
88
|
- **CI** — green, red, or still running. Name the failing check.
|
|
86
89
|
- **Merge state** — and what would clear it.
|
|
87
90
|
|
|
88
|
-
Then print the exact commands, and stop:
|
|
91
|
+
Then print the exact commands, and stop. The merge follows the CI rule: wait with ci-watch, and
|
|
92
|
+
merge only on `RESULT: pass`, only the head it watched (`HEAD:`), and never while a CI run on the
|
|
93
|
+
default branch is in progress.
|
|
89
94
|
|
|
90
95
|
```bash
|
|
91
96
|
# approve
|
|
92
97
|
gh pr review <n> --repo <owner/repo> --approve
|
|
93
|
-
|
|
98
|
+
# wait for CI; merge only on RESULT: pass. HEAD: is the watched head
|
|
99
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_lanes.py" ci-watch --pr <n> --repo <owner/repo>
|
|
100
|
+
# no in_progress or queued run may be listed
|
|
101
|
+
gh run list --repo <owner/repo> --branch <default branch> --json status
|
|
102
|
+
gh pr merge <n> --repo <owner/repo> --squash --delete-branch --match-head-commit <watched head>
|
|
94
103
|
|
|
95
104
|
# or ask for changes
|
|
96
105
|
gh pr review <n> --repo <owner/repo> --request-changes --body "..."
|
|
@@ -9,11 +9,12 @@ Ship the current working changes via this repo's actual delivery pipeline. The p
|
|
|
9
9
|
repo, so **detect it first**, then follow the matching lane. Preflight, staging, and commit are
|
|
10
10
|
identical across lanes; only monitoring and validation differ.
|
|
11
11
|
|
|
12
|
-
> **This is the express lane** —
|
|
13
|
-
>
|
|
14
|
-
>
|
|
15
|
-
> PR, monitor CI, stop at green) **→ `/ship-merge`** (merge the green PR behind a
|
|
16
|
-
> validate, clean up).
|
|
12
|
+
> **This is the express lane** — commit, push the current feature branch and watch its CI, with no
|
|
13
|
+
> review pause. **It never pushes to the default branch.** On the default branch (Gitea or GitHub lane)
|
|
14
|
+
> it moves the change to a new branch and hands over to the reviewed lane: **`/caddis:ship-pr`** (open
|
|
15
|
+
> a PR, monitor CI, stop at green) **→ `/caddis:ship-merge`** (merge the green PR behind a
|
|
16
|
+
> deploy-confirm, validate, clean up). Why: a direct push skips the PR, the ci-watch `RESULT: pass` on
|
|
17
|
+
> the watched head and the check that no default-branch run is in progress.
|
|
17
18
|
|
|
18
19
|
Optional message: **$ARGUMENTS** (if empty, derive a conventional commit message from staged changes)
|
|
19
20
|
|
|
@@ -36,6 +37,22 @@ names, branch, and service identifiers — never assume.
|
|
|
36
37
|
- Tests: run only if the user says they're needed or a gate explicitly requires them
|
|
37
38
|
- Fix any failures before proceeding. Do not commit broken code.
|
|
38
39
|
|
|
40
|
+
**1b. BRANCH CHECK** — Read the default branch as a bare name (don't assume `main`) and the current
|
|
41
|
+
branch. `git rev-parse --abbrev-ref origin/HEAD` prints `origin/<default>`, so strip the `origin/`
|
|
42
|
+
prefix before you compare, or the check never matches:
|
|
43
|
+
```bash
|
|
44
|
+
d=$(git rev-parse --abbrev-ref origin/HEAD 2>/dev/null) && d=${d#origin/} # prints origin/<default>: strip origin/
|
|
45
|
+
[ -n "$d" ] || d=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name) # origin/HEAD not set
|
|
46
|
+
git branch --show-current # compare with "$d"
|
|
47
|
+
```
|
|
48
|
+
- **On a non-default branch:** continue at Step 2, then Step 3 pushes that branch.
|
|
49
|
+
- **On the default branch, Gitea or GitHub lane:** do not commit here. Run `git switch -c ship/<slug>`
|
|
50
|
+
(the uncommitted changes go with you) and commit on it (Step 2). Then **STOP: `/ship` ends here.**
|
|
51
|
+
Do not run Step 3 or later. Hand over to `/caddis:ship-pr` → `/caddis:ship-merge`.
|
|
52
|
+
A direct push to the default branch is refused: it skips the PR, the CI pass on the watched head
|
|
53
|
+
and the in-progress check.
|
|
54
|
+
- **Local-only lane:** there is no CI and no PR; commit where you are.
|
|
55
|
+
|
|
39
56
|
**2. STAGE + COMMIT** — Stage only the intended files, by name (never `git add -A`, `git add .`, `git add -u`, a folder, or `git commit -a`):
|
|
40
57
|
```
|
|
41
58
|
git status --short # confirm what's staged
|
|
@@ -55,10 +72,12 @@ Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <
|
|
|
55
72
|
`<base>` is `origin/<default branch>` (on the default branch itself, the commit before this change). Tier 0 or 1-small: no model review. Tier 1: one `/caddis:cross-review`. Tier 2: two reviewers of two other vendors in one round. No `TIER:` line means tier 2.
|
|
56
73
|
<!-- /shared:cross-review-trigger -->
|
|
57
74
|
|
|
58
|
-
**3. PUSH** —
|
|
75
|
+
**3. PUSH** — only when Step 1b found a non-default branch (on the default branch, `/ship` stopped at Step 2):
|
|
59
76
|
```
|
|
60
|
-
git push origin <branch>
|
|
77
|
+
git push -u origin <feature branch>
|
|
61
78
|
```
|
|
79
|
+
Never `git push origin <default branch>`: the change reaches the default branch only through
|
|
80
|
+
`/caddis:ship-pr` → `/caddis:ship-merge`, which merge on ci-watch `RESULT: pass` at the watched head.
|
|
62
81
|
Confirm the push succeeded and the SHA is accepted by the remote. (Local-only lane: skip if there is
|
|
63
82
|
no remote, and note that nothing was pushed.)
|
|
64
83
|
|
|
@@ -28,6 +28,35 @@ Resolve the target PR from `$ARGUMENTS`, else the current branch's open PR. No o
|
|
|
28
28
|
that and point at `/ship-pr`. Read `AGENTS.md` + the workflow file(s) for the repo's real deploy
|
|
29
29
|
job names and default branch — never assume.
|
|
30
30
|
|
|
31
|
+
## Step 0b — Is this checkout safe to move?
|
|
32
|
+
|
|
33
|
+
<!-- checkout-safety: keep byte-identical in pr-merge, ship-pr, ship-merge and cloud-phases; a test pins it -->
|
|
34
|
+
Some steps below move the files of this checkout (`git rebase`, `switch`, `checkout <branch>`, `pull`, `merge`,
|
|
35
|
+
`stash`, `reset --hard`). Before the first of them, run:
|
|
36
|
+
```
|
|
37
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_checkout_guard.py" shared --root .
|
|
38
|
+
```
|
|
39
|
+
It prints `SHARED: yes <reason>` or `SHARED: no` and exits 0. It says yes when the repo's `AGENTS.md` has a line
|
|
40
|
+
`Shared checkout: yes` (a dev service serves from this checkout), or when `git status` lists a change. With no
|
|
41
|
+
`--own-files`, every change counts as another session's. A linked worktree is never shared.
|
|
42
|
+
|
|
43
|
+
- **On `SHARED: no`,** do the steps as written, in this checkout.
|
|
44
|
+
- **On `SHARED: yes`,** never move this checkout. Leave its changes as they are, and report them. Instead:
|
|
45
|
+
- **Rebase:** `git worktree add --detach "$TEMP/<repo>-rebase" <branch>`, then
|
|
46
|
+
`git -C <worktree> rebase origin/<default>` and `git -C <worktree> push --force-with-lease origin HEAD:<branch>`.
|
|
47
|
+
- **Pull a branch to test it:** `git fetch origin`, then
|
|
48
|
+
`git worktree add --detach "$TEMP/<repo>-<branch>" origin/<branch>` (for the default branch,
|
|
49
|
+
`origin/<default>`), and run the gates there. Install dependencies fresh; never link `node_modules` or a venv.
|
|
50
|
+
- **Clean up after a merge:** do not switch or pull. Run `git fetch --prune`, then
|
|
51
|
+
`git fetch origin <default>:<default>`: it fast-forwards the default branch with no checkout. Git refuses when a
|
|
52
|
+
checkout has the default branch out; then leave it and report it. Delete the local feature branch only when no
|
|
53
|
+
checkout has it out.
|
|
54
|
+
- Remove each worktree you made when its step ends: `git worktree remove <worktree>`.
|
|
55
|
+
|
|
56
|
+
`$TEMP` is `%TEMP%` (`$env:TEMP` in PowerShell). The caddis guard checks only the `Shared checkout: yes` line in
|
|
57
|
+
`AGENTS.md`, not a dirty tree: with that line, it asks before a tree move, and denies it in a headless session.
|
|
58
|
+
<!-- /checkout-safety -->
|
|
59
|
+
|
|
31
60
|
## Step 1 — Refuse unless green + mergeable + reviewed
|
|
32
61
|
|
|
33
62
|
All of, per the repo's own rules:
|
|
@@ -102,6 +131,8 @@ attempt a silent re-deploy — and **skip cleanup** (Step 6).
|
|
|
102
131
|
**Only after** Step 5 is green:
|
|
103
132
|
- Run `git status --short`. If it shows changes you did not make, do not switch, stash, reset or commit:
|
|
104
133
|
leave them, report them, and stop cleanup here.
|
|
134
|
+
- In a shared checkout (Step 0b says `SHARED: yes`), do not switch or pull. Clean up as Step 0b says:
|
|
135
|
+
`git fetch --prune`, `git fetch origin <default-branch>:<default-branch>`, then delete the branches.
|
|
105
136
|
- `git fetch --prune`, then switch to the default branch and fast-forward it to the merge commit.
|
|
106
137
|
- Delete the **remote** feature branch; delete the **local** feature branch (for a squash merge, compare
|
|
107
138
|
the branch tree with the merged tree first, not ancestry).
|
|
@@ -10,7 +10,7 @@ after. This command does the mechanics only: push safely, open (or update) the P
|
|
|
10
10
|
and **stop at green** with a mergeability verdict. It **never merges and never deploys** — on these
|
|
11
11
|
repos merge == deploy, so the merge stays a separate, deliberate act: `/ship-merge`.
|
|
12
12
|
|
|
13
|
-
For a
|
|
13
|
+
For a quick commit and push of a feature branch, use `/ship` (the express lane). It never pushes the default branch.
|
|
14
14
|
|
|
15
15
|
Optional argument: **$ARGUMENTS** (PR title override; default = derived from the branch's
|
|
16
16
|
conventional-commit summary).
|
|
@@ -27,11 +27,47 @@ conventional-commit summary).
|
|
|
27
27
|
Read `AGENTS.md` + the detected workflow file(s) first for the repo's real gate names, default
|
|
28
28
|
branch, and merge conventions — never assume `main`, never assume job names.
|
|
29
29
|
|
|
30
|
+
## Step 0b — Is this checkout safe to move?
|
|
31
|
+
|
|
32
|
+
<!-- checkout-safety: keep byte-identical in pr-merge, ship-pr, ship-merge and cloud-phases; a test pins it -->
|
|
33
|
+
Some steps below move the files of this checkout (`git rebase`, `switch`, `checkout <branch>`, `pull`, `merge`,
|
|
34
|
+
`stash`, `reset --hard`). Before the first of them, run:
|
|
35
|
+
```
|
|
36
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_checkout_guard.py" shared --root .
|
|
37
|
+
```
|
|
38
|
+
It prints `SHARED: yes <reason>` or `SHARED: no` and exits 0. It says yes when the repo's `AGENTS.md` has a line
|
|
39
|
+
`Shared checkout: yes` (a dev service serves from this checkout), or when `git status` lists a change. With no
|
|
40
|
+
`--own-files`, every change counts as another session's. A linked worktree is never shared.
|
|
41
|
+
|
|
42
|
+
- **On `SHARED: no`,** do the steps as written, in this checkout.
|
|
43
|
+
- **On `SHARED: yes`,** never move this checkout. Leave its changes as they are, and report them. Instead:
|
|
44
|
+
- **Rebase:** `git worktree add --detach "$TEMP/<repo>-rebase" <branch>`, then
|
|
45
|
+
`git -C <worktree> rebase origin/<default>` and `git -C <worktree> push --force-with-lease origin HEAD:<branch>`.
|
|
46
|
+
- **Pull a branch to test it:** `git fetch origin`, then
|
|
47
|
+
`git worktree add --detach "$TEMP/<repo>-<branch>" origin/<branch>` (for the default branch,
|
|
48
|
+
`origin/<default>`), and run the gates there. Install dependencies fresh; never link `node_modules` or a venv.
|
|
49
|
+
- **Clean up after a merge:** do not switch or pull. Run `git fetch --prune`, then
|
|
50
|
+
`git fetch origin <default>:<default>`: it fast-forwards the default branch with no checkout. Git refuses when a
|
|
51
|
+
checkout has the default branch out; then leave it and report it. Delete the local feature branch only when no
|
|
52
|
+
checkout has it out.
|
|
53
|
+
- Remove each worktree you made when its step ends: `git worktree remove <worktree>`.
|
|
54
|
+
|
|
55
|
+
`$TEMP` is `%TEMP%` (`$env:TEMP` in PowerShell). The caddis guard checks only the `Shared checkout: yes` line in
|
|
56
|
+
`AGENTS.md`, not a dirty tree: with that line, it asks before a tree move, and denies it in a headless session.
|
|
57
|
+
<!-- /checkout-safety -->
|
|
58
|
+
|
|
30
59
|
## Step 1 — Refuse on the default branch
|
|
31
60
|
|
|
32
|
-
A PR is *branch → default*.
|
|
33
|
-
|
|
34
|
-
|
|
61
|
+
A PR is *branch → default*. Read the default branch as a bare name: `git rev-parse --abbrev-ref
|
|
62
|
+
origin/HEAD` prints `origin/<default>`, so strip the `origin/` prefix before you compare.
|
|
63
|
+
```bash
|
|
64
|
+
d=$(git rev-parse --abbrev-ref origin/HEAD 2>/dev/null) && d=${d#origin/} # prints origin/<default>: strip origin/
|
|
65
|
+
[ -n "$d" ] || d=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name) # origin/HEAD not set
|
|
66
|
+
git branch --show-current # compare with "$d"
|
|
67
|
+
```
|
|
68
|
+
If HEAD **is** the default branch, stop: there is nothing to open a PR from. Offer to move the
|
|
69
|
+
uncommitted work to a feature branch (`git switch -c <branch>`), or run `/ship`, which does that and
|
|
70
|
+
hands back here.
|
|
35
71
|
|
|
36
72
|
## Step 2 — Preflight (local gates mirroring CI)
|
|
37
73
|
|
|
@@ -108,6 +144,8 @@ Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <
|
|
|
108
144
|
git rebase <default-branch>
|
|
109
145
|
git push --force-with-lease origin <branch> # never bare --force
|
|
110
146
|
```
|
|
147
|
+
- In a shared checkout (Step 0b says `SHARED: yes`), never rebase here: rebase in a detached worktree, as
|
|
148
|
+
Step 0b says.
|
|
111
149
|
|
|
112
150
|
## Step 5 — Push + create/update the PR
|
|
113
151
|
|