Resolve grabs to app source instead of UI library wrappers#446
Merged
Conversation
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
commit: |
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
getCachedFiberSource cached the first promise per element forever, so a grab that resolved before the fiber's source metadata was attached could never recover. Evict null resolutions so a later grab retries, while still deduping concurrent in-flight lookups.
ignorePaths was the only field of SourceOptions, so drop the whole source/sourceOptions plumbing (public Options.source, the API option on getElementContext, and the threading through resolution/copy/snippet). The built-in components/ui ignore stays; classification now depends solely on fileName, so it is always cacheable.
A reviewer suggested Math.min, which would collapse the hard cap onto the soft budget and disable digging past low-signal frames. Document why max is required.
aidenybai
commented
Jun 8, 2026
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Retain all PR functionality (source classification, low-signal trace digging, selector hints, descendant preview text) while cutting indirection: classify source paths once at construction, collapse the trusted/low-signal flag pair into one signal field, share one context composer, and revert noise churn. Split context.ts (820 -> ~475 lines) along clean seams into next-server-frames.ts and html-preview.ts, extract is-next-project-runtime.ts to fix a utils->core import inversion, and delete dead options, constants, and the CSS.escape polyfill. Fix two regressions found by adversarial review and pin them with mutation-verified e2e tests: getHTMLPreview kept child placeholders only for a/code/pre subsumption, and copy references preserve newlines inside attribute values. Revert the README example to match actual copy output.
Move the thrice-declared wire shapes (SourceLocation, ReactGrabStackFrame, ReactGrabEntry) to global types, with SourceLocation extending SourceInfo. Inline the dead-null resolveStackFrameSource branch, flatten the formatStackContext emit closure, collapse getTraceContext's duplicated leading-source fallback, and drop always-constant parameters. Revert the CLI GrabEntry to its four-field shape since it only reads commentText. Rename source-frame-policy to classify-source-path after its export, and replace vague locals (resolvedElement, resolved, cached, promise, name, value) with descriptive names throughout the touched files.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a149248. Configure here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why
When you grab an element, React Grab resolves its source location for the label, "open file", and the copied snippet. Today it trusts the first real on-disk source it finds — React's fiber
_debugSourceor the top owner-stack frame. That file is often a design-system / UI-library wrapper (shadcncomponents/ui, Radix, Pebble, …), not the app component that actually rendered it.So grabbing a button can point you at
components/ui/button.tsxor@radix-ui/react-*instead of the page that used it — sending you and the agent into wrapper code rather than your own.What changed
Grabs now resolve to your app's source, falling back to wrappers/packages only when there's nothing better.
components/uiby default for shadcn-style wrappers.node_modulessegment (bundled/minified deps, relative scoped paths like../@radix-ui/...).application/x-react-grabclipboard payload.New option:
source.ignorePathsMark your own design-system paths as wrappers. This accepts strings or
RegExp; strings also work via script-tagdata-options.This is purely additive —
Options.sourceis optional and existing behavior is unchanged when it's omitted.How it works
A single source-frame policy decides whether a frame is:
Resolution uses that same order:
React's fiber source is considered first within each tier, then owner-stack frames. The same policy is used everywhere source is resolved:
resolveSource, copy flow,getStackContext,getElementContext, primitives, and snippet generation.Notes
node_modules, Vite optimized deps, and CDN URLs.Testing
nr buildpnpm test(Playwright e2e + Vitest unit, including parser/policy/source-selection tests)pnpm lintpnpm typecheckpnpm format