feat(sessions): Copy as Markdown — export a session, scrubbed - #65
Merged
Conversation
The M4 export slice (levelcode-sessions-experience.md §6): one action turns a session into a clean Markdown transcript for pasting into a PR, and it is the seed of a later share-a-run. **It scrubs, and that is not incidental.** chat-sessions-design.md §10 already decided this: transcripts at rest are the same trust class as your code, but "anything that later *shares* a session must scrub — that is that feature's burden." Export is the first surface that shares one, so redactSecrets — built last week for project memory — is passed in at the call site rather than baked into the renderer, so the scrub is visible where it happens instead of being a property you have to know the module has. **Roles are bold labels, never headings.** A turn routinely contains `## …` and fenced code; a heading-based role label is visually outranked by the content it is supposed to delimit, and `### LevelCode` above a reply opening with `#` reads as though the model wrote the section title. Bold plus a rule survives every renderer at every nesting depth. The success message counts TURNS, not characters: "Copied 14 turns" tells you whether you got the session you meant. **The fifth button.** The action row is two fixed-height lines and `flex-wrap: nowrap`, so buttons that do not fit do not wrap — they overflow. Five labelled buttons need ~300px and a sidebar is routinely narrower, so the card is now a container and the labels collapse below 360px, leaving icons at ~184px. Every button already carried title + aria-label, so nothing is lost to a pointer or a screen reader — only to the eye, and only when there is no room. Both webviews carry the card, and the pure block between the SESSIONS-PURE markers must stay byte-identical across them — sessionsView.html is synced, which is the existing test catching exactly what it was written for. Tests: 5 new in sessionEvents.test.js (structure, heading safety, the scrub, the opt-in, degenerate sessions), 2 in webviewCss.test.js pinning the overflow guard in BOTH sheets, and the action-row test updated to five buttons. The CSS guard is pinned because the failure is invisible in a wide window: whoever adds a sixth button will not see it break — a user with a narrow sidebar will. Verified non-vacuous: dropping the container query 13/15, the container-type 13/15, the aria-label 14/15, the export scrub 10/13. All 32 suites green.
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a “Copy as Markdown” export path for chat sessions in the LevelCode AI extension, producing a shareable, scrubbed transcript suitable for pasting into PRs and optionally saving to disk.
Changes:
- Introduces
sessionEvents.toMarkdown()to render a session transcript with provenance and turn delimiters. - Adds an
exportsession-card action wired throughextension.jsto copy to clipboard and optionally save as a.mdfile. - Updates both sessions webviews (chat + sessions view) to include a fifth action button and container-query CSS to prevent overflow in narrow panes, with tests pinning the behavior.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| extensions/levelcode-ai/sessionEvents.js | Adds Markdown transcript renderer for session export. |
| extensions/levelcode-ai/extension.js | Wires new export action: copy Markdown to clipboard + optional save dialog. |
| extensions/levelcode-ai/media/chat.html | Adds export button + CSS container query to collapse labels in narrow panes. |
| extensions/levelcode-ai/media/sessionsView.html | Mirrors export button + narrow-pane label collapse behavior for the sessions view. |
| extensions/levelcode-ai/test/sessionEvents.test.js | Adds tests covering transcript structure, heading-safety, opt-in redaction, and degenerate sessions. |
| extensions/levelcode-ai/test/sessionsUi.test.js | Updates sessions card action-row expectations to include the new export action. |
| extensions/levelcode-ai/test/webviewCss.test.js | Adds tests pinning container-query behavior and accessible button labeling. |
| docs/levelcode-sessions-memory.md | Updates M4 status/docs to mark session export complete and document scrub/role-label rationale. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…ename Two review findings on #65: - toMarkdown trimmed each turn's text, which changes Markdown semantics: a leading 4-space indent (indented code block) got de-indented and a trailing " " (hard line break) was eaten. Turn text is now emitted verbatim aside from redaction — the `**role**` blank line already supplies the blank an indented block needs. Pinned by a new test (indented code + trailing hard-break survive). - The default save-dialog filename was derived from the RAW entry.title, not the scrubbed copy toMarkdown makes — and the filesystem sanitiser only strips slashes/colons, so a credential's own characters survive it (ghp_ABC… → ghp-abc…). entry.title now goes through redactSecrets before the stem, so a token in a title can't leak into the save path. Pinned by a source invariant. 32 suites green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Aug 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The M4 export slice (
levelcode-sessions-experience.md§6): one action turns a session into a clean Markdown transcript for pasting into a PR — and the seed of a later share-a-run.