Skip to content
Merged
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
10 changes: 9 additions & 1 deletion claude_code_log/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@
{
"file-history-snapshot", # Internal file backup metadata
"last-prompt", # Trailing marker written as the last line of a .jsonl
# Session metadata snapshots (positional state, no uuid/timestamp).
# Recorded whenever Claude Code writes a state checkpoint to the
# transcript; see #94 for the wider "propagate this state to
# surrounding messages" follow-up.
"permission-mode", # {permissionMode: 'acceptEdits'|...}
"custom-title", # {customTitle: <str>}
"agent-name", # {agentName: <str>}
"agent-color", # {agentColor: <str>}
}
)

Expand Down Expand Up @@ -365,7 +373,7 @@ def load_transcript(
# SILENT_SKIP_TYPES once confirmed safe to drop.
if not silent:
print(
f"Line {line_no} of {jsonl_path}: unrecognised message type "
f"Line {line_no} of {jsonl_path}: unrecognized message type "
f"{entry_type!r} - skipping"
)
except json.JSONDecodeError as e:
Expand Down
2 changes: 1 addition & 1 deletion test/test_dag_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -1319,7 +1319,7 @@ def test_multiple_passthrough_types(self, tmp_path: Path) -> None:
"p1", "s1", "2025-07-01T10:00:10.000Z", "u1", "attachment"
),
_make_passthrough_entry(
"p2", "s1", "2025-07-01T10:00:20.000Z", "p1", "permission-mode"
"p2", "s1", "2025-07-01T10:00:20.000Z", "p1", "other-unknown-type"
),
_make_passthrough_entry(
"p3", "s1", "2025-07-01T10:00:30.000Z", "p2", "unknown-future-type"
Expand Down
66 changes: 48 additions & 18 deletions test/test_silent_skip.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,39 @@ def test_constant_covers_issue_102(self) -> None:
assert "last-prompt" in SILENT_SKIP_TYPES
assert "file-history-snapshot" in SILENT_SKIP_TYPES

def test_constant_covers_session_metadata(self) -> None:
"""Issue #94: session-metadata types (no uuid/timestamp) drop silently."""
for t in ("permission-mode", "custom-title", "agent-name", "agent-color"):
assert t in SILENT_SKIP_TYPES

@pytest.mark.parametrize(
"entry",
[
{
"type": "permission-mode",
"permissionMode": "acceptEdits",
"sessionId": "s1",
},
{"type": "custom-title", "customTitle": "CCL (Monk)", "sessionId": "s1"},
{"type": "agent-name", "agentName": "CCL (Monk)", "sessionId": "s1"},
{"type": "agent-color", "agentColor": "purple", "sessionId": "s1"},
],
)
def test_session_metadata_silent(
self,
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
entry: dict[str, object],
) -> None:
jsonl = tmp_path / "session.jsonl"
_write_jsonl(jsonl, [entry])

messages = load_transcript(jsonl, silent=True)
captured = capsys.readouterr()

assert messages == []
assert captured.out == ""

def test_file_history_snapshot_silent(
self, tmp_path: Path, capsys: pytest.CaptureFixture[str]
) -> None:
Expand All @@ -55,12 +88,11 @@ def test_file_history_snapshot_silent(
],
)

messages = load_transcript(jsonl, silent=False)
messages = load_transcript(jsonl, silent=True)
captured = capsys.readouterr()

assert messages == []
assert "unrecognised" not in captured.out
assert "not a recognised" not in captured.out
assert captured.out == ""

def test_last_prompt_silent(
self, tmp_path: Path, capsys: pytest.CaptureFixture[str]
Expand All @@ -77,12 +109,11 @@ def test_last_prompt_silent(
],
)

messages = load_transcript(jsonl, silent=False)
messages = load_transcript(jsonl, silent=True)
captured = capsys.readouterr()

assert messages == []
assert "unrecognised" not in captured.out
assert "last-prompt" not in captured.out
assert captured.out == ""


class TestProgressStaysInDag:
Expand Down Expand Up @@ -111,27 +142,26 @@ def test_progress_becomes_passthrough(
],
)

messages = load_transcript(jsonl, silent=False)
messages = load_transcript(jsonl, silent=True)
captured = capsys.readouterr()

assert len(messages) == 1
assert isinstance(messages[0], PassthroughTranscriptEntry)
assert messages[0].type == "progress"
assert messages[0].uuid == "p1"
assert "unrecognised" not in captured.out
assert captured.out == ""


class TestUnrecognisedTypesWarn:
class TestUnrecognizedTypesWarn:
"""Unknown types with no DAG fields surface a warning so we notice
new Claude Code metadata worth supporting (custom-title, agent-name,
and anything that arrives later)."""
when Claude Code ships new metadata worth supporting — anything
outside the explicit silent-skip list or the Passthrough fallback."""

@pytest.mark.parametrize(
"entry",
[
{"type": "custom-title", "customTitle": "Dave", "sessionId": "s1"},
{"type": "agent-name", "agentName": "Dave", "sessionId": "s1"},
{"type": "future-metadata-type", "payload": 42},
{"type": "future-metadata-type", "payload": 42, "sessionId": "s1"},
{"type": "another-hypothetical", "something": "value"},
],
)
def test_unknown_without_uuid_warns(
Expand All @@ -147,14 +177,14 @@ def test_unknown_without_uuid_warns(
captured = capsys.readouterr()

assert messages == []
assert "unrecognised message type" in captured.out
assert "unrecognized message type" in captured.out
assert repr(entry["type"]) in captured.out

def test_silent_mode_suppresses_warning(
self, tmp_path: Path, capsys: pytest.CaptureFixture[str]
) -> None:
jsonl = tmp_path / "session.jsonl"
_write_jsonl(jsonl, [{"type": "custom-title", "customTitle": "x"}])
_write_jsonl(jsonl, [{"type": "future-unknown-type", "payload": 1}])

messages = load_transcript(jsonl, silent=True)
captured = capsys.readouterr()
Expand Down Expand Up @@ -182,9 +212,9 @@ def test_unknown_with_uuid_becomes_passthrough_silently(
],
)

messages = load_transcript(jsonl, silent=False)
messages = load_transcript(jsonl, silent=True)
captured = capsys.readouterr()

assert len(messages) == 1
assert isinstance(messages[0], PassthroughTranscriptEntry)
assert "unrecognised" not in captured.out
assert captured.out == ""
Loading
Loading