claude-code-log 0.2.2__tar.gz → 0.2.3__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.
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/.claude/settings.local.json +5 -1
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/CHANGELOG.md +6 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/PKG-INFO +8 -6
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/README.md +7 -5
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/claude_code_log/converter.py +6 -1
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/claude_code_log/models.py +0 -29
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/claude_code_log/parser.py +4 -3
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/claude_code_log/renderer.py +58 -33
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/claude_code_log/templates/transcript.html +80 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/pyproject.toml +2 -1
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/scripts/style_guide_output/index_style_guide.html +69 -45
- claude_code_log-0.2.3/scripts/style_guide_output/transcript_style_guide.html +689 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_command_handling.py +3 -1
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_data/edge_cases.jsonl +6 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_template_rendering.py +2 -1
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_todowrite_rendering.py +1 -1
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/uv.lock +12 -1
- claude_code_log-0.2.2/scripts/style_guide_output/transcript_style_guide.html +0 -430
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/.github/workflows/ci.yml +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/.gitignore +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/CLAUDE.md +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/LICENSE +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/claude_code_log/__init__.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/claude_code_log/cli.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/claude_code_log/py.typed +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/claude_code_log/templates/index.html +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/justfile +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/scripts/generate_style_guide.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/scripts/style_guide_output/index.html +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/README.md +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/__init__.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_data/representative_messages.jsonl +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_data/session_b.jsonl +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_data/todowrite_examples.jsonl +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_date_filtering.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_filtering.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_markdown_rendering.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_message_filtering.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_message_types.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_path_conversion.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_template_data.py +0 -0
- {claude_code_log-0.2.2 → claude_code_log-0.2.3}/test/test_template_utils.py +0 -0
|
@@ -24,7 +24,11 @@
|
|
|
24
24
|
"Bash(rg:*)",
|
|
25
25
|
"Bash(act:*)",
|
|
26
26
|
"Bash(just render-test-data:*)",
|
|
27
|
-
"Bash(find:*)"
|
|
27
|
+
"Bash(find:*)",
|
|
28
|
+
"Bash(open /tmp/test_output.html)",
|
|
29
|
+
"Bash(open /Users/dain/workspace/claude-code-log/scripts/style_guide_output/transcript_style_guide.html)",
|
|
30
|
+
"Bash(open /tmp/test_preview.html)",
|
|
31
|
+
"Bash(open /tmp/test_improved_preview.html)"
|
|
28
32
|
],
|
|
29
33
|
"deny": []
|
|
30
34
|
}
|
|
@@ -5,6 +5,12 @@ All notable changes to claude-code-log will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.3] - 2025-06-16
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Error handling**: Add more detailed error handling
|
|
13
|
+
|
|
8
14
|
## [0.2.2] - 2025-06-16
|
|
9
15
|
|
|
10
16
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-code-log
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Convert Claude Code transcript JSONL files to HTML
|
|
5
5
|
Project-URL: Homepage, https://github.com/daaain/claude-code-log
|
|
6
6
|
Project-URL: Issues, https://github.com/daaain/claude-code-log/issues
|
|
@@ -21,6 +21,8 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
|
|
22
22
|
A Python CLI tool that converts Claude Code transcript JSONL files into readable HTML format.
|
|
23
23
|
|
|
24
|
+
[claude_code_log.webm](https://github.com/user-attachments/assets/12d94faf-6901-4429-b4e6-ea5f102d0c1c)
|
|
25
|
+
|
|
24
26
|
## Project Overview
|
|
25
27
|
|
|
26
28
|
📋 **[View Changelog](CHANGELOG.md)** - See what's new in each release
|
|
@@ -41,11 +43,10 @@ uvx claude-code-log --open-browser
|
|
|
41
43
|
- **Single File or Directory Processing**: Convert individual JSONL files or specific directories
|
|
42
44
|
- **Chronological Ordering**: All messages sorted by timestamp across sessions
|
|
43
45
|
- **Session Demarcation**: Clear visual separators between different transcript sessions
|
|
44
|
-
- **User-Focused**: Shows only user messages by default (assistant responses filtered out)
|
|
45
46
|
- **Date Range Filtering**: Filter messages by date range using natural language (e.g., "today", "yesterday", "last week")
|
|
46
|
-
- **Summary Support**: Display summary messages with
|
|
47
|
+
- **Summary Support**: Display summary messages matched with corresponding sessions
|
|
47
48
|
- **System Command Visibility**: Show system commands (like `init`) in expandable details
|
|
48
|
-
- **Markdown Rendering**: Automatic markdown rendering in message content
|
|
49
|
+
- **Markdown Rendering**: Automatic markdown rendering in assistant message content
|
|
49
50
|
- **Project Navigation**: Master index page with project statistics and quick navigation
|
|
50
51
|
- **Space-Efficient Layout**: Compact design optimized for content density
|
|
51
52
|
- **CLI Interface**: Simple command-line tool using Click
|
|
@@ -116,7 +117,7 @@ The project uses:
|
|
|
116
117
|
- dateparser for natural language date parsing
|
|
117
118
|
- Standard library for JSON/HTML processing
|
|
118
119
|
- Minimal dependencies for portability
|
|
119
|
-
-
|
|
120
|
+
- mistune for quick Markdown rendering
|
|
120
121
|
|
|
121
122
|
## Development Commands
|
|
122
123
|
|
|
@@ -232,6 +233,7 @@ uv run claude-code-log
|
|
|
232
233
|
|
|
233
234
|
## TODO
|
|
234
235
|
|
|
235
|
-
- Show top level stats on index page
|
|
236
|
+
- **Show top level stats on index page**: token usage added up + time of last interaction
|
|
236
237
|
- **Tool Use Preview**: Show first few lines of tool use and other collapsed details
|
|
237
238
|
- **In-page Filtering**: Client-side filtering and search
|
|
239
|
+
- **Timeline view**: Show interaction on a timeline to get a better idea on timings and parallel calls
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
A Python CLI tool that converts Claude Code transcript JSONL files into readable HTML format.
|
|
4
4
|
|
|
5
|
+
[claude_code_log.webm](https://github.com/user-attachments/assets/12d94faf-6901-4429-b4e6-ea5f102d0c1c)
|
|
6
|
+
|
|
5
7
|
## Project Overview
|
|
6
8
|
|
|
7
9
|
📋 **[View Changelog](CHANGELOG.md)** - See what's new in each release
|
|
@@ -22,11 +24,10 @@ uvx claude-code-log --open-browser
|
|
|
22
24
|
- **Single File or Directory Processing**: Convert individual JSONL files or specific directories
|
|
23
25
|
- **Chronological Ordering**: All messages sorted by timestamp across sessions
|
|
24
26
|
- **Session Demarcation**: Clear visual separators between different transcript sessions
|
|
25
|
-
- **User-Focused**: Shows only user messages by default (assistant responses filtered out)
|
|
26
27
|
- **Date Range Filtering**: Filter messages by date range using natural language (e.g., "today", "yesterday", "last week")
|
|
27
|
-
- **Summary Support**: Display summary messages with
|
|
28
|
+
- **Summary Support**: Display summary messages matched with corresponding sessions
|
|
28
29
|
- **System Command Visibility**: Show system commands (like `init`) in expandable details
|
|
29
|
-
- **Markdown Rendering**: Automatic markdown rendering in message content
|
|
30
|
+
- **Markdown Rendering**: Automatic markdown rendering in assistant message content
|
|
30
31
|
- **Project Navigation**: Master index page with project statistics and quick navigation
|
|
31
32
|
- **Space-Efficient Layout**: Compact design optimized for content density
|
|
32
33
|
- **CLI Interface**: Simple command-line tool using Click
|
|
@@ -97,7 +98,7 @@ The project uses:
|
|
|
97
98
|
- dateparser for natural language date parsing
|
|
98
99
|
- Standard library for JSON/HTML processing
|
|
99
100
|
- Minimal dependencies for portability
|
|
100
|
-
-
|
|
101
|
+
- mistune for quick Markdown rendering
|
|
101
102
|
|
|
102
103
|
## Development Commands
|
|
103
104
|
|
|
@@ -213,6 +214,7 @@ uv run claude-code-log
|
|
|
213
214
|
|
|
214
215
|
## TODO
|
|
215
216
|
|
|
216
|
-
- Show top level stats on index page
|
|
217
|
+
- **Show top level stats on index page**: token usage added up + time of last interaction
|
|
217
218
|
- **Tool Use Preview**: Show first few lines of tool use and other collapsed details
|
|
218
219
|
- **In-page Filtering**: Client-side filtering and search
|
|
220
|
+
- **Timeline view**: Show interaction on a timeline to get a better idea on timings and parallel calls
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""Convert Claude transcript JSONL files to HTML."""
|
|
3
3
|
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
import traceback
|
|
5
6
|
from typing import List, Optional, Dict, Any
|
|
6
7
|
|
|
7
8
|
from .parser import (
|
|
@@ -107,7 +108,11 @@ def process_projects_hierarchy(
|
|
|
107
108
|
}
|
|
108
109
|
)
|
|
109
110
|
except Exception as e:
|
|
110
|
-
print(
|
|
111
|
+
print(
|
|
112
|
+
f"Warning: Failed to process {project_dir}: {e}\n"
|
|
113
|
+
f"Previous (in alphabetical order) file before error: {project_summaries[-1]}\n"
|
|
114
|
+
f"Traceback:\n{traceback.format_exc()}"
|
|
115
|
+
)
|
|
111
116
|
continue
|
|
112
117
|
|
|
113
118
|
# Generate index HTML
|
|
@@ -215,32 +215,3 @@ def parse_transcript_entry(data: Dict[str, Any]) -> TranscriptEntry:
|
|
|
215
215
|
return SummaryTranscriptEntry.model_validate(data)
|
|
216
216
|
else:
|
|
217
217
|
raise ValueError(f"Unknown transcript entry type: {entry_type}")
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
def try_parse_transcript_entry(entry_dict: Dict[str, Any]) -> Optional[TranscriptEntry]:
|
|
221
|
-
"""Try to parse a transcript entry, returning None if parsing fails."""
|
|
222
|
-
try:
|
|
223
|
-
return parse_transcript_entry(entry_dict)
|
|
224
|
-
except Exception:
|
|
225
|
-
return None
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
def parse_transcript_entry_with_fallback(
|
|
229
|
-
entry_dict: Dict[str, Any],
|
|
230
|
-
) -> Optional[TranscriptEntry]:
|
|
231
|
-
"""
|
|
232
|
-
Try to parse a transcript entry against different Pydantic models.
|
|
233
|
-
|
|
234
|
-
This function attempts to parse the entry using each model type in order,
|
|
235
|
-
using proper content parsing to avoid Union validation errors.
|
|
236
|
-
|
|
237
|
-
Args:
|
|
238
|
-
entry_dict: Dictionary parsed from JSON
|
|
239
|
-
|
|
240
|
-
Returns:
|
|
241
|
-
The appropriate TranscriptEntry subclass, or None if parsing fails
|
|
242
|
-
"""
|
|
243
|
-
try:
|
|
244
|
-
return parse_transcript_entry(entry_dict)
|
|
245
|
-
except Exception:
|
|
246
|
-
return None
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import json
|
|
5
5
|
from pathlib import Path
|
|
6
|
+
import traceback
|
|
6
7
|
from typing import List, Optional, Union, Dict
|
|
7
8
|
from datetime import datetime
|
|
8
9
|
import dateparser
|
|
@@ -109,7 +110,7 @@ def load_transcript(jsonl_path: Path) -> List[TranscriptEntry]:
|
|
|
109
110
|
if line:
|
|
110
111
|
try:
|
|
111
112
|
entry_dict = json.loads(line)
|
|
112
|
-
entry_type = entry_dict.get("type", "unknown")
|
|
113
|
+
entry_type = entry_dict.get("type", "unknown, missing type")
|
|
113
114
|
|
|
114
115
|
if entry_type in ["user", "assistant", "summary"]:
|
|
115
116
|
# Parse using Pydantic models
|
|
@@ -121,7 +122,7 @@ def load_transcript(jsonl_path: Path) -> List[TranscriptEntry]:
|
|
|
121
122
|
unhandled_types.get(entry_type, 0) + 1
|
|
122
123
|
)
|
|
123
124
|
except json.JSONDecodeError as e:
|
|
124
|
-
error_key = f"JSON decode error: {
|
|
125
|
+
error_key = f"JSON decode error: {str(e)}"
|
|
125
126
|
unique_errors[error_key] = unique_errors.get(error_key, 0) + 1
|
|
126
127
|
except ValueError as e:
|
|
127
128
|
# Extract a more descriptive error message
|
|
@@ -132,7 +133,7 @@ def load_transcript(jsonl_path: Path) -> List[TranscriptEntry]:
|
|
|
132
133
|
error_key = f"ValueError: {error_msg[:200]}..."
|
|
133
134
|
unique_errors[error_key] = unique_errors.get(error_key, 0) + 1
|
|
134
135
|
except Exception as e:
|
|
135
|
-
error_key = f"Unexpected error: {
|
|
136
|
+
error_key = f"Unexpected error: {str(e)}\n{traceback.format_exc()}"
|
|
136
137
|
unique_errors[error_key] = unique_errors.get(error_key, 0) + 1
|
|
137
138
|
|
|
138
139
|
# Print summary of errors if any occurred
|
|
@@ -37,6 +37,41 @@ def escape_html(text: str) -> str:
|
|
|
37
37
|
return html.escape(text)
|
|
38
38
|
|
|
39
39
|
|
|
40
|
+
def create_collapsible_details(
|
|
41
|
+
summary: str, content: str, css_classes: str = ""
|
|
42
|
+
) -> str:
|
|
43
|
+
"""Create a collapsible details element with consistent styling and preview functionality."""
|
|
44
|
+
class_attr = ' class="collapsible-details"'
|
|
45
|
+
wrapper_classes = f"tool-content{' ' + css_classes if css_classes else ''}"
|
|
46
|
+
|
|
47
|
+
# Extract first few lines for preview (up to ~3-5 lines, roughly 200 chars)
|
|
48
|
+
import re
|
|
49
|
+
|
|
50
|
+
# Remove HTML tags and get plain text for preview
|
|
51
|
+
plain_text = re.sub(r"<[^>]+>", "", content)
|
|
52
|
+
# Get first ~200 characters, break at word boundaries
|
|
53
|
+
preview_text = plain_text[:200]
|
|
54
|
+
if len(plain_text) > 200:
|
|
55
|
+
preview_text = preview_text.rsplit(" ", 1)[0] + "..."
|
|
56
|
+
|
|
57
|
+
# Render preview as markdown for better formatting
|
|
58
|
+
preview_html = render_markdown(preview_text)
|
|
59
|
+
|
|
60
|
+
return f"""
|
|
61
|
+
<div class="{wrapper_classes}">
|
|
62
|
+
<details{class_attr}>
|
|
63
|
+
<summary>
|
|
64
|
+
{summary}
|
|
65
|
+
<div class="preview-content">{preview_html}</div>
|
|
66
|
+
</summary>
|
|
67
|
+
<div class="details-content">
|
|
68
|
+
{content}
|
|
69
|
+
</div>
|
|
70
|
+
</details>
|
|
71
|
+
</div>
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
|
|
40
75
|
def render_markdown(text: str) -> str:
|
|
41
76
|
"""Convert markdown text to HTML using mistune."""
|
|
42
77
|
# Configure mistune with GitHub-flavored markdown features
|
|
@@ -172,18 +207,16 @@ def format_tool_use_content(tool_use: ToolUseContent) -> str:
|
|
|
172
207
|
except (TypeError, ValueError):
|
|
173
208
|
escaped_input = escape_html(str(tool_use.input))
|
|
174
209
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<
|
|
178
|
-
<
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
<pre>{escaped_input}</pre>
|
|
182
|
-
</div>
|
|
183
|
-
</details>
|
|
184
|
-
</div>
|
|
210
|
+
summary = f"<strong>🛠️ Tool Use:</strong> {escaped_name} (ID: {escaped_id})"
|
|
211
|
+
content = f"""
|
|
212
|
+
<div class="tool-input">
|
|
213
|
+
<strong>Input:</strong>
|
|
214
|
+
<pre>{escaped_input}</pre>
|
|
215
|
+
</div>
|
|
185
216
|
"""
|
|
186
217
|
|
|
218
|
+
return create_collapsible_details(summary, content, "tool-use")
|
|
219
|
+
|
|
187
220
|
|
|
188
221
|
def format_tool_result_content(tool_result: ToolResultContent) -> str:
|
|
189
222
|
"""Format tool result content as HTML."""
|
|
@@ -197,37 +230,27 @@ def format_tool_result_content(tool_result: ToolResultContent) -> str:
|
|
|
197
230
|
content_parts: List[str] = []
|
|
198
231
|
for item in tool_result.content:
|
|
199
232
|
if item.get("type") == "text":
|
|
200
|
-
|
|
233
|
+
text_value = item.get("text")
|
|
234
|
+
if isinstance(text_value, str):
|
|
235
|
+
content_parts.append(text_value)
|
|
201
236
|
escaped_content = escape_html("\n".join(content_parts))
|
|
202
237
|
|
|
203
238
|
error_indicator = " (🚨 Error)" if tool_result.is_error else ""
|
|
204
239
|
|
|
205
|
-
|
|
206
|
-
<div class="tool-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
<div class="tool-input">
|
|
210
|
-
<pre>{escaped_content}</pre>
|
|
211
|
-
</div>
|
|
212
|
-
</details>
|
|
213
|
-
</div>
|
|
214
|
-
"""
|
|
240
|
+
summary = f"<strong>🧰 Tool Result{error_indicator}:</strong> {escaped_id}"
|
|
241
|
+
content = f'<div class="tool-input"><pre>{escaped_content}</pre></div>'
|
|
242
|
+
|
|
243
|
+
return create_collapsible_details(summary, content, "tool-result")
|
|
215
244
|
|
|
216
245
|
|
|
217
246
|
def format_thinking_content(thinking: ThinkingContent) -> str:
|
|
218
247
|
"""Format thinking content as HTML."""
|
|
219
248
|
escaped_thinking = escape_html(thinking.thinking)
|
|
220
249
|
|
|
221
|
-
|
|
222
|
-
<div class="
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
<div class="thinking-text">
|
|
226
|
-
<pre>{escaped_thinking}</pre>
|
|
227
|
-
</div>
|
|
228
|
-
</details>
|
|
229
|
-
</div>
|
|
230
|
-
"""
|
|
250
|
+
summary = "<strong>💭 Thinking</strong>"
|
|
251
|
+
content = f'<div class="thinking-text"><pre>{escaped_thinking}</pre></div>'
|
|
252
|
+
|
|
253
|
+
return create_collapsible_details(summary, content, "thinking-content")
|
|
231
254
|
|
|
232
255
|
|
|
233
256
|
def format_image_content(image: ImageContent) -> str:
|
|
@@ -595,9 +618,11 @@ def generate_html(messages: List[TranscriptEntry], title: Optional[str] = None)
|
|
|
595
618
|
if command_args:
|
|
596
619
|
content_parts.append(f"<strong>Args:</strong> {escaped_command_args}")
|
|
597
620
|
if command_contents:
|
|
598
|
-
|
|
599
|
-
f"<
|
|
621
|
+
details_content = (
|
|
622
|
+
f"<div class='content'>{escaped_command_contents}</div>"
|
|
600
623
|
)
|
|
624
|
+
details_html = create_collapsible_details("Content", details_content)
|
|
625
|
+
content_parts.append(details_html)
|
|
601
626
|
|
|
602
627
|
content_html = "<br>".join(content_parts)
|
|
603
628
|
message_type = "system"
|
|
@@ -60,6 +60,86 @@
|
|
|
60
60
|
margin-bottom: 8px;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/* Collapsible details preview functionality */
|
|
64
|
+
.collapsible-details {
|
|
65
|
+
position: relative;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.collapsible-details summary {
|
|
69
|
+
position: relative;
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Preview content styling - shown when closed */
|
|
74
|
+
.collapsible-details:not([open]) .preview-content {
|
|
75
|
+
display: block;
|
|
76
|
+
margin-top: 8px;
|
|
77
|
+
padding: 6px 8px;
|
|
78
|
+
background-color: rgba(255, 255, 255, 0.3);
|
|
79
|
+
border-radius: 3px;
|
|
80
|
+
font-size: 0.9em;
|
|
81
|
+
font-weight: normal;
|
|
82
|
+
color: #555;
|
|
83
|
+
line-height: 1.3;
|
|
84
|
+
white-space: pre-wrap;
|
|
85
|
+
word-wrap: break-word;
|
|
86
|
+
position: relative;
|
|
87
|
+
max-height: 4em;
|
|
88
|
+
overflow: hidden;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Add subtle fade effect to preview content */
|
|
92
|
+
.collapsible-details:not([open]) .preview-content::after {
|
|
93
|
+
content: "";
|
|
94
|
+
position: absolute;
|
|
95
|
+
bottom: 0;
|
|
96
|
+
left: 0;
|
|
97
|
+
right: 0;
|
|
98
|
+
height: 1em;
|
|
99
|
+
background: linear-gradient(transparent, rgba(255, 255, 255, 0.3));
|
|
100
|
+
pointer-events: none;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Hide preview content when details is open */
|
|
104
|
+
.collapsible-details[open] .preview-content {
|
|
105
|
+
display: none;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Style the full details content to match preview */
|
|
109
|
+
.collapsible-details .details-content {
|
|
110
|
+
margin-top: 8px;
|
|
111
|
+
padding: 6px 8px;
|
|
112
|
+
background-color: rgba(255, 255, 255, 0.3);
|
|
113
|
+
border-radius: 3px;
|
|
114
|
+
font-size: 0.9em;
|
|
115
|
+
font-weight: normal;
|
|
116
|
+
color: #555;
|
|
117
|
+
line-height: 1.3;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Hide details content when closed */
|
|
121
|
+
.collapsible-details:not([open]) .details-content {
|
|
122
|
+
display: none;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Remove extra styling from nested elements */
|
|
126
|
+
.collapsible-details .details-content .tool-input {
|
|
127
|
+
background-color: transparent;
|
|
128
|
+
border: none;
|
|
129
|
+
box-shadow: none;
|
|
130
|
+
padding: 0;
|
|
131
|
+
margin: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.collapsible-details .details-content pre {
|
|
135
|
+
background-color: transparent;
|
|
136
|
+
padding: 0;
|
|
137
|
+
margin: 0;
|
|
138
|
+
font-family: inherit;
|
|
139
|
+
font-size: inherit;
|
|
140
|
+
color: inherit;
|
|
141
|
+
}
|
|
142
|
+
|
|
63
143
|
.tool-content {
|
|
64
144
|
background-color: #f8f9fa66;
|
|
65
145
|
border-radius: 4px;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "claude-code-log"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.3"
|
|
4
4
|
description = "Convert Claude Code transcript JSONL files to HTML"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -95,4 +95,5 @@ dev = [
|
|
|
95
95
|
"ruff>=0.11.2",
|
|
96
96
|
"pytest-xdist>=3.6.1",
|
|
97
97
|
"pyright>=1.1.350",
|
|
98
|
+
"vulture>=2.14",
|
|
98
99
|
]
|
{claude_code_log-0.2.2 → claude_code_log-0.2.3}/scripts/style_guide_output/index_style_guide.html
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang='en'>
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset='UTF-8'>
|
|
5
6
|
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
|
@@ -11,43 +12,54 @@
|
|
|
11
12
|
max-width: 1200px;
|
|
12
13
|
margin: 0 auto;
|
|
13
14
|
padding: 20px;
|
|
14
|
-
background
|
|
15
|
+
background: linear-gradient(90deg, #f3d6d2, #f1dcce, #f0e4ca, #eeecc7, #e3ecc3, #d5eac0, #c6e8bd, #b9e6bc, #b6e3c5, #b3e1cf);
|
|
15
16
|
color: #333;
|
|
16
17
|
}
|
|
18
|
+
|
|
17
19
|
h1 {
|
|
18
20
|
text-align: center;
|
|
19
21
|
color: #2c3e50;
|
|
20
22
|
margin-bottom: 30px;
|
|
21
23
|
font-size: 2em;
|
|
22
24
|
}
|
|
25
|
+
|
|
23
26
|
.project-list {
|
|
24
27
|
display: grid;
|
|
25
28
|
gap: 15px;
|
|
26
29
|
}
|
|
30
|
+
|
|
27
31
|
.project-card {
|
|
28
|
-
background:
|
|
32
|
+
background-color: #ffffff66;
|
|
29
33
|
border-radius: 8px;
|
|
30
34
|
padding: 20px;
|
|
31
|
-
box-shadow:
|
|
32
|
-
border-left:
|
|
35
|
+
box-shadow: -7px -7px 10px #eeeeee44, 7px 7px 10px #00000011;
|
|
36
|
+
border-left: #ffffff66 1px solid;
|
|
37
|
+
border-top: #ffffff66 1px solid;
|
|
38
|
+
border-bottom: #00000017 1px solid;
|
|
39
|
+
border-right: #00000017 1px solid;
|
|
33
40
|
}
|
|
41
|
+
|
|
34
42
|
.project-card:hover {
|
|
35
|
-
box-shadow:
|
|
43
|
+
box-shadow: -10px -10px 15px #eeeeee66, 10px 10px 15px #00000022;
|
|
36
44
|
transform: translateY(-1px);
|
|
37
45
|
transition: all 0.2s ease;
|
|
38
46
|
}
|
|
47
|
+
|
|
39
48
|
.project-name {
|
|
40
49
|
font-size: 1.2em;
|
|
41
50
|
font-weight: 600;
|
|
42
51
|
margin-bottom: 10px;
|
|
43
52
|
}
|
|
53
|
+
|
|
44
54
|
.project-name a {
|
|
45
55
|
text-decoration: none;
|
|
46
56
|
color: #2196f3;
|
|
47
57
|
}
|
|
58
|
+
|
|
48
59
|
.project-name a:hover {
|
|
49
60
|
text-decoration: underline;
|
|
50
61
|
}
|
|
62
|
+
|
|
51
63
|
.project-stats {
|
|
52
64
|
color: #666;
|
|
53
65
|
font-size: 0.9em;
|
|
@@ -55,42 +67,53 @@
|
|
|
55
67
|
gap: 20px;
|
|
56
68
|
flex-wrap: wrap;
|
|
57
69
|
}
|
|
70
|
+
|
|
58
71
|
.stat {
|
|
59
72
|
display: flex;
|
|
60
73
|
align-items: center;
|
|
61
74
|
gap: 5px;
|
|
62
75
|
}
|
|
76
|
+
|
|
63
77
|
.summary {
|
|
64
78
|
text-align: center;
|
|
65
79
|
margin-bottom: 30px;
|
|
66
80
|
padding: 15px;
|
|
67
|
-
background:
|
|
81
|
+
background-color: #ffffff66;
|
|
68
82
|
border-radius: 8px;
|
|
69
|
-
box-shadow:
|
|
83
|
+
box-shadow: -7px -7px 10px #eeeeee44, 7px 7px 10px #00000011;
|
|
84
|
+
border-left: #ffffff66 1px solid;
|
|
85
|
+
border-top: #ffffff66 1px solid;
|
|
86
|
+
border-bottom: #00000017 1px solid;
|
|
87
|
+
border-right: #00000017 1px solid;
|
|
70
88
|
}
|
|
89
|
+
|
|
71
90
|
.summary-stats {
|
|
72
91
|
display: flex;
|
|
73
92
|
justify-content: center;
|
|
74
93
|
gap: 30px;
|
|
75
94
|
flex-wrap: wrap;
|
|
76
95
|
}
|
|
96
|
+
|
|
77
97
|
.summary-stat {
|
|
78
98
|
text-align: center;
|
|
79
99
|
}
|
|
100
|
+
|
|
80
101
|
.summary-stat .number {
|
|
81
102
|
font-size: 1.5em;
|
|
82
103
|
font-weight: 600;
|
|
83
104
|
color: #2196f3;
|
|
84
105
|
}
|
|
106
|
+
|
|
85
107
|
.summary-stat .label {
|
|
86
108
|
color: #666;
|
|
87
109
|
font-size: 0.9em;
|
|
88
110
|
}
|
|
89
111
|
</style>
|
|
90
112
|
</head>
|
|
113
|
+
|
|
91
114
|
<body>
|
|
92
115
|
<h1>Claude Code Projects (from last week to today)</h1>
|
|
93
|
-
|
|
116
|
+
|
|
94
117
|
<div class='summary'>
|
|
95
118
|
<div class='summary-stats'>
|
|
96
119
|
<div class='summary-stat'>
|
|
@@ -107,53 +130,54 @@
|
|
|
107
130
|
</div>
|
|
108
131
|
</div>
|
|
109
132
|
</div>
|
|
110
|
-
|
|
133
|
+
|
|
111
134
|
<div class='project-list'>
|
|
112
135
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
</div>
|
|
117
|
-
<div class='project-stats'>
|
|
118
|
-
<div class='stat'>📁 12 transcript files</div>
|
|
119
|
-
<div class='stat'>💬 445 messages</div>
|
|
120
|
-
<div class='stat'>🕒 2023-11-15 19:03</div>
|
|
121
|
-
</div>
|
|
136
|
+
<div class='project-card'>
|
|
137
|
+
<div class='project-name'>
|
|
138
|
+
<a href='-org-internal-tools-automation/combined_transcripts.html'>org/internal/tools/automation</a>
|
|
122
139
|
</div>
|
|
140
|
+
<div class='project-stats'>
|
|
141
|
+
<div class='stat'>📁 12 transcript files</div>
|
|
142
|
+
<div class='stat'>💬 445 messages</div>
|
|
143
|
+
<div class='stat'>🕒 2023-11-15 19:03</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
123
146
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
</div>
|
|
128
|
-
<div class='project-stats'>
|
|
129
|
-
<div class='stat'>📁 8 transcript files</div>
|
|
130
|
-
<div class='stat'>💬 203 messages</div>
|
|
131
|
-
<div class='stat'>🕒 2023-11-15 12:06</div>
|
|
132
|
-
</div>
|
|
147
|
+
<div class='project-card'>
|
|
148
|
+
<div class='project-name'>
|
|
149
|
+
<a href='-user-workspace-my-web-app/combined_transcripts.html'>user/workspace/my/web/app</a>
|
|
133
150
|
</div>
|
|
151
|
+
<div class='project-stats'>
|
|
152
|
+
<div class='stat'>📁 8 transcript files</div>
|
|
153
|
+
<div class='stat'>💬 203 messages</div>
|
|
154
|
+
<div class='stat'>🕒 2023-11-15 12:06</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
134
157
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
</div>
|
|
139
|
-
<div class='project-stats'>
|
|
140
|
-
<div class='stat'>📁 3 transcript files</div>
|
|
141
|
-
<div class='stat'>💬 89 messages</div>
|
|
142
|
-
<div class='stat'>🕒 2023-11-15 05:10</div>
|
|
143
|
-
</div>
|
|
158
|
+
<div class='project-card'>
|
|
159
|
+
<div class='project-name'>
|
|
160
|
+
<a href='data-analysis-project/combined_transcripts.html'>data-analysis-project</a>
|
|
144
161
|
</div>
|
|
162
|
+
<div class='project-stats'>
|
|
163
|
+
<div class='stat'>📁 3 transcript files</div>
|
|
164
|
+
<div class='stat'>💬 89 messages</div>
|
|
165
|
+
<div class='stat'>🕒 2023-11-15 05:10</div>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
145
168
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
</div>
|
|
150
|
-
<div class='project-stats'>
|
|
151
|
-
<div class='stat'>📁 5 transcript files</div>
|
|
152
|
-
<div class='stat'>💬 127 messages</div>
|
|
153
|
-
<div class='stat'>🕒 2023-11-14 22:13</div>
|
|
154
|
-
</div>
|
|
169
|
+
<div class='project-card'>
|
|
170
|
+
<div class='project-name'>
|
|
171
|
+
<a href='claude-code-assistant/combined_transcripts.html'>claude-code-assistant</a>
|
|
155
172
|
</div>
|
|
173
|
+
<div class='project-stats'>
|
|
174
|
+
<div class='stat'>📁 5 transcript files</div>
|
|
175
|
+
<div class='stat'>💬 127 messages</div>
|
|
176
|
+
<div class='stat'>🕒 2023-11-14 22:13</div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
156
179
|
|
|
157
180
|
</div>
|
|
158
181
|
</body>
|
|
182
|
+
|
|
159
183
|
</html>
|