cc-sessions 1.0.2 → 1.1.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/bin/cc +143 -9
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 76dc4063f182c1d78b8eead156b8e57ffe2728198e72ae30efbcd3234a7fc2a6
4
- data.tar.gz: 4f739bbcde871c0db6b0473480ab2063d7777ea1ab73f5051fa7c6c6dc104b5d
3
+ metadata.gz: bb7625607c8b67ff39212aed3d7b9bcb8a9cf5fcbae0751a554b1a09427baea1
4
+ data.tar.gz: a40ac44c23feca33a5b91eeefb4d7665a0b74a4d7e3fe54f544cb2a1dc01e5e2
5
5
  SHA512:
6
- metadata.gz: 6998837a2bde9b9ce143d47f85d39e5cf1d12ac010849c8971ad1470b7e31d67a712668530a4fa960300e61140fa54e677ade91151bed102805ca4cf8e95cc1c
7
- data.tar.gz: 2990b688c7cef2a6c87559aa5ed8d6ecd933a4741f84c4af8d965024297a11bc9ef52c7948a81d82da5bd2f8eabeb3e77481cfe594a8fecdfd8423f11722e12d
6
+ metadata.gz: 8516229845736a7311f5d597c3218d6bff92533835b8a0b0f16851e05c503a62c98bbd2c388ee69ab42622961c57ca82efa539539b536f91cccb9d109a14133f
7
+ data.tar.gz: aa67d7f92b1d3882b10696f2b3fb4638ce902849d46c8069ce538f49d74aa9ff71ebc632c3e4864efcdd767c8c764c5a92e73b6659b39b7c1b02315118d6eb6b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.1.0] - 2025-01-23
4
+
5
+ ### Added
6
+ - Interactive session picker with `cc -l` (no external dependencies)
7
+ - Delete bookmarks with `d` key in list (with confirmation)
8
+ - Delete bookmarks from CLI with `cc -d <tag>`
9
+ - Vim-style navigation (j/k) in addition to arrow keys
10
+
11
+ ### Changed
12
+ - `cc -l` now shows interactive list with hidden cursor
13
+ - Zero external dependencies (removed tty-prompt)
14
+
3
15
  ## [1.0.2] - 2025-01-23
4
16
 
5
17
  ### Added
data/bin/cc CHANGED
@@ -15,6 +15,14 @@
15
15
 
16
16
  require 'json'
17
17
  require 'fileutils'
18
+ require 'io/console'
19
+
20
+ # Simple ANSI helpers
21
+ def cyan(s) = "\e[36m#{s}\e[0m"
22
+ def dim(s) = "\e[2m#{s}\e[0m"
23
+ def red(s) = "\e[31m#{s}\e[0m"
24
+ def rev(s) = "\e[7m#{s}\e[0m"
25
+ def clear_line = "\e[2K\r"
18
26
 
19
27
  CONFIG_DIR = File.expand_path('~/.cc-sessions')
20
28
  BOOKMARKS_FILE = File.join(CONFIG_DIR, 'bookmarks.json')
@@ -88,6 +96,43 @@ def session_exists_in_dir?(dir)
88
96
  Dir.glob(File.join(claude_dir, '**/*')).any? { |f| File.file?(f) }
89
97
  end
90
98
 
99
+ def read_key
100
+ input = $stdin.getch
101
+ if input == "\e"
102
+ begin
103
+ input << $stdin.read_nonblock(3)
104
+ rescue IO::WaitReadable
105
+ end
106
+ end
107
+ case input
108
+ when "\e[A", "k" then :up
109
+ when "\e[B", "j" then :down
110
+ when "\r", "\n" then :enter
111
+ when "q", "\e" then :quit
112
+ when "d" then :delete
113
+ else nil
114
+ end
115
+ end
116
+
117
+ def save_bookmarks(bookmarks)
118
+ File.write(BOOKMARKS_FILE, JSON.pretty_generate(bookmarks))
119
+ end
120
+
121
+ def delete_bookmark_by_tag(tag)
122
+ bookmarks = load_bookmarks
123
+ path = find_session_by_tag(tag)
124
+
125
+ if path
126
+ bookmarks.delete(path)
127
+ save_bookmarks(bookmarks)
128
+ puts "Deleted bookmark: #{path}"
129
+ puts " (was tagged: #{tag})"
130
+ else
131
+ puts "No session found with tag '#{tag}'"
132
+ exit 1
133
+ end
134
+ end
135
+
91
136
  def list_bookmarks
92
137
  bookmarks = load_bookmarks
93
138
 
@@ -98,14 +143,93 @@ def list_bookmarks
98
143
  return
99
144
  end
100
145
 
101
- puts "Bookmarked Claude Code sessions:"
102
- puts
146
+ items = bookmarks.map do |path, tags|
147
+ { path: path, tags: tags, exists: Dir.exist?(path) }
148
+ end
103
149
 
104
- bookmarks.each do |path, tags|
105
- exists = Dir.exist?(path) ? '' : ' [NOT FOUND]'
106
- puts "#{path}#{exists}"
107
- puts " Tags: #{tags.join(', ')}"
108
- puts
150
+ index = 0
151
+ puts "Select session (↑/↓/j/k move, Enter select, d delete, q quit):\n\n"
152
+
153
+ # Hide cursor
154
+ print "\e[?25l"
155
+
156
+ begin
157
+ loop do
158
+ # Render list
159
+ items.each_with_index do |item, i|
160
+ print clear_line
161
+ tag_str = cyan(item[:tags].join(', '))
162
+ path_str = dim(item[:path])
163
+ missing = item[:exists] ? '' : red(' [NOT FOUND]')
164
+ line = "#{tag_str} → #{path_str}#{missing}"
165
+
166
+ if i == index
167
+ puts "▸ #{line}"
168
+ else
169
+ puts " #{line}"
170
+ end
171
+ end
172
+
173
+ # Move cursor back to start
174
+ print "\e[#{items.size}A"
175
+
176
+ key = read_key
177
+ case key
178
+ when :up
179
+ index = (index - 1) % items.size
180
+ when :down
181
+ index = (index + 1) % items.size
182
+ when :delete
183
+ # Show confirmation
184
+ old_size = items.size
185
+ print "\e[#{old_size}B" # Move below list
186
+ print clear_line
187
+ print "Delete '#{items[index][:tags].join(', ')}'? (y/n) "
188
+ confirm = $stdin.getch
189
+ if confirm.downcase == 'y'
190
+ bookmarks.delete(items[index][:path])
191
+ save_bookmarks(bookmarks)
192
+ items.delete_at(index)
193
+ index = [index, items.size - 1].min
194
+ if items.empty?
195
+ # Clear list and confirmation line
196
+ print "\e[#{old_size}A"
197
+ (old_size + 1).times { print clear_line; puts }
198
+ print "\e[#{old_size + 1}A"
199
+ puts "All bookmarks deleted."
200
+ return
201
+ end
202
+ # Clear old list (one more line than new size)
203
+ print clear_line
204
+ print "\e[#{old_size}A"
205
+ (old_size).times { print clear_line; puts }
206
+ print "\e[#{old_size}A"
207
+ else
208
+ print clear_line
209
+ print "\e[#{old_size}A"
210
+ end
211
+ when :enter
212
+ # Clear the menu
213
+ (items.size).times { print clear_line; puts }
214
+ print "\e[#{items.size}A"
215
+
216
+ if items[index][:exists]
217
+ print "\e[?25h" # Show cursor before exec
218
+ resume_session(items[index][:path])
219
+ else
220
+ puts red("Directory not found: #{items[index][:path]}")
221
+ end
222
+ return
223
+ when :quit
224
+ # Clear the menu
225
+ (items.size).times { print clear_line; puts }
226
+ print "\e[#{items.size}A"
227
+ return
228
+ end
229
+ end
230
+ ensure
231
+ # Always show cursor
232
+ print "\e[?25h"
109
233
  end
110
234
  end
111
235
 
@@ -118,7 +242,8 @@ def show_help
118
242
  USAGE:
119
243
  cc Continue session in current directory, or start new
120
244
  cc <tag> Resume session bookmarked with <tag>
121
- cc -l, --list List all bookmarked sessions
245
+ cc -l, --list List all bookmarked sessions (interactive)
246
+ cc -d, --delete <tag> Delete bookmark matching <tag>
122
247
  cc -h, --help Show this help
123
248
 
124
249
  BOOKMARKING (inside Claude Code):
@@ -127,7 +252,8 @@ def show_help
127
252
  EXAMPLES:
128
253
  cc rtfm Resume session tagged 'rtfm'
129
254
  cc Continue in current dir or start fresh
130
- cc -l Show all bookmarked sessions
255
+ cc -l Show interactive list (d to delete, Enter to select)
256
+ cc -d rtfm Delete bookmark tagged 'rtfm'
131
257
 
132
258
  FILES:
133
259
  ~/.cc-sessions/bookmarks.json Bookmark storage
@@ -168,6 +294,14 @@ when '-h', '--help'
168
294
  show_help
169
295
  when '-l', '--list'
170
296
  list_bookmarks
297
+ when '-d', '--delete'
298
+ if ARGV[1]
299
+ delete_bookmark_by_tag(ARGV[1])
300
+ else
301
+ puts "Usage: cc -d <tag>"
302
+ puts "Delete bookmark matching the given tag."
303
+ exit 1
304
+ end
171
305
  when nil
172
306
  continue_or_start
173
307
  else
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cc-sessions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-01-23 00:00:00.000000000 Z
11
+ date: 2026-01-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A simple tool for bookmarking and resuming Claude Code sessions. Tag
14
14
  sessions with meaningful names using /bm inside Claude Code, then quickly resume