Skip to content
Open
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
20 changes: 18 additions & 2 deletions src/claude_code_transcripts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,30 @@ def get_session_summary(filepath, max_length=200):
def _get_jsonl_summary(filepath, max_length=200):
"""Extract summary from JSONL file."""
try:
# First priority: custom title (user renamed session via /rename)
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
try:
obj = json.loads(line)
if obj.get("type") == "custom-title" and obj.get("customTitle"):
title = obj["customTitle"]
if len(title) > max_length:
return title[: max_length - 3] + "..."
return title
except json.JSONDecodeError:
continue

# Second priority: summary type entries
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
try:
obj = json.loads(line)
# First priority: summary type entries
if obj.get("type") == "summary" and obj.get("summary"):
summary = obj["summary"]
if len(summary) > max_length:
Expand All @@ -131,7 +147,7 @@ def _get_jsonl_summary(filepath, max_length=200):
except json.JSONDecodeError:
continue

# Second pass: find first non-meta user message
# Third pass: find first non-meta user message
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
Expand Down
20 changes: 20 additions & 0 deletions tests/test_generate_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,26 @@ def test_truncates_long_summaries(self, tmp_path):
assert len(summary) <= 100
assert summary.endswith("...")

def test_gets_custom_title_from_jsonl(self, tmp_path):
"""Test extracting custom title from JSONL file (set via /rename)."""
jsonl_file = tmp_path / "test.jsonl"
jsonl_file.write_text(
'{"type":"custom-title","customTitle":"GIT stuff","sessionId":"abc123"}\n'
'{"type":"user","message":{"content":"Hello"}}\n'
)
summary = get_session_summary(jsonl_file)
assert summary == "GIT stuff"

def test_custom_title_takes_priority_over_summary(self, tmp_path):
"""Test that custom title takes priority over summary entry."""
jsonl_file = tmp_path / "test.jsonl"
jsonl_file.write_text(
'{"type":"custom-title","customTitle":"My Custom Title","sessionId":"abc123"}\n'
'{"type":"summary","summary":"Auto-generated summary"}\n'
)
summary = get_session_summary(jsonl_file)
assert summary == "My Custom Title"


class TestFindLocalSessions:
"""Tests for find_local_sessions which discovers local JSONL files."""
Expand Down