From 5ebb29dd2c22612934278ec571217bd4b71f9e9d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Mar 2026 20:58:39 +0000 Subject: [PATCH] Add time to filenames, improve output visuals, bump to v0.9.0 Filenames now include time when available (YYYY-MM-DD_HHMM_Title.html) instead of date-only prefix. This disambiguates multiple sessions on the same day and provides better chronological sorting. Visual improvements: - Copy button on code blocks (appears on hover) - Human-readable dates in session header (e.g. "Jun 15, 2025 at 10:30 AM") - Back-to-top button for long transcripts - Smooth scrolling - Colored accent bar on session header - Footer separator line - Reordered header metadata (date first, session ID last) https://claude.ai/code/session_0189aV17pTaCcifCjz3tsP3v --- Cargo.toml | 2 +- README.md | 14 +- pyproject.toml | 2 +- python/continue_transcripts/__init__.py | 2 +- src/main.rs | 239 +++++++++++++++++++++--- 5 files changed, 223 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 147a1f7..86d0387 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "continue-transcripts" -version = "0.8.0" +version = "0.9.0" edition = "2021" description = "Convert continue.dev session files to readable HTML transcripts" license = "MIT" diff --git a/README.md b/README.md index 9e56369..f152feb 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Convert [continue.dev](https://continue.dev) session files to readable, self-con - Optional title-based filtering with `--filter` - **Parallel processing** with configurable worker count (`--workers`) - **Terminal summary** — file counts, elapsed time, and per-file status indicators -- **Date-prefixed filenames** — output files are named `YYYY-MM-DD_Title.html` for easy chronological sorting +- **Date+time-prefixed filenames** — output files are named `YYYY-MM-DD_HHMM_Title.html` for easy chronological sorting (falls back to `YYYY-MM-DD_Title.html` when time is unavailable) - **Filename deduplication** — output filenames are truncated to 60 characters with automatic `_1`, `_2` suffixes on collision - Responsive design — works on desktop and mobile @@ -45,8 +45,8 @@ Output looks like: ``` Using 4 worker thread(s) Discovered 12 JSON file(s) - ✅ transcripts/2025-06-15_Fix_failing_tests_in_auth_module.html - ✅ transcripts/2025-06-14_Refactor_auth_module.html + ✅ transcripts/2025-06-15_1430_Fix_failing_tests_in_auth_module.html + ✅ transcripts/2025-06-14_0915_Refactor_auth_module.html ... ✅ transcripts/index.html @@ -73,7 +73,7 @@ Install globally so the `continue-transcripts` command is always available: ```sh uv tool install continue-transcripts \ --no-index \ - --find-links https://github.com/curtisalexander/continue-transcripts/releases/expanded_assets/v0.8.0 + --find-links https://github.com/curtisalexander/continue-transcripts/releases/expanded_assets/v0.9.0 ``` The `continue-transcripts` command is then available on your `PATH`. @@ -83,7 +83,7 @@ To upgrade later (update the version in the URL): ```sh uv tool install --upgrade continue-transcripts \ --no-index \ - --find-links https://github.com/curtisalexander/continue-transcripts/releases/expanded_assets/v0.8.0 + --find-links https://github.com/curtisalexander/continue-transcripts/releases/expanded_assets/v0.9.0 ``` To uninstall: @@ -100,7 +100,7 @@ Run without installing: uvx \ --no-index \ --from continue-transcripts \ - --find-links https://github.com/curtisalexander/continue-transcripts/releases/expanded_assets/v0.8.0 \ + --find-links https://github.com/curtisalexander/continue-transcripts/releases/expanded_assets/v0.9.0 \ continue-transcripts ./sessions ``` @@ -115,7 +115,7 @@ uv venv .venv source .venv/bin/activate uv pip install continue-transcripts \ --no-index \ - --find-links https://github.com/curtisalexander/continue-transcripts/releases/expanded_assets/v0.8.0 + --find-links https://github.com/curtisalexander/continue-transcripts/releases/expanded_assets/v0.9.0 ``` ### Building from source diff --git a/pyproject.toml b/pyproject.toml index 42773ef..585f5fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "continue-transcripts" -version = "0.8.0" +version = "0.9.0" description = "Convert continue.dev session files to readable HTML transcripts" readme = "README.md" license = { text = "MIT" } diff --git a/python/continue_transcripts/__init__.py b/python/continue_transcripts/__init__.py index 4d7a385..22722b5 100644 --- a/python/continue_transcripts/__init__.py +++ b/python/continue_transcripts/__init__.py @@ -1,3 +1,3 @@ """continue-transcripts - Convert continue.dev session files to readable HTML transcripts.""" -__version__ = "0.8.0" +__version__ = "0.9.0" diff --git a/src/main.rs b/src/main.rs index 661f8d3..6373e76 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1167,6 +1167,26 @@ fn file_modified_date(path: &Path) -> Option { Some(dt.format("%Y-%m-%d %H:%M").to_string()) } +/// Format a date string for human-readable display. +/// Converts ISO 8601 strings like "2025-06-15T10:30:00Z" into +/// "Jun 15, 2025 at 10:30 AM". Falls back to the raw string if parsing fails. +fn format_date_display(date: &str) -> String { + // Try RFC 3339 + if let Ok(dt) = chrono::DateTime::parse_from_rfc3339(date) { + return dt.format("%b %-d, %Y at %-I:%M %p").to_string(); + } + // Try ISO-ish with T separator + if date.len() >= 19 && date.as_bytes().get(10) == Some(&b'T') { + // Try parsing as NaiveDateTime + optional trailing Z/offset + let naive_str = &date[..19]; + if let Ok(ndt) = chrono::NaiveDateTime::parse_from_str(naive_str, "%Y-%m-%dT%H:%M:%S") { + return ndt.format("%b %-d, %Y at %-I:%M %p").to_string(); + } + } + // Already human-readable or plain date — return as-is + date.to_string() +} + /// Extract the model name from the session history. /// Looks through prompt logs for the first non-empty model title, /// falling back to the completion_options.model field. @@ -1661,7 +1681,7 @@ fn render_session(session: &Session, source_path: Option<&Path>) -> String { let date_str = session .date_created .as_deref() - .map(|s| s.to_string()) + .map(|s| format_date_display(s)) .or_else(|| source_path.and_then(file_modified_date)) .unwrap_or_else(|| "Unknown date".to_string()); @@ -1704,14 +1724,15 @@ fn render_session(session: &Session, source_path: Option<&Path>) -> String { +

{title}

- Session: {session_id} Date: {date}{model_meta} + {user_count} user · {assistant_count} assistant messages{tokens_meta} Workspace: {workspace} - {user_count} user messages · {assistant_count} assistant messages{tokens_meta} + Session: {session_id}
{system_prompt} @@ -1792,6 +1813,8 @@ const CSS: &str = r#"