carson 4.4.0 → 4.5.0
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/MANUAL.md +2 -0
- data/README.md +4 -0
- data/RELEASE.md +15 -0
- data/VERSION +1 -1
- data/lib/carson/runtime/local/worktree.rb +2 -1
- data/lib/carson/warehouse/workbench.rb +46 -22
- data/lib/carson/worktree.rb +3 -1
- 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: a8eb2ac9b4d1ac6375fc581b2be86768ad5f441685b36dca3358e31aa43715b8
|
|
4
|
+
data.tar.gz: e2c7e9e3b3a4b35e26c8fbb7d59c46c10db8cf67b01000b0893d528a84055ce1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58f5388783aa5efbd5a74393c75b6552278bab58d06bc00bcea1a4467353aac70b7aa54685517d02062d61d0befa16898867f82b5ca9c7fc2a0908baa441cf94
|
|
7
|
+
data.tar.gz: d8e760dba0ca676a9a5c6e88d729102fa86f8c9ea205507fbe46821280c42593352bc985d486d6c82b377311cb5564820f06d7d15ddb63e15ee17ebab750780e
|
data/MANUAL.md
CHANGED
|
@@ -153,6 +153,8 @@ carson worktree create my-feature
|
|
|
153
153
|
cd /path/to/.claude/worktrees/my-feature
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
+
The worktree lives under the calling harness's agent directory — `.claude/worktrees/` from Claude Code, `.pi/worktrees/` from Pi (detected via `PI_CODING_AGENT`). Set `CARSON_AGENT_DIR` to override. Commands that take a worktree name resolve it across all agent directories, so worktrees created by another harness remain reachable.
|
|
157
|
+
|
|
156
158
|
On the governed main working tree, Carson blocks raw `git add` / `git commit` and blocks raw `git worktree add/remove`, raw `git pull --rebase`, and raw `gh pr create/merge`. Use `carson worktree create`, `carson sync`, and `carson deliver` instead.
|
|
157
159
|
|
|
158
160
|
**2. Work** — make changes, test them, and either commit normally or let Carson create the delivery commit.
|
data/README.md
CHANGED
|
@@ -51,6 +51,10 @@ carson onboard your/repo/path
|
|
|
51
51
|
carson worktree create your-worktree
|
|
52
52
|
cd your/repo/path/.claude/worktrees/your-worktree
|
|
53
53
|
|
|
54
|
+
# Carson places the worktree under the calling harness's agent directory:
|
|
55
|
+
# .claude/worktrees/ from Claude Code, .pi/worktrees/ from Pi
|
|
56
|
+
# (detected via PI_CODING_AGENT). Set CARSON_AGENT_DIR to override.
|
|
57
|
+
|
|
54
58
|
# work and test, then commit and hand the branch to Carson
|
|
55
59
|
git add -A
|
|
56
60
|
git commit -m "fix: describe this delivery"
|
data/RELEASE.md
CHANGED
|
@@ -7,6 +7,21 @@ Release-note scope rule:
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 4.5.0
|
|
11
|
+
|
|
12
|
+
### New
|
|
13
|
+
|
|
14
|
+
- **Harness-aware worktree directories.** `carson checkin` / `carson worktree create` place the worktree under the calling harness's agent directory — `.pi/worktrees/` from a Pi session (detected via `PI_CODING_AGENT`), `.claude/worktrees/` otherwise, exactly as before. Set `CARSON_AGENT_DIR` to override. Bare-name resolution, `.git/info/exclude` bookkeeping, and diagnostics follow the chosen directory, and commands that take a worktree name resolve across all agent directories, so worktrees created by another harness remain reachable.
|
|
15
|
+
- **Sweep and reap cover `.pi/worktrees/`.** Both agent-directory lists gained `.pi`.
|
|
16
|
+
|
|
17
|
+
### Why
|
|
18
|
+
|
|
19
|
+
The worktree directory was hardcoded to `.claude/worktrees/`, so Pi sessions produced Claude-flavoured paths. Each harness's worktrees now live under their own directory.
|
|
20
|
+
|
|
21
|
+
### Migration
|
|
22
|
+
|
|
23
|
+
None. Existing `.claude/worktrees/` worktrees resolve by name as before.
|
|
24
|
+
|
|
10
25
|
## 4.4.0
|
|
11
26
|
|
|
12
27
|
### New
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.
|
|
1
|
+
4.5.0
|
|
@@ -8,7 +8,8 @@ module Carson
|
|
|
8
8
|
|
|
9
9
|
# --- Delegates to Warehouse::Workbench ---
|
|
10
10
|
|
|
11
|
-
# Creates a new
|
|
11
|
+
# Creates a new workbench under the calling harness's agent
|
|
12
|
+
# directory (<agent_dir>/worktrees/<name>, e.g. .pi from a Pi session).
|
|
12
13
|
def worktree_create!( name:, json_output: false )
|
|
13
14
|
result = worktree_warehouse.build_workbench!( name: name )
|
|
14
15
|
finish_worktree( result: result, json_output: json_output )
|
|
@@ -10,7 +10,9 @@ module Carson
|
|
|
10
10
|
module Workbench
|
|
11
11
|
|
|
12
12
|
# Agent directory names whose workbenches the warehouse may sweep.
|
|
13
|
-
AGENT_DIRS
|
|
13
|
+
# Carson::Worktree::AGENT_DIRS (legacy) carries the same list — keep
|
|
14
|
+
# both in lockstep until reap moves here.
|
|
15
|
+
AGENT_DIRS = %w[ .claude .codex .pi ].freeze
|
|
14
16
|
|
|
15
17
|
# --- Inventory ---
|
|
16
18
|
|
|
@@ -64,8 +66,9 @@ module Carson
|
|
|
64
66
|
end
|
|
65
67
|
|
|
66
68
|
# Resolve a bare name and find the workbench.
|
|
67
|
-
# Tries
|
|
68
|
-
#
|
|
69
|
+
# Tries the calling harness's agent directory first (scoped, then
|
|
70
|
+
# flat), then the other agent directories, then searches all
|
|
71
|
+
# registered workbenches by directory name.
|
|
69
72
|
def workbench_named( name )
|
|
70
73
|
if Pathname.new( name ).absolute?
|
|
71
74
|
return workbench_at( path: name )
|
|
@@ -76,18 +79,20 @@ module Carson
|
|
|
76
79
|
found = workbench_at( path: relative_candidate )
|
|
77
80
|
return found if found
|
|
78
81
|
|
|
79
|
-
# Try scoped path (e.g. "claude/foo" → .claude/worktrees/claude/foo)
|
|
82
|
+
# Try scoped path (e.g. "claude/foo" → .claude/worktrees/claude/foo),
|
|
83
|
+
# the calling harness's directory first.
|
|
80
84
|
if name.include?( "/" )
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
ordered_agent_dirs.each do |dir|
|
|
86
|
+
found = workbench_at( path: realpath_safe( File.join( main_worktree_root, dir, "worktrees", name ) ) )
|
|
87
|
+
return found if found
|
|
88
|
+
end
|
|
84
89
|
end
|
|
85
90
|
|
|
86
|
-
# Try flat layout:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
# Try flat layout: <agent_dir>/worktrees/<name>, calling harness first.
|
|
92
|
+
ordered_agent_dirs.each do |dir|
|
|
93
|
+
found = workbench_at( path: realpath_safe( File.join( main_worktree_root, dir, "worktrees", name ) ) )
|
|
94
|
+
return found if found
|
|
95
|
+
end
|
|
91
96
|
|
|
92
97
|
# Search all registered workbenches by dirname.
|
|
93
98
|
matches = workbenches.select { |wb| File.basename( wb.path ) == name }
|
|
@@ -105,11 +110,12 @@ module Carson
|
|
|
105
110
|
# --- Lifecycle ---
|
|
106
111
|
|
|
107
112
|
# Build a new workbench from local main.
|
|
108
|
-
# Creates the directory
|
|
109
|
-
#
|
|
113
|
+
# Creates the directory under the calling harness's agent directory,
|
|
114
|
+
# branches from the local standard, and excludes the agent directory
|
|
115
|
+
# from git status.
|
|
110
116
|
def build_workbench!( name: )
|
|
111
117
|
root = main_worktree_root
|
|
112
|
-
worktrees_dir = File.join( root,
|
|
118
|
+
worktrees_dir = File.join( root, agent_dir, "worktrees" )
|
|
113
119
|
workbench_path = File.join( worktrees_dir, name )
|
|
114
120
|
|
|
115
121
|
if Dir.exist?( workbench_path )
|
|
@@ -119,8 +125,8 @@ module Carson
|
|
|
119
125
|
recovery: "carson worktree remove #{name}, then retry" }
|
|
120
126
|
end
|
|
121
127
|
|
|
122
|
-
# Ensure
|
|
123
|
-
|
|
128
|
+
# Ensure the agent directory is excluded from git status.
|
|
129
|
+
ensure_agent_dir_excluded!
|
|
124
130
|
|
|
125
131
|
# Create the worktree with a new branch.
|
|
126
132
|
FileUtils.mkdir_p( File.dirname( workbench_path ) )
|
|
@@ -380,7 +386,7 @@ module Carson
|
|
|
380
386
|
wt_list, = git( "worktree", "list", "--porcelain" )
|
|
381
387
|
branch_list, = git( "branch", "--list", name )
|
|
382
388
|
git_version, = Open3.capture3( "git", "--version" )
|
|
383
|
-
workbench_path = File.join( root,
|
|
389
|
+
workbench_path = File.join( root, agent_dir, "worktrees", name )
|
|
384
390
|
entry = workbench_at( path: workbench_path )
|
|
385
391
|
{
|
|
386
392
|
git_stdout: git_stdout.to_s.strip,
|
|
@@ -395,8 +401,25 @@ module Carson
|
|
|
395
401
|
}
|
|
396
402
|
end
|
|
397
403
|
|
|
398
|
-
#
|
|
399
|
-
|
|
404
|
+
# The calling harness's workbench directory name.
|
|
405
|
+
# CARSON_AGENT_DIR wins over detection; absent detection, .claude is the
|
|
406
|
+
# historical default so Claude Code and Codex sessions behave as before.
|
|
407
|
+
# Pi sessions export PI_CODING_AGENT.
|
|
408
|
+
def agent_dir
|
|
409
|
+
override = ENV.fetch( "CARSON_AGENT_DIR", "" ).to_s.strip
|
|
410
|
+
return override unless override.empty?
|
|
411
|
+
return ".pi" if ENV.key?( "PI_CODING_AGENT" )
|
|
412
|
+
|
|
413
|
+
".claude"
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
# Agent directories in resolution order: the calling harness's first.
|
|
417
|
+
def ordered_agent_dirs
|
|
418
|
+
( [ agent_dir ] + AGENT_DIRS ).uniq
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# Ensure the calling harness's agent directory is in .git/info/exclude.
|
|
422
|
+
def ensure_agent_dir_excluded!
|
|
400
423
|
git_dir = File.join( main_worktree_root, ".git" )
|
|
401
424
|
return unless File.directory?( git_dir )
|
|
402
425
|
|
|
@@ -405,9 +428,10 @@ module Carson
|
|
|
405
428
|
|
|
406
429
|
FileUtils.mkdir_p( info_dir )
|
|
407
430
|
existing = File.exist?( exclude_path ) ? File.read( exclude_path ) : ""
|
|
408
|
-
|
|
431
|
+
entry = "#{agent_dir}/"
|
|
432
|
+
return if existing.lines.any? { |line| line.strip == entry }
|
|
409
433
|
|
|
410
|
-
File.open( exclude_path, "a" ) { |file| file.puts
|
|
434
|
+
File.open( exclude_path, "a" ) { |file| file.puts entry }
|
|
411
435
|
rescue StandardError
|
|
412
436
|
# Best-effort — do not block workbench creation.
|
|
413
437
|
end
|
data/lib/carson/worktree.rb
CHANGED
|
@@ -12,7 +12,9 @@ require "pathname"
|
|
|
12
12
|
module Carson
|
|
13
13
|
class Worktree
|
|
14
14
|
# Agent directory names whose worktrees Carson may sweep.
|
|
15
|
-
AGENT_DIRS
|
|
15
|
+
# Warehouse::Workbench::AGENT_DIRS carries the same list — keep both in
|
|
16
|
+
# lockstep until reap/sweep move to the warehouse.
|
|
17
|
+
AGENT_DIRS = %w[ .claude .codex .pi ].freeze
|
|
16
18
|
|
|
17
19
|
attr_reader :path, :branch, :prunable_reason
|
|
18
20
|
|