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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/bin/cc +143 -9
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bb7625607c8b67ff39212aed3d7b9bcb8a9cf5fcbae0751a554b1a09427baea1
|
|
4
|
+
data.tar.gz: a40ac44c23feca33a5b91eeefb4d7665a0b74a4d7e3fe54f544cb2a1dc01e5e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
102
|
-
|
|
146
|
+
items = bookmarks.map do |path, tags|
|
|
147
|
+
{ path: path, tags: tags, exists: Dir.exist?(path) }
|
|
148
|
+
end
|
|
103
149
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
|
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
|
|
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-
|
|
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
|