Skip to content

feat(annotate): per-file version diff for .md and .html (rendered HTML highlights)#961

Open
egouilliard-leyton wants to merge 4 commits into
backnotprop:mainfrom
egouilliard-leyton:feat/annotate-version-diff
Open

feat(annotate): per-file version diff for .md and .html (rendered HTML highlights)#961
egouilliard-leyton wants to merge 4 commits into
backnotprop:mainfrom
egouilliard-leyton:feat/annotate-version-diff

Conversation

@egouilliard-leyton

Copy link
Copy Markdown

Closes #960

What

Brings the version diff (the highlighted "what changed since the last version" view that plan mode has) to annotate mode, for both Markdown and HTML files. Annotate already has the diff UI (PlanDiffViewer, Version Browser, block-level comments) — it just never received previousPlan/versionInfo, because the annotate server didn't track history. This wires that up.

  • .md / .txt → the existing rendered Markdown diff (clean / classic / raw), with block comments.
  • .html with --render-html → the diff is rendered as the real page with inline <ins>/<del> highlights (not a source dump), so you see where it changed, and commenting still works because it's the same HtmlViewer iframe.

How

  • History keyed by file path. Unlike the plan flow (generateSlug = first-heading + date), annotate keys history by file path — annotate-{sanitized-basename}-{hash8} — so re-opening the same file groups its versions across edits even when headings change. Dedup + sequential numbering reuse the existing saveToHistory storage.
  • Server (packages/server/annotate.ts + Pi apps/pi-extension/server/serverAnnotate.ts). On open, save the markdown (or raw HTML source) to history, then expose previousPlan / versionInfo / diffCurrent on /api/plan and add /api/plan/version + /api/plan/versions. Both runtimes updated per AGENTS.md.
  • HTML rendered diff. New packages/shared/html-diff.ts: a small, dependency-light, tag-aware htmlDiff(old, new) that wraps changed text in <ins>/<del> while keeping tags balanced (<script>/<style> treated as opaque). The server sends diffHtml = rewriteHtml(htmlDiff(prev, current)); HtmlViewer injects ins/del highlight CSS and shows a "Show changes" toggle; App swaps the iframe to the diff page when toggled and suppresses the Markdown block-diff path on the HTML surface (where markdown is empty).

Testing

  • packages/shared/html-diff.test.ts — 9 unit tests (text change, word replace, added element, script/style opacity, identical-input no-op, structural balance).
  • tsc --noEmit clean for packages/shared, packages/server, packages/ui; frontend build clean.
  • Manually verified end to end on a real 58 KB HTML spec: the diff renders as the page with inline highlights, the toggle works, and commenting works on the diff view. /api/plan returns renderAs: html + diffHtml, and /api/plan/versions lists the stored versions.

Notes

  • HTML diff is a linear token diff (delete + insert for moves; attribute-only changes re-emit the tag without a visible marker). Good enough for the prose/spec-review use case; a tree-aware pass could be a follow-up.

🤖 Generated with Claude Code

Annotate mode never tracked version history, so the existing Plan Diff
(highlighted diff vs a previous version) only worked in plan mode. Wire
per-file version history into the annotate server so the same diff UI —
badge, Version Browser, block-level comments — works when annotating a
standalone .md/.txt/.html file.

- key history by file path (stable across edits) rather than the plan
  flow's heading+date slug
- save the markdown (or raw HTML source) to history on each open, expose
  previousPlan + versionInfo + diffCurrent on /api/plan
- add /api/plan/version and /api/plan/versions to the annotate server

Markdown lights up end to end; HTML needs frontend follow-ups (feed the
HTML source as the diff content, surface the badge on the html surface,
default to source diff mode).
For --render-html files, render the version diff as the real page with
inline <ins>/<del> highlights instead of a markdown/source diff:

- add packages/shared/html-diff.ts: a tag-aware htmlDiff() that wraps
  changed text in <ins>/<del> while keeping tags balanced (script/style
  opaque). 9 unit tests.
- annotate server computes diffHtml = rewriteHtml(htmlDiff(prev, current))
  and exposes it on /api/plan
- HtmlViewer: inject ins/del highlight CSS, add a 'Show/Hide changes'
  toggle in its action bar
- App: store diffHtml, swap the iframe to the diff page when toggled, and
  suppress the markdown block-diff path on the HTML surface

Commenting still works because the diff page renders through the same
HtmlViewer iframe bridge.
Parity for the Pi (node:http) runtime: per-file version history,
previousPlan/versionInfo/diffCurrent + diffHtml on /api/plan, the
/api/plan/version[s] endpoints, and project wiring from the Pi CLI.
Vendors @plannotator/shared/html-diff into pi-extension/generated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Annotate mode: show the version diff (highlighted) for .md and .html files

2 participants