Repository navigation
Commit 9d76ab8
Foldable messages (#42)
* Implement hierarchical conversation structure with margin-based indentation
Reorganized message margins to create clear visual hierarchy:
RIGHT-ALIGNED (user-initiated, left: 33%, right: 0):
- User messages (not compacted)
- System commands
- System errors
LEFT-ALIGNED (assistant-generated, progressive indentation):
- Assistant/Thinking: left: 0, right: 8em
- Tool use/result: left: 2em, right: 6em
- System warning/info: left: 2em, right: 6em
- Sidechain user: left: 4em, right: 4em
- Sidechain assistant: left: 4em, right: 4em
- Sidechain tools: left: 6em, right: 2em
Changes:
- Grouped all margin rules in dedicated "CONVERSATION STRUCTURE" section
- Removed scattered margin-left declarations from individual selectors
- Clear visual separation between user (right) and assistant (left) sides
- Progressive 2em indentation for nested assistant operations
- Sidechain (sub-assistant) hierarchy clearly distinguished
This creates a "conversation tree" visual where:
- User speaks from the right
- Assistant responds from the left with tools indented
- Sub-assistants (via Task tool) are further indented
- Each level uses 2em indentation increment
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Adjust sub-assistant prompt indentation to match Task level
Move sidechain user (sub-assistant prompt) from 4em to 2em indentation,
placing it at the same level as the Task tool that invokes it.
Previous hierarchy:
- Task tool: 2em
- Sub-assistant prompt: 4em (nested below)
- Sub-assistant: 4em
- Sub-tools: 6em
New hierarchy:
- Task tool: 2em
- Sub-assistant prompt: 2em (sibling, not child)
- Sub-assistant: 4em (nested below prompt)
- Sub-tools: 6em (nested below sub-assistant)
This better reflects the conversation flow where the Task and its prompt
are siblings in the dialogue, with the sub-assistant's response being the
nested continuation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Implement hierarchical fold/unfold functionality for conversation structure
Added interactive collapsing/expanding of messages based on hierarchical
conversation structure:
Backend (renderer.py):
- Added message_id, ancestry, and has_children fields to TemplateMessage
- Implemented _get_message_hierarchy_level() to determine nesting levels:
* Level 0 (0em): User, Assistant, Thinking, System
* Level 1 (2em): Tool use/result, Sidechain user (sub-assistant prompt)
* Level 2 (4em): Sidechain assistant/thinking
* Level 3 (6em): Sidechain tools
- Implemented _update_hierarchy_stack() to track message ancestry
- Added hierarchy tracking to all TemplateMessage creations (system, main,
tool messages)
- Implemented _mark_messages_with_children() to identify messages with
descendants
- Reset hierarchy stack at session boundaries
Frontend (transcript.html):
- Added ancestry classes to message divs (e.g., "d-10 d-23 d-42")
- Added data-message-id attribute to each message
- Added fold-toggle button for messages with children
- Implemented JavaScript fold/unfold logic:
* Toggle button changes between ▾ (unfolded) and ▸ (folded)
* Clicking folds/unfolds all descendants by hiding/showing messages
with parent ID in their class list
Styling (message_styles.css):
- Added .fold-toggle button styles
- Positioned button absolutely on the left edge of messages
- Added hover and folded states
This creates a tree-like conversation view where users can collapse/expand
branches of the conversation hierarchy (e.g., fold all tools under an
assistant message, or fold an entire sub-assistant chain).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix hierarchy level logic for correct message nesting
Corrected _get_message_hierarchy_level() to properly reflect logical nesting:
Before (incorrect):
- Level 0: User, Assistant, Thinking, System
- Level 1: Tools, System warnings/info, Sidechain user
- Level 2: Sidechain assistant/thinking
- Level 3: Sidechain tools
After (correct):
- Level 0: User (triggers everything), System
- Level 1: Assistant, Thinking, System warnings/info (nested under user)
- Level 2: Tool use/result (nested under assistant), Sidechain user
- Level 3: Sidechain assistant/thinking (nested under sidechain user)
- Level 4: Sidechain tools (nested under sidechain assistant)
This matches the logical conversation flow where:
- User messages trigger assistant responses
- Assistant responses contain tools
- Tools can spawn sub-assistants (sidechains)
- Sub-assistants have their own tool calls
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Make tool_result one level deeper than tool_use for proper folding
Tool results should be children of their corresponding tool_use messages
for folding purposes. When a tool_use is folded, its result should be
hidden as well.
Added special case in hierarchy tracking: tool_result messages get
level + 1, making them nested under their tool_use parent. This ensures
that folding a tool_use will hide both the tool call and its result.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix tool pair folding and add debug hierarchy display
Fixed two critical issues with hierarchical folding:
1. Tool pairs now fold as a unit:
- tool_result reuses its paired tool_use's message ID
- This makes tool_use + tool_result a single foldable unit
- Folding affects what comes AFTER the pair, not the pair itself
2. Assistant/Thinking messages now always created when they have tools:
- Previously skipped if no text content
- Now created with empty content when tools present
- Ensures fold buttons appear on Assistant/Thinking with tools
3. Added debug hierarchy display:
- Shows message ID and ancestry in message header
- Format: 'd-42 ← [d-10, d-23]' (ID ← ancestors)
- Helps troubleshoot hierarchy structure
This implements the correct folding logic where:
- User can fold everything they trigger
- Assistant/Thinking can fold their tools
- Tool pairs (use+result) fold as a unit
- Sub-assistant chains fold under the Task tool that spawned them
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix spurious empty assistant messages in hierarchy
Remove logic that created empty assistant container messages when
assistant entries only contained tools. This was causing:
- Spurious empty assistant messages before each tool pair
- Incorrect hierarchy stack management
- Message IDs being incremented for non-existent messages
Now only creates assistant/thinking messages when they have text
content. Tools become direct children of the current hierarchy level
(typically the user message) when assistant has no text.
This ensures folding behavior works correctly: folding a user message
folds ALL subsequent lower-level messages until the next user message.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove debug ancestry display from message headers
The ancestry information (message_id and ancestor chain) was useful for
debugging the hierarchy implementation but is not needed in production.
This debug feature can be restored by reverting this commit if needed
for troubleshooting hierarchy issues.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Implement horizontal fold bar UI with default folded state
This commit introduces a new fold/unfold UI based on horizontal bars below
messages, replacing the small button approach with a more accessible design.
**Key Features:**
- Horizontal fold bars below messages with children
- Two-zone interaction: fold one level (left) vs fold all (right)
- Visual feedback: counts, descriptive labels, double-line when folded
- Border colors match parent message type
- Default folded state: all messages start collapsed except sessions
- Fast animations (200ms transitions)
- Efficient O(n) descendant counting during hierarchy building
**Implementation:**
- Enhanced TemplateMessage with immediate_children_count and total_descendants_count
- Optimized _mark_messages_with_children() for O(n) counting
- New fold-bar HTML structure with two clickable sections
- CSS styling with border-color matching and gradient backgrounds
- JavaScript handlers for fold-one and fold-all actions
- Auto-fold on page load (top-level messages only)
**UI Design:**
Folded: ═══════════════
↓ 2 messages ↓↓ 125 total
Unfolded: △ fold 2 △△ fold all
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Refine fold UI: fix initial state, styling, and session support
Address all feedback from initial fold UI implementation:
1. Fix initial state synchronization
- Remove default 'folded' class - messages start visible
- Use expanded icons (▼/▼▼) by default
- Remove auto-folding on page load
- First click now works correctly
2. Improve visual integration
- Set message padding-bottom to 0 when fold-bar present
- Use CSS :has() selector for clean integration
- Fold bar now looks like natural extension of message
3. Add session header folding support
- Sessions now have fold bars like regular messages
- Session headers become fold parents via message_id
- All session messages can be folded/expanded
- Added session-header border color
4. Optimize fold bar layout
- Hide "fold all" button when counts match
- Show single full-width button for single-level folds
- Better use of horizontal space
5. Update fold icons for better aesthetics
- 1-level folded: ▶, expanded: ▼
- All levels folded: ▶▶, expanded: ▼▼
- Cleaner, more professional appearance
6. Fix test compatibility
- Update todowrite test for new HTML structure
- Allow for ancestor IDs in class attribute
Files changed:
- renderer.py: Session headers as fold parents, type-aware counting
- transcript.html: Conditional rendering, updated icons, removed auto-fold
- message_styles.css: Padding fix, full-width button support, new colors
- global_styles.css: Added message type color variables
- test_todowrite_rendering.py: More flexible class matching
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix Pyright type errors in _format_type_counts function
Added explicit type annotation `parts: list[str] = []` to resolve
type inference issues at lines 1440, 1443, 1444, and 1445.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix message hierarchy structure for proper fold organization
Updated hierarchy levels to properly reflect logical nesting:
- Level 0: Session headers (unchanged)
- Level 1: User messages (was 0)
- Level 2: System messages, Assistant, Thinking (was 0-1)
- Level 3: Tools, Sidechain user (was 2)
- Level 4: Sidechain assistant/thinking (was 3)
- Level 5: Sidechain tools (was 4)
This ensures:
- User messages fold under sessions
- System messages fold under user messages (not siblings)
- All messages have proper parent-child relationships
Also fixed test assertions to be flexible about ancestor IDs
in CSS class attributes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Keep images inline for user messages, extract for assistant messages
Images in user messages are now rendered inline on the right side
with the text content, while images in assistant messages are still
extracted as separate message items.
This provides better visual grouping - user-uploaded images appear
together with the user's text, matching the natural flow of
"here's my question and screenshot".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix session fold-one-level button to recognize session IDs
Updated handleFoldOne JavaScript to recognize both regular message
IDs (d-XXX) and session IDs (session-XXX) when filtering for
ancestor classes.
Previously, clicking "fold one level" on a session did nothing
because the code only looked for ancestor IDs starting with 'd-',
missing session IDs that start with 'session-'.
Now both fold buttons work correctly for sessions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add fold button coordination and intelligent initial state
Implemented coordination between fold-one and fold-all buttons:
- Folding immediate children also folds all descendants (sync ▶/▶▶)
- Unfolding all descendants also unfolds immediate children (sync ▼/▼▼)
- Folding all descendants also folds immediate children (sync ▶/▶▶)
- Unfolding immediate children keeps fold-all at ▶▶ (independent)
Initial page load state:
- Sessions: unfolded at first level (▼/▶▶) - shows user messages
- User messages: unfolded at first level (▼/▶▶) - shows assistant/system
- Assistant/system/thinking/tools: fully folded (▶/▶▶) - hidden
This provides a clean initial view showing the conversation structure
while hiding implementation details until explicitly expanded.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Small stylistic improvement: less visually intrusive fold bar
* Fixup a9cd857: remove 'test_project_fold_ui.html'
* Improve fold UI: three-state behavior, styling fixes, and initial states
This commit implements six key improvements to the horizontal fold bar UI:
1. **Sub-assistant fold-bar styling**: Sidechain (sub-assistant) fold bars now
use dashed borders matching the message's left border style, instead of
solid black borders.
2. **Sub-assistant initial visibility**: Fixed bug where sub-assistant messages
were incorrectly shown initially even when parent assistant was folded.
Newly revealed children are now properly initialized to folded state.
3. **User messages with only tools**: User messages that have only tool
use/result pairs as children (no assistant/system/thinking) now start in
fully folded state for cleaner initial view.
4. **Tool pair display**: Fixed count display to show "N tool_pairs" instead
of "N tools, N results" when tool_use and tool_result counts match, even
when other message types are present.
5. **System info indentation**: System and system-info messages now align at
level 2 (same as assistant messages) with proper right margins (8em for
system, 10em for system-info).
6. **Three-state fold button behavior**: Implemented new state machine where
the "fold all" button (▼▼→▶▶) goes back to first level visible (State B)
instead of fully folded (State A), creating a natural exploration pattern:
nothing → all levels → first level → nothing.
Files changed:
- claude_code_log/renderer.py: Modified _format_type_counts() to combine tool pairs
- claude_code_log/templates/transcript.html: Updated fold button handlers and initial state logic
- claude_code_log/templates/components/message_styles.css: Fixed sidechain and system message styling
- FOLD_STATE_DIAGRAM.md: Added comprehensive state diagram documenting the three-state behavior
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* OK, keep FOLD_STATE_DIAGRAM.md but out of the way.
* Add message structure example to FOLD_STATE_DIAGRAM.md
* Fix critical performance issue in fold one level operation
The "Fold (to all levels) ▼" operation was taking ~60 seconds for sessions
with ~5000 messages due to O(n²) complexity from recursive DOM queries.
Problem:
The hideMessageAndDescendants() function recursively called
document.querySelectorAll() for each message in the hierarchy, resulting
in potentially thousands of DOM queries for large sessions.
Solution:
Replaced recursive approach with single querySelectorAll() call to get ALL
descendants at once, then hide them with a simple forEach loop. This matches
the efficient pattern used by handleFoldAll().
Changes:
- Removed obsolete hideMessageAndDescendants() function
- Modified handleFoldOne() to use single DOM query for all descendants
- Performance improved from ~60s to ~1-2s (on par with other fold operations)
Performance impact:
- Before: O(n²) or worse - recursive DOM queries per message
- After: O(n) - single DOM query, simple iteration
- Real-world: 60s → 1-2s for 5000 message session
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix fold bar styling for compacted user messages
Compacted user messages (generated when a session runs out of context) have
css_class "user compacted" instead of just "user", which caused the fold bar
border colors to not match the CSS selectors.
Changes:
- Added "user compacted" variant to fold bar border color selector
- This ensures compacted user messages have orange fold bars like regular user messages
Note: The padding-bottom issue mentioned was due to mistune's HTML structure
placing the fold-bar div as a non-immediate child of the message div, causing
the :has(.fold-bar) selector to not apply. This will be addressed separately
when we add mistune HTML cleanup/validation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Optimize setInitialFoldState() to eliminate O(n²) performance issue
Replace repeated querySelectorAll() calls with cached hierarchy lookups:
- Build messagesByParentId and allDescendantsByParentId maps in single O(n) pass
- Use cached lookups instead of DOM queries inside message processing loop
- Reduces complexity from O(n²) to O(n) for n messages
For transcripts with 5000 messages, this reduces ~15,000 DOM queries to
~10,000 in-memory operations, significantly improving page load time.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add dynamic tooltips to fold controls showing action intent
Implement context-aware tooltips that change based on fold button state:
- ▶ (folded, fold-one): "Unfold (1st level)..."
- ▼ (unfolded, fold-one): "Fold (all levels)..."
- ▶▶ (folded, fold-all): "Unfold (all levels)..."
- ▼▼ (unfolded, fold-all): "Fold (to 1st level)..."
Implementation uses data-driven approach:
- Store both tooltip variants as data attributes (data-title-folded/unfolded)
- Single lightweight updateTooltip() function reads current state
- Called only when fold state changes (no performance impact)
- Zero code duplication, minimal changes to existing code
Benefits:
- Users see what WILL happen when clicking (not current state)
- < 1ms per update (just attribute reads/writes)
- Maintainable: tooltip text lives in template near generation logic
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix template rendering tests for fold UI ancestry classes
Update CSS class assertions to handle ancestry tracking classes
added by fold UI. Tests now check for "class='message user"
(substring) instead of "class='message user'" (exact match).
Messages now include ancestry classes like:
- class='message user session-test_session'
- class='message assistant session-test_session d-0'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Enhance system message rendering with memory input, command pairing, and CSS variables
This commit improves the handling and display of system messages, user memory inputs,
and slash command interactions in the transcript viewer.
**Memory Input Support:**
- Detect and extract user memory inputs (messages starting with '#' in Claude Code)
- Display with "💭 Memory" title instead of "🤷 User"
- Extract content from <user-memory-input> tags and hide wrapper
**System Command Message Pairing:**
- Implement UUID-based pairing for parent-child system messages
- Extract command names from <command-name> tags (e.g., /memory, /init)
- Extract output from <local-command-stdout> tags
- Pair command invocations with their responses using parentUuid relationships
- Visual pairing similar to tool_use/tool_result pairs
**CSS Class Logic:**
- User-initiated commands (with <command-name>): "system" class (right-aligned, orange border)
- Command output responses (with <local-command-stdout>): "system system-info" class (blue border)
- Paired system-info messages override default left-alignment to stay with parent command
**CSS Variable Standardization:**
- Replace hardcoded color values (#d98100, #2196f3, #f44336, #4caf50) with CSS variables
- Use var(--system-color), var(--system-warning-color), var(--system-error-color), var(--tool-use-color)
- Applied in both message_styles.css and filter_styles.css for consistency
**Technical Implementation:**
- Added uuid and parent_uuid fields to TemplateMessage class
- Enhanced _identify_message_pairs() with UUID-based index for system messages
- Modified render_user_message_content() to return (content_html, is_compacted, is_memory_input)
- Added uuid_to_msg_id mapping for parent-child hierarchy tracking
- Hierarchy adjustments based on parentUuid relationships
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix test for render_user_message_content return value change
Updated test_render_user_message_with_multi_item_content to handle the new
three-value return from render_user_message_content (content_html, is_compacted,
is_memory_input).
Added assertion to verify is_memory_input is False for non-memory messages.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix pyright type errors in renderer.py
- Add explicit type annotation for memory_content_list to fix List[ContentItem] type error
- Rename loop variable from 'i' to 'idx' to avoid shadowing outer loop variable
- Correct hierarchy_stack tuple unpacking order: (stack_level, stack_msg_id) instead of (stack_id, stack_level)
- Add explicit type annotation for current_level: int
All pyright errors resolved: 0 errors, 0 warnings, 0 informations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Ignore uv's pinned Python version
* Improve message counting to treat paired messages as single visual units
When counting immediate children and descendants, skip the second message
in pairs (pair_last) since pairs visually appear as a single two-sided
element. This provides more accurate counts that match the visual
presentation and simplifies the counting logic.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix missing import in simplified deduplication logic
Add AssistantTranscriptEntry import alongside SystemTranscriptEntry
since it's still referenced elsewhere in the code (lines 2534, 2711).
The simplified deduplication logic uses (message_type, timestamp) as
the key, treating messages with identical timestamps as duplicates
regardless of content differences (e.g., IDE selection tags).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove unused import
* Fix data-border-color CSS to handle multi-class attributes
The data-border-color attribute now contains space-separated CSS classes
(e.g., "user sidechain", "tool_result error"), but the CSS selectors were
only matching single-class values. This caused fold-bar borders to not
display with the correct colors for messages with multiple classes.
Changes:
- Add CSS rules for all multi-class combinations (sidechain, compacted, error)
- Add missing CSS rules for new message types (image, unknown, bash-input, bash-output)
- Add .markdown to font-family rule for consistency
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Improve sidechain/agent support with automatic file loading and enhanced Task tool rendering
This commit adds comprehensive support for Claude Code's agent/sidechain
system, including automatic loading of agent files and improved rendering
of Task tool calls and their results.
Agent File Loading:
- Automatically detect agentId references in UserTranscriptEntry messages
- Load corresponding agent-{agentId}.jsonl files from the same directory
- Insert agent messages at their point of use (preserving hierarchy)
- Handle recursive agent loading (agents that spawn sub-agents)
- Prevent infinite recursion with cycle detection
Models (claude_code_log/models.py):
- Add agentId field to ToolResultContent for agent references
- Add agentId field to UserTranscriptEntry to preserve agent associations
Parser (claude_code_log/parser.py):
- Extract agentId from toolUseResult before Pydantic parsing
- Load agent files recursively when agentId references are found
- Build agent message map and insert at point of use
- Add _loaded_files parameter to prevent infinite recursion
Renderer (claude_code_log/renderer.py):
- Add format_task_tool_content() to render Task prompts as markdown
- Add get_tool_summary() support for Task tool description
- Add format_tool_result_content() support for Task results as markdown
- Add base_type property to TemplateMessage for CSS class extraction
- Add Task tool title formatting with subagent_type and description
- Track last_task_tool_id for sidechain prompt deduplication
- Skip redundant sidechain user prompts that duplicate Task prompts
The result is a seamless viewing experience where agent conversations
appear inline at their logical point in the main transcript, maintaining
the hierarchical structure of agent spawning and execution.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Implement bidirectional Task result deduplication for sidechain assistants
Add intelligent deduplication to eliminate redundant content between Task tool
results and sub-agent assistant messages. When a Task tool result and a
sidechain assistant message contain identical content, the assistant message
is replaced with a forward link to the Task result.
Key implementation details:
- Use unified content_map to track both Task results and sidechain assistants
- Support bidirectional matching (either can appear first in message stream)
- Extract text content consistently from both message types
- Replace duplicate assistant content with HTML forward link
- Preserve parent-child relationship in fold structure
This reduces visual redundancy when viewing sub-agent transcripts while
maintaining full traceability through clickable links.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix forward link targets and add Pygments highlighting to Task content
Two bug fixes for Task result deduplication feature:
1. Forward link targets: Add id attributes to message elements
- Added id='msg-{{ message.message_id }}' to both session headers and regular messages
- Links like #msg-d-3172 now have valid anchor targets
- Previously only had data-message-id attributes which aren't valid link targets
2. Pygments syntax highlighting: Use render_markdown() for Task content
- Replaced manual mistune instances with render_markdown() function
- Applied to both Task tool input (prompt) and tool result (output)
- Ensures consistent syntax highlighting across all markdown content
- Simplified code by using shared rendering function
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix sidechain agent tests and add comprehensive test data
- Fixed all 5 sidechain agent tests (test_agent_insertion, test_deduplication_task_result_vs_sidechain, test_no_deduplication_when_content_different, test_agent_messages_marked_as_sidechain, test_multiple_agent_invocations)
- Created proper test data files from real examples with truncated strings:
- test/test_data/sidechain_main.jsonl (3 main transcript messages)
- test/test_data/sidechain_agent.jsonl (3 agent messages)
- test/test_data/dedup_main.jsonl (deduplication scenario - main)
- test/test_data/dedup_agent.jsonl (deduplication scenario - agent)
- Fixed imports from converter to parser/renderer modules
- Removed agent_dir parameter (agent files auto-discovered by load_transcript)
- Updated test assertions to use correct agentId (e1c84ba5) and UUIDs from real data
- Added Pydantic-compatible inline test data for multiple agent invocations test
- All 253 unit tests now passing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix duplicate HTML IDs for paired messages
Paired messages (tool_use/tool_result, thinking/assistant, etc.) now have
unique IDs with -first/-last suffixes instead of sharing the same ID.
Changes:
- Template: Add pair_role suffix to message IDs (e.g., msg-d-5-first, msg-d-5-last)
- Template: Remove duplicate id attribute from session headers
- Renderer: Update deduplication links to point to -last suffix for tool results
- All 253 unit tests passing
Fixes invalid HTML where both messages in a pair had identical id attributes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Improve deduplication message phrasing
Changed from technical "Content duplicates Task tool result above" to
more user-friendly "Task summary — already displayed in Task tool result above"
Changes:
- Updated both deduplication link messages (above/below cases)
- Updated test assertions to match new phrasing
- All 253 unit tests passing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Refactor tool message ID generation to remove brittle pairing logic
Remove redundant pairing logic during message creation in favor of the
robust _identify_message_pairs() function. This clarifies the architecture
by separating message creation (which generates unique IDs) from pairing
logic (which marks relationships between messages).
Changes:
- Reuse tool_is_sidechain variable instead of calling getattr() twice
- Remove brittle "look back 10 messages" logic (lines 3210-3222)
- Always generate unique message IDs during creation
- Add comment clarifying that pairing is handled later
The early pairing logic was attempting to make tool_use/tool_result pairs
share message IDs for folding, but this was:
1. Brittle - only checked last 10 messages
2. Redundant - _identify_message_pairs() does this robustly with no limits
3. Unnecessary - template now uses -first/-last ID suffixes anyway
All sidechain agent tests pass with this cleaner architecture.
* Update FOLD_STATE_DIAGRAM.md to reflect implemented behavior
Sync documentation with actual implementation before branch merge:
- Improve hierarchy diagram with visual pairing notation
- Add notes on paired messages, sidechain nesting, and deduplication
- Change "Proposed Behavior" to "Fold Bar Behavior" (now implemented)
- Fix "four states" to "three states" (A, B, C only)
- Add Dynamic Tooltips section documenting context-aware tooltips
- Add Implementation Notes on performance and type-aware labels
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove unused .jsonl test data (noted by the CodeRabbit review)
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 34422bc commit 9d76ab8
18 files changed
Lines changed: 1619 additions & 133 deletions
File tree
- claude_code_log
- templates
- components
- dev-docs
- test
- test_data
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
| 77 | + | |
77 | 78 | | |
78 | 79 | | |
79 | 80 | | |
| |||
202 | 203 | | |
203 | 204 | | |
204 | 205 | | |
| 206 | + | |
205 | 207 | | |
206 | 208 | | |
207 | 209 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
120 | 121 | | |
121 | 122 | | |
122 | 123 | | |
| 124 | + | |
123 | 125 | | |
124 | | - | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
125 | 140 | | |
126 | 141 | | |
127 | 142 | | |
| |||
139 | 154 | | |
140 | 155 | | |
141 | 156 | | |
| 157 | + | |
142 | 158 | | |
143 | 159 | | |
144 | 160 | | |
| |||
154 | 170 | | |
155 | 171 | | |
156 | 172 | | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
157 | 192 | | |
158 | 193 | | |
159 | 194 | | |
| |||
195 | 230 | | |
196 | 231 | | |
197 | 232 | | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
198 | 274 | | |
199 | 275 | | |
200 | 276 | | |
| |||
0 commit comments