Add a Resume Session button to the transcript HTML toolbar - #308
Add a Resume Session button to the transcript HTML toolbar#308max-nothacker wants to merge 2 commits into
Conversation
Single-session HTML pages get a floating '▶ Resume Session' button that copies `cd <cwd> && claude -r <session-id>` to the clipboard and shows a toast prompting the user to paste it into a terminal. The command's quoting follows the OS the transcript was recorded on, detected from the recorded cwd's path shape (the host-decoupled idiom of path_looks_absolute, daaain#151) — the session must be resumed on the machine that recorded it, wherever the page is viewed. Combined pages spanning several trunk sessions don't render the button since `claude -r` would be ambiguous there. The TUI already resumes sessions (the 'c' binding execs claude -r); this brings the same capability to the HTML output, where spawning a process isn't possible. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> in the session with id 4229268a
📝 WalkthroughWalkthroughThe HTML renderer now creates a resume command for single-session transcripts. The transcript adds a floating button that copies the command or uses a prompt fallback. CSS, snapshots, unit tests, and Playwright tests cover the new behavior. ChangesResume Session workflow
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant HTMLRenderer
participant transcript.html
participant Browser
participant ClipboardAPI
HTMLRenderer->>transcript.html: pass resume_command
transcript.html-->>Browser: render Resume Session button
Browser->>ClipboardAPI: copy resume command
ClipboardAPI-->>Browser: return success or failure
Browser-->>Browser: show toast or prompt fallback
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
test/test_resume_session_browser.py (2)
15-16: 📐 Maintainability & Code Quality | 🔵 TrivialRun the required validation before pushing.
As per coding guidelines, run Ruff formatting and linting plus
pyrightortyfor this Python change. Runjust cibefore pushing.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/test_resume_session_browser.py` around lines 15 - 16, Before pushing, run the repository’s required validation for the Python test changes in test_resume_session_browser.py: execute Ruff formatting and linting, run pyright or ty, and complete the full just ci check.Source: Coding guidelines
85-96: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd browser coverage for the
window.promptfallback.This helper always provides a successful
navigator.clipboard.writeText. The browser suite cannot detect a regression in the fallback required by this workflow. Add a test that makes clipboard writes fail or unavailable, stubswindow.prompt, and verifies the command and toast.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/test_resume_session_browser.py` around lines 85 - 96, Extend the browser coverage around the clipboard setup in test_resume_session_browser.py with a case where navigator.clipboard.writeText fails or is unavailable, stub window.prompt, and verify the expected command plus success toast from the fallback workflow. Keep the existing successful clipboard path intact while ensuring the fallback behavior is exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@claude_code_log/html/templates/components/global_styles.css`:
- Around line 367-376: Update the font-family declaration in
.resume-session.floating-btn to remove the quotes around SFMono-Regular while
preserving the existing fallback fonts and styling.
In `@claude_code_log/html/templates/transcript.html`:
- Around line 291-301: Update the toast creation block for resumeToast to set
role="status" and aria-live="polite" before appending the element to
document.body, ensuring copy confirmations are announced by assistive
technology.
In `@claude_code_log/utils.py`:
- Around line 215-238: Harden resume_command_for_session by validating and
normalizing session_id as the expected UUID before constructing any command,
rejecting invalid values. For Windows paths, reject embedded double quotes (or
otherwise generate syntax safe for one explicitly supported Windows shell)
before inserting cwd into the command. Preserve the existing POSIX/Windows
command behavior for valid inputs, and add regression coverage for shell
metacharacters in session_id and quoted Windows cwd values.
In `@test/__snapshots__/test_snapshot_html.ambr`:
- Around line 5214-5227: Add role="status" and aria-live="polite" to the
resumeToast element created in showResumeToast, then regenerate the affected
HTML snapshots to capture the accessibility attributes.
In `@test/test_resume_session_browser.py`:
- Line 98: Replace the file URL construction in both browser navigation calls in
the resume-session test with the HTML path’s Path.as_uri() result, passing that
portable URI to Page.goto. Before pushing the changes, remind the user to run
just ci.
---
Nitpick comments:
In `@test/test_resume_session_browser.py`:
- Around line 15-16: Before pushing, run the repository’s required validation
for the Python test changes in test_resume_session_browser.py: execute Ruff
formatting and linting, run pyright or ty, and complete the full just ci check.
- Around line 85-96: Extend the browser coverage around the clipboard setup in
test_resume_session_browser.py with a case where navigator.clipboard.writeText
fails or is unavailable, stub window.prompt, and verify the expected command
plus success toast from the fallback workflow. Keep the existing successful
clipboard path intact while ensuring the fallback behavior is exercised.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c40b1757-7232-4c39-85e1-80985c736b7b
📒 Files selected for processing (7)
claude_code_log/html/renderer.pyclaude_code_log/html/templates/components/global_styles.cssclaude_code_log/html/templates/transcript.htmlclaude_code_log/utils.pytest/__snapshots__/test_snapshot_html.ambrtest/test_resume_session_browser.pytest/test_resume_session_button.py
| .resume-session.floating-btn { | ||
| bottom: 340px; | ||
| border-radius: 6px; | ||
| width: auto; | ||
| height: 28px; | ||
| padding: 0 10px; | ||
| font-size: 0.65em; | ||
| font-family: 'SFMono-Regular', Consolas, monospace; | ||
| font-weight: 600; | ||
| white-space: nowrap; |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the Stylelint font-family violation.
Line 374 quotes SFMono-Regular, but the configured Stylelint rule rejects these quotes. Remove them so linting passes.
Proposed fix
- font-family: 'SFMono-Regular', Consolas, monospace;
+ font-family: SFMono-Regular, Consolas, monospace;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .resume-session.floating-btn { | |
| bottom: 340px; | |
| border-radius: 6px; | |
| width: auto; | |
| height: 28px; | |
| padding: 0 10px; | |
| font-size: 0.65em; | |
| font-family: 'SFMono-Regular', Consolas, monospace; | |
| font-weight: 600; | |
| white-space: nowrap; | |
| .resume-session.floating-btn { | |
| bottom: 340px; | |
| border-radius: 6px; | |
| width: auto; | |
| height: 28px; | |
| padding: 0 10px; | |
| font-size: 0.65em; | |
| font-family: SFMono-Regular, Consolas, monospace; | |
| font-weight: 600; | |
| white-space: nowrap; |
🧰 Tools
🪛 Stylelint (17.14.1)
[error] 374-374: Expected no quotes around "SFMono-Regular" (font-family-name-quotes)
(font-family-name-quotes)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@claude_code_log/html/templates/components/global_styles.css` around lines 367
- 376, Update the font-family declaration in .resume-session.floating-btn to
remove the quotes around SFMono-Regular while preserving the existing fallback
fonts and styling.
Source: Linters/SAST tools
- resume_command_for_session returns None (no button) for session ids outside a conservative charset, Windows cwds containing " % ! $ or backtick (cmd/PowerShell expand those inside double quotes), and any cwd with a newline (pasting multi-line text can execute each line). Regression tests for each rejection plus shlex-escaping of a single quote in a POSIX cwd. - Toast gets role=status + aria-live=polite so screen readers announce the copy confirmation; snapshots regenerated serially (additive). - Browser test navigations use Path.as_uri(); docstrings added to new test helpers and methods. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> in the session with id 4229268a
|
Addressed the review in the latest push — per-finding outcome:
Full gate re-run locally: unit + browser suites, |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@claude_code_log/utils.py`:
- Around line 250-255: Update the Windows command generation in the
drive-handling branch of the relevant utility to switch to the recorded drive as
well as the directory, using syntax compatible with both cmd.exe and PowerShell
(such as pushd). Add a regression test covering a D: working directory while the
terminal starts on C:, and update the corresponding expectations in
test_resume_session_button.py.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b1a04016-d372-463e-9e9a-1a6778a8ef3f
📒 Files selected for processing (5)
claude_code_log/html/templates/transcript.htmlclaude_code_log/utils.pytest/__snapshots__/test_snapshot_html.ambrtest/test_resume_session_browser.pytest/test_resume_session_button.py
🚧 Files skipped from review as they are similar to previous changes (3)
- test/test_resume_session_browser.py
- claude_code_log/html/templates/transcript.html
- test/snapshots/test_snapshot_html.ambr
| if PureWindowsPath(cwd).drive: | ||
| if _WINDOWS_CWD_UNSAFE_RE.search(cwd): | ||
| return None | ||
| # Windows shells (PowerShell 7+, cmd): double quotes handle | ||
| # spaces; backslashes are literal inside them. | ||
| return f'cd "{cwd}" && claude -r {session_id}' |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Use a command that changes the Windows drive.
cmd.exe keeps its active drive after cd "D:\repo". If the terminal starts on C:, this command starts Claude from the current C: directory instead of the recorded working directory. The comment states that the command supports both cmd and PowerShell.
Generate syntax that works in each declared shell, such as pushd, or explicitly support one shell. Add a regression test for a D: working directory when the terminal starts on C:. Update the command expectations in test/test_resume_session_button.py.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@claude_code_log/utils.py` around lines 250 - 255, Update the Windows command
generation in the drive-handling branch of the relevant utility to switch to the
recorded drive as well as the directory, using syntax compatible with both
cmd.exe and PowerShell (such as pushd). Add a regression test covering a D:
working directory while the terminal starts on C:, and update the corresponding
expectations in test_resume_session_button.py.
Summary
Adds a floating ▶ Resume Session button to transcript HTML pages, next to the existing
md/uuid/ timeline / search / details / scroll-to-top buttons. Clicking it copiesto the clipboard and shows a toast prompting the user to paste it into a terminal. The TUI already resumes sessions (the
cbinding runsclaude -rdirectly); this brings the same capability to the HTML output, where spawning a process isn't possible — the clipboard is the next best thing.Behavior
collect_trunk_session_ids, so agent sidechains coalesce onto their parent and warmup-only sessions are ignored). Combined pages spanning several sessions don't get it —claude -rwould be ambiguous there.resume_command_for_sessioninutils.py) from the session's recordedcwd(the same canonical cwd already computed for SHA linkification). Path shape decides the quoting —PureWindowsPath(cwd).drive→ double quotes for Windows shells, otherwiseshlex.quotefor POSIX — following the host-decoupled path-shape idiom ofpath_looks_absolute(Support Obsidian-friendly output #151). Detecting the viewer's OS would be wrong: the session must be resumed on the machine that recorded it, wherever the HTML is being read.claude -r <session-id>.window.promptshows the command for manual copying.Tests
test/test_resume_session_button.py— unit tests forresume_command_for_session(Windows/POSIX/spaces/no-cwd) and for button presence/absence + attribute escaping in generated HTML.test/test_resume_session_browser.py— Playwright tests: clicking copies the exact command (clipboard stubbed) and shows the toast; multi-session pages have no button.-n0 --snapshot-update); the.ambrdiff is purely additive (+768/−0), and the button element appears only in single-session snapshots.ruff format,ruff check,pyright(0 errors),ty check.🤖 Generated with Claude Code in the session with id 4229268a
Summary by CodeRabbit