carson 3.13.0 → 3.13.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d653b3c6ec67aa729186db46215c6e51c85a42ac82ca782f5004f9d84e32a31
4
- data.tar.gz: 5caa70de1a5c9538c3ef3027ba0862445c9ff2d985ec6f4659231bb40d8e5cb7
3
+ metadata.gz: d49ac2582d874ea7b4a25a9d71401fd8424b33ef8740ef8c9d1588d81616b00a
4
+ data.tar.gz: 37d5ba4ebe4c7455eb1751a55cff6724f073bcce37463080fa3324db86c42fac
5
5
  SHA512:
6
- metadata.gz: 91bd6ee521d91f31c3593558e1b544fcba99eefd1d084fb8c618fad428c470d308ed774e7655b31be9d0fc35969bd9d5354832d5002042396e3d48b8ffde77b2
7
- data.tar.gz: 10758df9aeb5d246211592671eb19c59156cbd9fd7cb5d6e31e32186ee36d1caef8fe3dc7c785bdbfbac4e1339ee8d56bf445556a6722395f8eb42a2bfdabe12
6
+ metadata.gz: 33498b92e55ab4caab2ddb9935ca1ce2b1965e61f03898849720cedbd24e878d981662fa1acad7312addb08d7bb90e83ab72e2f55658087f2af2c3f3d9c37f2c
7
+ data.tar.gz: 01ee3460c17e00db79f9216592bda4171cc135ceb90ff88d3c83fa8925653f50ad1b3b8ea98e1f6ef37bce1a4f0f2e868d06968d7788e466f54d7d21e99b842b
data/MANUAL.md CHANGED
@@ -108,6 +108,40 @@ Carson discovers files in this directory and syncs them to governed repos alongs
108
108
 
109
109
  **Why this design.** Lint, CI, and tooling config are personal decisions — not governance decisions. Carson's job is to deliver your canonical files reliably, not to decide what they should contain.
110
110
 
111
+ ## Agent Worktree Workflow
112
+
113
+ The core workflow for coding agents using Carson. One command per step, full lifecycle.
114
+
115
+ **1. Create a worktree** — Carson auto-syncs main before branching (3.13.0+), so the worktree always starts from the latest code:
116
+
117
+ ```bash
118
+ carson worktree create my-feature
119
+ cd /path/to/.claude/worktrees/my-feature
120
+ ```
121
+
122
+ **2. Work** — make changes, commit, iterate.
123
+
124
+ **3. Deliver and merge** — push, create PR, merge when CI passes. After merge, Carson prints the exact next command (3.13.0+):
125
+
126
+ ```bash
127
+ carson deliver --merge
128
+ # Output: Merged PR #N via squash.
129
+ # Next: cd /path/to/repo && carson worktree remove my-feature
130
+ ```
131
+
132
+ **4. Clean up** — follow the printed next step. After squash merge, Carson detects the content is on main and allows removal without `--force` (3.13.1+):
133
+
134
+ ```bash
135
+ cd /path/to/repo && carson worktree remove my-feature
136
+ carson prune
137
+ ```
138
+
139
+ **Safety guards** — `worktree remove` blocks when:
140
+ - Shell CWD is inside the worktree (prevents session crash).
141
+ - Branch has unpushed commits with content that differs from main (prevents data loss).
142
+
143
+ After squash or rebase merge, the content matches main — removal proceeds without `--force`.
144
+
111
145
  ## Daily Operations
112
146
 
113
147
  **Start of work:**
data/RELEASE.md CHANGED
@@ -5,6 +5,23 @@ Release-note scope rule:
5
5
  - `RELEASE.md` records only version deltas, breaking changes, and migration actions.
6
6
  - Operational usage guides live in `MANUAL.md` and `API.md`.
7
7
 
8
+ ## 3.13.2
9
+
10
+ ### What changed
11
+
12
+ - **Fix CI detection in `deliver --merge`** — `check_pr_ci` queried `gh pr checks --json name,state,conclusion` but `conclusion` is not a valid field in current `gh` CLI versions. Every `deliver --merge` silently fell back to "CI: none" and skipped the merge step. Now uses `--json name,bucket` which returns `pass`/`fail`/`pending` directly.
13
+ - **Document agent worktree workflow** — added "Agent Worktree Workflow" section to MANUAL.md covering the full create → work → deliver → clean up lifecycle with 3.13.x improvements.
14
+
15
+ ### UX improvement
16
+
17
+ - `deliver --merge` now actually detects CI status and merges when green. Previously it always said "CI: none" due to the broken field query.
18
+
19
+ ## 3.13.1
20
+
21
+ ### What changed
22
+
23
+ - **Content-aware unpushed-commits guard** — `carson worktree remove` no longer falsely blocks after squash or rebase merges. Previously it compared commit SHAs, which differ after squash merge even though the content is on main. Now it compares tree content via `git diff --quiet`: if the branch's content matches main, the work is already merged and removal proceeds without `--force`.
24
+
8
25
  ## 3.13.0
9
26
 
10
27
  ### What changed
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.13.0
1
+ 3.13.2
@@ -214,25 +214,23 @@ module Carson
214
214
  end
215
215
 
216
216
  # Checks CI status on a PR. Returns :pass, :fail, :pending, or :none.
217
- def check_pr_ci( number: )
218
- stdout, _, success, = gh_run(
219
- "pr", "checks", number.to_s,
220
- "--json", "name,state,conclusion"
221
- )
222
- return :none unless success
223
-
224
- checks = JSON.parse( stdout ) rescue []
225
- return :none if checks.empty?
226
-
227
- conclusions = checks.map { |c| c[ "conclusion" ].to_s.upcase }
228
- states = checks.map { |c| c[ "state" ].to_s.upcase }
229
-
230
- return :fail if conclusions.any? { |c| c == "FAILURE" || c == "CANCELLED" || c == "TIMED_OUT" }
231
- return :pending if states.any? { |s| s == "PENDING" || s == "QUEUED" || s == "IN_PROGRESS" } ||
232
- conclusions.any? { |c| c == "" || c == "PENDING" }
233
-
234
- :pass
235
- end
217
+ # Uses the `bucket` field (pass/fail/pending) from `gh pr checks --json`.
218
+ def check_pr_ci( number: )
219
+ stdout, _, success, = gh_run(
220
+ "pr", "checks", number.to_s,
221
+ "--json", "name,bucket"
222
+ )
223
+ return :none unless success
224
+
225
+ checks = JSON.parse( stdout ) rescue []
226
+ return :none if checks.empty?
227
+
228
+ buckets = checks.map { |c| c[ "bucket" ].to_s.downcase }
229
+ return :fail if buckets.include?( "fail" )
230
+ return :pending if buckets.include?( "pending" )
231
+
232
+ :pass
233
+ end
236
234
 
237
235
  # Checks review decision on a PR. Returns :approved, :changes_requested, :review_required, or :none.
238
236
  def check_pr_review( number: )
@@ -220,6 +220,7 @@ module Carson
220
220
  end
221
221
 
222
222
  # Checks whether a branch has unpushed commits that would be lost on removal.
223
+ # Content-aware: after squash/rebase merge, SHAs differ but tree content may match main. Compares content, not SHAs.
223
224
  # Returns nil if safe, or { error:, recovery: } hash if unpushed work exists.
224
225
  def check_unpushed_commits( branch:, worktree_path: )
225
226
  return nil unless branch
@@ -231,8 +232,16 @@ module Carson
231
232
  # Remote ref does not exist. Only block if the branch has unique commits vs main.
232
233
  unique, _, unique_status, = Open3.capture3( "git", "rev-list", "--count", "#{config.main_branch}..#{branch}", chdir: worktree_path )
233
234
  if unique_status.success? && unique.strip.to_i > 0
234
- return { error: "branch has not been pushed to #{remote}",
235
- recovery: "git -C #{worktree_path} push -u #{remote} #{branch}, or use --force to override" }
235
+ # Content-aware check: after squash/rebase merge, commit SHAs differ
236
+ # but the tree content may be identical to main. Compare content,
237
+ # not SHAs — if the diff is empty, the work is already on main.
238
+ diff_out, _, diff_ok, = Open3.capture3( "git", "diff", "--quiet", config.main_branch, branch, chdir: worktree_path )
239
+ unless diff_ok.success?
240
+ return { error: "branch has not been pushed to #{remote}",
241
+ recovery: "git -C #{worktree_path} push -u #{remote} #{branch}, or use --force to override" }
242
+ end
243
+ # Diff is empty — content is on main (squash/rebase merged). Safe.
244
+ puts_verbose "branch #{branch} content matches main — squash/rebase merged, safe to remove"
236
245
  end
237
246
  elsif ahead.strip.to_i > 0
238
247
  return { error: "worktree has unpushed commits",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carson
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.13.0
4
+ version: 3.13.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hailei Wang