cc-sessions 1.4.2 → 1.5.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/CHANGELOG.md +23 -0
- data/bin/cc +15 -12
- data/bin/cc-bookmark +35 -41
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 17f3d3abaf69a414fca43e117ab74e8c8ee7ae7160916eeac37f500ede7ba67f
|
|
4
|
+
data.tar.gz: 9090fe2bb7999335aef10e4d9058c741353e2066408f4db764429339e2ace16f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b245ba85c136be80547fcedc840f2e9a90dda0230c0da14f90221cef2471555e42d38b7783b9c872dd60579add274c8cfafe950c6d5de9ee2b3cf06b07b17e6d
|
|
7
|
+
data.tar.gz: 04717d6bde89c7419ceb3176c5998ab30b2a3efedba977cfc1834c15cf7c510e1f5c22d25e4ade820d6920d2089f84dc7c5f065995b82105d848563f3360a249
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.5.1] - 2026-03-04
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Multiple sessions sharing a project dir no longer steal each other's bookmarks
|
|
7
|
+
- `detect_session_id` (newest `.jsonl`) no longer overrides `CC_SESSION_ID` when the original session file exists
|
|
8
|
+
- Query mode migration only triggers on true context continuation (original `.jsonl` gone), not when another session is simply newer
|
|
9
|
+
- Reserved words ("query", "?", "status", "show") now trigger query mode instead of being saved as tag names
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `session_file_exists?` helper to distinguish "context continuation" from "another active session"
|
|
13
|
+
|
|
14
|
+
## [1.5.0] - 2026-03-03
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Sessions no longer inherit bookmarks from unrelated sessions in the same directory
|
|
18
|
+
- Removed path-based sibling matching in `find_resume_breadcrumb` — now only matches exact session IDs
|
|
19
|
+
- Removed `find_tags_for_path` from `cc` — running session tags now resolved by session ID, not directory path
|
|
20
|
+
- Running indicator (green dot) in `cc -l` now matches by session ID instead of path
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- `find_resume_breadcrumb` takes a session ID only, not a directory — eliminates cross-contamination
|
|
24
|
+
- `cc -C` uses session-ID-based tag lookup instead of path matching
|
|
25
|
+
|
|
3
26
|
## [1.4.2] - 2026-03-03
|
|
4
27
|
|
|
5
28
|
### Fixed
|
data/bin/cc
CHANGED
|
@@ -139,11 +139,12 @@ def find_session_by_tag(tag)
|
|
|
139
139
|
nil
|
|
140
140
|
end
|
|
141
141
|
|
|
142
|
-
def
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
[]
|
|
142
|
+
def find_tags_for_session_dir(session_dir, bookmarks)
|
|
143
|
+
session_id = detect_session_id(session_dir)
|
|
144
|
+
return [] unless session_id
|
|
145
|
+
|
|
146
|
+
entry = bookmarks['sessions'][session_id]
|
|
147
|
+
entry ? entry['tags'] : []
|
|
147
148
|
end
|
|
148
149
|
|
|
149
150
|
def session_exists_in_dir?(dir)
|
|
@@ -187,18 +188,20 @@ def delete_bookmark_by_tag(tag)
|
|
|
187
188
|
end
|
|
188
189
|
end
|
|
189
190
|
|
|
190
|
-
def
|
|
191
|
+
def running_session_ids
|
|
191
192
|
pids = `pgrep -x claude 2>/dev/null`.split.map(&:to_i)
|
|
192
|
-
|
|
193
|
+
ids = Set.new
|
|
193
194
|
pids.each do |pid|
|
|
194
195
|
cwd_link = "/proc/#{pid}/cwd"
|
|
195
196
|
next unless File.exist?(cwd_link)
|
|
196
197
|
begin
|
|
197
|
-
|
|
198
|
+
session_dir = resolve_session_dir(File.readlink(cwd_link))
|
|
199
|
+
sid = detect_session_id(session_dir)
|
|
200
|
+
ids << sid if sid
|
|
198
201
|
rescue Errno::EACCES
|
|
199
202
|
end
|
|
200
203
|
end
|
|
201
|
-
|
|
204
|
+
ids
|
|
202
205
|
end
|
|
203
206
|
|
|
204
207
|
def list_bookmarks
|
|
@@ -211,11 +214,11 @@ def list_bookmarks
|
|
|
211
214
|
return
|
|
212
215
|
end
|
|
213
216
|
|
|
214
|
-
running =
|
|
217
|
+
running = running_session_ids
|
|
215
218
|
|
|
216
219
|
items = bookmarks['sessions'].map do |id, entry|
|
|
217
220
|
{ id: id, path: entry['path'], tags: entry['tags'], exists: Dir.exist?(entry['path']),
|
|
218
|
-
running: running.include?(
|
|
221
|
+
running: running.include?(id) }
|
|
219
222
|
end
|
|
220
223
|
|
|
221
224
|
index = 0
|
|
@@ -337,7 +340,7 @@ def show_current_sessions
|
|
|
337
340
|
begin
|
|
338
341
|
cwd = File.readlink(cwd_link)
|
|
339
342
|
session_dir = resolve_session_dir(cwd)
|
|
340
|
-
tags =
|
|
343
|
+
tags = find_tags_for_session_dir(session_dir, bookmarks)
|
|
341
344
|
tag_str = tags.empty? ? dim('(no tags)') : green(tags.join(', '))
|
|
342
345
|
|
|
343
346
|
puts " PID #{cyan(pid.to_s)}: #{session_dir}"
|
data/bin/cc-bookmark
CHANGED
|
@@ -39,33 +39,23 @@ def detect_session_id(session_dir, exclude_id: nil)
|
|
|
39
39
|
File.basename(newest, '.jsonl')
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
#
|
|
43
|
-
def
|
|
42
|
+
# Check if a session's .jsonl file still exists in the project dir
|
|
43
|
+
def session_file_exists?(session_id, session_dir)
|
|
44
|
+
return false unless session_id
|
|
44
45
|
encoded = session_dir.gsub('/', '-')
|
|
45
|
-
|
|
46
|
-
return [] unless Dir.exist?(project_dir)
|
|
47
|
-
|
|
48
|
-
Dir.glob(File.join(project_dir, '*.jsonl'))
|
|
49
|
-
.select { |f| File.file?(f) }
|
|
50
|
-
.map { |f| File.basename(f, '.jsonl') }
|
|
46
|
+
File.exist?(File.join(CLAUDE_PROJECTS, encoded, "#{session_id}.jsonl"))
|
|
51
47
|
end
|
|
52
48
|
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return nil unless Dir.exist?(RESUME_DIR)
|
|
49
|
+
# Find resume breadcrumb for a specific session ID only.
|
|
50
|
+
# Only matches exact session IDs — never scans siblings by path.
|
|
51
|
+
def find_resume_breadcrumb(session_id)
|
|
52
|
+
return nil unless session_id && Dir.exist?(RESUME_DIR)
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
next if sid == current_id
|
|
62
|
-
breadcrumb = File.join(RESUME_DIR, "#{sid}.json")
|
|
63
|
-
next unless File.exist?(breadcrumb)
|
|
54
|
+
breadcrumb = File.join(RESUME_DIR, "#{session_id}.json")
|
|
55
|
+
return nil unless File.exist?(breadcrumb)
|
|
64
56
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
end
|
|
68
|
-
nil
|
|
57
|
+
tags = JSON.parse(File.read(breadcrumb))
|
|
58
|
+
tags.is_a?(Array) ? tags : nil
|
|
69
59
|
rescue
|
|
70
60
|
nil
|
|
71
61
|
end
|
|
@@ -116,15 +106,23 @@ cwd ||= resolve_session_dir(Dir.pwd)
|
|
|
116
106
|
session_id = detect_session_id(cwd) # Fallback — picks newest .jsonl
|
|
117
107
|
tags = ARGV
|
|
118
108
|
|
|
109
|
+
# Treat reserved words as query mode, not tag names
|
|
110
|
+
QUERY_WORDS = %w[? query status show].freeze
|
|
111
|
+
if tags.length == 1 && QUERY_WORDS.include?(tags.first.downcase)
|
|
112
|
+
tags = [] # Convert to query mode
|
|
113
|
+
end
|
|
114
|
+
|
|
119
115
|
if tags.empty?
|
|
120
116
|
# Query mode: show tags for current session
|
|
121
117
|
# Priority: check the known original session ID first (from env var)
|
|
122
118
|
if original_id
|
|
123
119
|
entry = bookmarks['sessions'][original_id]
|
|
124
120
|
if entry
|
|
125
|
-
# Check if session was continued
|
|
126
|
-
|
|
127
|
-
|
|
121
|
+
# Check if session was continued: original .jsonl is GONE and a newer one exists.
|
|
122
|
+
# If original .jsonl still exists, another session is just more recent — NOT a continuation.
|
|
123
|
+
original_gone = !session_file_exists?(original_id, cwd)
|
|
124
|
+
if original_gone && session_id && session_id != original_id
|
|
125
|
+
# True context continuation — migrate bookmark to the new session ID
|
|
128
126
|
bookmarks['sessions'].delete(original_id)
|
|
129
127
|
bookmarks['sessions'][session_id] = entry
|
|
130
128
|
save_bookmarks(bookmarks)
|
|
@@ -169,29 +167,25 @@ if tags.empty?
|
|
|
169
167
|
if entry
|
|
170
168
|
puts "Current bookmark: #{entry['tags'].join(', ')}"
|
|
171
169
|
else
|
|
172
|
-
|
|
173
|
-
match = find_resume_breadcrumb(cwd, session_id, bookmarks)
|
|
174
|
-
if match
|
|
175
|
-
old_id, old_tags = match
|
|
176
|
-
bookmarks['sessions'].delete(old_id)
|
|
177
|
-
bookmarks['sessions'][session_id] = { 'path' => cwd, 'tags' => old_tags }
|
|
178
|
-
save_bookmarks(bookmarks)
|
|
179
|
-
FileUtils.rm_f(File.join(RESUME_DIR, "#{old_id}.json"))
|
|
180
|
-
puts "Current bookmark: #{old_tags.join(', ')}"
|
|
181
|
-
else
|
|
182
|
-
puts "No bookmark for this session. Usage: /bm tag1 tag2 ..."
|
|
183
|
-
end
|
|
170
|
+
puts "No bookmark for this session. Usage: /bm tag1 tag2 ..."
|
|
184
171
|
end
|
|
185
172
|
else
|
|
186
173
|
puts "Could not detect session ID. Usage: /bm tag1 tag2 ..."
|
|
187
174
|
end
|
|
188
175
|
else
|
|
189
176
|
# Bookmark mode: set tags for current session
|
|
190
|
-
#
|
|
191
|
-
#
|
|
192
|
-
|
|
177
|
+
# Use CC_SESSION_ID when its .jsonl still exists (it's the real session).
|
|
178
|
+
# Only fall back to detect_session_id when the original is gone (context continuation).
|
|
179
|
+
if original_id && session_file_exists?(original_id, cwd)
|
|
180
|
+
key = original_id
|
|
181
|
+
elsif original_id && session_id && session_id != original_id
|
|
182
|
+
# Context continuation — original .jsonl gone, use the new one
|
|
183
|
+
key = session_id
|
|
184
|
+
else
|
|
185
|
+
key = session_id || original_id || "path:#{cwd}"
|
|
186
|
+
end
|
|
193
187
|
|
|
194
|
-
# Clean up old bookmark if session ID changed (migration)
|
|
188
|
+
# Clean up old bookmark if session ID changed (true migration)
|
|
195
189
|
if original_id && original_id != key && bookmarks['sessions'][original_id]
|
|
196
190
|
bookmarks['sessions'].delete(original_id)
|
|
197
191
|
FileUtils.rm_f(File.join(RESUME_DIR, "#{original_id}.json"))
|
metadata
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cc-sessions
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.5.1
|
|
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-03-
|
|
11
|
+
date: 2026-03-04 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
|
|
15
|
-
them with ''cc <tag>'' from anywhere. v1.
|
|
16
|
-
|
|
15
|
+
them with ''cc <tag>'' from anywhere. v1.5.1: Fix multi-session bookmark isolation
|
|
16
|
+
— sessions sharing a project dir no longer steal each other''s bookmarks.'
|
|
17
17
|
email:
|
|
18
18
|
- g@isene.com
|
|
19
19
|
executables:
|