claude-code-tools 0.2.1__tar.gz → 0.2.2__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.

Files changed (22) hide show
  1. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/PKG-INFO +13 -2
  2. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/README.md +12 -1
  3. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/claude_code_tools/__init__.py +1 -1
  4. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/claude_code_tools/find_claude_session.py +39 -25
  5. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/claude_code_tools/find_codex_session.py +13 -16
  6. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/pyproject.toml +2 -2
  7. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/.gitignore +0 -0
  8. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/LICENSE +0 -0
  9. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/claude_code_tools/codex_bridge_mcp.py +0 -0
  10. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/claude_code_tools/dotenv_vault.py +0 -0
  11. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/claude_code_tools/env_safe.py +0 -0
  12. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/claude_code_tools/tmux_cli_controller.py +0 -0
  13. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/claude_code_tools/tmux_remote_controller.py +0 -0
  14. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/docs/cc-codex-instructions.md +0 -0
  15. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/docs/claude-code-chutes.md +0 -0
  16. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/docs/claude-code-tmux-tutorials.md +0 -0
  17. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/docs/dot-zshrc.md +0 -0
  18. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/docs/find-claude-session.md +0 -0
  19. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/docs/lmsh.md +0 -0
  20. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/docs/reddit-post.md +0 -0
  21. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/docs/tmux-cli-instructions.md +0 -0
  22. {claude_code_tools-0.2.1 → claude_code_tools-0.2.2}/docs/vault-documentation.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-code-tools
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Collection of tools for working with Claude Code
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.11
@@ -215,10 +215,16 @@ fcs "keywords" -g
215
215
 
216
216
  ### Features
217
217
 
218
+ - **Action menu** after session selection:
219
+ - Resume session (default)
220
+ - Show session file path
221
+ - Copy session file to file (*.jsonl) or directory
218
222
  - Interactive session selection with previews
219
- - Cross-project search capabilities
223
+ - Cross-project search capabilities (local by default, `-g` for global)
224
+ - Shows last user message preview (filtered, multi-line wrapping)
220
225
  - Automatic session resumption with `claude -r`
221
226
  - Persistent directory changes when resuming cross-project sessions
227
+ - Press Enter to cancel (no need for Ctrl+C)
222
228
 
223
229
  Note: You can also use `find-claude-session` directly, but directory changes
224
230
  won't persist after exiting Claude Code.
@@ -259,6 +265,10 @@ find-codex-session "keywords" --codex-home /custom/path
259
265
 
260
266
  ### Features
261
267
 
268
+ - **Action menu** after session selection:
269
+ - Resume session (default)
270
+ - Show session file path
271
+ - Copy session file to file (*.jsonl) or directory
262
272
  - **Project filtering**: Search current project only (default) or all projects with `-g`
263
273
  - Case-insensitive AND keyword search across all session content
264
274
  - Interactive session selection with Rich table display
@@ -267,6 +277,7 @@ find-codex-session "keywords" --codex-home /custom/path
267
277
  - Cross-project session support with directory change prompts
268
278
  - Reverse chronological ordering (most recent first)
269
279
  - Multi-line preview wrapping for better readability
280
+ - Press Enter to cancel (no need for Ctrl+C)
270
281
 
271
282
  Looks like this --
272
283
 
@@ -201,10 +201,16 @@ fcs "keywords" -g
201
201
 
202
202
  ### Features
203
203
 
204
+ - **Action menu** after session selection:
205
+ - Resume session (default)
206
+ - Show session file path
207
+ - Copy session file to file (*.jsonl) or directory
204
208
  - Interactive session selection with previews
205
- - Cross-project search capabilities
209
+ - Cross-project search capabilities (local by default, `-g` for global)
210
+ - Shows last user message preview (filtered, multi-line wrapping)
206
211
  - Automatic session resumption with `claude -r`
207
212
  - Persistent directory changes when resuming cross-project sessions
213
+ - Press Enter to cancel (no need for Ctrl+C)
208
214
 
209
215
  Note: You can also use `find-claude-session` directly, but directory changes
210
216
  won't persist after exiting Claude Code.
@@ -245,6 +251,10 @@ find-codex-session "keywords" --codex-home /custom/path
245
251
 
246
252
  ### Features
247
253
 
254
+ - **Action menu** after session selection:
255
+ - Resume session (default)
256
+ - Show session file path
257
+ - Copy session file to file (*.jsonl) or directory
248
258
  - **Project filtering**: Search current project only (default) or all projects with `-g`
249
259
  - Case-insensitive AND keyword search across all session content
250
260
  - Interactive session selection with Rich table display
@@ -253,6 +263,7 @@ find-codex-session "keywords" --codex-home /custom/path
253
263
  - Cross-project session support with directory change prompts
254
264
  - Reverse chronological ordering (most recent first)
255
265
  - Multi-line preview wrapping for better readability
266
+ - Press Enter to cancel (no need for Ctrl+C)
256
267
 
257
268
  Looks like this --
258
269
 
@@ -1,3 +1,3 @@
1
1
  """Claude Code Tools - Collection of utilities for Claude Code."""
2
2
 
3
- __version__ = "0.2.1"
3
+ __version__ = "0.2.2"
@@ -220,17 +220,17 @@ def get_session_preview(filepath: Path) -> str:
220
220
  return last_user_message if last_user_message else "No preview available"
221
221
 
222
222
 
223
- 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]]]:
223
+ def find_sessions(keywords: List[str], global_search: bool = False, claude_home: Optional[str] = None) -> List[Tuple[str, float, float, int, str, str, str, Optional[str]]]:
224
224
  """
225
225
  Find all Claude Code sessions containing the specified keywords.
226
-
226
+
227
227
  Args:
228
228
  keywords: List of keywords to search for
229
229
  global_search: If True, search all projects; if False, search current project only
230
230
  claude_home: Optional custom Claude home directory (defaults to ~/.claude)
231
-
231
+
232
232
  Returns:
233
- List of tuples (session_id, modification_time, line_count, project_name, preview, project_path, git_branch) sorted by modification time
233
+ List of tuples (session_id, modification_time, creation_time, line_count, project_name, preview, project_path, git_branch) sorted by modification time
234
234
  """
235
235
  matching_sessions = []
236
236
 
@@ -256,23 +256,29 @@ def find_sessions(keywords: List[str], global_search: bool = False, claude_home:
256
256
  matches, line_count, git_branch = search_keywords_in_file(jsonl_file, keywords)
257
257
  if matches:
258
258
  session_id = jsonl_file.stem
259
- mod_time = jsonl_file.stat().st_mtime
259
+ stat = jsonl_file.stat()
260
+ mod_time = stat.st_mtime
261
+ # Get creation time (birthtime on macOS, ctime elsewhere)
262
+ create_time = getattr(stat, 'st_birthtime', stat.st_ctime)
260
263
  preview = get_session_preview(jsonl_file)
261
- matching_sessions.append((session_id, mod_time, line_count, project_name, preview, original_path, git_branch))
264
+ matching_sessions.append((session_id, mod_time, create_time, line_count, project_name, preview, original_path, git_branch))
262
265
 
263
266
  progress.advance(task)
264
267
  else:
265
268
  # Fallback without rich
266
269
  for project_dir, original_path in projects:
267
270
  project_name = extract_project_name(original_path)
268
-
271
+
269
272
  for jsonl_file in project_dir.glob("*.jsonl"):
270
273
  matches, line_count, git_branch = search_keywords_in_file(jsonl_file, keywords)
271
274
  if matches:
272
275
  session_id = jsonl_file.stem
273
- mod_time = jsonl_file.stat().st_mtime
276
+ stat = jsonl_file.stat()
277
+ mod_time = stat.st_mtime
278
+ # Get creation time (birthtime on macOS, ctime elsewhere)
279
+ create_time = getattr(stat, 'st_birthtime', stat.st_ctime)
274
280
  preview = get_session_preview(jsonl_file)
275
- matching_sessions.append((session_id, mod_time, line_count, project_name, preview, original_path, git_branch))
281
+ matching_sessions.append((session_id, mod_time, create_time, line_count, project_name, preview, original_path, git_branch))
276
282
  else:
277
283
  # Search current project only
278
284
  claude_dir = get_claude_project_dir(claude_home)
@@ -287,9 +293,12 @@ def find_sessions(keywords: List[str], global_search: bool = False, claude_home:
287
293
  matches, line_count, git_branch = search_keywords_in_file(jsonl_file, keywords)
288
294
  if matches:
289
295
  session_id = jsonl_file.stem
290
- mod_time = jsonl_file.stat().st_mtime
296
+ stat = jsonl_file.stat()
297
+ mod_time = stat.st_mtime
298
+ # Get creation time (birthtime on macOS, ctime elsewhere)
299
+ create_time = getattr(stat, 'st_birthtime', stat.st_ctime)
291
300
  preview = get_session_preview(jsonl_file)
292
- matching_sessions.append((session_id, mod_time, line_count, project_name, preview, os.getcwd(), git_branch))
301
+ matching_sessions.append((session_id, mod_time, create_time, line_count, project_name, preview, os.getcwd(), git_branch))
293
302
 
294
303
  # Sort by modification time (newest first)
295
304
  matching_sessions.sort(key=lambda x: x[1], reverse=True)
@@ -326,19 +335,22 @@ def display_interactive_ui(sessions: List[Tuple[str, float, int, str, str, str,
326
335
  table.add_column("Session ID", style="dim")
327
336
  table.add_column("Project", style="green")
328
337
  table.add_column("Branch", style="magenta")
329
- table.add_column("Date", style="blue")
338
+ table.add_column("Date-Range", style="blue")
330
339
  table.add_column("Lines", style="cyan", justify="right")
331
340
  table.add_column("Preview", style="white", max_width=60, overflow="fold")
332
341
 
333
- for idx, (session_id, mod_time, line_count, project_name, preview, _, git_branch) in enumerate(display_sessions, 1):
334
- mod_date = datetime.fromtimestamp(mod_time).strftime('%Y-%m-%d %H:%M')
342
+ for idx, (session_id, mod_time, create_time, line_count, project_name, preview, _, git_branch) in enumerate(display_sessions, 1):
343
+ # Format: "10/04 - 10/09 13:45"
344
+ create_date = datetime.fromtimestamp(create_time).strftime('%m/%d')
345
+ mod_date = datetime.fromtimestamp(mod_time).strftime('%m/%d %H:%M')
346
+ date_display = f"{create_date} - {mod_date}"
335
347
  branch_display = git_branch if git_branch else "N/A"
336
348
  table.add_row(
337
349
  str(idx),
338
350
  session_id[:8] + "...",
339
351
  project_name,
340
352
  branch_display,
341
- mod_date,
353
+ date_display,
342
354
  str(line_count),
343
355
  preview
344
356
  )
@@ -402,13 +414,13 @@ def display_interactive_ui(sessions: List[Tuple[str, float, int, str, str, str,
402
414
  ui_console.print("[red]Invalid choice. Please try again.[/red]")
403
415
 
404
416
 
405
- def show_action_menu(session_info: Tuple[str, float, int, str, str, str, Optional[str]]) -> Optional[str]:
417
+ def show_action_menu(session_info: Tuple[str, float, float, int, str, str, str, Optional[str]]) -> Optional[str]:
406
418
  """
407
419
  Show action menu for selected session.
408
420
 
409
421
  Returns: action choice ('resume', 'path', 'copy') or None if cancelled
410
422
  """
411
- session_id, _, _, project_name, _, project_path, git_branch = session_info
423
+ session_id, _, _, _, project_name, _, project_path, git_branch = session_info
412
424
 
413
425
  print(f"\n=== Session: {session_id[:8]}... ===")
414
426
  print(f"Project: {project_name}")
@@ -649,7 +661,7 @@ To persist directory changes when resuming sessions:
649
661
  return
650
662
 
651
663
  session_id = selected_session[0]
652
- project_path = selected_session[5]
664
+ project_path = selected_session[6] # Updated index after adding creation_time
653
665
 
654
666
  # Perform selected action
655
667
  if action == "resume":
@@ -665,22 +677,24 @@ To persist directory changes when resuming sessions:
665
677
  # Fallback: print session IDs as before
666
678
  if not args.shell:
667
679
  print("\nMatching sessions:")
668
- for idx, (session_id, mod_time, line_count, project_name, preview, project_path, git_branch) in enumerate(matching_sessions[:args.num_matches], 1):
669
- mod_date = datetime.fromtimestamp(mod_time).strftime('%Y-%m-%d %H:%M:%S')
680
+ for idx, (session_id, mod_time, create_time, line_count, project_name, preview, project_path, git_branch) in enumerate(matching_sessions[:args.num_matches], 1):
681
+ create_date = datetime.fromtimestamp(create_time).strftime('%m/%d')
682
+ mod_date = datetime.fromtimestamp(mod_time).strftime('%m/%d %H:%M')
683
+ date_display = f"{create_date} - {mod_date}"
670
684
  branch_display = git_branch if git_branch else "N/A"
671
685
  if getattr(args, 'global'):
672
- print(f"{idx}. {session_id} | {project_name} | {branch_display} | {mod_date} | {line_count} lines", file=sys.stderr if args.shell else sys.stdout)
686
+ print(f"{idx}. {session_id} | {project_name} | {branch_display} | {date_display} | {line_count} lines", file=sys.stderr if args.shell else sys.stdout)
673
687
  else:
674
- print(f"{idx}. {session_id} | {branch_display} | {mod_date} | {line_count} lines", file=sys.stderr if args.shell else sys.stdout)
675
-
688
+ print(f"{idx}. {session_id} | {branch_display} | {date_display} | {line_count} lines", file=sys.stderr if args.shell else sys.stdout)
689
+
676
690
  if len(matching_sessions) > args.num_matches:
677
691
  print(f"\n... and {len(matching_sessions) - args.num_matches} more sessions", file=sys.stderr if args.shell else sys.stdout)
678
-
692
+
679
693
  # Simple selection without rich
680
694
  if len(matching_sessions) == 1:
681
695
  if not args.shell:
682
696
  print("\nOnly one match found. Resuming automatically...")
683
- session_id, _, _, _, _, project_path, _ = matching_sessions[0]
697
+ session_id, _, _, _, _, _, project_path, _ = matching_sessions[0]
684
698
  resume_session(session_id, project_path, shell_mode=args.shell)
685
699
  else:
686
700
  try:
@@ -242,19 +242,15 @@ def find_sessions(
242
242
  if current_cwd and metadata["cwd"] != current_cwd:
243
243
  continue
244
244
 
245
- # Parse timestamp
246
- timestamp_str = metadata["timestamp"]
247
- if timestamp_str:
248
- try:
249
- dt = datetime.fromisoformat(
250
- timestamp_str.replace("Z", "+00:00")
251
- )
252
- date_str = dt.strftime("%Y-%m-%d %H:%M")
253
- except ValueError:
254
- date_str = timestamp_str[:16]
255
- else:
256
- # Fallback to directory date
257
- date_str = f"{year_dir.name}-{month_dir.name}-{day_dir.name}"
245
+ # Get file stats for timestamps
246
+ stat = session_file.stat()
247
+ mod_time = stat.st_mtime
248
+ create_time = getattr(stat, 'st_birthtime', stat.st_ctime)
249
+
250
+ # Format dates: "10/04 - 10/09 13:45"
251
+ create_date = datetime.fromtimestamp(create_time).strftime("%m/%d")
252
+ mod_date = datetime.fromtimestamp(mod_time).strftime("%m/%d %H:%M")
253
+ date_str = f"{create_date} - {mod_date}"
258
254
 
259
255
  matches.append(
260
256
  {
@@ -262,6 +258,7 @@ def find_sessions(
262
258
  "project": get_project_name(metadata["cwd"]),
263
259
  "branch": metadata["branch"] or "",
264
260
  "date": date_str,
261
+ "mod_time": mod_time, # For sorting
265
262
  "lines": line_count,
266
263
  "preview": preview or "No preview",
267
264
  "cwd": metadata["cwd"],
@@ -273,8 +270,8 @@ def find_sessions(
273
270
  if len(matches) >= num_matches * 3:
274
271
  break
275
272
 
276
- # Sort by date (reverse chronological) and limit
277
- matches.sort(key=lambda x: x["date"], reverse=True)
273
+ # Sort by modification time (newest first) and limit
274
+ matches.sort(key=lambda x: x["mod_time"], reverse=True)
278
275
  return matches[:num_matches]
279
276
 
280
277
 
@@ -297,7 +294,7 @@ def display_interactive_ui(
297
294
  table.add_column("Session ID", style="yellow", no_wrap=True)
298
295
  table.add_column("Project", style="green")
299
296
  table.add_column("Branch", style="magenta")
300
- table.add_column("Date", style="blue")
297
+ table.add_column("Date-Range", style="blue")
301
298
  table.add_column("Lines", justify="right")
302
299
  table.add_column("Preview", style="dim", max_width=60, overflow="fold")
303
300
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "claude-code-tools"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "Collection of tools for working with Claude Code"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -43,7 +43,7 @@ exclude = [
43
43
 
44
44
  [tool.commitizen]
45
45
  name = "cz_conventional_commits"
46
- version = "0.2.1"
46
+ version = "0.2.2"
47
47
  tag_format = "v$version"
48
48
  version_files = [
49
49
  "pyproject.toml:version",