react-doctor 0.9.12-dev.a2b460d → 0.9.12-dev.ac87f7d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -1
- package/bin/react-doctor.js +1 -9
- package/dist/active-run-trace-dlIZeEvb.js +18 -0
- package/dist/active-scan-abort-registry-DwG6tSPy.js +28 -0
- package/dist/{build-section-divider-Vz879zXD.js → build-section-divider-BpENvzwG.js} +10 -25
- package/dist/{ci-BVYrYekU.js → ci-BhOBG3T0.js} +13 -12
- package/dist/cli.js +84 -32
- package/dist/{design-D-TYN_tr.js → design-Bq6di1tM.js} +4 -4
- package/dist/{devtools-DPRVRu3S.js → devtools-BiC-AP3B.js} +4 -4
- package/dist/{exit-gracefully-Cjv5kC_l.js → exit-gracefully-CYfF0GCJ.js} +15 -9
- package/dist/get-east-asian-width-Cglw13G7.js +444 -0
- package/dist/{report-error-1l7v6_dE.js → handle-error-CU-FMRyI.js} +18 -68
- package/dist/index.d.ts +53 -42
- package/dist/index.js +55121 -54716
- package/dist/{inspect-kkvDHKDE.js → inspect-B9H_IT4O.js} +22 -20
- package/dist/{install-ZeYvD9Rw.js → install-DoihOMNC.js} +9 -8
- package/dist/{install-doctor-script-D58Hr1dM.js → install-doctor-script-GGnj8tcj.js} +7 -449
- package/dist/{install-github-workflow-DkMicv8E.js → install-github-workflow-DWmRP55H.js} +10 -6
- package/dist/{install-react-doctor-CjgE52al.js → install-react-doctor-Gzbw8Ue9.js} +47 -45
- package/dist/{run-scan-app-Ciq22jzp.js → jsx-runtime-CMY_Q08d.js} +281 -2759
- package/dist/{print-branded-header-D4QYSu-h.js → print-branded-header-CqvClso3.js} +4 -4
- package/dist/project-analysis-worker.d.ts +1 -0
- package/dist/project-analysis-worker.js +51901 -0
- package/dist/prompt-runtime-scan-url-3SOiiFcU.js +240 -0
- package/dist/{read-object-file-OFRlvCAL.js → read-object-file-NSp2cOs9.js} +4 -4
- package/dist/{record-metric-CMe2d1Xv.js → record-metric-DVm5sVu2.js} +3259 -6046
- package/dist/report-error-JXHy8xn6.js +64 -0
- package/dist/{report-workflow-result-EagkH_v9.js → report-workflow-result-CPMR84K_.js} +5 -5
- package/dist/{resolve-scope-CMNrOdDf.js → resolve-scope-CWo3o4bf.js} +6 -6
- package/dist/{rules-CzR1qUru.js → rules-B4Dq5c0s.js} +6 -6
- package/dist/run-scan-app-DiVEX1yA.js +2510 -0
- package/dist/runtime-scan/browser-probe.iife.js +855 -0
- package/dist/runtime-scan-WErSEFfG.js +770 -0
- package/dist/sanitize-runtime-url-BB5x484j.js +76 -0
- package/dist/{scan-D4m5r4Rs.js → scan-58Yq0rYJ.js} +10 -22
- package/dist/semver-DFtnEmN-.js +3219 -0
- package/dist/{should-fail-scan-gate-lMTlhEhE.js → should-fail-scan-gate-BCCblBL_.js} +153 -184
- package/dist/{should-skip-prompts-mXKZBNCz.js → should-skip-prompts-DzzBAamD.js} +4 -4
- package/dist/should-use-tui-DVrQvWL6.js +25 -0
- package/dist/skills/improve-threejs/SKILL.md +102 -0
- package/dist/skills/performance/SKILL.md +113 -0
- package/dist/skills/react-doctor/SKILL.md +6 -0
- package/dist/{unref-stdin-Cxhw67r6.js → telemetry-runtime-B45Ns9aS.js} +57 -33
- package/dist/unref-stdin-BKT_s38a.js +12 -0
- package/dist/{version-CnvVY2VD.js → version-Cad39N0q.js} +4 -4
- package/dist/{why-BktDEhhH.js → why-DIEM7rdZ.js} +4 -4
- package/dist/with-run-span-B9ScJJx3.js +110 -0
- package/package.json +8 -9
- package/dist/chunk-q7NCDQ7-.js +0 -28
- package/dist/lsp.js +0 -81145
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
-
import {
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="f06aa592-3758-5107-8839-c5374c76b1f7")}catch(e){}}();
|
|
3
|
+
import { B as isNonInteractiveEnvironment } from "./record-metric-DVm5sVu2.js";
|
|
4
4
|
//#region src/cli/utils/should-skip-prompts.ts
|
|
5
5
|
const shouldSkipPrompts = (input = {}) => Boolean(input.yes) || Boolean(input.json) || isNonInteractiveEnvironment() || !process.stdin.isTTY;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { shouldSkipPrompts as t };
|
|
8
8
|
|
|
9
|
-
//# sourceMappingURL=should-skip-prompts-
|
|
10
|
-
//# debugId=
|
|
9
|
+
//# sourceMappingURL=should-skip-prompts-DzzBAamD.js.map
|
|
10
|
+
//# debugId=f06aa592-3758-5107-8839-c5374c76b1f7
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bf1397cc-4b46-5916-b023-686dc1b693e4")}catch(e){}}();
|
|
3
|
+
import { B as isNonInteractiveEnvironment } from "./record-metric-DVm5sVu2.js";
|
|
4
|
+
//#region src/cli/utils/resolve-tui-environment.ts
|
|
5
|
+
const resolveTuiEnvironment = (outputIsTty = process.stdout.isTTY === true) => ({
|
|
6
|
+
isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
|
|
7
|
+
nodeMajorVersion: Number(process.versions.node.split(".")[0]),
|
|
8
|
+
outputIsTty,
|
|
9
|
+
stdinIsTty: process.stdin.isTTY === true,
|
|
10
|
+
supportsRawMode: typeof process.stdin.setRawMode === "function",
|
|
11
|
+
terminalName: process.env.TERM
|
|
12
|
+
});
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/cli/utils/should-use-tui.ts
|
|
15
|
+
const isTuiEnvironmentSupported = (input) => !input.isNonInteractiveEnvironment && input.stdinIsTty && input.outputIsTty && input.supportsRawMode && input.nodeMajorVersion >= 22 && input.terminalName !== "dumb";
|
|
16
|
+
const shouldUseTui = (input) => {
|
|
17
|
+
if (!isTuiEnvironmentSupported(input)) return false;
|
|
18
|
+
const flags = input.flags;
|
|
19
|
+
return !(flags.score === true || flags.json === true || flags.jsonCompact === true || flags.jsonOut !== void 0 || flags.staged === true || flags.changedFilesFrom !== void 0);
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { shouldUseTui as n, resolveTuiEnvironment as r, isTuiEnvironmentSupported as t };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=should-use-tui-DVrQvWL6.js.map
|
|
25
|
+
//# debugId=bf1397cc-4b46-5916-b023-686dc1b693e4
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: improve-threejs
|
|
3
|
+
description: Audit and fix Three.js and React Three Fiber apps for frame-loop performance, GPU memory leaks, scene-graph correctness, and visual defects like z-fighting, shadow acne, wrong color space, and broken resize handling. Uses React Doctor as the scanning engine plus a visual rubric checked against rendered output. Use when the user asks to improve, audit, scan, or clean up a Three.js, R3F, react-three-fiber, drei, or WebGL app, or types `/improve-threejs`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Improve Three.js
|
|
7
|
+
|
|
8
|
+
Audits a Three.js or React Three Fiber (R3F) codebase and fixes what hurts most: work that runs every frame, GPU resources that never get disposed, scene-graph objects rebuilt on every render, and visual defects the user can see. React Doctor supplies the machine-verified code scan; this skill supplies the frame-loop judgment and the visual inspection a general React scanner lacks.
|
|
9
|
+
|
|
10
|
+
The core principle: severity follows the render loop. Code inside `useFrame` or a `requestAnimationFrame` callback runs 60 times per second, so a minor inefficiency there outweighs a major one in a settings panel. Rank every finding by where it runs, not by the rule's default severity.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
|
|
14
|
+
### Step 1: Recon
|
|
15
|
+
|
|
16
|
+
Identify the stack before scanning: plain Three.js or R3F, which helper libraries are in use (drei, postprocessing, rapier), and where the render loop lives (`useFrame` hooks, `requestAnimationFrame`, the `<Canvas frameloop>` setting).
|
|
17
|
+
|
|
18
|
+
Build a hot-path map: every `useFrame` body, every RAF callback, every pointer-move handler. These files get the strictest review in Step 3.
|
|
19
|
+
|
|
20
|
+
### Step 2: Scan
|
|
21
|
+
|
|
22
|
+
Run React Doctor read-only to collect structured evidence:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx react-doctor@latest --verbose
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
For a regression check after making changes, run with `--scope changed` and confirm the score did not drop.
|
|
29
|
+
|
|
30
|
+
### Step 3: Triage by frame-loop leverage
|
|
31
|
+
|
|
32
|
+
Re-rank the scanner's findings using the hot-path map, then hunt for the Three.js-specific problems the scanner cannot see. Confirm every finding at its `file:line` before reporting it.
|
|
33
|
+
|
|
34
|
+
**HIGH severity, runs every frame or leaks GPU memory:**
|
|
35
|
+
|
|
36
|
+
- **Allocation inside `useFrame`**: `new Vector3()`, `new Color()`, or fresh arrays passed to Three.js APIs each frame. Fix: hoist a scratch object to module scope or `useMemo`, then mutate it in place
|
|
37
|
+
- **`setState` inside `useFrame`**: re-renders the React tree on every frame. Fix: mutate refs directly; reserve state for discrete changes like selection or visibility
|
|
38
|
+
- **Missing disposal**: geometries, materials, textures, or render targets created imperatively and never disposed. Fix: call `dispose()` in the cleanup function, or move the object into R3F's declarative tree so it owns the lifecycle
|
|
39
|
+
- **Object reconstruction in render**: geometry or material instances created without `useMemo`, or inline `args` arrays whose identity changes each render, forcing R3F to rebuild the underlying object
|
|
40
|
+
|
|
41
|
+
**MEDIUM severity, per-render or per-interaction waste:**
|
|
42
|
+
|
|
43
|
+
- **Unstable scene-graph props**: inline `new THREE.Vector3()` or fresh material objects as props (plain arrays like `position={[x, y, z]}` are fine; R3F handles them)
|
|
44
|
+
- **Missing instancing**: hundreds of identical meshes rendered individually instead of through `<Instances>` or `InstancedMesh`
|
|
45
|
+
- **Wasted frames**: `frameloop="always"` on a scene that only changes on interaction. Fix: `frameloop="demand"` plus `invalidate()`
|
|
46
|
+
- **Uncached asset loading**: textures and models loaded outside `useLoader`, `useTexture`, or `useGLTF`, losing caching and Suspense integration
|
|
47
|
+
|
|
48
|
+
**LOW severity, hygiene:** React Doctor findings on non-canvas UI code, missing `<Preload>`, oversized textures.
|
|
49
|
+
|
|
50
|
+
### Step 4: Visual audit
|
|
51
|
+
|
|
52
|
+
Inspect what the scene actually renders. Every visual finding needs evidence: a screenshot, a frame capture, or a reproduced observation, never a guess from reading source. When a dev server and browser are available, load the app, capture the first stable frame, then capture again after moving the camera and interacting. When no browser is available, check the code-level causes listed below and label each finding as inferred from source.
|
|
53
|
+
|
|
54
|
+
Apply the mini rubric. A row fails only when the evidence shows the failure condition:
|
|
55
|
+
|
|
56
|
+
| Area | Check | Fail when |
|
|
57
|
+
| ---------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
58
|
+
| Render sanity | The scene reaches a stable frame after load | Black canvas, WebGL context errors, or content that never appears |
|
|
59
|
+
| Geometry | Move the camera along seams, edges, and boundaries | Gaps, missing faces, visible backfaces, or two surfaces flickering at the same depth (z-fighting) |
|
|
60
|
+
| Transparency and depth | Cross depth-order boundaries with overlapping or transmissive surfaces | Wrong sort order, halos, opaque surfaces that should transmit, or flicker at grazing angles |
|
|
61
|
+
| Textures | View mapped surfaces close, far, and at grazing angles | Missing textures, stretching, seams, moiré, shimmer, or washed-out colors from a wrong color space |
|
|
62
|
+
| Materials and lighting | Change light and view direction on lit surfaces | Surfaces that ignore light direction, or reflective metals with no environment to reflect |
|
|
63
|
+
| Shadows | Move casters, receivers, and the light through their range | Acne, detached or floating shadows, flicker at rest, or shadows that outlive their caster |
|
|
64
|
+
| Camera | Follow the primary subject through movement and transitions | Subject leaves frame, camera clips into geometry, or foreground blocks the play area |
|
|
65
|
+
| Scale and contact | Compare object scale and resting contact against surroundings | Objects float above, sink into, or intersect their support surface, or sit at implausible scale |
|
|
66
|
+
| Image stability | Pan the camera slowly at supported resolutions | Silhouettes, thin geometry, or highlights that crawl, sparkle, or ghost |
|
|
67
|
+
| Resize and DPR | Change viewport size, zoom, and device pixel ratio | Distortion, blur, stretched output, or content leaving the viewport |
|
|
68
|
+
|
|
69
|
+
Each rubric row has a small set of usual code-level causes. Check these first when a row fails:
|
|
70
|
+
|
|
71
|
+
- **Washed-out or too-dark colors**: `renderer.outputColorSpace` not set to `SRGBColorSpace`, color textures missing `texture.colorSpace = SRGBColorSpace`, or a data texture (normal, roughness) wrongly marked sRGB
|
|
72
|
+
- **Z-fighting**: coplanar geometry needing `polygonOffset` or a position nudge, or a near plane set far too small for the scene scale
|
|
73
|
+
- **Shadow acne or floating shadows**: `shadow.bias` and `shadow.normalBias` untuned, or a shadow camera frustum far larger than the scene
|
|
74
|
+
- **Blurry or stretched canvas**: renderer size not synced to canvas CSS size, `setPixelRatio` never called, or a resize handler that forgets `camera.updateProjectionMatrix()`
|
|
75
|
+
- **Black metals**: `metalness: 1` with no `scene.environment` set
|
|
76
|
+
- **Transparency sorting glitches**: large transparent meshes needing `depthWrite: false`, manual `renderOrder`, or a split into smaller meshes
|
|
77
|
+
- **Shimmer and crawl**: missing texture anisotropy, antialiasing disabled, or thin geometry needing thicker forms
|
|
78
|
+
|
|
79
|
+
### Step 5: Fix
|
|
80
|
+
|
|
81
|
+
Fix in severity order: HIGH performance findings and failed visual rows first. When a finding maps to a React Doctor rule, fetch the canonical recipe instead of improvising:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
https://www.react.doctor/prompts/rules/<plugin>/<rule>.md
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For Three.js-specific findings, apply the fix named in the triage list or the cause list above.
|
|
88
|
+
|
|
89
|
+
### Step 6: Validate
|
|
90
|
+
|
|
91
|
+
Run `npx react-doctor@latest --verbose --scope changed` and confirm the score did not regress. Re-check every visual rubric row that failed, using the same viewpoint and interaction as the original evidence, and confirm it now passes. Then verify behavior: the scene renders, animations play, and interactions respond. If browser dev tools are available, watch the memory profile while orbiting an idle scene; a rising heap during idle means a disposal leak survived.
|
|
92
|
+
|
|
93
|
+
## Checks the scanner always misses
|
|
94
|
+
|
|
95
|
+
Review these by hand on every audit:
|
|
96
|
+
|
|
97
|
+
- `dispose()` coverage for every imperatively created GPU resource
|
|
98
|
+
- Allocations and `setState` inside `useFrame` and RAF callbacks
|
|
99
|
+
- Event listeners and `ResizeObserver`s on the canvas or window without cleanup
|
|
100
|
+
- Raycasting against the full scene on every pointer move instead of a filtered target list
|
|
101
|
+
- Shadows or postprocessing enabled globally when one part of the scene needs them
|
|
102
|
+
- Color space configuration on the renderer and every color texture
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: performance
|
|
3
|
+
description: Diagnose React runtime performance with React Doctor traces, live render outlines, Long Animation Frames, interaction timing, and component render evidence. Use when invoked as `/performance` for a slow interaction, unexpected re-renders, or a measured before-and-after comparison.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Diagnose React runtime performance
|
|
8
|
+
|
|
9
|
+
Measure one reproducible interaction, connect browser work to React renders, and report only conclusions supported by the trace.
|
|
10
|
+
|
|
11
|
+
## Define the interaction
|
|
12
|
+
|
|
13
|
+
Before recording:
|
|
14
|
+
|
|
15
|
+
1. Identify the target URL
|
|
16
|
+
2. Write the exact actions to reproduce
|
|
17
|
+
3. Choose the expected result
|
|
18
|
+
4. Confirm whether authentication is required
|
|
19
|
+
|
|
20
|
+
Use a production build when available. Development builds add framework work that can distort render and script timings. If you must measure a development build, label that limitation in the report.
|
|
21
|
+
|
|
22
|
+
## Record the trace
|
|
23
|
+
|
|
24
|
+
Run the scan in an interactive terminal:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx react-doctor@latest scan http://localhost:3000 --format json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
React Doctor opens an isolated Chrome profile. Perform the planned interaction while purple outlines identify rendered components. Press Enter after the interaction settles; recordings stop automatically after five minutes.
|
|
31
|
+
|
|
32
|
+
Interactive users can omit the URL and choose a detected localhost app or enter another URL. Agents must always pass the explicit URL so automated runs never wait for input.
|
|
33
|
+
|
|
34
|
+
For an authenticated session, connect through the Chrome DevTools Protocol (CDP):
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx react-doctor@latest scan https://app.example.com \
|
|
38
|
+
--cdp http://127.0.0.1:9222 \
|
|
39
|
+
--format json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use a dedicated debug profile for CDP because Chrome tracing is browser-wide. Sign in, close every non-blank tab, and then start the scan. React Doctor closes leftover blank tabs before tracing. Never request cookies, copy a browser profile, or close an externally managed browser.
|
|
43
|
+
|
|
44
|
+
The compressed `.json.gz` trace can contain URLs, source paths, and application behavior. Keep it local unless an upload is explicitly approved.
|
|
45
|
+
|
|
46
|
+
## Read the report
|
|
47
|
+
|
|
48
|
+
Evaluate the report in this order:
|
|
49
|
+
|
|
50
|
+
1. **Capture support**: confirm React detection, build type, React tracks, and Long Animation Frame support
|
|
51
|
+
2. **User impact**: inspect the worst interaction, total blocking duration, Largest Contentful Paint (LCP), and Cumulative Layout Shift (CLS)
|
|
52
|
+
3. **Browser work**: inspect long frames and script hotspots for event handling, JavaScript, style, layout, and paint cost
|
|
53
|
+
4. **React work**: inspect component render count, total self time, and maximum self time
|
|
54
|
+
5. **Capture limits**: read every warning, especially dropped event counts
|
|
55
|
+
|
|
56
|
+
Follow these interpretation rules:
|
|
57
|
+
|
|
58
|
+
- A high render count is evidence, not a defect. Pair it with duration and user impact
|
|
59
|
+
- Generated chunk names identify browser work, not the owning source component
|
|
60
|
+
- A slow interaction can be browser-bound even when every component render is cheap
|
|
61
|
+
- Repeated Event Timing records with one interaction identifier represent one interaction
|
|
62
|
+
- Dropped component events make hotspot totals incomplete
|
|
63
|
+
- Use purple labels to identify the active subtree, then use recorded timings to set severity
|
|
64
|
+
|
|
65
|
+
## Connect measurements to source
|
|
66
|
+
|
|
67
|
+
Search the repository for measured component display names and event handlers. Confirm that each candidate runs in the recorded flow before reporting it.
|
|
68
|
+
|
|
69
|
+
Open the DevTools trace when the summary cannot explain a long frame. Correlate the interaction timestamp with script tasks, style or layout work, React tracks, and paint. Do not infer causality from neighboring timestamps alone.
|
|
70
|
+
|
|
71
|
+
## Report findings
|
|
72
|
+
|
|
73
|
+
Use this structure:
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
## Flow tested
|
|
77
|
+
|
|
78
|
+
tested_url, build_type, and exact_interaction
|
|
79
|
+
|
|
80
|
+
## Verdict
|
|
81
|
+
|
|
82
|
+
one_evidence_backed_paragraph
|
|
83
|
+
|
|
84
|
+
## Evidence
|
|
85
|
+
|
|
86
|
+
| Signal | Measurement | Interpretation |
|
|
87
|
+
| ----------------- | ---------------------------: | --------------- |
|
|
88
|
+
| Worst interaction | duration_ms | measured_cause |
|
|
89
|
+
| Total blocking | duration_ms | measured_scope |
|
|
90
|
+
| Top component | render_count and duration_ms | measured_impact |
|
|
91
|
+
|
|
92
|
+
## Findings
|
|
93
|
+
|
|
94
|
+
1. `path/to/component.tsx:42`: measured_problem, evidence, and smallest_fix
|
|
95
|
+
|
|
96
|
+
## Limits
|
|
97
|
+
|
|
98
|
+
capture_warnings, missing_support, or environmental_caveats
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Do not pad the report with static lint findings. Include source findings only when runtime evidence connects them to the tested flow.
|
|
102
|
+
|
|
103
|
+
## Validate a fix
|
|
104
|
+
|
|
105
|
+
Do not edit code unless code changes are requested. After a fix:
|
|
106
|
+
|
|
107
|
+
1. Rebuild with the same mode
|
|
108
|
+
2. Record the same interaction at the same viewport
|
|
109
|
+
3. Run three before and three after samples when timing variance could change the conclusion
|
|
110
|
+
4. Compare medians for interaction, blocking, and component duration
|
|
111
|
+
5. Confirm behavior and accessibility did not regress
|
|
112
|
+
|
|
113
|
+
Reject improvements that only move work outside the recorded window or disable useful behavior.
|
|
@@ -22,6 +22,12 @@ Run `npx react-doctor@latest --verbose` (the default `--scope full`) to scan the
|
|
|
22
22
|
|
|
23
23
|
Run `npx react-doctor@latest design --verbose`. This selects only design-tagged UI composition, typography, interaction, accessibility, and motion rules, including focused rules that remain opt-in during a general health scan.
|
|
24
24
|
|
|
25
|
+
## For runtime performance problems:
|
|
26
|
+
|
|
27
|
+
Run `npx react-doctor@latest scan <url> --format json` in an interactive terminal. React Doctor opens an isolated system Chrome profile, records a DevTools trace while the user reproduces the slow interaction, and flashes purple outlines with component names as React renders. It stops when they press Enter. Read the structured summary first, then inspect the returned local `.json.gz` trace for CPU, browser, and React component evidence.
|
|
28
|
+
|
|
29
|
+
If the user needs their authenticated browser state, use `--cdp <remote-debugging-url>`. This requires Chrome to already be running with remote debugging. Never ask for cookies or copy the user's browser profile. Treat the trace as sensitive local application data and never upload it without explicit permission.
|
|
30
|
+
|
|
25
31
|
## /doctor — full local triage workflow
|
|
26
32
|
|
|
27
33
|
When the user types `/doctor`, says "run react doctor", or asks for a full triage / cleanup pass (not just a regression check), fetch the canonical local-triage playbook and follow every step in it:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
-
import {
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="64a6738f-28f7-548a-a501-c85862cab36f")}catch(e){}}();
|
|
3
|
+
import { $t as layerObservability, Cr as messageFromUnknown, Jn as makeUnsafe, Rn as runPromise, Un as buildWithScope, Xn as void_, Xt as isReactDoctorError, Yt as isProjectDiscoveryError, _ as VERSION, br as isErrnoException, i as isTelemetryEnabled, kn as make, qn as close, z as CliInputError, zn as runSync } from "./record-metric-DVm5sVu2.js";
|
|
4
4
|
//#region src/cli/utils/is-environment-error.ts
|
|
5
5
|
const ENVIRONMENT_ERROR_CODES = new Set([
|
|
6
6
|
"EACCES",
|
|
@@ -61,6 +61,51 @@ const formatEnvironmentError = (error) => {
|
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
63
|
//#endregion
|
|
64
|
+
//#region src/cli/utils/is-npm-cache-corruption-error.ts
|
|
65
|
+
const MISSING_AJV_META_SCHEMA_MESSAGES = new Set(["Cannot find module './meta/unevaluated.json'", "Cannot find module './meta/validation.json'"]);
|
|
66
|
+
const NPX_AJV_META_SCHEMA_REQUIRE_PATH_PATTERN = /(?:^|\/)_npx\/(?<cacheKey>[a-f0-9]{16})\/node_modules\/ajv\/dist\/refs\/json-schema-2020-12\/index\.js$/;
|
|
67
|
+
const isModuleNotFoundError = (error) => error instanceof Error && "code" in error && error.code === "MODULE_NOT_FOUND";
|
|
68
|
+
const findNpmCacheCorruptionError = (error) => {
|
|
69
|
+
const pendingErrors = [error];
|
|
70
|
+
const visitedErrors = /* @__PURE__ */ new Set();
|
|
71
|
+
while (pendingErrors.length > 0) {
|
|
72
|
+
const currentError = pendingErrors.pop();
|
|
73
|
+
if (typeof currentError !== "object" || currentError === null) continue;
|
|
74
|
+
if (visitedErrors.has(currentError)) continue;
|
|
75
|
+
visitedErrors.add(currentError);
|
|
76
|
+
if (isModuleNotFoundError(currentError)) {
|
|
77
|
+
const [message] = currentError.message.split("\n");
|
|
78
|
+
if (message && MISSING_AJV_META_SCHEMA_MESSAGES.has(message)) {
|
|
79
|
+
const requireStack = Array.isArray(currentError.requireStack) ? currentError.requireStack : [];
|
|
80
|
+
for (const requirePath of requireStack) {
|
|
81
|
+
if (typeof requirePath !== "string") continue;
|
|
82
|
+
const cacheKey = requirePath.replaceAll("\\", "/").match(NPX_AJV_META_SCHEMA_REQUIRE_PATH_PATTERN)?.groups?.cacheKey;
|
|
83
|
+
if (cacheKey !== void 0) return {
|
|
84
|
+
cacheKey,
|
|
85
|
+
moduleNotFoundError: currentError
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (currentError instanceof Error && currentError.cause !== void 0) pendingErrors.push(currentError.cause);
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
};
|
|
94
|
+
const isNpmCacheCorruptionError = (error) => findNpmCacheCorruptionError(error) !== null;
|
|
95
|
+
const formatNpmCacheCorruptionError = (error) => {
|
|
96
|
+
const corruptionMatch = findNpmCacheCorruptionError(error);
|
|
97
|
+
if (!corruptionMatch) return messageFromUnknown(error);
|
|
98
|
+
return [
|
|
99
|
+
"The npx cache has an incomplete Ajv installation.",
|
|
100
|
+
"",
|
|
101
|
+
"Remove this cache entry, then run React Doctor again:",
|
|
102
|
+
` npm cache npx rm ${corruptionMatch.cacheKey}`,
|
|
103
|
+
" npx react-doctor@latest",
|
|
104
|
+
"",
|
|
105
|
+
`Original error: ${corruptionMatch.moduleNotFoundError.message}`
|
|
106
|
+
].join("\n");
|
|
107
|
+
};
|
|
108
|
+
//#endregion
|
|
64
109
|
//#region src/cli/utils/is-expected-user-error.ts
|
|
65
110
|
/**
|
|
66
111
|
* Whether `error` is an expected, user-actionable failure — the user's project
|
|
@@ -69,7 +114,7 @@ const formatEnvironmentError = (error) => {
|
|
|
69
114
|
* `handleUserError` (a plain message — no "Something went wrong", prefilled
|
|
70
115
|
* issue, Discord link, or Sentry reference), since there is no bug to report.
|
|
71
116
|
*
|
|
72
|
-
*
|
|
117
|
+
* Five distinct shapes reach the CLI's catch blocks:
|
|
73
118
|
*
|
|
74
119
|
* - **Project-discovery failures** (`NoReactDependencyError`,
|
|
75
120
|
* `ProjectNotFoundError`, `PackageJsonNotFoundError`, `NotADirectoryError`,
|
|
@@ -89,12 +134,15 @@ const formatEnvironmentError = (error) => {
|
|
|
89
134
|
* actionable message instead of crashing. See `is-environment-error.ts` for
|
|
90
135
|
* why the set stays narrow (codes that usually mean our bug keep reaching
|
|
91
136
|
* Sentry).
|
|
137
|
+
* - **npm cache corruption** (missing Ajv meta-schema files inside `_npx`) —
|
|
138
|
+
* an incomplete npx package installation that the user can remove and
|
|
139
|
+
* reinstall.
|
|
92
140
|
*
|
|
93
141
|
* This composes the existing core narrowers rather than introducing a new
|
|
94
142
|
* error-shape helper (AGENTS.md): it encodes CLI-layer reporting policy, not
|
|
95
143
|
* knowledge of the `ReactDoctorError` shape.
|
|
96
144
|
*/
|
|
97
|
-
const isExpectedUserError = (error) => error instanceof CliInputError || isProjectDiscoveryError(error) || isEnvironmentError(error) || isReactDoctorError(error) && (error.reason._tag === "GitBaseBranchInvalid" || error.reason._tag === "GitBaseBranchMissing");
|
|
145
|
+
const isExpectedUserError = (error) => error instanceof CliInputError || isProjectDiscoveryError(error) || isEnvironmentError(error) || isNpmCacheCorruptionError(error) || isReactDoctorError(error) && (error.reason._tag === "GitBaseBranchInvalid" || error.reason._tag === "GitBaseBranchMissing");
|
|
98
146
|
//#endregion
|
|
99
147
|
//#region src/cli/utils/resolve-axiom-telemetry-options.ts
|
|
100
148
|
/**
|
|
@@ -153,11 +201,8 @@ let pendingShutdown = null;
|
|
|
153
201
|
*
|
|
154
202
|
* Returns `null` when telemetry is disabled or unconfigured, which is what keeps
|
|
155
203
|
* `--no-telemetry` and unconfigured builds from opening a scope at all.
|
|
156
|
-
*
|
|
157
|
-
* `exportIntervalMs` lets a long-running process (the language server) ship
|
|
158
|
-
* telemetry periodically instead of only at shutdown.
|
|
159
204
|
*/
|
|
160
|
-
const getTelemetryContext = (
|
|
205
|
+
const getTelemetryContext = () => {
|
|
161
206
|
if (isBuilt) return telemetryContext;
|
|
162
207
|
isBuilt = true;
|
|
163
208
|
if (!isTelemetryEnabled()) return null;
|
|
@@ -165,10 +210,7 @@ const getTelemetryContext = (overrides = {}) => {
|
|
|
165
210
|
if (options === null && !isUserOtlpConfigured()) return null;
|
|
166
211
|
try {
|
|
167
212
|
const scope = makeUnsafe();
|
|
168
|
-
telemetryContext = runSync(buildWithScope(layerObservability(options
|
|
169
|
-
...options,
|
|
170
|
-
...overrides
|
|
171
|
-
}), scope));
|
|
213
|
+
telemetryContext = runSync(buildWithScope(layerObservability(options), scope));
|
|
172
214
|
telemetryScope = scope;
|
|
173
215
|
} catch {
|
|
174
216
|
telemetryContext = null;
|
|
@@ -203,25 +245,7 @@ const shutdownTelemetry = async () => {
|
|
|
203
245
|
return pendingShutdown;
|
|
204
246
|
};
|
|
205
247
|
//#endregion
|
|
206
|
-
|
|
207
|
-
let activeRunTrace = null;
|
|
208
|
-
const setActiveRunTrace = (trace) => {
|
|
209
|
-
activeRunTrace = trace;
|
|
210
|
-
};
|
|
211
|
-
const getActiveRunTrace = () => activeRunTrace;
|
|
212
|
-
let lastRunTraceId = null;
|
|
213
|
-
const recordRunTraceId = (traceId) => {
|
|
214
|
-
lastRunTraceId = traceId;
|
|
215
|
-
};
|
|
216
|
-
const getLastRunTraceId = () => lastRunTraceId;
|
|
217
|
-
//#endregion
|
|
218
|
-
//#region src/cli/utils/unref-stdin.ts
|
|
219
|
-
const unrefStdin = () => {
|
|
220
|
-
if (process.stdin.isTTY) return;
|
|
221
|
-
process.stdin.unref?.();
|
|
222
|
-
};
|
|
223
|
-
//#endregion
|
|
224
|
-
export { setActiveRunTrace as a, isExpectedUserError as c, recordRunTraceId as i, formatEnvironmentError as l, getActiveRunTrace as n, getTelemetryContext as o, getLastRunTraceId as r, shutdownTelemetry as s, unrefStdin as t, isEnvironmentError as u };
|
|
248
|
+
export { isNpmCacheCorruptionError as a, formatNpmCacheCorruptionError as i, shutdownTelemetry as n, formatEnvironmentError as o, isExpectedUserError as r, isEnvironmentError as s, getTelemetryContext as t };
|
|
225
249
|
|
|
226
|
-
//# sourceMappingURL=
|
|
227
|
-
//# debugId=
|
|
250
|
+
//# sourceMappingURL=telemetry-runtime-B45Ns9aS.js.map
|
|
251
|
+
//# debugId=64a6738f-28f7-548a-a501-c85862cab36f
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/cli/utils/unref-stdin.ts
|
|
2
|
+
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bb265729-ea99-5b37-b53e-561ac78da6ac")}catch(e){}}();
|
|
4
|
+
const unrefStdin = () => {
|
|
5
|
+
if (process.stdin.isTTY) return;
|
|
6
|
+
process.stdin.unref?.();
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { unrefStdin as t };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=unref-stdin-BKT_s38a.js.map
|
|
12
|
+
//# debugId=bb265729-ea99-5b37-b53e-561ac78da6ac
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
-
import {
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ddcace85-66bc-501f-b435-7a8d479f5a13")}catch(e){}}();
|
|
3
|
+
import { T as METRIC, _ as VERSION, t as recordCount } from "./record-metric-DVm5sVu2.js";
|
|
4
4
|
//#region src/cli/commands/version.ts
|
|
5
5
|
/**
|
|
6
6
|
* oclif-style version line. 12-factor CLI Apps (#3, "What version am I
|
|
@@ -17,5 +17,5 @@ const versionAction = () => {
|
|
|
17
17
|
//#endregion
|
|
18
18
|
export { versionAction };
|
|
19
19
|
|
|
20
|
-
//# sourceMappingURL=version-
|
|
21
|
-
//# debugId=
|
|
20
|
+
//# sourceMappingURL=version-Cad39N0q.js.map
|
|
21
|
+
//# debugId=ddcace85-66bc-501f-b435-7a8d479f5a13
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
-
import { t as inspectAction } from "./inspect-
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e58602c5-9e3c-58ac-be89-9055d0de41a0")}catch(e){}}();
|
|
3
|
+
import { t as inspectAction } from "./inspect-B9H_IT4O.js";
|
|
4
4
|
//#region src/cli/commands/why.ts
|
|
5
5
|
/**
|
|
6
6
|
* `why <file:line>` — explains why a rule fired (or why a suppression didn't
|
|
@@ -17,5 +17,5 @@ const whyAction = async (location, options) => {
|
|
|
17
17
|
//#endregion
|
|
18
18
|
export { whyAction };
|
|
19
19
|
|
|
20
|
-
//# sourceMappingURL=why-
|
|
21
|
-
//# debugId=
|
|
20
|
+
//# sourceMappingURL=why-DIEM7rdZ.js.map
|
|
21
|
+
//# debugId=e58602c5-9e3c-58ac-be89-9055d0de41a0
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c4d80bbb-61a2-538c-a5bb-27fc0fd5641d")}catch(e){}}();
|
|
3
|
+
import { D as NANOSECONDS_PER_MILLISECOND, In as provideContext, Xn as void_, Yn as fail, c as setSentryProjectInfo, jn as makeSpan, o as buildSentryScope, r as toSpanAttributes, s as buildSentryProjectContext, zn as runSync } from "./record-metric-DVm5sVu2.js";
|
|
4
|
+
import { t as getTelemetryContext } from "./telemetry-runtime-B45Ns9aS.js";
|
|
5
|
+
import { i as setActiveRunTrace, r as recordRunTraceId } from "./active-run-trace-dlIZeEvb.js";
|
|
6
|
+
//#region src/cli/utils/with-run-span.ts
|
|
7
|
+
/**
|
|
8
|
+
* Ends the run span without letting a telemetry failure change the run's
|
|
9
|
+
* outcome — the invariant every other emit site here already holds.
|
|
10
|
+
*
|
|
11
|
+
* The failure path is the reason this matters most: a throw from `end` there
|
|
12
|
+
* would replace the user's original scan error, so a project-config mistake
|
|
13
|
+
* could surface as an exporter stack trace, be reclassified as a crash, and get
|
|
14
|
+
* reported as one.
|
|
15
|
+
*/
|
|
16
|
+
const endSpanSafely = (span, exit) => {
|
|
17
|
+
try {
|
|
18
|
+
span.end(BigInt(Date.now()) * NANOSECONDS_PER_MILLISECOND, exit);
|
|
19
|
+
} catch {}
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Clears the module-level run-scoped telemetry state — the current scanned
|
|
23
|
+
* project and the active run trace. `inspect()` calls this at the start of every
|
|
24
|
+
* run and again after a clean one, so a prior or just-finished scan can't attach
|
|
25
|
+
* its project tags / trace to a later run or to a non-scan error (e.g.
|
|
26
|
+
* inspectAction's post-loop finalize/handoff steps). A thrown scan error skips
|
|
27
|
+
* the post-run reset, leaving the state for the command catch to attribute and
|
|
28
|
+
* link the crash. Concurrent batch members (`concurrentScan`) never touch this
|
|
29
|
+
* state — they neither write nor reset it. Safe to call when telemetry is off
|
|
30
|
+
* (the refs are read only when an event is built).
|
|
31
|
+
*/
|
|
32
|
+
const resetSentryRunState = () => {
|
|
33
|
+
setSentryProjectInfo(null);
|
|
34
|
+
setActiveRunTrace(null);
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Runs an inspect invocation inside a root span so each `react-doctor` run is a
|
|
38
|
+
* first-class trace with timing and the run snapshot as attributes. The span is
|
|
39
|
+
* handed to `run` so the scan's Effect spans parent under it and so the wide
|
|
40
|
+
* event can be stamped onto it once the outcome is known.
|
|
41
|
+
*
|
|
42
|
+
* A no-op pass-through when telemetry is off (`--no-telemetry`, tests, or an
|
|
43
|
+
* unconfigured build) — `run` receives `undefined` and no span is created, so
|
|
44
|
+
* there's no added exit latency.
|
|
45
|
+
*
|
|
46
|
+
* The span is created against the shared telemetry context rather than a
|
|
47
|
+
* freshly-provided layer, so it lives in the same tracer as the scan program's
|
|
48
|
+
* spans; see `telemetry-runtime.ts` for why that matters. It is started and
|
|
49
|
+
* ended manually because the body it wraps is a promise-returning imperative
|
|
50
|
+
* function, not an Effect — the same shape the Sentry inactive span had.
|
|
51
|
+
*
|
|
52
|
+
* While the span runs, its trace context is recorded as the active run trace so
|
|
53
|
+
* `reportErrorToSentry` can attach a crash thrown during the scan back to this
|
|
54
|
+
* trace (errors surface in the command catch, after the span has ended).
|
|
55
|
+
*
|
|
56
|
+
* A `concurrentScan` (one member of the CLI's multi-project pool) still gets its
|
|
57
|
+
* own root span, but skips recording the active run trace — the module-level
|
|
58
|
+
* handle has single-scan semantics, and overlapping writers would link a crash
|
|
59
|
+
* to an arbitrary sibling's trace.
|
|
60
|
+
*/
|
|
61
|
+
const withRunSpan = async (run, options = {}) => {
|
|
62
|
+
const telemetryContext = getTelemetryContext();
|
|
63
|
+
if (telemetryContext === null) return run(void 0);
|
|
64
|
+
const { tags } = buildSentryScope();
|
|
65
|
+
const command = typeof tags.command === "string" ? tags.command : "inspect";
|
|
66
|
+
let rootSpan;
|
|
67
|
+
try {
|
|
68
|
+
rootSpan = runSync(makeSpan(`react-doctor ${command}`, { attributes: toSpanAttributes(tags) }).pipe(provideContext(telemetryContext)));
|
|
69
|
+
} catch {
|
|
70
|
+
return run(void 0);
|
|
71
|
+
}
|
|
72
|
+
recordRunTraceId(rootSpan.traceId);
|
|
73
|
+
if (options.concurrentScan !== true) setActiveRunTrace({
|
|
74
|
+
traceId: rootSpan.traceId,
|
|
75
|
+
spanId: rootSpan.spanId,
|
|
76
|
+
sampled: rootSpan.sampled
|
|
77
|
+
});
|
|
78
|
+
try {
|
|
79
|
+
const result = await run(rootSpan);
|
|
80
|
+
endSpanSafely(rootSpan, void_);
|
|
81
|
+
return result;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
endSpanSafely(rootSpan, fail(options.mapErrorForSpan?.(error) ?? error));
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Records the scanned project (discovered in the `beforeLint` hook): remembers
|
|
89
|
+
* it for the lazy Sentry error-capture path (`buildSentryScope` folds it into
|
|
90
|
+
* exception events) and for per-emit metric attributes, and sets it on the run's
|
|
91
|
+
* root span so the trace carries the project shape too. Always cheap — the span
|
|
92
|
+
* attributes are skipped when `rootSpan` is absent (telemetry off), and storing
|
|
93
|
+
* the info is a plain assignment.
|
|
94
|
+
*
|
|
95
|
+
* A `concurrentScan` only sets the span attributes: the module-level project ref
|
|
96
|
+
* has single-scan semantics, and overlapping writers would stamp events and
|
|
97
|
+
* metrics with an arbitrary sibling's project. Wide events keep full attribution
|
|
98
|
+
* (they ride the span); per-emit metrics simply omit the project shape during a
|
|
99
|
+
* concurrent batch (absent, never wrong).
|
|
100
|
+
*/
|
|
101
|
+
const recordSentryProjectContext = (projectInfo, rootSpan, options = {}) => {
|
|
102
|
+
if (options.concurrentScan !== true) setSentryProjectInfo(projectInfo);
|
|
103
|
+
if (rootSpan === void 0) return;
|
|
104
|
+
for (const [key, value] of Object.entries(toSpanAttributes(buildSentryProjectContext(projectInfo).tags))) rootSpan.attribute(key, value);
|
|
105
|
+
};
|
|
106
|
+
//#endregion
|
|
107
|
+
export { resetSentryRunState as n, withRunSpan as r, recordSentryProjectContext as t };
|
|
108
|
+
|
|
109
|
+
//# sourceMappingURL=with-run-span-B9ScJJx3.js.map
|
|
110
|
+
//# debugId=c4d80bbb-61a2-538c-a5bb-27fc0fd5641d
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.9.12-dev.
|
|
3
|
+
"version": "0.9.12-dev.ac87f7d",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -53,22 +53,22 @@
|
|
|
53
53
|
"@astrojs/compiler": "^4.0.0",
|
|
54
54
|
"@sentry/node": "^10.54.0",
|
|
55
55
|
"agent-install": "0.0.5",
|
|
56
|
+
"bippy": "^0.6.1",
|
|
56
57
|
"conf": "^15.1.0",
|
|
57
58
|
"confbox": "^0.2.4",
|
|
58
59
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
60
|
+
"is-unicode-supported": "^2.1.0",
|
|
59
61
|
"jiti": "^2.7.0",
|
|
60
62
|
"magicast": "^0.5.3",
|
|
63
|
+
"oxc-parser": "^0.146.0",
|
|
61
64
|
"oxc-resolver": "^11.24.2",
|
|
62
|
-
"oxlint": ">=1.
|
|
65
|
+
"oxlint": ">=1.79.0 <1.80.0",
|
|
66
|
+
"playwright-core": "^1.62.1",
|
|
63
67
|
"prompts": "^2.4.2",
|
|
64
68
|
"typescript": ">=5.0.4 <6",
|
|
65
|
-
"vscode-languageserver": "^9.0.1",
|
|
66
|
-
"vscode-languageserver-textdocument": "^1.0.12",
|
|
67
|
-
"vscode-uri": "^3.1.0",
|
|
68
69
|
"yaml": "^2.9.0",
|
|
69
70
|
"yoga-layout": "~3.2.1",
|
|
70
|
-
"
|
|
71
|
-
"oxlint-plugin-react-doctor": "0.9.12-dev.a2b460d"
|
|
71
|
+
"oxlint-plugin-react-doctor": "0.9.12-dev.ac87f7d"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@types/babel__code-frame": "^7.27.0",
|
|
@@ -82,8 +82,7 @@
|
|
|
82
82
|
"react": "19.2.5",
|
|
83
83
|
"react-devtools-core": "^7.0.1",
|
|
84
84
|
"@react-doctor/api": "0.9.12",
|
|
85
|
-
"@react-doctor/core": "0.9.12"
|
|
86
|
-
"@react-doctor/language-server": "0.9.12"
|
|
85
|
+
"@react-doctor/core": "0.9.12"
|
|
87
86
|
},
|
|
88
87
|
"engines": {
|
|
89
88
|
"node": "^20.19.0 || >=22.13.0"
|