@presto1314w/vite-devtools-browser 0.3.3 → 0.3.6

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Vercel, Inc.
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vercel, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,322 +1,135 @@
1
- # vite-browser
2
-
3
- **Explain why your Vite app broke after a hot update.**
4
-
5
- `vite-browser` is a runtime diagnostics toolchain for Vite apps. It connects current errors to recent HMR activity, traces store and module updates into rerender paths, and returns structured terminal output that both developers and AI agents can reason about directly.
6
-
7
- No plugin installation. No GUI. Just connect to a running Vite dev server and start querying.
8
-
9
- **CLI**
10
- ```bash
11
- npm install -g @presto1314w/vite-devtools-browser
12
- npx playwright install chromium
13
- ```
14
-
15
- **Agent Skill**
16
- ```bash
17
- npx skills add MapleCity1314/vite-browser
18
- ```
19
-
20
- ---
21
-
22
- ## The Problem It Solves
23
-
24
- You save a file. Vite hot-updates. The page breaks.
25
-
26
- The error overlay tells you *what* broke. It does not tell you *why the update caused it*.
27
-
28
- You want to know:
29
- - which module change triggered this error
30
- - whether a store update propagated into a broken render path
31
- - what the HMR timeline looked like before the failure
32
-
33
- `vite-browser` answers these questions from the terminal, without touching your project config.
34
-
35
- ---
36
-
37
- ## Quickstart
38
-
39
- ```bash
40
- # terminal A - your app
41
- cd my-app && npm run dev
42
-
43
- # terminal B - diagnostics
44
- vite-browser open http://localhost:5173
45
- vite-browser vite runtime
46
- vite-browser errors --mapped --inline-source
47
- vite-browser correlate errors --mapped --window 5000
48
- vite-browser close
49
- ```
50
-
51
- ---
52
-
53
- ## Example: Tracing a Broken HMR Update
54
-
55
- You edit `src/store/cart.ts`. The page breaks with `TypeError: cannot read properties of undefined`.
56
-
57
- ```bash
58
- # 1. check what the error actually is
59
- $ vite-browser errors --mapped --inline-source
60
-
61
- TypeError: Cannot read properties of undefined (reading 'items')
62
-
63
- # Mapped Stack
64
- - /src/components/CartSummary.tsx:14:12
65
- 14 | total = cart.items.reduce(...)
66
- ```
67
-
68
- ```bash
69
- # 2. correlate with recent HMR activity
70
- $ vite-browser correlate errors --mapped --window 5000
71
-
72
- # Error Correlation
73
- Confidence: high
74
- HMR update observed within 5000ms of the current error
75
- Matching modules: /src/store/cart.ts
76
- ```
77
-
78
- ```bash
79
- # 3. trace how the update propagated
80
- $ vite-browser correlate renders --window 5000
81
-
82
- # Render Correlation
83
- Confidence: high
84
- Recent store update likely propagated through 1 render step(s).
85
-
86
- ## Store Updates
87
- - cart
88
-
89
- ## Changed Keys
90
- - items
91
-
92
- ## Render Path
93
- - AppShell > ShoppingCart > CartSummary
94
- ```
95
-
96
- ```bash
97
- # 4. get a structured diagnosis
98
- $ vite-browser diagnose propagation --window 5000
99
-
100
- # Propagation Diagnosis
101
- Status: fail
102
- Confidence: high
103
- A plausible store -> render -> error propagation path was found.
104
- ```
105
-
106
- Four commands. You know the store update broke the render path. You know where to fix it.
107
-
108
- ---
109
-
110
- ## Built For Agents
111
-
112
- Models cannot visually inspect a DevTools panel. They work much better when runtime signals are structured commands that can be queried, compared, and chained in a loop.
113
-
114
- `vite-browser` turns Vite runtime state, HMR activity, module graph changes, framework component trees, mapped errors, and network activity into terminal output an agent can consume directly.
115
-
116
- Each command is a one-shot request against a long-lived browser daemon - no browser lifecycle management on every step, no GUI dependency, no project config changes required.
117
-
118
- ```bash
119
- # an agent debugging loop looks like this
120
- vite-browser vite runtime
121
- vite-browser errors --mapped --inline-source
122
- vite-browser correlate errors --mapped --window 5000
123
- vite-browser correlate renders --window 5000
124
- vite-browser diagnose propagation --window 5000
125
- vite-browser diagnose hmr --limit 50
126
- ```
127
-
128
- Agent Skill workflows are also available for scenario-based debugging in coding assistants:
129
-
130
- ```bash
131
- npx skills add MapleCity1314/vite-browser
132
- ```
133
-
134
- ---
135
-
136
- ## Core Capabilities
137
-
138
- **Framework detection**
139
- - Vue, React, Svelte best-effort detection with version hinting
140
-
141
- **Vue runtime**
142
- - component tree and details
143
- - Pinia stores, getters, and changed keys
144
- - Vue Router state
145
-
146
- **React runtime**
147
- - component tree with props, state, hooks, context, and source metadata
148
-
149
- **Svelte runtime**
150
- - component tree when metadata is available
151
-
152
- **Vite runtime diagnostics**
153
- - runtime status and HMR health
154
- - HMR timeline, summary, and clear
155
- - module graph snapshot, diff, trace, and clear
156
- - error / HMR correlation over configurable time windows
157
- - store and module update / render path correlation
158
- - propagation diagnosis with store updates, changed keys, and render paths
159
- - rule-based HMR diagnosis with confidence levels
160
- - source-mapped errors with optional inline source snippets
161
-
162
- **Debug utilities**
163
- - console logs, network tracing, screenshot, page `eval`
164
-
165
- ---
166
-
167
- ## Positioning
168
-
169
- | Tool | Best for | Gap vs `vite-browser` |
170
- |---|---|---|
171
- | `agent-browser` | general browser automation | no Vite runtime awareness |
172
- | `next-browser` | Next.js + React debugging | not a Vite runtime tool |
173
- | `vite-plugin-vue-mcp` | Vue MCP integration | requires plugin install, Vue only |
174
- | `vite-browser` | Vite runtime diagnostics for agents and developers | browser lifecycle coverage still expanding |
175
-
176
- `vite-browser` requires no changes to your project. It works against any running Vite dev server across Vue, React, and Svelte.
177
-
178
- ---
179
-
180
- ## Recommended Workflows
181
-
182
- ### HMR / runtime triage
183
- ```bash
184
- vite-browser vite runtime
185
- vite-browser errors --mapped --inline-source
186
- vite-browser correlate errors --mapped --window 5000
187
- vite-browser diagnose hmr --limit 50
188
- vite-browser vite hmr trace --limit 50
189
- vite-browser vite module-graph trace --limit 200
190
- ```
191
-
192
- ### Propagation / rerender triage
193
- ```bash
194
- vite-browser correlate renders --window 5000
195
- vite-browser diagnose propagation --window 5000
196
- vite-browser vue pinia
197
- vite-browser vue tree
198
- ```
199
-
200
- ### Data / API triage
201
- ```bash
202
- vite-browser errors --mapped
203
- vite-browser logs
204
- vite-browser network
205
- vite-browser network <idx>
206
- vite-browser eval '<state probe>'
207
- ```
208
-
209
- ### Component / state triage
210
- ```bash
211
- vite-browser detect
212
- vite-browser vue tree
213
- vite-browser vue pinia
214
- vite-browser vue router
215
- vite-browser react tree
216
- vite-browser svelte tree
217
- ```
218
-
219
- ---
220
-
221
- ## Command Reference
222
-
223
- ### Browser
224
- ```bash
225
- vite-browser open <url> [--cookies-json <file>]
226
- vite-browser close
227
- vite-browser goto <url>
228
- vite-browser back
229
- vite-browser reload
230
- ```
231
-
232
- ### Framework
233
- ```bash
234
- vite-browser detect
235
- vite-browser vue tree [id]
236
- vite-browser vue pinia [store]
237
- vite-browser vue router
238
- vite-browser react tree [id]
239
- vite-browser svelte tree [id]
240
- ```
241
-
242
- ### Vite Runtime
243
- ```bash
244
- vite-browser vite restart
245
- vite-browser vite runtime
246
- vite-browser vite hmr
247
- vite-browser vite hmr trace [--limit <n>]
248
- vite-browser vite hmr clear
249
- vite-browser vite module-graph [--filter <txt>] [--limit <n>]
250
- vite-browser vite module-graph trace [--filter <txt>] [--limit <n>]
251
- vite-browser vite module-graph clear
252
- vite-browser errors
253
- vite-browser errors --mapped
254
- vite-browser errors --mapped --inline-source
255
- vite-browser correlate errors [--window <ms>]
256
- vite-browser correlate renders [--window <ms>]
257
- vite-browser correlate errors --mapped --inline-source
258
- vite-browser diagnose hmr [--window <ms>] [--limit <n>]
259
- vite-browser diagnose propagation [--window <ms>]
260
- ```
261
-
262
- ### Utilities
263
- ```bash
264
- vite-browser logs
265
- vite-browser network [idx]
266
- vite-browser screenshot
267
- vite-browser eval <script>
268
- ```
269
-
270
- ---
271
-
272
- ## Current Boundaries
273
-
274
- `v0.3.3` is strong at:
275
- - surfacing runtime state as structured shell output
276
- - linking current errors to recent HMR and module activity
277
- - detecting common HMR failure patterns with confidence levels
278
- - narrowing likely store/module -> render paths in Vue-first flows
279
- - capturing browser-side runtime errors even when the Vite overlay is absent
280
- - correlating sparse HMR traces back to the right source module more reliably
281
- - retaining `changedKeys` and source-module hints when one side of the event stream is incomplete
282
- - clearing stale runtime errors after recovery so the current page lifecycle is easier to trust
283
-
284
- `correlate renders` and `diagnose propagation` are **high-confidence propagation clues**, not strict causal proof. They do not reliably trace deep chains like `store -> component A -> component B -> error` across arbitrary graphs, and intentionally fall back to conservative output when evidence is incomplete.
285
-
286
- React store inspection (Zustand, Redux) and deeper cross-framework propagation tracing are on the roadmap.
287
-
288
- ---
289
-
290
- ## Skill Packs
291
-
292
- ```
293
- skills/vite-browser-core-debug/SKILL.md
294
- skills/vite-browser-runtime-diagnostics/SKILL.md
295
- skills/vite-browser-network-regression/SKILL.md
296
- skills/vite-browser-release-smoke/SKILL.md
297
- ```
298
-
299
- Router: [skills/SKILL.md](./skills/SKILL.md)
300
-
301
- ---
302
-
303
- ## Local Development
304
-
305
- ```bash
306
- pnpm install
307
- pnpm build
308
- pnpm test
309
- pnpm test:coverage
310
- pnpm test:evals
311
- pnpm test:evals:e2e
312
- ```
313
-
314
- ## Requirements
315
-
316
- - Node.js `>=20`
317
- - Chromium via Playwright
318
- - Running Vite dev server
319
-
320
- ## License
321
-
322
- MIT
1
+ # vite-browser
2
+
3
+ **Know why your Vite app broke not just where.**
4
+
5
+ Runtime diagnostics CLI for Vite applications. Connect to a running dev server, correlate errors with recent HMR activity, trace store-to-render propagation paths, and inspect framework state all from the terminal, with zero project setup.
6
+
7
+ Built for developers and AI coding agents alike.
8
+
9
+ 📖 [Documentation](https://maplecity1314.github.io/vite-browser/) · 📦 [npm](https://www.npmjs.com/package/@presto1314w/vite-devtools-browser)
10
+
11
+ ## Install
12
+
13
+ **Agent Skill** (recommended):
14
+
15
+ ```bash
16
+ npx skills add MapleCity1314/vite-browser
17
+ ```
18
+
19
+ **CLI only:**
20
+
21
+ ```bash
22
+ npm install -g @presto1314w/vite-devtools-browser
23
+ npx playwright install chromium
24
+ ```
25
+
26
+ ## The problem
27
+
28
+ You save a file. Vite hot-updates. The page breaks.
29
+
30
+ The error overlay tells you _what_ failed — but not _which update caused it_, how the change propagated through your component tree, or whether the real problem is a stale store, a broken import, or a network regression.
31
+
32
+ ## What vite-browser does
33
+
34
+ ```bash
35
+ # 1. See the current error with source context
36
+ $ vite-browser errors --mapped --inline-source
37
+
38
+ TypeError: Cannot read properties of undefined (reading 'items')
39
+ → /src/components/CartSummary.tsx:14:12
40
+ 14 | total = cart.items.reduce(...)
41
+
42
+ # 2. Correlate with recent HMR activity
43
+ $ vite-browser correlate errors --mapped --window 5000
44
+
45
+ Confidence: high
46
+ HMR update observed within 5000ms of the current error
47
+ Matching modules: /src/store/cart.ts
48
+
49
+ # 3. Trace the propagation path
50
+ $ vite-browser diagnose propagation --window 5000
51
+
52
+ Status: fail | Confidence: high
53
+ Store Render Error path found:
54
+ store: cart (changedKeys: items)
55
+ render: AppShell > ShoppingCart > CartSummary
56
+ ```
57
+
58
+ Four commands. You know the store update broke the render path. You know where to fix it.
59
+
60
+ ## Key features
61
+
62
+ - **Error correlation** — Match errors against recent HMR-updated modules within a time window
63
+ - **Propagation diagnosis** — Trace `store → render → error` paths with confidence levels
64
+ - **HMR diagnosis** — Detect patterns like `missing-module`, `circular-dependency`, `hmr-websocket-closed`
65
+ - **Framework inspection** Vue trees, Pinia stores, Vue Router, React props/hooks/state, Svelte trees
66
+ - **Mapped errors** — Source-mapped stack traces with inline source snippets
67
+ - **Zero config** — No plugins, no project changes. Works with any running Vite dev server
68
+
69
+ ## Agent Skills
70
+
71
+ `vite-browser` is designed skill-first. The skill router automatically picks the right debugging workflow based on the symptom:
72
+
73
+ | Symptom | Routed to |
74
+ |---|---|
75
+ | Broad / unclear failure | `core-debug` |
76
+ | Recent edit or HMR breakage | `runtime-diagnostics` |
77
+ | Wrong data or failed requests | `network-regression` |
78
+ | Pre-merge verification | `release-smoke` |
79
+
80
+ AI coding agents (Claude Code, Codex, Cursor) follow the structured workflow instead of guessing.
81
+
82
+ [Agent Skills guide](https://maplecity1314.github.io/vite-browser/guide/agent-skills) · [AI IDE Setup](https://maplecity1314.github.io/vite-browser/guide/ide-setup)
83
+
84
+ ## Quick reference
85
+
86
+ ```bash
87
+ # Browser
88
+ vite-browser open <url> # Launch and navigate
89
+ vite-browser close # Close browser and daemon
90
+
91
+ # Diagnostics
92
+ vite-browser errors --mapped --inline-source
93
+ vite-browser correlate errors --mapped --window <ms>
94
+ vite-browser correlate renders --window <ms>
95
+ vite-browser diagnose hmr --limit <n>
96
+ vite-browser diagnose propagation --window <ms>
97
+
98
+ # Framework
99
+ vite-browser detect
100
+ vite-browser vue tree | vue pinia | vue router
101
+ vite-browser react tree
102
+ vite-browser svelte tree
103
+
104
+ # Vite runtime
105
+ vite-browser vite runtime
106
+ vite-browser vite hmr trace --limit <n>
107
+ vite-browser vite module-graph trace --limit <n>
108
+
109
+ # Utilities
110
+ vite-browser logs | network | screenshot | eval <script>
111
+ ```
112
+
113
+ → [Full CLI reference](https://maplecity1314.github.io/vite-browser/reference/cli)
114
+
115
+ ## Current scope
116
+
117
+ `v0.3.3` is reliable at surfacing runtime state, correlating errors with HMR activity, detecting common HMR failure patterns, and narrowing `store → render → error` paths in Vue + Pinia workflows.
118
+
119
+ `correlate renders` and `diagnose propagation` are **high-confidence narrowing tools**, not strict causal proof. They intentionally produce conservative output when evidence is incomplete.
120
+
121
+ React store inspection (Zustand, Redux) and deeper cross-framework propagation tracing are on the roadmap.
122
+
123
+ ## Development
124
+
125
+ ```bash
126
+ pnpm install
127
+ pnpm build
128
+ pnpm test
129
+ ```
130
+
131
+ **Requirements:** Node.js 20 · Chromium via Playwright · Running Vite dev server
132
+
133
+ ## License
134
+
135
+ MIT
@@ -10,8 +10,11 @@ export function initBrowserEventCollector() {
10
10
  q.shift();
11
11
  };
12
12
  }
13
+ const getVueApp = () => document.querySelector("#app")?.__vue_app__ ||
14
+ document.querySelector("[data-v-app]")?.__vue_app__ ||
15
+ null;
13
16
  const inferFramework = () => {
14
- if (window.__VUE__ || window.__VUE_DEVTOOLS_GLOBAL_HOOK__)
17
+ if (window.__VUE__ || window.__VUE_DEVTOOLS_GLOBAL_HOOK__ || getVueApp())
15
18
  return "vue";
16
19
  if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__ || window.React)
17
20
  return "react";
@@ -30,10 +33,8 @@ export function initBrowserEventCollector() {
30
33
  const inferVueRenderDetails = () => {
31
34
  const hook = window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
32
35
  const apps = hook?.apps;
33
- if (!Array.isArray(apps) || apps.length === 0)
34
- return null;
35
- const app = apps[0];
36
- const rootInstance = app?._instance || app?._container?._vnode?.component;
36
+ const app = getVueApp() || (Array.isArray(apps) ? apps[0] : null);
37
+ const rootInstance = app?._instance || app?._container?._vnode?.component || app?._component?.subTree?.component;
37
38
  if (!rootInstance)
38
39
  return null;
39
40
  const names = [];
@@ -120,7 +121,7 @@ export function initBrowserEventCollector() {
120
121
  };
121
122
  const attachPiniaSubscriptions = () => {
122
123
  const hook = window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
123
- const app = Array.isArray(hook?.apps) ? hook.apps[0] : null;
124
+ const app = getVueApp() || (Array.isArray(hook?.apps) ? hook.apps[0] : null);
124
125
  const pinia = window.__PINIA__ || window.pinia || app?.config?.globalProperties?.$pinia;
125
126
  const registry = pinia?._s;
126
127
  if (!(registry instanceof Map) || registry.size === 0)
@@ -1,5 +1,15 @@
1
1
  import type { Page } from "playwright";
2
2
  import type { BrowserFramework, BrowserSessionState } from "./browser-session.js";
3
+ export declare function detectFrameworkFromGlobals(globals: {
4
+ vueVersion?: string | null;
5
+ hasVueHook?: boolean;
6
+ hasVueAppMarker?: boolean;
7
+ hasReactGlobal?: boolean;
8
+ hasReactRootMarker?: boolean;
9
+ reactRendererVersion?: string | null;
10
+ svelteVersion?: string | null;
11
+ hasSvelteHook?: boolean;
12
+ }): string;
3
13
  export declare function detectBrowserFramework(page: Page): Promise<{
4
14
  detected: string;
5
15
  framework: BrowserFramework;
@@ -1,26 +1,51 @@
1
1
  import * as vueDevtools from "./vue/devtools.js";
2
2
  import * as reactDevtools from "./react/devtools.js";
3
+ import { checkHookHealth, injectHook } from "./react/hook-manager.js";
3
4
  import * as svelteDevtools from "./svelte/devtools.js";
5
+ export function detectFrameworkFromGlobals(globals) {
6
+ if (globals.vueVersion || globals.hasVueHook || globals.hasVueAppMarker) {
7
+ return `vue@${globals.vueVersion || "unknown"}`;
8
+ }
9
+ if (globals.reactRendererVersion || globals.hasReactGlobal || globals.hasReactRootMarker) {
10
+ return `react@${globals.reactRendererVersion || "unknown"}`;
11
+ }
12
+ if (globals.svelteVersion || globals.hasSvelteHook) {
13
+ return `svelte@${globals.svelteVersion || "unknown"}`;
14
+ }
15
+ return "unknown";
16
+ }
4
17
  export async function detectBrowserFramework(page) {
18
+ await page.waitForFunction?.(() => Boolean(window.__VUE__ ||
19
+ window.__VUE_DEVTOOLS_GLOBAL_HOOK__ ||
20
+ window.React ||
21
+ window.__SVELTE__ ||
22
+ window.__svelte ||
23
+ document.querySelector("[data-v-app]") ||
24
+ document.querySelector("#app")?.__vue_app__ ||
25
+ document.querySelector("[data-reactroot]")), undefined, { timeout: 1_000 }).catch(() => { });
5
26
  const detected = await page.evaluate(() => {
6
- if (window.__VUE__ || window.__VUE_DEVTOOLS_GLOBAL_HOOK__) {
7
- const version = window.__VUE__?.version || "unknown";
8
- return `vue@${version}`;
9
- }
10
27
  const reactHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
11
- if (reactHook || window.React || document.querySelector("[data-reactroot]")) {
12
- const renderers = reactHook?.renderers;
13
- const firstRenderer = renderers ? renderers.values().next().value : null;
14
- const version = firstRenderer?.version || window.React?.version || "unknown";
15
- return `react@${version}`;
28
+ const firstRenderer = reactHook?.renderers?.values?.().next?.().value ?? null;
29
+ const globals = {
30
+ vueVersion: window.__VUE__?.version ?? null,
31
+ hasVueHook: Boolean(window.__VUE_DEVTOOLS_GLOBAL_HOOK__),
32
+ hasVueAppMarker: Boolean(document.querySelector("#app")?.__vue_app__ ||
33
+ document.querySelector("[data-v-app]")?.__vue_app__ ||
34
+ document.querySelector("[data-v-app]")),
35
+ hasReactGlobal: Boolean(window.React),
36
+ hasReactRootMarker: Boolean(document.querySelector("[data-reactroot]")),
37
+ reactRendererVersion: firstRenderer?.version ?? window.React?.version ?? null,
38
+ svelteVersion: window.__SVELTE__?.VERSION || window.__svelte?.version || null,
39
+ hasSvelteHook: Boolean(window.__SVELTE_DEVTOOLS_GLOBAL_HOOK__),
40
+ };
41
+ if (globals.vueVersion || globals.hasVueHook || globals.hasVueAppMarker) {
42
+ return `vue@${globals.vueVersion || "unknown"}`;
16
43
  }
17
- if (window.__SVELTE__ ||
18
- window.__svelte ||
19
- window.__SVELTE_DEVTOOLS_GLOBAL_HOOK__) {
20
- const version = window.__SVELTE__?.VERSION ||
21
- window.__svelte?.version ||
22
- "unknown";
23
- return `svelte@${version}`;
44
+ if (globals.reactRendererVersion || globals.hasReactGlobal || globals.hasReactRootMarker) {
45
+ return `react@${globals.reactRendererVersion || "unknown"}`;
46
+ }
47
+ if (globals.svelteVersion || globals.hasSvelteHook) {
48
+ return `svelte@${globals.svelteVersion || "unknown"}`;
24
49
  }
25
50
  return "unknown";
26
51
  });
@@ -40,13 +65,13 @@ export async function inspectVueRouter(page) {
40
65
  }
41
66
  export async function inspectReactTree(state, page, id) {
42
67
  if (!id) {
43
- state.lastReactSnapshot = await reactDevtools.snapshot(page);
68
+ state.lastReactSnapshot = await withReactInspectorRecovery(page, () => reactDevtools.snapshot(page));
44
69
  return reactDevtools.format(state.lastReactSnapshot);
45
70
  }
46
71
  const parsed = Number.parseInt(id, 10);
47
72
  if (!Number.isFinite(parsed))
48
73
  throw new Error("react component id must be a number");
49
- const inspected = await reactDevtools.inspect(page, parsed);
74
+ const inspected = await withReactInspectorRecovery(page, () => reactDevtools.inspect(page, parsed));
50
75
  const lines = [];
51
76
  const componentPath = reactDevtools.path(state.lastReactSnapshot, parsed);
52
77
  if (componentPath)
@@ -61,6 +86,26 @@ export async function inspectReactTree(state, page, id) {
61
86
  export async function inspectSvelteTree(page, id) {
62
87
  return id ? svelteDevtools.getComponentDetails(page, id) : svelteDevtools.getComponentTree(page);
63
88
  }
89
+ async function withReactInspectorRecovery(page, read) {
90
+ try {
91
+ return await read();
92
+ }
93
+ catch (error) {
94
+ if (!isRecoverableReactInspectorError(error))
95
+ throw error;
96
+ const health = await checkHookHealth(page);
97
+ if (!health.installed) {
98
+ await injectHook(page);
99
+ }
100
+ await page.waitForTimeout(60).catch(() => { });
101
+ return read();
102
+ }
103
+ }
104
+ function isRecoverableReactInspectorError(error) {
105
+ if (!(error instanceof Error))
106
+ return false;
107
+ return /hook not installed|no React renderer attached/i.test(error.message);
108
+ }
64
109
  function toBrowserFramework(detected) {
65
110
  if (detected.startsWith("vue"))
66
111
  return "vue";