feat(react-grab): inline source snippets, fiber props, and stack-tail collapse#325
Conversation
… collapse Three targeted improvements to the clipboard payload that AI agents read: - Source-snippet inlining: when an owner-stack frame resolves to a same-origin source file we now embed a small window of authored code around the call site with a `>` marker on the resolved line. Snippets that fail a JSX/component- name trust check are tagged `(approximate)` so the agent doesn't blindly edit noise. Vite's `_jsxDEV`-rewritten output is fingerprinted and rejected. - Component instance snapshot: the innermost user-source stack line falls back to a JSX-call signature (`in <Link href="..." />`) sourced from the React fiber's `memoizedProps` when no trustworthy snippet is available. We dedupe against the snippet so the agent never sees the same call site twice. - Stack-tail collapse: when multiple grabbed elements share a suffix in their React stack we emit the diverging prefixes per entry and the shared tail once at the bottom, materially shrinking the payload for list-heavy grabs. Also extracts `is-useful-component-name`, `find-longest-common-suffix`, and `escape-regexp` into one-util-per-file modules per AGENTS.md, and adds 18 new unit tests covering the new utilities and the trust/transform guards. Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
commit: |
There was a problem hiding this comment.
4 issues found across 20 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/react-grab/src/utils/get-source-snippet.ts">
<violation number="1" location="packages/react-grab/src/utils/get-source-snippet.ts:55">
P1: Indexed source maps are skipped due to an early return, so snippet lookup fails when sources are only in `sections`.</violation>
</file>
<file name="packages/react-grab/src/core/context.ts">
<violation number="1" location="packages/react-grab/src/core/context.ts:545">
P2: Include the fiber component instance in this fallback path. Otherwise, when source snippets are unavailable because the owner stack cannot be formatted, the memoizedProps JSX-call fallback is skipped and only bare component names are copied.</violation>
</file>
<file name="packages/react-grab/src/utils/format-component-instance.ts">
<violation number="1" location="packages/react-grab/src/utils/format-component-instance.ts:35">
P2: Formatting invalid `Date` props can throw and break component snapshot generation.</violation>
<violation number="2" location="packages/react-grab/src/utils/format-component-instance.ts:61">
P3: Overflow count is computed before filtering non-renderable values, so `/* +N more */` can overcount.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- get-source-snippet: don't bail on indexed source maps. Maps that only
expose `sections` (no top-level `sources`/`sourcesContent`) were short-
circuited before the recursion; now we always recurse when sections exist.
- format-component-instance: invalid Date props (`new Date("nope")`)
used to throw inside `toISOString()` and break snapshot generation.
Guard via `Number.isNaN(getTime())` and emit `{Date(Invalid)}`.
- format-component-instance: stop counting `undefined`-valued props past the
cap toward `/* +N more */`. Move the limit check after `formatPropValue` so
values that wouldn't have rendered don't inflate the overflow marker.
- core/context: when the owner stack isn't formattable but we have fiber
component names, surface the innermost component's `memoizedProps` as a
JSX-call signature instead of just the bare name — same fallback the
source-snippet path already provides.
Adds two unit tests (invalid Date, undefined-past-limit overflow). 96 unit
tests pass; 13 element-context e2e pass; lint/typecheck/format clean.
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Thanks for the review. All four issues addressed in 9522b96:
Verified: 96 unit tests pass (+2 new), 13 element-context e2e pass, lint/typecheck/format clean. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9522b96. Configure here.
- join-snippets: collapsed shared stack tail's first line lost its indent. `formatStackLines` produced `\n line1\n line2`, then `.trimStart()` stripped both the leading newline AND the two-space indent, leaving the first tail line flush-left while the rest stayed indented. Replace with `indentStackLines` (joins on `\n`) and `formatDivergingStackLines` (only prefixes with `\n` when there is content), which keeps every shared-tail line at the same indent level. New unit test guards the regression. - generate-snippet: `emptyParts` was a shared mutable singleton; a stray `push` from any consumer would corrupt every future error fallback. Build a fresh `ElementContextParts` per rejection. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Bugbot follow-up addressed in c4d9a68:
97 unit tests pass, 13 element-context e2e pass, lint/typecheck/format clean. |
|
react review |
8 similar comments
|
react review |
|
react review |
|
react review |
|
react review |
|
react review |
|
react review |
|
react review |
|
react review |

Summary
Three targeted improvements to the clipboard payload that AI coding agents consume when a user grabs an element:
>marker on the resolved line. Snippets that fail a JSX/component-name trust check are tagged(approximate). Vite's_jsxDEV-rewritten dev output is fingerprinted and rejected so the agent never sees transformed noise.in <Link href=\"...\" />) sourced from the React fiber'smemoizedPropswhen a trustworthy snippet is not available. The two signals are deduped so the agent never sees the same call site twice.Why
Author confidence in the snippet matters more than verbosity:
memoizedPropsis the only signal that survives across all bundlers, so it's the natural fallback when source snippets are unavailable.Implementation notes
getSourceContentdedupes in-flight fetches but evictsnullresults so a transient HMR-rebuild failure doesn't permanently block snippets.sourcesarrays (webpack://,vite://) are handled via suffix matching, but only when the lookup has ≥2 path segments to prevent basenames from cross-file false-matching.new URL(fileName, location.origin)so a doctored_debugSource.fileNamecan't trigger cross-origin requests, including via//host/...protocol-relative paths.<UpperCase); broader tokens like=>orfunctionwould silently mark wrong-target resolutions as trustworthy.is-useful-component-name,find-longest-common-suffix, andescape-regexpextracted as one-util-per-file modules perAGENTS.md.Public API (
generateSnippet,joinSnippets,getStackContext) is preserved.Test plan
pnpm lint/pnpm typecheck/pnpm formatcleancopy-feedback.spec.tsflakes verified on baseline (unrelated)Stacked on
Base is #323. When that lands, this PR will auto-rebase onto
main.Made with Cursor
Note
Medium Risk
Changes the core clipboard-context generation pipeline (stack formatting, snippet joining, and new source fetching), which could affect correctness/size of copied output and introduce edge cases across bundlers despite added tests and same-origin guards.
Overview
Improves the clipboard payload agents receive by inlining a nearby authored source snippet (with approximate/trust markings) when a stack frame resolves to a same-origin source file, and by falling back to a JSX-like component instance signature derived from fiber
memoizedPropswhen a trustworthy snippet isn’t available.Refactors context generation to produce structured
ElementContextPartsand updates copy/join logic to collapse shared React stack suffixes across multi-element grabs (emitting per-entry diverging prefixes plus one shared tail, and sharing a single snippet block when identical), while preserving existing public APIs (generateSnippet,joinSnippets,getStackContext).Updates docs/readmes copy and expands coverage with new unit + e2e tests around snippet trust/transform detection, prop formatting, and stack-tail collapsing behavior.
Reviewed by Cursor Bugbot for commit e059f9f. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
In
react-grab, inline authored source snippets, attach component props to the innermost stack frame, and collapse shared stack tails to make copied context smaller and clearer. Now more robust with indexed source maps and safer prop formatting, plus clearer READMEs and Storybook docs.New Features
_jsxDEV.memoizedProps, renderingin <Component ... />when no trustworthy snippet is available; deduped so the call site never appears twice and never applied to library frames.Bug Fixes
sections, fixing missing snippets for sectioned maps.Dateprops and stop countingundefinedvalues toward the prop overflow marker; improves instance rendering and avoids errors.memoizedPropson the innermost line for consistent fallback.generateSnippetPartsto prevent cross-entry mutation leaks.Written for commit e059f9f. Summary will update on new commits.