claude-code-tools 0.1.13__tar.gz → 0.1.14__tar.gz

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.

Potentially problematic release.


This version of claude-code-tools might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-code-tools
3
- Version: 0.1.13
3
+ Version: 0.1.14
4
4
  Summary: Collection of tools for working with Claude Code
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: click>=8.0.0
@@ -1,3 +1,3 @@
1
1
  """Claude Code Tools - Collection of utilities for Claude Code."""
2
2
 
3
- __version__ = "0.1.13"
3
+ __version__ = "0.1.14"
@@ -121,39 +121,51 @@ def extract_project_name(original_path: str) -> str:
121
121
  return parts[-1] if parts else "unknown"
122
122
 
123
123
 
124
- def search_keywords_in_file(filepath: Path, keywords: List[str]) -> tuple[bool, int]:
124
+ def search_keywords_in_file(filepath: Path, keywords: List[str]) -> tuple[bool, int, Optional[str]]:
125
125
  """
126
- Check if all keywords are present in the JSONL file and count lines.
126
+ Check if all keywords are present in the JSONL file, count lines, and extract git branch.
127
127
 
128
128
  Args:
129
129
  filepath: Path to the JSONL file
130
130
  keywords: List of keywords to search for (case-insensitive)
131
131
 
132
132
  Returns:
133
- Tuple of (matches: bool, line_count: int)
133
+ Tuple of (matches: bool, line_count: int, git_branch: Optional[str])
134
134
  - matches: True if ALL keywords are found in the file
135
135
  - line_count: Total number of lines in the file
136
+ - git_branch: Git branch name from the first message that has it, or None
136
137
  """
137
138
  # Convert keywords to lowercase for case-insensitive search
138
139
  keywords_lower = [k.lower() for k in keywords]
139
140
  found_keywords = set()
140
141
  line_count = 0
142
+ git_branch = None
141
143
 
142
144
  try:
143
145
  with open(filepath, 'r', encoding='utf-8') as f:
144
146
  for line in f:
145
147
  line_count += 1
146
148
  line_lower = line.lower()
149
+
150
+ # Extract git branch from JSON if not already found
151
+ if git_branch is None:
152
+ try:
153
+ data = json.loads(line.strip())
154
+ if 'gitBranch' in data and data['gitBranch']:
155
+ git_branch = data['gitBranch']
156
+ except (json.JSONDecodeError, KeyError):
157
+ pass
158
+
147
159
  # Check which keywords are in this line
148
160
  for keyword in keywords_lower:
149
161
  if keyword in line_lower:
150
162
  found_keywords.add(keyword)
151
163
  except Exception:
152
164
  # Skip files that can't be read
153
- return False, 0
165
+ return False, 0, None
154
166
 
155
167
  matches = len(found_keywords) == len(keywords_lower)
156
- return matches, line_count
168
+ return matches, line_count, git_branch
157
169
 
158
170
 
159
171
  def get_session_preview(filepath: Path) -> str:
@@ -187,7 +199,7 @@ def get_session_preview(filepath: Path) -> str:
187
199
  return "No preview available"
188
200
 
189
201
 
190
- def find_sessions(keywords: List[str], global_search: bool = False, claude_home: Optional[str] = None) -> List[Tuple[str, float, int, str, str, str]]:
202
+ def find_sessions(keywords: List[str], global_search: bool = False, claude_home: Optional[str] = None) -> List[Tuple[str, float, int, str, str, str, Optional[str]]]:
191
203
  """
192
204
  Find all Claude Code sessions containing the specified keywords.
193
205
 
@@ -197,7 +209,7 @@ def find_sessions(keywords: List[str], global_search: bool = False, claude_home:
197
209
  claude_home: Optional custom Claude home directory (defaults to ~/.claude)
198
210
 
199
211
  Returns:
200
- List of tuples (session_id, modification_time, line_count, project_name, preview, project_path) sorted by modification time
212
+ List of tuples (session_id, modification_time, line_count, project_name, preview, project_path, git_branch) sorted by modification time
201
213
  """
202
214
  matching_sessions = []
203
215
 
@@ -220,12 +232,12 @@ def find_sessions(keywords: List[str], global_search: bool = False, claude_home:
220
232
 
221
233
  # Search all JSONL files in this project directory
222
234
  for jsonl_file in project_dir.glob("*.jsonl"):
223
- matches, line_count = search_keywords_in_file(jsonl_file, keywords)
235
+ matches, line_count, git_branch = search_keywords_in_file(jsonl_file, keywords)
224
236
  if matches:
225
237
  session_id = jsonl_file.stem
226
238
  mod_time = jsonl_file.stat().st_mtime
227
239
  preview = get_session_preview(jsonl_file)
228
- matching_sessions.append((session_id, mod_time, line_count, project_name, preview, original_path))
240
+ matching_sessions.append((session_id, mod_time, line_count, project_name, preview, original_path, git_branch))
229
241
 
230
242
  progress.advance(task)
231
243
  else:
@@ -234,12 +246,12 @@ def find_sessions(keywords: List[str], global_search: bool = False, claude_home:
234
246
  project_name = extract_project_name(original_path)
235
247
 
236
248
  for jsonl_file in project_dir.glob("*.jsonl"):
237
- matches, line_count = search_keywords_in_file(jsonl_file, keywords)
249
+ matches, line_count, git_branch = search_keywords_in_file(jsonl_file, keywords)
238
250
  if matches:
239
251
  session_id = jsonl_file.stem
240
252
  mod_time = jsonl_file.stat().st_mtime
241
253
  preview = get_session_preview(jsonl_file)
242
- matching_sessions.append((session_id, mod_time, line_count, project_name, preview, original_path))
254
+ matching_sessions.append((session_id, mod_time, line_count, project_name, preview, original_path, git_branch))
243
255
  else:
244
256
  # Search current project only
245
257
  claude_dir = get_claude_project_dir(claude_home)
@@ -251,12 +263,12 @@ def find_sessions(keywords: List[str], global_search: bool = False, claude_home:
251
263
 
252
264
  # Search all JSONL files in the directory
253
265
  for jsonl_file in claude_dir.glob("*.jsonl"):
254
- matches, line_count = search_keywords_in_file(jsonl_file, keywords)
266
+ matches, line_count, git_branch = search_keywords_in_file(jsonl_file, keywords)
255
267
  if matches:
256
268
  session_id = jsonl_file.stem
257
269
  mod_time = jsonl_file.stat().st_mtime
258
270
  preview = get_session_preview(jsonl_file)
259
- matching_sessions.append((session_id, mod_time, line_count, project_name, preview, os.getcwd()))
271
+ matching_sessions.append((session_id, mod_time, line_count, project_name, preview, os.getcwd(), git_branch))
260
272
 
261
273
  # Sort by modification time (newest first)
262
274
  matching_sessions.sort(key=lambda x: x[1], reverse=True)
@@ -264,7 +276,7 @@ def find_sessions(keywords: List[str], global_search: bool = False, claude_home:
264
276
  return matching_sessions
265
277
 
266
278
 
267
- def display_interactive_ui(sessions: List[Tuple[str, float, int, str, str, str]], keywords: List[str], stderr_mode: bool = False, num_matches: int = 10) -> Optional[Tuple[str, str]]:
279
+ def display_interactive_ui(sessions: List[Tuple[str, float, int, str, str, str, Optional[str]]], keywords: List[str], stderr_mode: bool = False, num_matches: int = 10) -> Optional[Tuple[str, str]]:
268
280
  """Display interactive UI for session selection."""
269
281
  if not RICH_AVAILABLE:
270
282
  return None
@@ -292,16 +304,19 @@ def display_interactive_ui(sessions: List[Tuple[str, float, int, str, str, str]]
292
304
  table.add_column("#", style="bold yellow", width=3)
293
305
  table.add_column("Session ID", style="dim")
294
306
  table.add_column("Project", style="green")
307
+ table.add_column("Branch", style="magenta")
295
308
  table.add_column("Date", style="blue")
296
309
  table.add_column("Lines", style="cyan", justify="right")
297
310
  table.add_column("Preview", style="white", overflow="fold")
298
311
 
299
- for idx, (session_id, mod_time, line_count, project_name, preview, _) in enumerate(display_sessions, 1):
312
+ for idx, (session_id, mod_time, line_count, project_name, preview, _, git_branch) in enumerate(display_sessions, 1):
300
313
  mod_date = datetime.fromtimestamp(mod_time).strftime('%Y-%m-%d %H:%M')
314
+ branch_display = git_branch if git_branch else "N/A"
301
315
  table.add_row(
302
316
  str(idx),
303
317
  session_id[:8] + "...",
304
318
  project_name,
319
+ branch_display,
305
320
  mod_date,
306
321
  str(line_count),
307
322
  preview
@@ -327,6 +342,11 @@ def display_interactive_ui(sessions: List[Tuple[str, float, int, str, str, str]]
327
342
  console=ui_console
328
343
  )
329
344
 
345
+ # Handle empty input
346
+ if not choice or not choice.strip():
347
+ ui_console.print("[red]Invalid choice. Please try again.[/red]")
348
+ continue
349
+
330
350
  # Restore stdout
331
351
  if stderr_mode:
332
352
  sys.stdout.close()
@@ -340,7 +360,10 @@ def display_interactive_ui(sessions: List[Tuple[str, float, int, str, str, str]]
340
360
  except KeyboardInterrupt:
341
361
  ui_console.print("\n[yellow]Cancelled[/yellow]")
342
362
  return None
343
- except (ValueError, EOFError):
363
+ except EOFError:
364
+ ui_console.print("\n[yellow]Cancelled (EOF)[/yellow]")
365
+ return None
366
+ except ValueError:
344
367
  ui_console.print("[red]Invalid choice. Please try again.[/red]")
345
368
 
346
369
 
@@ -496,12 +519,13 @@ To persist directory changes when resuming sessions:
496
519
  # Fallback: print session IDs as before
497
520
  if not args.shell:
498
521
  print("\nMatching sessions:")
499
- for idx, (session_id, mod_time, line_count, project_name, preview, project_path) in enumerate(matching_sessions[:args.num_matches], 1):
522
+ for idx, (session_id, mod_time, line_count, project_name, preview, project_path, git_branch) in enumerate(matching_sessions[:args.num_matches], 1):
500
523
  mod_date = datetime.fromtimestamp(mod_time).strftime('%Y-%m-%d %H:%M:%S')
524
+ branch_display = git_branch if git_branch else "N/A"
501
525
  if getattr(args, 'global'):
502
- print(f"{idx}. {session_id} | {project_name} | {mod_date} | {line_count} lines", file=sys.stderr if args.shell else sys.stdout)
526
+ print(f"{idx}. {session_id} | {project_name} | {branch_display} | {mod_date} | {line_count} lines", file=sys.stderr if args.shell else sys.stdout)
503
527
  else:
504
- print(f"{idx}. {session_id} | {mod_date} | {line_count} lines", file=sys.stderr if args.shell else sys.stdout)
528
+ print(f"{idx}. {session_id} | {branch_display} | {mod_date} | {line_count} lines", file=sys.stderr if args.shell else sys.stdout)
505
529
 
506
530
  if len(matching_sessions) > args.num_matches:
507
531
  print(f"\n... and {len(matching_sessions) - args.num_matches} more sessions", file=sys.stderr if args.shell else sys.stdout)
@@ -510,7 +534,7 @@ To persist directory changes when resuming sessions:
510
534
  if len(matching_sessions) == 1:
511
535
  if not args.shell:
512
536
  print("\nOnly one match found. Resuming automatically...")
513
- session_id, _, _, _, _, project_path = matching_sessions[0]
537
+ session_id, _, _, _, _, project_path, _ = matching_sessions[0]
514
538
  resume_session(session_id, project_path, shell_mode=args.shell)
515
539
  else:
516
540
  try:
@@ -521,10 +545,15 @@ To persist directory changes when resuming sessions:
521
545
  choice = sys.stdin.readline().strip()
522
546
  else:
523
547
  choice = input("\nEnter number to resume session (or Ctrl+C to cancel): ")
548
+
549
+ # Handle empty input or EOF
550
+ if not choice:
551
+ print("Cancelled (EOF)", file=sys.stderr)
552
+ sys.exit(0)
524
553
 
525
554
  idx = int(choice) - 1
526
555
  if 0 <= idx < min(args.num_matches, len(matching_sessions)):
527
- session_id, _, _, _, _, project_path = matching_sessions[idx]
556
+ session_id, _, _, _, _, project_path, _ = matching_sessions[idx]
528
557
  resume_session(session_id, project_path, shell_mode=args.shell)
529
558
  else:
530
559
  print("Invalid choice", file=sys.stderr)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "claude-code-tools"
3
- version = "0.1.13"
3
+ version = "0.1.14"
4
4
  description = "Collection of tools for working with Claude Code"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -40,7 +40,7 @@ exclude = [
40
40
 
41
41
  [tool.commitizen]
42
42
  name = "cz_conventional_commits"
43
- version = "0.1.13"
43
+ version = "0.1.14"
44
44
  tag_format = "v$version"
45
45
  version_files = [
46
46
  "pyproject.toml:version",