claude-code-analytics 0.1.0__cp311-abi3-macosx_11_0_arm64.whl

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.
@@ -0,0 +1,690 @@
1
+ Metadata-Version: 2.4
2
+ Name: claude-code-analytics
3
+ Version: 0.1.0
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Intended Audience :: Developers
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.11
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Programming Language :: Rust
12
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
+ License-File: LICENSE
14
+ Summary: Python SDK for Claude Code with Rust core
15
+ Author-email: Darin Kishore <darinkishore@protonmail.com>
16
+ License: MIT
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
19
+ Project-URL: Homepage, https://github.com/darinkishore/rust_sdk
20
+ Project-URL: Documentation, https://github.com/darinkishore/rust_sdk#readme
21
+ Project-URL: Repository, https://github.com/darinkishore/rust_sdk.git
22
+ Project-URL: Issues, https://github.com/darinkishore/rust_sdk/issues
23
+
24
+ # Claude SDK for Python
25
+
26
+ A high-performance Python library for parsing and analyzing Claude Code session data. Built with Rust for speed, designed with Python developers in mind.
27
+
28
+ ## Table of Contents
29
+
30
+ - [Installation](#installation)
31
+ - [Quick Start](#quick-start)
32
+ - [Core Concepts](#core-concepts)
33
+ - [API Reference](#api-reference)
34
+ - [Functions](#functions)
35
+ - [Classes](#classes)
36
+ - [Exceptions](#exceptions)
37
+ - [Examples](#examples)
38
+ - [Performance](#performance)
39
+ - [Troubleshooting](#troubleshooting)
40
+ - [Development](#development)
41
+
42
+ ## Installation
43
+
44
+ ### Prerequisites
45
+
46
+ - Python 3.8 or higher
47
+ - pip or uv package manager
48
+
49
+ ### Install from PyPI (when published)
50
+
51
+ ```bash
52
+ pip install claude-code-analytics
53
+ ```
54
+
55
+ ### Install from source
56
+
57
+ ```bash
58
+ # Clone the repository
59
+ git clone https://github.com/darinkishore/claude-code-analytics.git
60
+ cd claude-code-analytics
61
+
62
+ # Or using uv (recommended)
63
+ uv pip install ./python
64
+ ```
65
+
66
+ ### Development installation
67
+
68
+ ```bash
69
+ cd python
70
+ uv build
71
+ ```
72
+
73
+ ## Quick Start
74
+
75
+ ```python
76
+ import claude_sdk
77
+
78
+ # Load a session from a JSONL file
79
+ session = claude_sdk.load("~/.claude/projects/myproject/session_20240101_120000.jsonl")
80
+
81
+ # Basic session info
82
+ print(f"Session ID: {session.session_id}")
83
+ print(f"Total cost: ${session.total_cost:.4f}")
84
+ print(f"Message count: {len(session.messages)}")
85
+ print(f"Tools used: {', '.join(session.tools_used)}")
86
+
87
+ # Iterate through messages
88
+ for message in session:
89
+ print(f"{message.role}: {message.text[:100]}...")
90
+
91
+ # Find all your sessions
92
+ sessions = claude_sdk.find_sessions()
93
+ for session_path in sessions:
94
+ print(f"Found session: {session_path}")
95
+ ```
96
+
97
+ ## Core Concepts
98
+
99
+ ### Sessions
100
+
101
+ A **Session** represents a complete conversation with Claude, loaded from a JSONL file. Each session contains:
102
+
103
+ - Messages exchanged between user and assistant
104
+ - Tool executions and their results
105
+ - Token usage and cost information
106
+ - Conversation structure (including branches and sidechains)
107
+ - Metadata and statistics
108
+
109
+ ### Messages
110
+
111
+ **Messages** are the individual exchanges in a conversation. Each message has:
112
+
113
+ - `role`: Either "user" or "assistant"
114
+ - `text`: The complete text content
115
+ - `tools`: List of tools used (if any)
116
+ - `cost`: Cost in USD for this specific message
117
+ - `timestamp`: When the message was created
118
+ - Threading information (`uuid`, `parent_uuid`)
119
+
120
+ ### Projects
121
+
122
+ A **Project** is a collection of related sessions, typically stored in the same directory. Projects provide aggregate statistics across all sessions.
123
+
124
+ ### Conversation Trees
125
+
126
+ The SDK automatically reconstructs the conversation structure, handling:
127
+
128
+ - Linear conversations
129
+ - Branching (when you retry or edit messages)
130
+ - Sidechains (alternate conversation paths)
131
+ - Orphaned messages (missing parents)
132
+
133
+ ## API Reference
134
+
135
+ ### Functions
136
+
137
+ #### `load(file_path: str | Path) -> Session`
138
+
139
+ Load a Claude Code session from a JSONL file.
140
+
141
+ ```python
142
+ session = claude_sdk.load("path/to/session.jsonl")
143
+ ```
144
+
145
+ **Parameters:**
146
+ - `file_path`: Path to the JSONL session file
147
+
148
+ **Returns:** `Session` object
149
+
150
+ **Raises:**
151
+ - `FileNotFoundError`: If the file doesn't exist
152
+ - `ParseError`: If the JSONL is malformed
153
+ - `ValidationError`: If the session data is invalid
154
+
155
+ #### `find_sessions(base_path: Optional[str] = None, project: Optional[str] = None) -> List[Path]`
156
+
157
+ Discover Claude Code session files.
158
+
159
+ ```python
160
+ # Find all sessions
161
+ all_sessions = claude_sdk.find_sessions()
162
+
163
+ # Find sessions in a specific project
164
+ project_sessions = claude_sdk.find_sessions(project="myproject")
165
+
166
+ # Search in a custom location
167
+ custom_sessions = claude_sdk.find_sessions(base_path="/custom/path")
168
+ ```
169
+
170
+ **Parameters:**
171
+ - `base_path`: Root directory to search (default: `~/.claude/projects/`)
172
+ - `project`: Filter by specific project name
173
+
174
+ **Returns:** List of `Path` objects to session files
175
+
176
+ #### `find_projects(base_path: Optional[str] = None) -> List[Path]`
177
+
178
+ Find all Claude Code projects.
179
+
180
+ ```python
181
+ projects = claude_sdk.find_projects()
182
+ for project_path in projects:
183
+ print(f"Project: {project_path.name}")
184
+ ```
185
+
186
+ **Parameters:**
187
+ - `base_path`: Root directory to search (default: `~/.claude/projects/`)
188
+
189
+ **Returns:** List of `Path` objects to project directories
190
+
191
+ #### `load_project(project_identifier: str | Path, base_path: Optional[str] = None) -> Project`
192
+
193
+ Load an entire project with all its sessions.
194
+
195
+ ```python
196
+ # Load by project name
197
+ project = claude_sdk.load_project("myproject")
198
+
199
+ # Load by path
200
+ project = claude_sdk.load_project("/path/to/project")
201
+
202
+ print(f"Total sessions: {len(project.sessions)}")
203
+ print(f"Total cost: ${project.total_cost:.2f}")
204
+ ```
205
+
206
+ **Parameters:**
207
+ - `project_identifier`: Project name or path
208
+ - `base_path`: Base path for project lookup (if using name)
209
+
210
+ **Returns:** `Project` object
211
+
212
+ **Raises:**
213
+ - `FileNotFoundError`: If project doesn't exist
214
+ - `SessionError`: If no valid sessions found
215
+
216
+ ### Classes
217
+
218
+ #### Session
219
+
220
+ Primary container for Claude Code session data.
221
+
222
+ **Properties:**
223
+
224
+ | Property | Type | Description |
225
+ |----------|------|-------------|
226
+ | `session_id` | `str` | Unique session identifier |
227
+ | `messages` | `List[Message]` | All messages in conversation order |
228
+ | `total_cost` | `float` | Total cost in USD |
229
+ | `tools_used` | `List[str]` | Unique tool names used |
230
+ | `duration` | `Optional[float]` | Session duration in seconds |
231
+ | `conversation_tree` | `ConversationTree` | Message threading structure |
232
+ | `metadata` | `SessionMetadata` | Detailed statistics |
233
+ | `tool_executions` | `List[ToolExecution]` | All tool runs |
234
+ | `tool_costs` | `Dict[str, float]` | Cost breakdown by tool |
235
+ | `cost_by_turn` | `List[float]` | Cost per message |
236
+ | `project_path` | `Optional[Path]` | Project directory |
237
+ | `project_name` | `Optional[str]` | Project name |
238
+
239
+ **Methods:**
240
+
241
+ ```python
242
+ # Get main conversation (excluding sidechains)
243
+ main_messages = session.get_main_chain()
244
+
245
+ # Filter by role
246
+ user_messages = session.get_messages_by_role("user")
247
+ assistant_messages = session.get_messages_by_role("assistant")
248
+
249
+ # Find messages using specific tools
250
+ bash_messages = session.get_messages_by_tool("bash")
251
+
252
+ # Get a specific message
253
+ message = session.get_message_by_uuid("msg-uuid-123")
254
+
255
+ # Custom filtering
256
+ long_messages = session.filter_messages(lambda m: len(m.text) > 1000)
257
+
258
+ # Get conversation thread
259
+ thread = session.get_thread("msg-uuid-789") # Returns path from root
260
+
261
+ # Iteration and length
262
+ for msg in session:
263
+ print(msg.text)
264
+
265
+ print(f"Total messages: {len(session)}")
266
+ ```
267
+
268
+ #### Message
269
+
270
+ Represents a single message in the conversation.
271
+
272
+ **Properties:**
273
+
274
+ | Property | Type | Description |
275
+ |----------|------|-------------|
276
+ | `role` | `str` | "user" or "assistant" |
277
+ | `text` | `str` | Complete text content |
278
+ | `model` | `Optional[str]` | Model used (e.g., "claude-3-sonnet-20240229") |
279
+ | `cost` | `Optional[float]` | Cost in USD |
280
+ | `tools` | `List[str]` | Tool names used |
281
+ | `stop_reason` | `Optional[str]` | Why generation stopped |
282
+ | `usage` | `Optional[TokenUsage]` | Token usage details |
283
+ | `timestamp` | `str` | RFC3339 timestamp |
284
+ | `uuid` | `str` | Unique identifier |
285
+ | `parent_uuid` | `Optional[str]` | Parent message UUID |
286
+ | `is_sidechain` | `bool` | Whether part of a sidechain |
287
+ | `cwd` | `Optional[Path]` | Working directory |
288
+ | `total_tokens` | `int` | Total token count |
289
+ | `input_tokens` | `int` | Input token count |
290
+ | `output_tokens` | `int` | Output token count |
291
+
292
+ **Methods:**
293
+
294
+ ```python
295
+ # Check for tool usage
296
+ if message.has_tool_use():
297
+ tools = message.get_tool_blocks()
298
+ for tool in tools:
299
+ print(f"Tool: {tool.name}, Input: {tool.input}")
300
+
301
+ # Get text content blocks
302
+ text_blocks = message.get_text_blocks()
303
+
304
+ # Get all content blocks with proper typing
305
+ for block in message.get_content_blocks():
306
+ if isinstance(block, claude_sdk.TextBlock):
307
+ print(f"Text: {block.text}")
308
+ elif isinstance(block, claude_sdk.ToolUseBlock):
309
+ print(f"Tool: {block.name}")
310
+ ```
311
+
312
+ #### Project
313
+
314
+ Container for multiple sessions in a project.
315
+
316
+ **Properties:**
317
+
318
+ | Property | Type | Description |
319
+ |----------|------|-------------|
320
+ | `name` | `str` | Project name |
321
+ | `sessions` | `List[Session]` | All sessions in project |
322
+ | `total_cost` | `float` | Aggregate cost |
323
+ | `total_messages` | `int` | Total message count |
324
+ | `tool_usage_count` | `Dict[str, int]` | Tool usage frequency |
325
+ | `total_duration` | `Optional[float]` | Total time in seconds |
326
+
327
+ ```python
328
+ project = claude_sdk.load_project("myproject")
329
+
330
+ # Analyze tool usage patterns
331
+ for tool, count in project.tool_usage_count.items():
332
+ avg_per_session = count / len(project.sessions)
333
+ print(f"{tool}: {count} uses ({avg_per_session:.1f} per session)")
334
+
335
+ # Find expensive sessions
336
+ expensive = [s for s in project.sessions if s.total_cost > 1.0]
337
+ ```
338
+
339
+ #### ToolExecution
340
+
341
+ Complete record of a tool invocation.
342
+
343
+ **Properties:**
344
+
345
+ | Property | Type | Description |
346
+ |----------|------|-------------|
347
+ | `tool_name` | `str` | Name of the tool |
348
+ | `input` | `Dict[str, Any]` | Input parameters |
349
+ | `output` | `ToolResult` | Execution result |
350
+ | `duration_ms` | `Optional[int]` | Execution time |
351
+ | `timestamp` | `str` | When executed |
352
+
353
+ **Methods:**
354
+
355
+ ```python
356
+ # Check success
357
+ if execution.is_success():
358
+ print(f"{execution.tool_name} completed in {execution.duration_ms}ms")
359
+ else:
360
+ print(f"Failed: {execution.output.stderr}")
361
+ ```
362
+
363
+ #### ConversationTree
364
+
365
+ Tree structure representing conversation flow.
366
+
367
+ **Properties:**
368
+
369
+ | Property | Type | Description |
370
+ |----------|------|-------------|
371
+ | `root_messages` | `List[ConversationNode]` | Root nodes |
372
+ | `orphaned_messages` | `List[str]` | Messages with missing parents |
373
+ | `circular_references` | `List[str]` | Circular reference UUIDs |
374
+ | `stats` | `ConversationStats` | Tree statistics |
375
+
376
+ **Methods:**
377
+
378
+ ```python
379
+ tree = session.conversation_tree
380
+
381
+ # Get tree metrics
382
+ print(f"Max depth: {tree.max_depth()}")
383
+ print(f"Branch points: {tree.count_branches()}")
384
+
385
+ # Traverse tree
386
+ def walk_tree(node, depth=0):
387
+ print(" " * depth + node.message.text[:50])
388
+ for child in node.children:
389
+ walk_tree(child, depth + 1)
390
+
391
+ for root in tree.root_messages:
392
+ walk_tree(root)
393
+ ```
394
+
395
+ ### Exceptions
396
+
397
+ ```python
398
+ # Exception hierarchy
399
+ claude_sdk.ClaudeSDKError # Base exception
400
+ ├── claude_sdk.ParseError # JSONL parsing failed
401
+ ├── claude_sdk.ValidationError # Invalid data
402
+ └── claude_sdk.SessionError # Session-specific issues
403
+
404
+ # Example handling
405
+ try:
406
+ session = claude_sdk.load("session.jsonl")
407
+ except claude_sdk.ParseError as e:
408
+ print(f"Failed to parse: {e}")
409
+ except claude_sdk.ClaudeSDKError as e:
410
+ print(f"SDK error: {e}")
411
+ ```
412
+
413
+ ## Examples
414
+
415
+ ### Basic Session Analysis
416
+
417
+ ```python
418
+ import claude_sdk
419
+
420
+ # Load session
421
+ session = claude_sdk.load("session.jsonl")
422
+
423
+ # Print summary
424
+ print(f"Session: {session.session_id}")
425
+ print(f"Duration: {session.duration / 60:.1f} minutes" if session.duration else "Duration unknown")
426
+ print(f"Messages: {len(session)} ({len(session.get_messages_by_role('user'))} from user)")
427
+ print(f"Cost: ${session.total_cost:.4f}")
428
+ print(f"Tools: {', '.join(session.tools_used) or 'None'}")
429
+
430
+ # Analyze token usage
431
+ total_tokens = sum(msg.total_tokens for msg in session.messages)
432
+ print(f"Total tokens: {total_tokens:,}")
433
+ ```
434
+
435
+ ### Tool Usage Patterns
436
+
437
+ ```python
438
+ import claude_sdk
439
+ from collections import defaultdict
440
+
441
+ session = claude_sdk.load("session.jsonl")
442
+
443
+ # Count tool usage by message
444
+ tool_messages = defaultdict(list)
445
+ for msg in session.messages:
446
+ if msg.has_tool_use():
447
+ for tool in msg.tools:
448
+ tool_messages[tool].append(msg)
449
+
450
+ # Print tool usage summary
451
+ for tool, messages in sorted(tool_messages.items()):
452
+ print(f"\n{tool}: {len(messages)} uses")
453
+
454
+ # Show first few uses
455
+ for msg in messages[:3]:
456
+ preview = msg.text[:100].replace('\n', ' ')
457
+ print(f" - {preview}...")
458
+ ```
459
+
460
+ ### Cost Analysis Across Projects
461
+
462
+ ```python
463
+ import claude_sdk
464
+
465
+ # Find all projects
466
+ projects = claude_sdk.find_projects()
467
+
468
+ # Analyze costs
469
+ project_costs = []
470
+ for project_path in projects:
471
+ try:
472
+ project = claude_sdk.load_project(project_path)
473
+ project_costs.append((project.name, project.total_cost, len(project.sessions)))
474
+ except Exception as e:
475
+ print(f"Failed to load {project_path}: {e}")
476
+
477
+ # Sort by cost
478
+ project_costs.sort(key=lambda x: x[1], reverse=True)
479
+
480
+ # Print report
481
+ print("Project Cost Analysis")
482
+ print("-" * 50)
483
+ for name, cost, session_count in project_costs:
484
+ avg_cost = cost / session_count if session_count > 0 else 0
485
+ print(f"{name:20} ${cost:8.2f} ({session_count:3} sessions, avg ${avg_cost:.2f})")
486
+ ```
487
+
488
+ ### Conversation Flow Analysis
489
+
490
+ ```python
491
+ import claude_sdk
492
+
493
+ session = claude_sdk.load("session.jsonl")
494
+ tree = session.conversation_tree
495
+
496
+ # Find branching points
497
+ for root in tree.root_messages:
498
+ def find_branches(node, path=[]):
499
+ current_path = path + [node.message.uuid]
500
+
501
+ if len(node.children) > 1:
502
+ print(f"\nBranch point at message {len(current_path)}:")
503
+ print(f" {node.message.text[:100]}...")
504
+ print(f" Branches into {len(node.children)} paths")
505
+
506
+ for child in node.children:
507
+ find_branches(child, current_path)
508
+
509
+ find_branches(root)
510
+
511
+ # Analyze sidechains
512
+ sidechain_messages = [m for m in session.messages if m.is_sidechain]
513
+ if sidechain_messages:
514
+ print(f"\nFound {len(sidechain_messages)} sidechain messages")
515
+ ```
516
+
517
+ ### Exporting Session Data
518
+
519
+ ```python
520
+ import claude_sdk
521
+ import json
522
+ import csv
523
+
524
+ session = claude_sdk.load("session.jsonl")
525
+
526
+ # Export to JSON
527
+ export_data = {
528
+ "session_id": session.session_id,
529
+ "total_cost": session.total_cost,
530
+ "messages": [
531
+ {
532
+ "role": msg.role,
533
+ "text": msg.text,
534
+ "cost": msg.cost,
535
+ "timestamp": msg.timestamp,
536
+ "tools": msg.tools
537
+ }
538
+ for msg in session.messages
539
+ ]
540
+ }
541
+
542
+ with open("session_export.json", "w") as f:
543
+ json.dump(export_data, f, indent=2)
544
+
545
+ # Export tool usage to CSV
546
+ with open("tool_usage.csv", "w", newline="") as f:
547
+ writer = csv.writer(f)
548
+ writer.writerow(["Timestamp", "Tool", "Duration (ms)", "Success"])
549
+
550
+ for exec in session.tool_executions:
551
+ writer.writerow([
552
+ exec.timestamp,
553
+ exec.tool_name,
554
+ exec.duration_ms or "N/A",
555
+ exec.is_success()
556
+ ])
557
+ ```
558
+
559
+ ## Performance
560
+
561
+ The Claude SDK is built with Rust for exceptional performance:
562
+
563
+ - **Parsing speed**: 1000+ messages per second
564
+ - **Memory efficient**: Streaming parser for large files
565
+ - **Zero-copy strings**: Minimal memory allocation
566
+ - **Thread safe**: Can be used in multi-threaded applications
567
+
568
+ ### Benchmarks
569
+
570
+ | File Size | Messages | Parse Time | Memory Usage |
571
+ |-----------|----------|------------|--------------|
572
+ | 100 KB | 50 | <10ms | 2 MB |
573
+ | 1 MB | 500 | <50ms | 8 MB |
574
+ | 10 MB | 5000 | <300ms | 35 MB |
575
+ | 100 MB | 50000 | <3s | 350 MB |
576
+
577
+ ## Troubleshooting
578
+
579
+ ### Common Issues
580
+
581
+ #### ImportError: No module named 'claude_sdk'
582
+
583
+ **Solution**: Ensure you've installed the package:
584
+ ```bash
585
+ pip install claude-code-analytics
586
+ # or for development
587
+ uv build
588
+ ```
589
+
590
+ #### FileNotFoundError when loading sessions
591
+
592
+ **Solution**: Check the file path and ensure you have read permissions:
593
+ ```python
594
+ import os
595
+ path = os.path.expanduser("~/.claude/projects/myproject/session.jsonl")
596
+ if os.path.exists(path):
597
+ session = claude_sdk.load(path)
598
+ ```
599
+
600
+ #### ParseError: Invalid JSONL format
601
+
602
+ **Solution**: Ensure the file is a valid Claude Code session file:
603
+ ```bash
604
+ # Check first few lines
605
+ head -n 5 session.jsonl
606
+
607
+ # Validate JSON
608
+ python -m json.tool session.jsonl
609
+ ```
610
+
611
+ #### High memory usage with large files
612
+
613
+ **Solution**: Process sessions in batches:
614
+ ```python
615
+ # Instead of loading all sessions at once
616
+ sessions = []
617
+ for path in claude_sdk.find_sessions(project="large_project"):
618
+ session = claude_sdk.load(path)
619
+ # Process session
620
+ del session # Free memory
621
+ ```
622
+
623
+ ### Debug Mode
624
+
625
+ Enable detailed logging for troubleshooting:
626
+
627
+ ```python
628
+ import logging
629
+ logging.basicConfig(level=logging.DEBUG)
630
+
631
+ # Now SDK operations will print debug info
632
+ session = claude_sdk.load("session.jsonl")
633
+ ```
634
+
635
+ ## Development
636
+
637
+ ### Building from source
638
+
639
+ ```bash
640
+ # Clone repository
641
+ git clone https://github.com/yourusername/claude-code-analytics.git
642
+ cd claude-code-analytics
643
+
644
+ # Build Rust library
645
+ cargo build --release
646
+
647
+ # Build Python package
648
+ uv build
649
+ ```
650
+
651
+ ### Running tests
652
+
653
+ ```bash
654
+ # Rust tests
655
+ cargo test
656
+
657
+ # Python tests
658
+ uv build
659
+ uv run -m pytest tests/
660
+ ```
661
+
662
+ The Python test suite includes fixtures for malformed JSONL and a multi-megabyte
663
+ session to ensure `ParseError` is raised correctly and large files load
664
+ successfully.
665
+
666
+ ### Contributing
667
+
668
+ 1. Fork the repository
669
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
670
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
671
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
672
+ 5. Open a Pull Request
673
+
674
+ ## License
675
+
676
+ This project is licensed under the MIT License - see the LICENSE file for details.
677
+
678
+ ## Acknowledgments
679
+
680
+ Built with:
681
+ - [PyO3](https://pyo3.rs/) - Rust bindings for Python
682
+ - [Maturin](https://maturin.rs/) - Build and publish Rust Python extensions
683
+ - [Serde](https://serde.rs/) - Serialization framework for Rust
684
+
685
+ ## Support
686
+
687
+ - **Issues**: [GitHub Issues](https://github.com/yourusername/claude-code-analytics/issues)
688
+ - **Discussions**: [GitHub Discussions](https://github.com/yourusername/claude-code-analytics/discussions)
689
+ - **Documentation**: [Full API Docs](https://yourusername.github.io/claude-code-analytics/)
690
+
@@ -0,0 +1,6 @@
1
+ claude_code_analytics-0.1.0.dist-info/METADATA,sha256=gJa9SdZOx4sNnWFQuQ8ESQ_xvIr9Ov4IVgy8xxzKX8s,18530
2
+ claude_code_analytics-0.1.0.dist-info/WHEEL,sha256=l9jBLnRRly5LD7TW-oNpYWU1DRojZivxrl_VDrtEJF4,103
3
+ claude_code_analytics-0.1.0.dist-info/licenses/LICENSE,sha256=VOy5LfrbCUMxLGMwcxF3KTEyMO8xzEBm713UCA6sQng,1069
4
+ claude_sdk/__init__.py,sha256=ZOdoUccrl-IPf563jSRbyHBfzhTDScrE_qVRSZ7GiB8,3571
5
+ claude_sdk/_core.abi3.so,sha256=hQccQ4bfAyqY6d5hN8tIERNBWzMIcn_fAH0SzQBI31Q,1087808
6
+ claude_code_analytics-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.9.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp311-abi3-macosx_11_0_arm64
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Darin Kishore
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
claude_sdk/__init__.py ADDED
@@ -0,0 +1,139 @@
1
+ """Claude SDK - Python wrapper for Claude Code sessions.
2
+
3
+ This SDK provides a clean interface for parsing and analyzing Claude Code
4
+ JSONL session files. It allows you to load session data, access messages, and analyze
5
+ costs, tool usage, and conversation patterns.
6
+ """
7
+
8
+ from pathlib import Path
9
+ from typing import Optional, Union, List
10
+
11
+ # Import from Rust core
12
+ try:
13
+ from claude_sdk._core import (
14
+ # Main functions
15
+ load,
16
+ find_sessions as _find_sessions_internal,
17
+ find_projects as _find_projects_internal,
18
+ load_project as _load_project_internal,
19
+ # Classes
20
+ Session,
21
+ Message,
22
+ Project,
23
+ # Model classes
24
+ SessionMetadata,
25
+ ToolResult,
26
+ ToolExecution,
27
+ ConversationStats,
28
+ ConversationNode,
29
+ ConversationTree,
30
+ TextBlock,
31
+ ToolUseBlock,
32
+ ThinkingBlock,
33
+ ImageBlock,
34
+ ToolResultBlock,
35
+ TokenUsage,
36
+ # Exceptions
37
+ ClaudeSDKError,
38
+ ParseError,
39
+ ValidationError,
40
+ SessionError,
41
+ )
42
+ except ImportError as e:
43
+ raise ImportError(
44
+ "Failed to import Rust core module. Make sure the package was built with maturin."
45
+ ) from e
46
+
47
+ __version__ = "0.1.0"
48
+
49
+ # All classes are now imported from Rust
50
+
51
+
52
+ # The load function is already imported from Rust, no need to redefine it
53
+
54
+
55
+ def find_sessions(
56
+ base_path: Optional[Union[str, Path]] = None,
57
+ project: Optional[Union[str, Path]] = None
58
+ ) -> List[Path]:
59
+ """Find Claude Code session files.
60
+
61
+ Args:
62
+ base_path: Directory to search (defaults to ~/.claude/projects/)
63
+ project: Optional project name/path to filter by
64
+
65
+ Returns:
66
+ List of paths to JSONL session files
67
+ """
68
+ base_path_str = str(base_path) if base_path else None
69
+ project_str = str(project) if project else None
70
+
71
+ paths = _find_sessions_internal(base_path_str, project_str)
72
+ return [Path(p) for p in paths]
73
+
74
+
75
+ def find_projects(base_path: Optional[Union[str, Path]] = None) -> List[Path]:
76
+ """Find Claude Code project directories.
77
+
78
+ Args:
79
+ base_path: Directory to search (defaults to ~/.claude/projects/)
80
+
81
+ Returns:
82
+ List of paths to project directories
83
+ """
84
+ base_path_str = str(base_path) if base_path else None
85
+ paths = _find_projects_internal(base_path_str)
86
+ return [Path(p) for p in paths]
87
+
88
+
89
+ def load_project(
90
+ project_identifier: Union[str, Path],
91
+ base_path: Optional[Union[str, Path]] = None
92
+ ) -> Project:
93
+ """Load a Claude Code project by name or path.
94
+
95
+ Args:
96
+ project_identifier: Project name or full path
97
+ base_path: Base directory to search in
98
+
99
+ Returns:
100
+ Project: Project object with all sessions loaded
101
+ """
102
+ project_str = str(project_identifier)
103
+ base_path_str = str(base_path) if base_path else None
104
+
105
+ return _load_project_internal(project_str, base_path_str)
106
+
107
+
108
+ # Type exports for static analysis
109
+ __all__ = [
110
+ # Error handling
111
+ "ClaudeSDKError",
112
+ "ParseError",
113
+ "ValidationError",
114
+ "SessionError",
115
+ # Main classes
116
+ "Session",
117
+ "Message",
118
+ "Project",
119
+ # Model classes
120
+ "SessionMetadata",
121
+ "ToolResult",
122
+ "ToolExecution",
123
+ "ConversationStats",
124
+ "ConversationNode",
125
+ "ConversationTree",
126
+ "TextBlock",
127
+ "ToolUseBlock",
128
+ "ThinkingBlock",
129
+ "ImageBlock",
130
+ "ToolResultBlock",
131
+ "TokenUsage",
132
+ # Functions
133
+ "load",
134
+ "find_sessions",
135
+ "find_projects",
136
+ "load_project",
137
+ # Version
138
+ "__version__",
139
+ ]
Binary file