claude-worktree 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c13372671d9041cb88fbe74d783caec8d15cba40c9c0395b6ab64ef6105913c
4
- data.tar.gz: dcf190dcc57792301fdddaf01ac7e880b56a14c97ee67f2095283ddc459b53dd
3
+ metadata.gz: f68f3cf3d0c293ec2a023f465bc7cd2a9dd4115011e93fb027c9ca0a94ced718
4
+ data.tar.gz: ebfaeb8f5ef8a443dc03b5565c682ee11300f2749a7659935ac15cf620bb51ac
5
5
  SHA512:
6
- metadata.gz: c1c74c92f54d58d1799bb99fa42526899dccf851c191d3db5ac193f03b49a93438f80866c28a37cd52243722863445d8a0619f81b834d376df434c3e48b722e2
7
- data.tar.gz: 3c0e53ec321f5dd06aa0d79caec3f2bca13a7647e338f30c354a1a287c2712b4f83ef161f4ce37835b5b3196d547707ee68e7d5cbfeb3da10d35391a97b33036
6
+ metadata.gz: 56b6b1e6f4990a10834095b1ffcea614a999c3463668fb9191ee51ac0f4fd30c9a4790b1c2757c4a84b69eb7e2c714ba424297682c19d5dd04e713dde2b27533
7
+ data.tar.gz: 0fad5b624dbe7ee5084dcd792c01fe6b7a8e1caafe09a1e7e09d88f8997d0b72d27c1ba7bf511e0742b5543b185966e3293fc5cd821f74458ddf98a063dd171a
data/README.md CHANGED
@@ -69,6 +69,14 @@ npm ci
69
69
  echo "Ready to rock!"
70
70
  ```
71
71
 
72
+ ### Base Branch
73
+
74
+ By default, new worktrees branch off of `HEAD`. To always branch from a specific starting point (e.g., `main`), set the `CWT_START_POINT` environment variable:
75
+
76
+ ```bash
77
+ export CWT_START_POINT=main
78
+ ```
79
+
72
80
  ## 🎮 Usage
73
81
 
74
82
  Run `cwt` in the root of any Git repository.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Claude
4
4
  module Worktree
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
@@ -80,7 +80,7 @@ module Cwt
80
80
  end
81
81
 
82
82
  worktrees.find do |wt|
83
- wt.name == name_or_path || wt.path == normalized_path
83
+ wt.name == name_or_path || wt.branch == name_or_path || wt.path == normalized_path
84
84
  end
85
85
  end
86
86
 
@@ -89,16 +89,21 @@ module Cwt
89
89
  def create_worktree(name)
90
90
  require_relative 'worktree'
91
91
 
92
- # Sanitize name
93
- safe_name = name.strip.gsub(/[^a-zA-Z0-9_\-]/, '_')
92
+ # Sanitize name (allow / for branch name hierarchy)
93
+ safe_name = name.strip
94
+ .gsub(%r{[^a-zA-Z0-9_\-/]}, '_')
95
+ .gsub(%r{/+}, '/')
96
+ .gsub(%r{^/|/$}, '')
94
97
  path = File.join(worktrees_dir, safe_name)
95
98
  absolute_path = File.join(@root, WORKTREE_DIR, safe_name)
96
99
 
97
- # Ensure .worktrees exists
98
- FileUtils.mkdir_p(worktrees_dir)
100
+ # Ensure parent directories exist (e.g. .worktrees/feat/ for feat/my-feature)
101
+ FileUtils.mkdir_p(File.dirname(path))
99
102
 
100
103
  # Create worktree with new branch
101
104
  cmd = ["git", "-C", @root, "worktree", "add", "-b", safe_name, path]
105
+ base_branch = ENV["CWT_START_POINT"]
106
+ cmd << base_branch if base_branch && !base_branch.strip.empty?
102
107
  _stdout, stderr, status = Open3.capture3(*cmd)
103
108
 
104
109
  unless status.success?
data/lib/cwt/view.rb CHANGED
@@ -40,7 +40,7 @@ module Cwt
40
40
  )
41
41
 
42
42
  draw_header(tui, frame, header_area)
43
- draw_list(model, tui, frame, list_area)
43
+ draw_table(model, tui, frame, list_area)
44
44
  draw_footer(model, tui, frame, footer_area)
45
45
 
46
46
  return unless model.mode == :creating
@@ -72,23 +72,32 @@ module Cwt
72
72
  frame.render_widget(title, area)
73
73
  end
74
74
 
75
- def self.draw_list(model, tui, frame, area)
76
- items = model.visible_worktrees.map do |wt|
77
- # Status Icons
75
+ def self.draw_table(model, tui, frame, area)
76
+ rows = model.visible_worktrees.map do |wt|
78
77
  status_icon = wt.dirty ? '●' : ' '
79
78
  status_style = wt.dirty ? tui.style(**THEME[:dirty]) : tui.style(**THEME[:clean])
80
79
 
81
- time = wt.last_commit || ''
82
-
83
- # Consistent Column Widths
84
- tui.text_line(spans: [
85
- tui.text_span(content: " #{status_icon} ", style: status_style),
86
- tui.text_span(content: wt.name.ljust(25), style: tui.style(modifiers: [:bold])),
87
- tui.text_span(content: (wt.branch || 'HEAD').ljust(25), style: tui.style(**THEME[:dim])),
88
- tui.text_span(content: time.rjust(15), style: tui.style(**THEME[:accent]))
80
+ tui.row(cells: [
81
+ tui.table_cell(content: " #{status_icon} ", style: status_style),
82
+ tui.table_cell(
83
+ content: tui.text_span(content: wt.name, style: tui.style(modifiers: [:bold]))
84
+ ),
85
+ tui.table_cell(
86
+ content: tui.text_span(content: wt.branch || 'HEAD', style: tui.style(**THEME[:dim]))
87
+ ),
88
+ tui.table_cell(
89
+ content: tui.text_span(content: (wt.last_commit || ''), style: tui.style(**THEME[:accent]))
90
+ )
89
91
  ])
90
92
  end
91
93
 
94
+ widths = [
95
+ tui.constraint_length(3),
96
+ tui.constraint_fill(1),
97
+ tui.constraint_fill(1),
98
+ tui.constraint_length(15)
99
+ ]
100
+
92
101
  # Dynamic Title based on context
93
102
  title_content = if model.mode == :filtering
94
103
  tui.text_line(spans: [
@@ -102,10 +111,11 @@ module Cwt
102
111
  tui.text_line(spans: [tui.text_span(content: ' SESSIONS ', style: tui.style(**THEME[:dim]))])
103
112
  end
104
113
 
105
- list = tui.list(
106
- items: items,
107
- selected_index: model.selection_index,
108
- highlight_style: tui.style(**THEME[:selection]),
114
+ table = tui.table(
115
+ rows: rows,
116
+ widths: widths,
117
+ selected_row: model.selection_index,
118
+ row_highlight_style: tui.style(**THEME[:selection]),
109
119
  highlight_symbol: '▎',
110
120
  block: tui.block(
111
121
  titles: [{ content: title_content }],
@@ -114,7 +124,7 @@ module Cwt
114
124
  )
115
125
  )
116
126
 
117
- frame.render_widget(list, area)
127
+ frame.render_widget(table, area)
118
128
  end
119
129
 
120
130
  def self.draw_footer(model, tui, frame, area)
data/lib/cwt/worktree.rb CHANGED
@@ -21,7 +21,8 @@ module Cwt
21
21
  end
22
22
 
23
23
  def name
24
- File.basename(@path)
24
+ resolve = ->(p) { File.realpath(p) rescue File.expand_path(p) }
25
+ resolve.call(@path).delete_prefix("#{resolve.call(@repository.worktrees_dir)}/")
25
26
  end
26
27
 
27
28
  def exists?
@@ -94,7 +95,10 @@ module Cwt
94
95
  end
95
96
  end
96
97
 
97
- # Step 3: Delete Branch
98
+ # Step 3: Clean up empty parent directories under .worktrees/
99
+ cleanup_empty_parents
100
+
101
+ # Step 4: Delete Branch
98
102
  delete_branch(force: force)
99
103
  end
100
104
 
@@ -173,10 +177,20 @@ module Cwt
173
177
  end
174
178
  end
175
179
 
180
+ def cleanup_empty_parents
181
+ worktrees_dir = @repository.worktrees_dir
182
+ dir = File.dirname(@path)
183
+ while dir != worktrees_dir && dir.start_with?(worktrees_dir)
184
+ break unless Dir.exist?(dir) && (Dir.entries(dir) - %w[. ..]).empty?
185
+ Dir.rmdir(dir)
186
+ dir = File.dirname(dir)
187
+ end
188
+ end
189
+
176
190
  def delete_branch(force: false)
177
191
  branch_flag = force ? "-D" : "-d"
178
192
  _stdout, stderr, status = Open3.capture3(
179
- "git", "-C", @repository.root, "branch", branch_flag, name
193
+ "git", "-C", @repository.root, "branch", branch_flag, @branch
180
194
  )
181
195
 
182
196
  if status.success?
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: claude-worktree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Garcia
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-02-23 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: ratatui_ruby
@@ -54,6 +55,7 @@ metadata:
54
55
  homepage_uri: https://github.com/bucket-robotics/claude-worktree
55
56
  source_code_uri: https://github.com/bucket-robotics/claude-worktree
56
57
  changelog_uri: https://github.com/bucket-robotics/claude-worktree/blob/main/CHANGELOG.md
58
+ post_install_message:
57
59
  rdoc_options: []
58
60
  require_paths:
59
61
  - lib
@@ -68,7 +70,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
70
  - !ruby/object:Gem::Version
69
71
  version: '0'
70
72
  requirements: []
71
- rubygems_version: 3.6.9
73
+ rubygems_version: 3.5.22
74
+ signing_key:
72
75
  specification_version: 4
73
76
  summary: A TUI tool to manage Git Worktrees for AI coding agents.
74
77
  test_files: []