feat(panel): Code tab and inbox code cards on Pierre, Luke's note under the lines
PR 4 of the approved "Pierre for File tabs and code snippets" plan. Built on #4283 (File tab and page source on Pierre), now merged; this PR targets main.
What it does
- Code tab cards are drawn by
@pierre/diffs(code-snippet.tsx,code-snippet-model.ts).- Each card's lines become one context-only hunk starting at the card's first line (
@@ -N,M +N,M @@), drawn through the bundle'smount. Review-thread previews already use this path, so line numbers match the file's. - Drawn unified and
excerpt, with no indicators, backgrounds or inline diff. The lines Luke pointed at are lit throughsetSelectedLines. - Follows View settings: theme, font, size, line height, ligatures, wrap and line numbers.
- Mounted as the card comes within 800px of the view; until then it holds roughly the height its lines will take.
- Coloured in the kept worker pool, through a new optional
pooledonDiffViewProps. This is additive:mount's default is unchanged, so thread previews are not affected.
- Each card's lines become one context-only hunk starting at the card's first line (
- Luke's note moves under the last pointed line as a Pierre annotation, drawn by #4283's
FileNoteAnnotationon the sharedAnnotationCard:- Luke's mark, his name and the time.
- ⋯ with View in conversation and Copy link, from
LINK_PLACE.TURN. - It folds.
- Hover or keyboard focus lights its lines.
- With Minimize inline comments on, the note becomes #4283's
MinimizedChipfloating at the end of its line. Hovering the chip lights the lines too. - The card's header (path, copy, open file) stays React, outside Pierre.
- The inbox code card (
inbox-code-card.tsx) uses the same component. So does the File tab's refused-file snippet fallback, which still draws every note that falls in the snippet. - Prefetch: while a call stands on the open task, the diff bundle's module starts loading (
usePrefetchDiffBundle), so the first card doesn't wait on the import. Only the module is imported; the worker pool starts on the first card's mount.- Cost to a call that never shows code: one import of
diff-view.js(822 KB minified, about 243 KB gzipped). Here that was about 150 ms of fetch, parse and eval with no long task, plus about 7 MB of heap, once per window.
- Cost to a call that never shows code: one import of
What retires
highlightCodein the host (task-code.ts).TaskCodeShowing.codenow carries plain lines (ShownCode), still cut down bycodeExcerpt.compose-tasks.tsno longer colours shown code.- The old card drawing:
CodeLinesincode-pane.tsx, the note above the lines (.code-card-noteand its CSS), andcopiedLines' token joining. notesAfter(file-note.tsx) anduseLinesLook(code-lines.tsx): their last caller was the snippet fallback. Their tests now drawFileNoteAnnotation. The two tests that only checkednotesAfter's row placement are deleted; placement is covered by this PR'scode-snippet.test.tsand #4283's whole-file tests.code-lines.tsxand its test, since #4285 landed first:runColoursmoves intotranscript-markdown.tsx, which still colours fences; the.code-lines*/.code-line*CSS,.file-note's dead margins and the--code-line-number*/--code-pointedtokens go; so do the now-unusedCodeTypeandisPointedexports.- Not removed here:
highlightFileand theTASKS_FILEcolouring step, still used by the File tab's commit probe and the inbox card's read. The File-tab agent's follow-up removes them.
Measured
Throwaway harness, as in the plan: esbuild with production defines, the build's own highlight worker, the built styles.css, headless Chromium, a 720px pane, 10 cards, median of 3. This PR against the base's card drawing (main). Main's colours are computed by the host before the view arrives, so main shows 0 ms of colouring in the window. The host spent 584 ms on the first card (highlighter load) and 1–213 ms on each card after.
| main | this PR | |
|---|---|---|
| During a call (one card every 400 ms): first card drawn | 61 ms | 210 ms (bundle import, without prefetch) |
| … each later card drawn after it lands | 0 ms | 19 ms |
| … each card coloured after it lands | 0 ms in window (host: 5–200 ms) | 115 ms median, 426 ms for the first (cold workers) |
| Opening the tab with 10 cards: lines drawn | 125 ms | 301 ms |
| Long tasks after the first card | 0 ms | 0 ms |
| Long tasks scrolling the Code tab (60 px/frame, there and back) | 0 ms | 0 ms |
| Longest frame while scrolling | 29 ms | 30 ms |
panel.js / diff-view.js | 291.3 KB / 821.9 KB | 291.3 KB / 822.0 KB |
These are Linux headless numbers; the plan measured the import at about 40 ms on a Mac. With the prefetch, the import happens before the first show_code lands.
Screenshots
Headless Chromium on the real built bundle and stylesheet (the harness above). Light and dark, wide (760px) and narrow (380px).
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
On a card that points at lines, the note is on exactly those lines, which are already lit at rest, so hovering it changes nothing visible there; that stays by design.
Tests
code-snippet.test.ts uses the real bundle in jsdom:
- the hunk's numbers match the snippet's, and the pointed lines are lit
- the note sits in the slot under the last pointed line and is said once
- a whole-file showing's note sits under the last line, and hovering it lights every line
- ⋯ View in conversation and Copy link work
- the note folds
- with Minimize on, the chip takes the note's place and shows it when pressed
- the inbox card draws the lines it read with the named ones lit
- the diff bundle starts loading once a call stands, and not before
Host test updated: shown code arrives with plain lines.
Checks run
Per-package tsc (panel, host, voice, features, desktop, web); the panel's tests (190 files under src/tasks, src/diff-view and src/desktop) plus the host's and features' affected tests; biome, ./scripts/oxlint.sh, pnpm knip, ./scripts/repository-checks.sh; node scripts/build.mjs. pnpm check:affected ran out of memory on the panel's typecheck, so that and the others were run one by one.
No service change.
Made with Luke













