Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
os: ["ubuntu-latest", "windows-latest"]
python-version: ["3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
include:
- os: "ubuntu-latest"
python-version: "3.12"
Expand Down
43 changes: 0 additions & 43 deletions .github/workflows/docs.yml

This file was deleted.

4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,7 @@ test/test_data/*.html
.claude/settings.local.json
.vscode/settings.json
local.ps1

# Generated documentation examples (uploaded to GitHub releases instead)
docs/claude-code-log-transcript.html
docs/cache/
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [0.8.0] - 2025-11-08

### Changed

- **Regenerate HTML files + couple tiny changes**
- **Use Pygments to render files and code snippets (#39)**
- **Fix Unicode escape in tool use content rendering (#38)**
- **Introduce visual structure for the conversation and some specialized tool rendering (#37)**


## [0.7.0] - 2025-10-22

### Changed
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ claude-code-log /path/to/directory --from-date "3 days ago" --to-date "yesterday

The project uses:

- Python 3.12+ with uv package management
- Python 3.10+ with uv package management
- Click for CLI interface and argument parsing
- Textual for interactive Terminal User Interface
- Pydantic for robust data modelling and validation
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ TUI demo:

This tool generates clean, minimalist HTML pages showing user prompts and assistant responses chronologically. It's designed to create a readable log of your Claude Code interactions with support for both individual files and entire project hierarchies.

[See example log (generated from real usage on this project).](https://daaain.github.io/claude-code-log/claude-code-log-transcript.html)
📄 **[View Example HTML Output](https://github.com/daaain/claude-code-log/releases/latest/download/claude-code-log-transcript.html)** - Download a real example generated from this project's development (large file, ~100 MB)

## Quickstart

Expand Down Expand Up @@ -152,7 +152,7 @@ claude-code-log /path/to/directory --from-date "3 days ago" --to-date "yesterday

The project uses:

- Python 3.12+ with uv package management
- Python 3.10+ with uv package management
- Click for CLI interface and argument parsing
- Pydantic for robust data modeling and validation
- dateparser for natural language date parsing
Expand Down Expand Up @@ -379,7 +379,6 @@ uv run claude-code-log
- Localised number formatting and timezone adjustment runtime? For this we'd need to make Jinja template variables more granular
- convert images to WebP as screenshots are often huge PNGs – this might be time consuming to keep redoing (so would also need some caching) and need heavy dependencies with compilation (unless there are fast pure Python conversation libraries? Or WASM?)
- add special formatting for built-in tools: Bash, Glob, Grep, LS, exit_plan_mode, Read, Edit, MultiEdit, Write, NotebookRead, NotebookEdit, WebFetch, TodoRead, TodoWrite, WebSearch
- render Edit / MultiEdit as diff(s)?
- do we need to handle compacted conversation?
- Thinking block should have Markdown rendering as sometimes they have formatting
- system blocks like `init` also don't render perfectly, losing new lines
Expand Down
22 changes: 22 additions & 0 deletions claude_code_log/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,26 @@ class SystemTranscriptEntry(BaseTranscriptEntry):
level: Optional[str] = None # e.g., "warning", "info", "error"


class QueueOperationTranscriptEntry(BaseModel):
"""Queue operations (enqueue/dequeue) for message queueing tracking.

These are internal operations that track when messages are queued and dequeued.
They are parsed but not rendered, as the content duplicates actual user messages.
"""

type: Literal["queue-operation"]
operation: Literal["enqueue", "dequeue"]
timestamp: str
sessionId: str
content: Optional[List[ContentItem]] = None # Only present for enqueue operations


TranscriptEntry = Union[
UserTranscriptEntry,
AssistantTranscriptEntry,
SummaryTranscriptEntry,
SystemTranscriptEntry,
QueueOperationTranscriptEntry,
]


Expand Down Expand Up @@ -398,5 +413,12 @@ def parse_transcript_entry(data: Dict[str, Any]) -> TranscriptEntry:
elif entry_type == "system":
return SystemTranscriptEntry.model_validate(data)

elif entry_type == "queue-operation":
# Parse content if present (only in enqueue operations)
data_copy = data.copy()
if "content" in data_copy and isinstance(data_copy["content"], list):
data_copy["content"] = parse_message_content(data_copy["content"])
return QueueOperationTranscriptEntry.model_validate(data_copy)

else:
raise ValueError(f"Unknown transcript entry type: {entry_type}")
8 changes: 7 additions & 1 deletion claude_code_log/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,13 @@ def load_transcript(

entry_type: str | None = entry_dict.get("type")

if entry_type in ["user", "assistant", "summary", "system"]:
if entry_type in [
"user",
"assistant",
"summary",
"system",
"queue-operation",
]:
# Parse using Pydantic models
entry = parse_transcript_entry(entry_dict)
messages.append(entry)
Expand Down
Loading