carson 3.12.0 → 3.13.1
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 +4 -4
- data/RELEASE.md +18 -0
- data/VERSION +1 -1
- data/lib/carson/runtime/deliver.rb +22 -0
- data/lib/carson/runtime/local/worktree.rb +18 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bb773d053eb0271bf5b1997349eaf9afa972ad5ba8612a3930764e2ace68592d
|
|
4
|
+
data.tar.gz: 957745cc1c1f0ee91e2a58062e6730b4ff09f3c78e7c7178f7d7d602ac74b858
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f547c3aa8645e9da8877c24e645dad85896cd3640890f9da2c6d35cd5557fe0fcd784e3dd75a74910d677544be2294aace0720bd6267e56f1fb7e99c3abe094b
|
|
7
|
+
data.tar.gz: 01a7ec9498cae31c12e1f68a3498381ad8f7bb5a229de5b2e833c410b06cca4759abd426583b39c766b931d1e829c3fae1cb9272d12b60ea52e59328296bb287
|
data/RELEASE.md
CHANGED
|
@@ -5,6 +5,24 @@ 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.1
|
|
9
|
+
|
|
10
|
+
### What changed
|
|
11
|
+
|
|
12
|
+
- **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`.
|
|
13
|
+
|
|
14
|
+
## 3.13.0
|
|
15
|
+
|
|
16
|
+
### What changed
|
|
17
|
+
|
|
18
|
+
- **Worktree create auto-syncs main** — `carson worktree create` now pulls the main branch from remote (`--ff-only`) before branching. Prevents stale-base merge conflicts that waste agent context resolving later. Best-effort: if pull fails (offline, non-fast-forward), creation continues from the local main.
|
|
19
|
+
- **Deliver prints next steps after merge** — `carson deliver --merge` now tells the agent exactly what to do after a successful merge. If running inside a worktree, prints `cd <main_root> && carson worktree remove <name>`. If not, suggests `carson prune`. Available in both human and JSON output (`next_step` field).
|
|
20
|
+
|
|
21
|
+
### UX improvement
|
|
22
|
+
|
|
23
|
+
- Agents no longer need to remember post-merge cleanup steps — Carson tells them.
|
|
24
|
+
- Agents no longer hit merge conflicts from stale main — Carson syncs before branching.
|
|
25
|
+
|
|
8
26
|
## 3.12.0
|
|
9
27
|
|
|
10
28
|
### What changed
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.13.1
|
|
@@ -77,6 +77,9 @@ module Carson
|
|
|
77
77
|
# Step 6: sync main in the main worktree.
|
|
78
78
|
sync_after_merge!( remote: remote, main: main, result: result )
|
|
79
79
|
|
|
80
|
+
# Step 7: compute next-step guidance for the agent.
|
|
81
|
+
compute_post_merge_next_step!( result: result )
|
|
82
|
+
|
|
80
83
|
deliver_finish( result: result, exit_code: EXIT_OK, json_output: json_output )
|
|
81
84
|
end
|
|
82
85
|
|
|
@@ -128,6 +131,7 @@ module Carson
|
|
|
128
131
|
|
|
129
132
|
if result[ :merged ]
|
|
130
133
|
puts_line "Merged PR ##{result[ :pr_number ]} via #{result[ :merge_method ]}."
|
|
134
|
+
puts_line " Next: #{result[ :next_step ]}" if result[ :next_step ]
|
|
131
135
|
end
|
|
132
136
|
end
|
|
133
137
|
|
|
@@ -290,6 +294,24 @@ module Carson
|
|
|
290
294
|
puts_verbose "sync failed: #{pull_stderr.to_s.strip}"
|
|
291
295
|
end
|
|
292
296
|
end
|
|
297
|
+
|
|
298
|
+
# Builds next-step guidance after a successful merge.
|
|
299
|
+
# Detects whether the agent is inside a worktree and suggests cleanup.
|
|
300
|
+
def compute_post_merge_next_step!( result: )
|
|
301
|
+
main_root = main_worktree_root
|
|
302
|
+
cwd = realpath_safe( Dir.pwd )
|
|
303
|
+
current_wt = worktree_list.select { |wt| wt.fetch( :path ) != realpath_safe( main_root ) }
|
|
304
|
+
.find { |wt| cwd == wt.fetch( :path ) || cwd.start_with?( File.join( wt.fetch( :path ), "" ) ) }
|
|
305
|
+
|
|
306
|
+
if current_wt
|
|
307
|
+
wt_name = File.basename( current_wt.fetch( :path ) )
|
|
308
|
+
result[ :next_step ] = "cd #{main_root} && carson worktree remove #{wt_name}"
|
|
309
|
+
else
|
|
310
|
+
result[ :next_step ] = "carson prune"
|
|
311
|
+
end
|
|
312
|
+
rescue StandardError
|
|
313
|
+
# Best-effort — do not fail deliver because of next-step detection.
|
|
314
|
+
end
|
|
293
315
|
end
|
|
294
316
|
|
|
295
317
|
include Deliver
|
|
@@ -24,6 +24,13 @@ module Carson
|
|
|
24
24
|
# Determine the base branch (main branch from config).
|
|
25
25
|
base = config.main_branch
|
|
26
26
|
|
|
27
|
+
# Sync main from remote before branching so the worktree starts
|
|
28
|
+
# from the latest code. Prevents stale-base merge conflicts later.
|
|
29
|
+
# Best-effort — if pull fails (non-ff, offline), continue anyway.
|
|
30
|
+
main_root = main_worktree_root
|
|
31
|
+
_, _, pull_ok, = Open3.capture3( "git", "-C", main_root, "pull", "--ff-only", config.git_remote, base )
|
|
32
|
+
puts_verbose pull_ok.success? ? "synced #{base} before branching" : "sync skipped — continuing from local #{base}"
|
|
33
|
+
|
|
27
34
|
# Ensure .claude/ is excluded from git status in the host repository.
|
|
28
35
|
# Uses .git/info/exclude (local-only, never committed) to respect the outsider boundary.
|
|
29
36
|
ensure_claude_dir_excluded!
|
|
@@ -213,6 +220,7 @@ module Carson
|
|
|
213
220
|
end
|
|
214
221
|
|
|
215
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.
|
|
216
224
|
# Returns nil if safe, or { error:, recovery: } hash if unpushed work exists.
|
|
217
225
|
def check_unpushed_commits( branch:, worktree_path: )
|
|
218
226
|
return nil unless branch
|
|
@@ -224,8 +232,16 @@ module Carson
|
|
|
224
232
|
# Remote ref does not exist. Only block if the branch has unique commits vs main.
|
|
225
233
|
unique, _, unique_status, = Open3.capture3( "git", "rev-list", "--count", "#{config.main_branch}..#{branch}", chdir: worktree_path )
|
|
226
234
|
if unique_status.success? && unique.strip.to_i > 0
|
|
227
|
-
|
|
228
|
-
|
|
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"
|
|
229
245
|
end
|
|
230
246
|
elsif ahead.strip.to_i > 0
|
|
231
247
|
return { error: "worktree has unpushed commits",
|