Category toggles and the auto-redact checkbox now survive page
reloads. On mount, useFilters reads from localStorage keys
session-viewer:enabledCategories and session-viewer:autoRedact,
falling back to defaults when storage is empty, corrupted, or
contains invalid category names. Each state change writes back
to localStorage in a useEffect.
Tests cover round-trip persistence, invalid data recovery, corrupted
JSON fallback, and the boolean coercion for auto-redact.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change the default-hidden message categories from [thinking,
hook_progress] to [tool_result, system_message, hook_progress,
file_snapshot]. This hides the verbose machine-oriented categories
by default while keeping thinking blocks visible — they contain
useful reasoning context that users typically want to see.
Also rename the "summary" category label from "Summaries" to
"Compactions" to better reflect what Claude's summary messages
actually represent (context-window compaction artifacts).
Tests updated to match the new defaults: the filter test now
asserts that tool_result, system_message, hook_progress, and
file_snapshot are all excluded, producing 5 visible messages
instead of the previous 7.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded absolute paths in test assertions with dynamically
constructed paths matching the temp directory. This makes tests portable
across environments where path.resolve() produces different results.
Add test verifying that absolute paths pointing outside the projects
directory (e.g. /etc/shadow.jsonl) are rejected by the discovery filter.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Visual overhaul of exported HTML to match the new client dark design:
- Replace category-specific CSS classes with inline border/dot/text styles
from a CATEGORY_STYLES map matching client-side colors
- Add message header layout with category dot, label, and timestamp
- Add Inter font family, refined prose typography, and proper code styling
- Add print-friendly media query
- Redesign redacted divider with SVG eye-slash icon and red accent
- Add SVG icons to session header metadata (project, date, message count)
- Fix singular/plural for '1 message' vs 'N messages'
Performance: Skip markdown parsing for hook_progress, tool_result, and
file_snapshot categories (structured data). Render as preformatted text
instead, avoiding expensive marked.parse() on large JSON blobs (~300ms each).
Replace local escapeHtml with shared/escape-html module. Add formatTimestamp
helper. Add cast safety comment for marked.parse() sync usage.
Update test to verify singular message count ('1 message' not '1 messages').
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The keyword pre-filter used case-sensitive string matching for all patterns,
but several regex patterns use the /i flag (e.g. generic_api_key). This meant
inputs like 'ApiKey = "secret"' would skip the keyword check for 'api_key'
and miss the redaction entirely.
Changes:
- Add caseInsensitive parameter to hasKeyword() that lowercases both content
and keywords before comparison
- Detect /i flag on pattern regex and pass it through automatically
- Narrow IP address keywords from ["."] to ["0.", "1.", ..., "9."] to reduce
false-positive regex invocations on content containing periods
- Fix email regex character class [A-Z|a-z] → [A-Za-z] (the pipe was literal)
- Add clarifying comment on url_with_creds pattern
- Add test cases for mixed-case and UPPER_CASE key assignments
- Relax SECRET_KEY test assertion to accept either redaction label
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security: Reject session paths containing '..' traversal segments or
non-.jsonl extensions before resolving them. This prevents a malicious
sessions-index.json from tricking the viewer into reading arbitrary files.
Performance: Process all project directories concurrently with Promise.all
instead of sequentially awaiting each one. Each directory's stat + readFile
is independent I/O that benefits from parallelism.
Add test case verifying that traversal paths and non-JSONL paths are rejected
while valid paths pass through.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>