diff --git a/AGENTS.md b/AGENTS.md index 3b4734420..33b038182 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1489,7 +1489,7 @@ When a user denies a plan and Claude resubmits, the UI shows what changed betwee **State** (`packages/ui/hooks/usePlanDiff.ts`): Manages base version selection, diff computation, and version fetching. The server sends `previousPlan` with the initial `/api/plan` response; the hook auto-diffs against it. Users can select any prior version from the sidebar Version Browser. -**Diff annotations:** The clean diff view supports block-level annotation — hover over added/removed/modified sections to annotate entire blocks. Annotations carry a `diffContext` field (`added`/`removed`/`modified`). Exported feedback includes `[In diff content]` labels. +**Diff annotations:** The clean diff view supports block-level annotation — hover over added/removed/modified sections to annotate entire blocks. Annotations carry a `diffContext` field (`added`/`removed`/`modified`). Exported feedback includes `[In diff content]` labels. A diff annotation's `blockId` is `diff-block-N` (N indexes the diff against the selected base, not a document block), so the export cannot place it in the document: diff comments print together AFTER the document's other comments, in diff order (`sortAnnotationsInDocumentOrder` in `packages/ui/utils/parser.ts`); a document with no diff comments sorts exactly as before. **Annotation hook** (`packages/ui/hooks/useAnnotationHighlighter.ts`): Annotation infrastructure used by `Viewer.tsx`. Manages web-highlighter lifecycle, toolbar/popover state, annotation creation, text-based restoration, and scroll-to-selected. The diff view uses its own block-level hover system instead. @@ -1629,7 +1629,7 @@ Share links carry the FENCED form in the payload's `p` (`shareableDocumentMarkdo **Raw-HTML annotate:** the sandboxed viewer never mutates the visited page's DOM. Committed annotations render as numbered placed comment markers plus overlay-projected highlight rectangles inside a shadow-rooted fixed overlay host: the durable anchor data (element selector, text snapshot, normalized selected point) is persisted, and the markers/highlights are disposable projections re-resolved from it on every reconcile. Shift-click multi-select joins additional elements to one comment (`htmlAdditionalTargets`). -**Element context (agent-facing).** A pinpoint also captures a bounded description of the element at click time, `elementContext` on the annotation (`HtmlElementContext` in `packages/ui/types.ts`; extra targets carry a smaller one as `context`), built by `buildElementContext` in the bridge and re-validated at the parent trust boundary by `parseHtmlElementContext`, which lives in `packages/core/html-anchor.ts` beside `parseHtmlElementAnchor` (#1549); `useHtmlAnnotation.ts` imports and re-exports it rather than mirroring it, and the host persistence helpers in that same core module (`buildPersistedHtmlAnchor`, `projectHostThreads`) run it too, so a host that persists and projects through core keeps the field instead of dropping it on save. It is purely descriptive, never read by restore. Fields: tag, id, author classes, an ancestor `path`, explicit-or-implicit `role`, accessible `name`, an ALLOWLISTED attribute set (href/src scrubbed of query and fragment, `data:` truncated to its media type), rendered `text` (300), a collapsed HTML `outline` (600 chars; two child levels, then one, then a per-tag count, whichever first fits), child count, viewport `rect`, nearest `landmark` and `heading`, a `component` hint from `data-component`/`data-testid` ancestry (deliberately no React fiber reads), and in live-app sessions the `page` route and title. Never captured: form values, `on*` handlers, `style`, script/style/template contents, full innerHTML. Hard cap 2 KiB serialized per primary (1 KiB per extra target), shedding outline → text → attrs → classes → path → heading → landmark → component. Under the persisted anchor's own 16 KiB budget `buildPersistedHtmlAnchor` sheds contexts — per-target first, from the end, then the primary — BEFORE it drops any target, since a context is descriptive and re-derivable on the next click while a dropped target loses a marker the reviewer placed; `DEFAULT_HTML_ANCHOR_MAX_BYTES` is unchanged and the dropped-target counts still count targets only. The export (`elementContextExportBlock` in `packages/ui/utils/parser.ts`) prints a 4-backtick `html` fence of the outline plus `selector` / `path` / `role` · `name` · `component` / `attrs` / `text` / `box` / `near` lines under the comment; a text-less pinpoint's placeholder quote names WHICH element it is, not just its kind: the hover label plus the accessible name (`ctxName`: aria-label, alt, title, …) plus, for media (`img`, `video`/`audio` and their ``, `iframe`, `embed`, `object`, `input type=image`, svg ``), the source FILE name through the same `ctxScrubUrl` scrub (`[element: Image "Team photo" (team.jpg)]`, `[element: Image (data:image/png)]`; brackets and double quotes are swapped so it stays one token; `describeTextlessElement` in the bridge, used for the primary and every shift-click extra target). Restore never reads that quote (the anchor binds a text-less element), so pins saved with the older bare `[element: Image]` keep restoring. The export rewrites the placeholder to `Feedback on the