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
50 changes: 49 additions & 1 deletion claude_code_log/html/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,33 @@ def _tool_title(
return f"{prefix}{escaped_name}"

def title_TodoWriteInput(self, message: TemplateMessage) -> str: # noqa: ARG002
"""
Return the display title used for Todo write tool messages.

Returns:
title (str): The title string "📝 Todo List".
"""
return "📝 Todo List"

def title_AskUserQuestionInput(self, message: TemplateMessage) -> str: # noqa: ARG002
"""
Render the title for an AskUserQuestion tool input.

Returns:
title (str): The title string "❓ Asking questions...".
"""
return "❓ Asking questions..."

def title_TaskInput(self, message: TemplateMessage) -> str:
"""
Builds the HTML title for a Task tool input, showing an icon, the tool name, and optional description and subagent.

Parameters:
message (TemplateMessage): Message whose content is a Task tool use; its content provides `tool_name` and an `input` with optional `description` and `subagent_type`. Values are HTML-escaped before insertion.

Returns:
str: HTML-formatted title starting with a wrench icon ("🔧") followed by the escaped tool name. If present, the description is included in a `<span class='tool-summary'>...</span>` and the subagent is included in a `<span class='tool-subagent'>(...)</span>`.
"""
content = cast(ToolUseMessage, message.content)
input = cast(TaskInput, content.input)
escaped_name = escape_html(content.tool_name)
Expand All @@ -309,6 +330,15 @@ def title_WriteInput(self, message: TemplateMessage) -> str:
return self._tool_title(message, "📝", input.file_path)

def title_ReadInput(self, message: TemplateMessage) -> str:
"""
Builds a display title for a ReadInput tool use that includes the file path and optional 1-based line range.

Parameters:
message (TemplateMessage): A message whose content is a ToolUseMessage with a ReadInput in `content.input`. The ReadInput's `file_path`, `offset`, and `limit` fields are used to compose the title.

Returns:
str: HTML-escaped title string prefixed with a document icon ("📄") and containing the file path; if `limit` is provided, appends either "line N" or "lines N-M" using 1-based line numbers.
"""
input = cast(ReadInput, cast(ToolUseMessage, message.content).input)
summary = input.file_path
# Add line range info if available
Expand All @@ -321,13 +351,31 @@ def title_ReadInput(self, message: TemplateMessage) -> str:
return self._tool_title(message, "📄", summary)

def title_GlobInput(self, message: TemplateMessage) -> str:
"""
Create a title for a GlobInput tool use, using a magnifying-glass icon and the glob pattern (optionally including the path).

Parameters:
message (TemplateMessage): A template message whose content is a ToolUseMessage containing a GlobInput.

Returns:
str: Title string containing the "🔍" icon and the glob pattern; appends "in <path>" when the input specifies a path.
"""
input = cast(GlobInput, cast(ToolUseMessage, message.content).input)
summary = input.pattern
if input.path:
summary = f"{summary} in {input.path}"
return self._tool_title(message, "🔍", summary)

def title_BashInput(self, message: TemplateMessage) -> str:
"""
Builds the title for a Bash tool input using a computer icon and the input's description.

Parameters:
message (TemplateMessage): Message whose content is a ToolUseMessage with a BashInput.

Returns:
title (str): A string containing the "💻" icon followed by the tool input's description.
"""
input = cast(BashInput, cast(ToolUseMessage, message.content).input)
return self._tool_title(message, "💻", input.description)

Expand Down Expand Up @@ -526,4 +574,4 @@ def generate_projects_index_html(

This is a convenience function that delegates to HtmlRenderer.generate_projects_index.
"""
return HtmlRenderer().generate_projects_index(project_summaries, from_date, to_date)
return HtmlRenderer().generate_projects_index(project_summaries, from_date, to_date)
46 changes: 32 additions & 14 deletions claude_code_log/html/tool_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,18 @@


def _render_question_item(q: AskUserQuestionItem) -> str:
"""Render a single question item to HTML."""
"""
Render a single question item into an HTML question block.

Parameters:
q (AskUserQuestionItem): Question item containing optional `header`, the main `question` text,
optional `options` (each with `label` and optional `description`), and a `multiSelect` flag.

Returns:
html (str): HTML string representing the question block. Includes an optional header, the
question text prefixed with a "Q:" label, and an optional options list with a "(select one)"
or "(select multiple)" hint.
"""
html_parts: list[str] = ['<div class="question-block">']

# Header (if present)
Expand Down Expand Up @@ -116,12 +127,18 @@ def format_askuserquestion_input(ask_input: AskUserQuestionInput) -> str:


def format_askuserquestion_result(content: str) -> str:
"""Format AskUserQuestion tool result with styled question/answer pairs.

Parses the result format:
'User has answered your questions: "Q1"="A1", "Q2"="A2". You can now continue...'

Returns HTML with styled Q&A blocks matching the input styling.
"""
Render AskUserQuestion tool result into HTML with styled Q/A blocks.

Parses a success message containing quoted Question="Answer" pairs (the expected
format begins with "User has answered your question" and contains entries like
"Q"="A") and returns an escaped HTML fragment with each pair rendered as a
question block and an answer block. Returns an empty string if the input does
not match the expected success format or contains no pairs.

Returns:
html (str): HTML fragment containing the rendered Q/A blocks, or an empty
string when the input format is not a recognized successful response.
"""
# Check if this is a successful answer
if not content.startswith("User has answered your question"):
Expand Down Expand Up @@ -381,13 +398,14 @@ def format_task_output(output: TaskOutput) -> str:


def format_askuserquestion_output(output: AskUserQuestionOutput) -> str:
"""Format AskUserQuestion tool result with styled Q&A pairs.

Args:
output: Parsed AskUserQuestionOutput with Q&A pairs

"""
Render an AskUserQuestionOutput as HTML containing styled question and answer blocks.

Parameters:
output (AskUserQuestionOutput): Parsed tool output containing a sequence of Q/A pairs.

Returns:
HTML string with styled question/answer blocks
html (str): HTML string with one styled question/answer block per pair.
"""
html_parts: list[str] = [
'<div class="askuserquestion-content askuserquestion-result">'
Expand Down Expand Up @@ -822,4 +840,4 @@ def format_tool_result_content_raw(tool_result: ToolResultContent) -> str:
"format_tool_use_title",
# Generic
"render_params_table",
]
]