Closes#114.
Three orthogonal bugs that surfaced together when live mode picked an
element inside a Vite React/TSX component with sibling branches:
1. JSX wrapper insertion produced invalid TSX
- Replacing a single picked JSX child with [comment, <div>, comment]
yields three adjacent siblings, which oxc rejects with "Adjacent
JSX elements must be wrapped in an enclosing tag."
- A Fragment `<></>` solves the adjacency case but breaks
`cloneElement`-using parents (Radix `asChild`, Headless UI, etc.)
with "Invalid prop supplied to React.Fragment."
- Fix: keep the wrapper `<div data-impeccable-variants="ID">` as the
single JSX-slot child and tuck both marker comments INSIDE it.
accept/discard now expands its replacement range to include the
wrapper's `<div>` open/close lines via div-depth tracking.
2. carbonize produced nested template literals in TSX `<style>`
- extractCss captured `{` / `` `} `` lines from the agent's existing
`<style>{`…`}</style>` template, then handleAccept re-wrapped with
another pair, producing `<style>{`{`@scope…`}`}</style>` which oxc
rejects with "Expected `}` but found `@`".
- Fix: extractCss now strips a leading `{` and trailing `` `} ``
wherever they appear in the captured content (own line OR attached
to the first/last CSS line), so re-wrapping always yields exactly
one `{` ` … ` `}` pair.
3. Ambiguous source matching for repeated JSX branches
- `findElement` returned the first substring match. Multiple
`<aside className="card">` siblings all matched the same query, so
wrap silently landed on the first regardless of which one the user
picked.
- Fix: live-wrap accepts `--text TEXT` (the picked element's
textContent), collects ALL candidates via `findAllElements`, and
narrows by a tag-stripped, JSX-expression-stripped substring match.
Returns `element_ambiguous + candidates[]` when multiple branches
match equally; falls back to first-match when source uses dynamic
content (`<h1>{title}</h1>`) so existing flows aren't broken.
- The fake e2e agent now forwards `event.element.textContent` to
wrap, and live.md tells the agent to do the same.
Test coverage:
- New `vite8-react-tsx-repeated-aside` e2e fixture: three identical
`<aside>` branches, picks the second card's <h1>, runs the full
wrap → Go → cycle → accept → carbonize cycle on a real Vite + TSX
dev server, asserts that Hero One and Hero Three survive untouched
(proving wrap landed on the correct branch).
- Six new unit tests across live-wrap.test.mjs and live-accept.test.mjs
covering the Fragment-replacement design, both leading/trailing
template-literal placements, --text disambiguation, the dynamic-
content fallback, and the element_ambiguous error shape.
- New `runtime.assertSourceContains` fixture hook so other regression
fixtures can assert sibling-branch survivability cheaply.
All 186 unit + static-fixture tests pass; all 21 live e2e fixtures
(20 prior + new TSX) pass with no console errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>