claude-code-log 1.0.0__tar.gz → 1.1.1__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-1.1.1/.claude/skills/tool-renderer/SKILL.md +414 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/.vscode/settings.json +4 -1
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/CHANGELOG.md +30 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/CONTRIBUTING.md +3 -3
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/PKG-INFO +1 -2
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/README.md +0 -1
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/converter.py +14 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/factories/tool_factory.py +228 -9
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/__init__.py +4 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/renderer.py +38 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/global_styles.css +7 -1
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/message_styles.css +88 -4
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/tool_formatters.py +126 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/markdown/renderer.py +73 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/models.py +55 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/renderer.py +11 -2
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/tui.py +1 -0
- claude_code_log-1.1.1/dev-docs/implementing-a-tool-renderer.md +273 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/restoring-archived-sessions.md +25 -20
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/justfile +56 -56
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/pyproject.toml +3 -2
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/uv.lock +5 -5
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/.claude/settings.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/.github/workflows/ci.yml +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/.github/workflows/claude.yml +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/.gitignore +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/CLAUDE.md +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/LICENSE +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/__init__.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/cache.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/cli.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/factories/__init__.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/factories/assistant_factory.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/factories/meta_factory.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/factories/system_factory.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/factories/transcript_factory.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/factories/user_factory.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/ansi_colors.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/assistant_formatters.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/renderer_code.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/system_formatters.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/edit_diff_styles.css +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/filter_styles.css +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/page_nav_styles.css +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/project_card_styles.css +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/pygments_styles.css +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/search.html +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/search_inline.html +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/search_inline_script.html +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/search_results_panel.html +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/search_styles.css +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/session_nav.html +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/session_nav_styles.css +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/timeline.html +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/timeline_styles.css +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/timezone_converter.js +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/components/todo_styles.css +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/index.html +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/templates/transcript.html +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/user_formatters.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/html/utils.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/image_export.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/markdown/__init__.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/migrations/001_initial_schema.sql +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/migrations/002_html_cache.sql +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/migrations/003_html_pagination.sql +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/migrations/__init__.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/migrations/runner.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/parser.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/py.typed +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/renderer_timings.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/claude_code_log/utils.py +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/FOLD_STATE_DIAGRAM.md +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/css-classes.md +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/assistant/assistant.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/assistant/assistant.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/assistant/assistant_sidechain.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/assistant/assistant_sidechain.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/assistant/thinking.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/assistant/thinking.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/system/file_history_snapshot.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/system/file_history_snapshot.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/system/queue_operation.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/system/queue_operation.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/system/summary.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/system/summary.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/system/system_info.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/system/system_info.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/AskUserQuestion-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/AskUserQuestion-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/AskUserQuestion-tool_result_error.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/AskUserQuestion-tool_result_error.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/AskUserQuestion-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/AskUserQuestion-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Bash-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Bash-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Bash-tool_result_error.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Bash-tool_result_error.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Bash-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Bash-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/BashOutput-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/BashOutput-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/BashOutput-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/BashOutput-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Edit-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Edit-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Edit-tool_result_error.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Edit-tool_result_error.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Edit-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Edit-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/ExitPlanMode-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/ExitPlanMode-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/ExitPlanMode-tool_result_error.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/ExitPlanMode-tool_result_error.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/ExitPlanMode-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/ExitPlanMode-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Glob-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Glob-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Glob-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Glob-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Grep-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Grep-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Grep-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Grep-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/KillShell-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/KillShell-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/KillShell-tool_result_error.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/KillShell-tool_result_error.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/KillShell-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/KillShell-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/LS-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/LS-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/LS-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/LS-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/MultiEdit-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/MultiEdit-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/MultiEdit-tool_result_error.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/MultiEdit-tool_result_error.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/MultiEdit-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/MultiEdit-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Read-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Read-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Read-tool_result_error.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Read-tool_result_error.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Read-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Read-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Task-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Task-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Task-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Task-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/TodoWrite-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/TodoWrite-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/TodoWrite-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/TodoWrite-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/WebFetch-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/WebFetch-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/WebFetch-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/WebFetch-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/WebSearch-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/WebSearch-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/WebSearch-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/WebSearch-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Write-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Write-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Write-tool_result_error.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Write-tool_result_error.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Write-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/Write-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/exit_plan_mode-tool_result.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/exit_plan_mode-tool_result.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/exit_plan_mode-tool_use.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/tools/exit_plan_mode-tool_use.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/bash_input.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/bash_input.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/bash_output.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/bash_output.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/command_output.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/command_output.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/image.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/image.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/user.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/user.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/user_command.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/user_command.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/user_sidechain.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/user_sidechain.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/user_slash_command.json +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages/user/user_slash_command.jsonl +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/messages.md +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/rendering-architecture.md +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/dev-docs/rendering-next.md +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/mise.toml +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/stubs/pygments/__init__.pyi +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/stubs/pygments/formatter.pyi +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/stubs/pygments/formatters/__init__.pyi +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/stubs/pygments/lexer.pyi +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/stubs/pygments/lexers/__init__.pyi +0 -0
- {claude_code_log-1.0.0 → claude_code_log-1.1.1}/stubs/pygments/util.pyi +0 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tool-renderer
|
|
3
|
+
description: Implement specialized rendering for Claude Code tools. Use when adding a new tool type (WebSearch, WebFetch, etc.) to the transcript viewer, or when asked to implement tool rendering.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Implementing a Tool Renderer
|
|
7
|
+
|
|
8
|
+
This guide walks through adding rendering support for a new Claude Code tool, using WebSearch as an example.
|
|
9
|
+
|
|
10
|
+
## Before You Start
|
|
11
|
+
|
|
12
|
+
**Examine existing test data** to understand the tool's actual JSON structure:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Find test files containing the tool
|
|
16
|
+
rg -l "ToolName" test/test_data/
|
|
17
|
+
|
|
18
|
+
# Look at actual JSONL entries
|
|
19
|
+
rg '"name":\s*"ToolName"' test/test_data/ -A 2 -B 2
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Key fields to identify:
|
|
23
|
+
- **Input parameters**: What's in `tool_use.input`?
|
|
24
|
+
- **toolUseResult structure**: What metadata does the structured result contain?
|
|
25
|
+
- **tool_result.content**: What does the raw text output look like?
|
|
26
|
+
|
|
27
|
+
The `toolUseResult` field on transcript entries often contains richer structured data than `tool_result.content`. **Always prefer parsing from `toolUseResult` when available.**
|
|
28
|
+
|
|
29
|
+
## Overview
|
|
30
|
+
|
|
31
|
+
Tool rendering involves several components working together:
|
|
32
|
+
|
|
33
|
+
1. **Models** (`models.py`) - Type definitions for tool inputs and outputs
|
|
34
|
+
2. **Factory** (`factories/tool_factory.py`) - Parsing raw JSON into typed models
|
|
35
|
+
3. **HTML Formatters** (`html/tool_formatters.py`) - HTML rendering functions
|
|
36
|
+
4. **Renderers** - Integration with HTML and Markdown renderers
|
|
37
|
+
|
|
38
|
+
## Step 1: Define Models
|
|
39
|
+
|
|
40
|
+
### Tool Input Model
|
|
41
|
+
|
|
42
|
+
Add a Pydantic model for the tool's input parameters in `models.py`:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
class WebSearchInput(BaseModel):
|
|
46
|
+
"""Input parameters for the WebSearch tool."""
|
|
47
|
+
query: str
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Tool Output Model
|
|
51
|
+
|
|
52
|
+
Add a dataclass for the parsed output. Output models are dataclasses (not Pydantic) since they're created by our parsers, not from JSON:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
@dataclass
|
|
56
|
+
class WebSearchLink:
|
|
57
|
+
"""Single search result link."""
|
|
58
|
+
title: str
|
|
59
|
+
url: str
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class WebSearchOutput:
|
|
63
|
+
"""Parsed WebSearch tool output."""
|
|
64
|
+
query: str
|
|
65
|
+
links: list[WebSearchLink]
|
|
66
|
+
preamble: Optional[str] = None # Text before the Links
|
|
67
|
+
summary: Optional[str] = None # Markdown analysis after the Links
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Note:** Some tools have structured output with multiple sections. WebSearch is parsed as **preamble/links/summary** - text before Links, the Links JSON array, and markdown analysis after. This allows flexible rendering while preserving all content.
|
|
71
|
+
|
|
72
|
+
### Update Type Unions
|
|
73
|
+
|
|
74
|
+
Add the new types to the `ToolInput` and `ToolOutput` unions:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
ToolInput = Union[
|
|
78
|
+
# ... existing types ...
|
|
79
|
+
WebSearchInput,
|
|
80
|
+
ToolUseContent, # Generic fallback - keep last
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
ToolOutput = Union[
|
|
84
|
+
# ... existing types ...
|
|
85
|
+
WebSearchOutput,
|
|
86
|
+
ToolResultContent, # Generic fallback - keep last
|
|
87
|
+
]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Step 2: Implement Factory Functions
|
|
91
|
+
|
|
92
|
+
In `factories/tool_factory.py`:
|
|
93
|
+
|
|
94
|
+
### Register Input Model
|
|
95
|
+
|
|
96
|
+
Add the input model to `TOOL_INPUT_MODELS`:
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
TOOL_INPUT_MODELS: dict[str, type[BaseModel]] = {
|
|
100
|
+
# ... existing entries ...
|
|
101
|
+
"WebSearch": WebSearchInput,
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Implement Output Parser
|
|
106
|
+
|
|
107
|
+
**Important**: Always check if the tool has structured `toolUseResult` data available. This is the preferred approach because:
|
|
108
|
+
- It's more reliable than regex parsing of text content
|
|
109
|
+
- It often contains metadata (timing, byte counts, status codes) not in the text
|
|
110
|
+
- The structure is well-defined and type-safe
|
|
111
|
+
|
|
112
|
+
Example `toolUseResult` structures in test data:
|
|
113
|
+
```json
|
|
114
|
+
// WebSearch
|
|
115
|
+
{"query": "...", "results": [...], "durationSeconds": 15.7}
|
|
116
|
+
|
|
117
|
+
// WebFetch
|
|
118
|
+
{"url": "...", "result": "...", "code": 200, "codeText": "OK", "bytes": 12345, "durationMs": 1500}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Create a parser function that extracts from `toolUseResult`:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
def _parse_websearch_from_structured(
|
|
125
|
+
tool_use_result: ToolUseResult,
|
|
126
|
+
) -> Optional[WebSearchOutput]:
|
|
127
|
+
"""Parse WebSearch from structured toolUseResult data.
|
|
128
|
+
|
|
129
|
+
The toolUseResult for WebSearch has the format:
|
|
130
|
+
{
|
|
131
|
+
"query": "search query",
|
|
132
|
+
"results": [
|
|
133
|
+
{"tool_use_id": "...", "content": [{"title": "...", "url": "..."}]},
|
|
134
|
+
"Analysis text..."
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
"""
|
|
138
|
+
if not isinstance(tool_use_result, dict):
|
|
139
|
+
return None
|
|
140
|
+
query = tool_use_result.get("query")
|
|
141
|
+
results = tool_use_result.get("results")
|
|
142
|
+
# ... extract links from results[0].content, summary from results[1] ...
|
|
143
|
+
return WebSearchOutput(query=query, links=links, preamble=None, summary=summary)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def parse_websearch_output(
|
|
147
|
+
tool_result: ToolResultContent,
|
|
148
|
+
file_path: Optional[str],
|
|
149
|
+
tool_use_result: Optional[ToolUseResult] = None, # Extended signature
|
|
150
|
+
) -> Optional[WebSearchOutput]:
|
|
151
|
+
"""Parse WebSearch tool result from structured toolUseResult."""
|
|
152
|
+
del tool_result, file_path # Unused
|
|
153
|
+
if tool_use_result is None:
|
|
154
|
+
return None
|
|
155
|
+
return _parse_websearch_from_structured(tool_use_result)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Register Output Parser
|
|
159
|
+
|
|
160
|
+
Add to `TOOL_OUTPUT_PARSERS` and **register in `PARSERS_WITH_TOOL_USE_RESULT`** if using the extended signature:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
TOOL_OUTPUT_PARSERS: dict[str, ToolOutputParser] = {
|
|
164
|
+
# ... existing entries ...
|
|
165
|
+
"WebSearch": parse_websearch_output,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
# REQUIRED for parsers that use toolUseResult - without this, the structured
|
|
169
|
+
# data won't be passed to your parser!
|
|
170
|
+
PARSERS_WITH_TOOL_USE_RESULT: set[str] = {"WebSearch", "WebFetch"}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Note**: If your parser has the 3-argument signature `(tool_result, file_path, tool_use_result)`, you MUST add it to `PARSERS_WITH_TOOL_USE_RESULT`. Otherwise `create_tool_output()` won't pass the structured data.
|
|
174
|
+
|
|
175
|
+
## Step 3: Implement HTML Formatters
|
|
176
|
+
|
|
177
|
+
In `html/tool_formatters.py`:
|
|
178
|
+
|
|
179
|
+
### Input Formatter
|
|
180
|
+
|
|
181
|
+
**Design consideration**: The title already shows key info (tool name + primary parameter). Only show content in the body if it adds value or is too long for the title.
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
def format_websearch_input(search_input: WebSearchInput) -> str:
|
|
185
|
+
"""Format WebSearch tool use content."""
|
|
186
|
+
# If query is short enough to fit in title, return empty
|
|
187
|
+
if len(search_input.query) <= 100:
|
|
188
|
+
return "" # Full query shown in title
|
|
189
|
+
escaped_query = escape_html(search_input.query)
|
|
190
|
+
return f'<div class="websearch-query">{escaped_query}</div>'
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
This avoids redundancy when the title already shows everything important.
|
|
194
|
+
|
|
195
|
+
### Output Formatter
|
|
196
|
+
|
|
197
|
+
For tools with structured content like WebSearch, combine all parts into markdown then render:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
def _websearch_as_markdown(output: WebSearchOutput) -> str:
|
|
201
|
+
"""Convert WebSearch output to markdown: preamble + links list + summary."""
|
|
202
|
+
parts = []
|
|
203
|
+
if output.preamble:
|
|
204
|
+
parts.extend([output.preamble, ""])
|
|
205
|
+
for link in output.links:
|
|
206
|
+
parts.append(f"- [{link.title}]({link.url})")
|
|
207
|
+
if output.summary:
|
|
208
|
+
parts.extend(["", output.summary])
|
|
209
|
+
return "\n".join(parts)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def format_websearch_output(output: WebSearchOutput) -> str:
|
|
213
|
+
"""Format WebSearch as single collapsible markdown block."""
|
|
214
|
+
markdown_content = _websearch_as_markdown(output)
|
|
215
|
+
return render_markdown_collapsible(markdown_content, "websearch-results")
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Update Exports
|
|
219
|
+
|
|
220
|
+
Add functions to `__all__`:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
__all__ = [
|
|
224
|
+
# ... existing exports ...
|
|
225
|
+
"format_websearch_input",
|
|
226
|
+
"format_websearch_output",
|
|
227
|
+
]
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Step 4: Wire Up HTML Renderer
|
|
231
|
+
|
|
232
|
+
In `html/renderer.py`:
|
|
233
|
+
|
|
234
|
+
### Import Formatters
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
from .tool_formatters import (
|
|
238
|
+
# ... existing imports ...
|
|
239
|
+
format_websearch_input,
|
|
240
|
+
format_websearch_output,
|
|
241
|
+
)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Add Format Methods
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
def format_WebSearchInput(self, input: WebSearchInput, _: TemplateMessage) -> str:
|
|
248
|
+
return format_websearch_input(input)
|
|
249
|
+
|
|
250
|
+
def format_WebSearchOutput(self, output: WebSearchOutput, _: TemplateMessage) -> str:
|
|
251
|
+
return format_websearch_output(output)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Add Title Method (Optional)
|
|
255
|
+
|
|
256
|
+
For a custom title in the message header:
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
def title_WebSearchInput(self, input: WebSearchInput, message: TemplateMessage) -> str:
|
|
260
|
+
return self._tool_title(message, "🔎", f'"{input.query}"')
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Step 5: Implement Markdown Renderer
|
|
264
|
+
|
|
265
|
+
In `markdown/renderer.py`:
|
|
266
|
+
|
|
267
|
+
### Import Models
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
from ..models import (
|
|
271
|
+
# ... existing imports ...
|
|
272
|
+
WebSearchInput,
|
|
273
|
+
WebSearchOutput,
|
|
274
|
+
)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Add Format Methods
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
def format_WebSearchInput(self, input: WebSearchInput, _: TemplateMessage) -> str:
|
|
281
|
+
"""Format -> empty (query shown in title)."""
|
|
282
|
+
return ""
|
|
283
|
+
|
|
284
|
+
def format_WebSearchOutput(self, output: WebSearchOutput, _: TemplateMessage) -> str:
|
|
285
|
+
"""Format -> markdown list of links."""
|
|
286
|
+
parts = [f"Query: *{output.query}*", ""]
|
|
287
|
+
for link in output.links:
|
|
288
|
+
parts.append(f"- [{link.title}]({link.url})")
|
|
289
|
+
return "\n".join(parts)
|
|
290
|
+
|
|
291
|
+
def title_WebSearchInput(self, input: WebSearchInput, _: TemplateMessage) -> str:
|
|
292
|
+
"""Title -> '🔎 WebSearch `query`'."""
|
|
293
|
+
return f'🔎 WebSearch `{input.query}`'
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Step 6: Add Tests
|
|
297
|
+
|
|
298
|
+
Create a dedicated test file `test/test_{toolname}_rendering.py`. Tests are **required** - they catch regressions and document expected behavior.
|
|
299
|
+
|
|
300
|
+
### Test Structure
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
"""Test cases for {ToolName} tool rendering."""
|
|
304
|
+
|
|
305
|
+
from claude_code_log.factories.tool_factory import parse_{toolname}_output
|
|
306
|
+
from claude_code_log.html.tool_formatters import (
|
|
307
|
+
format_{toolname}_input,
|
|
308
|
+
format_{toolname}_output,
|
|
309
|
+
)
|
|
310
|
+
from claude_code_log.models import (
|
|
311
|
+
ToolResultContent,
|
|
312
|
+
{ToolName}Input,
|
|
313
|
+
{ToolName}Output,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class Test{ToolName}Input:
|
|
318
|
+
"""Test input model and formatting."""
|
|
319
|
+
|
|
320
|
+
def test_input_basic(self):
|
|
321
|
+
"""Test input model creation."""
|
|
322
|
+
...
|
|
323
|
+
|
|
324
|
+
def test_format_input_short(self):
|
|
325
|
+
"""Test formatting when content fits in title."""
|
|
326
|
+
...
|
|
327
|
+
|
|
328
|
+
def test_format_input_long(self):
|
|
329
|
+
"""Test formatting when content is too long for title."""
|
|
330
|
+
...
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class Test{ToolName}Parser:
|
|
334
|
+
"""Test output parsing."""
|
|
335
|
+
|
|
336
|
+
def test_parse_structured_output(self):
|
|
337
|
+
"""Test parsing from structured toolUseResult."""
|
|
338
|
+
...
|
|
339
|
+
|
|
340
|
+
def test_parse_minimal_output(self):
|
|
341
|
+
"""Test parsing with only required fields."""
|
|
342
|
+
...
|
|
343
|
+
|
|
344
|
+
def test_parse_missing_field(self):
|
|
345
|
+
"""Test graceful failure with missing required field."""
|
|
346
|
+
...
|
|
347
|
+
|
|
348
|
+
def test_parse_no_tool_use_result(self):
|
|
349
|
+
"""Test returns None when no toolUseResult."""
|
|
350
|
+
...
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
class Test{ToolName}OutputFormatting:
|
|
354
|
+
"""Test output HTML formatting."""
|
|
355
|
+
|
|
356
|
+
def test_format_output_full(self):
|
|
357
|
+
"""Test formatting with all metadata."""
|
|
358
|
+
...
|
|
359
|
+
|
|
360
|
+
def test_format_output_minimal(self):
|
|
361
|
+
"""Test formatting with minimal data."""
|
|
362
|
+
...
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Running Tests
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
# Run just your new tests
|
|
369
|
+
uv run pytest test/test_{toolname}_rendering.py -v
|
|
370
|
+
|
|
371
|
+
# Run full test suite to check for regressions
|
|
372
|
+
uv run pytest -n auto -m "not (tui or browser)" -v
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Checklist
|
|
376
|
+
|
|
377
|
+
### Models (`models.py`)
|
|
378
|
+
- [ ] Add input model (Pydantic `BaseModel`)
|
|
379
|
+
- [ ] Add output model (dataclass with all fields from `toolUseResult`)
|
|
380
|
+
- [ ] Update `ToolInput` union
|
|
381
|
+
- [ ] Update `ToolOutput` union
|
|
382
|
+
|
|
383
|
+
### Factory (`factories/tool_factory.py`)
|
|
384
|
+
- [ ] Add to `TOOL_INPUT_MODELS`
|
|
385
|
+
- [ ] Import output model
|
|
386
|
+
- [ ] Implement output parser with 3-arg signature if using `toolUseResult`
|
|
387
|
+
- [ ] Add to `TOOL_OUTPUT_PARSERS`
|
|
388
|
+
- [ ] Add to `PARSERS_WITH_TOOL_USE_RESULT` (required if parser uses `toolUseResult`)
|
|
389
|
+
|
|
390
|
+
### HTML (`html/tool_formatters.py`, `html/renderer.py`)
|
|
391
|
+
- [ ] Import models
|
|
392
|
+
- [ ] Add input formatter function
|
|
393
|
+
- [ ] Add output formatter function
|
|
394
|
+
- [ ] Update `__all__` exports
|
|
395
|
+
- [ ] Wire up `format_{Input}` method in renderer
|
|
396
|
+
- [ ] Wire up `format_{Output}` method in renderer
|
|
397
|
+
- [ ] Add `title_{Input}` method in renderer
|
|
398
|
+
|
|
399
|
+
### Markdown (`markdown/renderer.py`)
|
|
400
|
+
- [ ] Import models
|
|
401
|
+
- [ ] Add `format_{Input}` method
|
|
402
|
+
- [ ] Add `format_{Output}` method
|
|
403
|
+
- [ ] Add `title_{Input}` method
|
|
404
|
+
|
|
405
|
+
### Tests (`test/test_{toolname}_rendering.py`)
|
|
406
|
+
- [ ] Create test file
|
|
407
|
+
- [ ] Test input model creation
|
|
408
|
+
- [ ] Test input formatting (short/long content)
|
|
409
|
+
- [ ] Test parser with full structured data
|
|
410
|
+
- [ ] Test parser with minimal data
|
|
411
|
+
- [ ] Test parser with missing fields (graceful failure)
|
|
412
|
+
- [ ] Test parser with no `toolUseResult`
|
|
413
|
+
- [ ] Test output formatting
|
|
414
|
+
- [ ] Run full test suite to verify no regressions
|
|
@@ -6,6 +6,36 @@ 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
8
|
|
|
9
|
+
## [1.1.1] - 2026-03-10
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **Fix build cold start + format justfile**
|
|
14
|
+
- **fix: handle None level in SystemMessage title (#100)**
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [1.1.0] - 2026-03-06
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **Fix WebSearch and WebFetch rendering in agent transcripts (#98)**
|
|
22
|
+
- **Fix fold-bar colors and System Hook alignment (#89)**
|
|
23
|
+
- **Add WebFetch tool renderer (#87)**
|
|
24
|
+
- **Merge pull request #83 from daaain/dev/websearch-tool-renderer**
|
|
25
|
+
- **Update some outdated docs + VS Code insists on these settings (#86)**
|
|
26
|
+
- **Fix double tab opening when clicking links in TUI MarkdownViewer**
|
|
27
|
+
- **Simplify WebSearch parser and improve rendering**
|
|
28
|
+
- **Use structured toolUseResult for WebSearch parsing**
|
|
29
|
+
- **Add analysis content support to WebSearch output**
|
|
30
|
+
- **Add documentation for implementing tool renderers**
|
|
31
|
+
- **Add WebSearch HTML and Markdown formatters**
|
|
32
|
+
- **Add WebSearch tool models and factory parser**
|
|
33
|
+
- **Fix snapshot + make sure snapshot order is stable**
|
|
34
|
+
- **Improve CSS layout to be responsive for mobile small screens (#77)**
|
|
35
|
+
- **Update pyright to 1.1.408 (#82)**
|
|
36
|
+
- **Support subagents directory structure (Claude Code 2.1.2+) (#80)**
|
|
37
|
+
|
|
38
|
+
|
|
9
39
|
## [1.0.0] - 2026-01-22
|
|
10
40
|
|
|
11
41
|
BREAKING CHANGE: cache is now using a SQLite database instead of JSON files!
|
|
@@ -226,14 +226,14 @@ The interactive timeline is implemented in JavaScript within `claude_code_log/te
|
|
|
226
226
|
|
|
227
227
|
## Cache System
|
|
228
228
|
|
|
229
|
-
The tool implements a caching system for performance:
|
|
229
|
+
The tool implements a SQLite-based caching system for performance:
|
|
230
230
|
|
|
231
|
-
- **Location**:
|
|
231
|
+
- **Location**: `claude-code-log-cache.db` in the projects directory (or set `CLAUDE_CODE_LOG_CACHE_PATH` env var)
|
|
232
232
|
- **Contents**: Pre-parsed session metadata (IDs, summaries, timestamps, token usage)
|
|
233
233
|
- **Invalidation**: Automatic detection based on file modification times
|
|
234
234
|
- **Performance**: 10-100x faster loading for large projects
|
|
235
235
|
|
|
236
|
-
The cache automatically rebuilds when source files change or cache version changes.
|
|
236
|
+
The cache automatically rebuilds when source files change or cache schema version changes.
|
|
237
237
|
|
|
238
238
|
## Release Process
|
|
239
239
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-code-log
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.1
|
|
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
|
|
@@ -271,5 +271,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and archi
|
|
|
271
271
|
- add minimalist theme and make it light + dark; animate gradient background in fancy theme
|
|
272
272
|
- do we need special handling for hooks?
|
|
273
273
|
- make processing parallel, currently we only use 1 CPU (core) and it's slow
|
|
274
|
-
- migrate cache from JSON files to SQLite to make it faster and more versatile for downstream tasks and analytics
|
|
275
274
|
- merge git worktree directories
|
|
@@ -247,5 +247,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and archi
|
|
|
247
247
|
- add minimalist theme and make it light + dark; animate gradient background in fancy theme
|
|
248
248
|
- do we need special handling for hooks?
|
|
249
249
|
- make processing parallel, currently we only use 1 CPU (core) and it's slow
|
|
250
|
-
- migrate cache from JSON files to SQLite to make it faster and more versatile for downstream tasks and analytics
|
|
251
250
|
- merge git worktree directories
|
|
@@ -252,11 +252,25 @@ def load_transcript(
|
|
|
252
252
|
agent_messages_map: dict[str, list[TranscriptEntry]] = {}
|
|
253
253
|
if agent_ids:
|
|
254
254
|
parent_dir = jsonl_path.parent
|
|
255
|
+
session_basename = (
|
|
256
|
+
jsonl_path.stem
|
|
257
|
+
) # e.g., "29ccd257-68b1-427f-ae5f-6524b7cb6f20"
|
|
255
258
|
for agent_id in agent_ids:
|
|
259
|
+
# Try legacy location first (same directory as session file)
|
|
256
260
|
agent_file = parent_dir / f"agent-{agent_id}.jsonl"
|
|
257
261
|
# Skip if the agent file is the same as the current file (self-reference)
|
|
258
262
|
if agent_file == jsonl_path:
|
|
259
263
|
continue
|
|
264
|
+
# Try new subagents directory structure (Claude Code 2.1.2+)
|
|
265
|
+
if not agent_file.exists():
|
|
266
|
+
subagent_file = (
|
|
267
|
+
parent_dir
|
|
268
|
+
/ session_basename
|
|
269
|
+
/ "subagents"
|
|
270
|
+
/ f"agent-{agent_id}.jsonl"
|
|
271
|
+
)
|
|
272
|
+
if subagent_file.exists():
|
|
273
|
+
agent_file = subagent_file
|
|
260
274
|
if agent_file.exists():
|
|
261
275
|
if not silent:
|
|
262
276
|
print(f"Loading agent file {agent_file}...")
|