Repository navigation
Add page tools with React provider - #5
Conversation
There was a problem hiding this comment.
Findings marked 🟡 are optional suggestions and need no follow-up push.
Additional findings (outside the current diff — GitHub can't attach inline comments there):
-
🟡
skills/browsergnome/scripts/doctor.mjs— Target repos get an untracked.bgn/render-profile.jsonafter every render-overlay pass, because the new artifact is not gitignored. Unlikedep-pulse.json, it is not listed inGITIGNORE_CONTENT. SKILL.md:112 tells the agent to write this file, but.bgn/is otherwise committed with the app. Fix: addrender-profile.jsontoGITIGNORE_CONTENT, the bootstrap message at doctor.mjs:249 and SKILL.md:228, so the existing backfill also covers repos bootstrapped earlier.Why this was flagged
SKILL.md:111-114 tells the agent to write
.bgn/render-profile.json(dev-build render counts andselfMstimings) and pass it tobuild_perf_map.mjs --renders..bgn/lives in the target repo and is tracked: config, ledger and perf-memory are committed. The doctor.mjs:217.gitignorecovers onlyreport.html,run-state.jsonanddep-pulse.json, its list of generated run artifacts. Nothing ignores the new file, so it appears as?? .bgn/render-profile.json. The nextdoctor.mjsrun lists it under "pre-existing change(s)" fromparseGitState. It can also be swept into a commit, which puts dev-build timings into the app's history. On the base branch no such file is written. The existing backfill loop at doctor.mjs:242-245 appends missing GITIGNORE_CONTENT lines, so it would also fix older repos once the line is added. Nothing here adds it.Verification: SKILL.md:111-114 (added in this diff) tells the agent to "write
.bgn/render-profile.jsonas[{file, renders, selfMs}]".GITIGNORE_CONTENT(doctor.mjs:217-221) lists onlyreport.html,run-state.jsonanddep-pulse.json. The diff does not addrender-profile.jsonthere. As a result, the file shows up as?? .bgn/render-profile.jsonin the target repo. -
🟡
skills/browsergnome/scripts/page_tools.mjs— nit: the check for leftover ESM syntax can reject a valid provider bundle.TOP_LEVEL_ESM(/^(import\s*[\w{*'"]|export\s)/m) also matches column-0 identifiers such asimportScripts(orimportantFlag = 1, because\s*can match zero characters. Thenserveexits. Fix: require a realimportstatement, e.g.^import(\s+[\w{*]|\s*['"{*]). Also add an unindentedimportScripts();case to the self-test at line 723, which only tests the indented form.Why this was flagged
toClassicScriptruns on the provider's dist/register.js at serve time (page_tools.mjs:687). A future pinnedreact-devtools-cdt-mcpbundle could have a top-level line starting with an identifier that begins withimport, which is common in unminified esbuild output.TOP_LEVEL_ESMwould match it asimportplus a\wcharacter and throw 'provider script has top-level ESM syntax beyond the trailing export'.servethen exits 1 and every Page Tools pass is unavailable. The self-test case 'ignores "import"/"export" inside indented code and identifiers' only feeds an indentedimportScripts();, so it does not cover this.Verification: In skills/browsergnome/scripts/page_tools.mjs line 57,
const TOP_LEVEL_ESM = /^(import\s*[\w{*'"]|export\s)/m;uses\s*, which can match zero characters.importScripts(matches asimport+S.toClassicScript(lines 66-71) then throws, and it is called at serve time (line 202), so a valid bundle would be rejected. The self-test at line 238 only covers the indentedimportScripts();.
3927944 to
0a6df8f
Compare
Description
Adds Page Tools: a framework-neutral layer that injects a provider script into the target's dev-server page, with zero edits to the target repo. That lets the agent use chrome-devtools-mcp's third-party developer tools (
--categoryExperimentalThirdParty). The first provider is React'sreact-devtools-cdt-mcp, pinned at0.1.0.How injection works:
page_tools.mjs servehosts the provider script on127.0.0.1with CORS. A one-line sync-XHRinitScriptloader (page_tools.mjs loader), passed on everynavigate_page/reload, evaluates it before React loads.On React targets it powers:
interaction: the components that rendered in the slow interaction, ranked by self time, withfile:line.re-renderspreset: gates on total components rendered (ΣcomponentsChanged) for one fixed interaction. 3 baseline captures pick the gate shape: identical → deterministicminEffect: 0, otherwise → N-run.re-rendersinstead of staying advisory, and carry measured evidence.build_perf_map.mjs --renders.The four existing prod-build gates are unchanged. Page Tools runs as its own dev-server pass, and that pass's teardown always runs.
Design spec:
docs/superpowers/specs/2026-10-26-page-tools-react-design.md(§8 records the deviations found during verification).Related issues
N/A
Impacted areas
.mcp.json:--categoryExperimentalThirdParty. It only addslist_3p_developer_tools/execute_3p_developer_tool(29 → 31 tools); no existing tool or schema changes.package.json: new exact runtime dependencyreact-devtools-cdt-mcp@0.1.0.CLAUDE.md's runtime-deps rule is amended, and the SessionStart hook guard now also checks for it.scripts/page_tools.mjs:serve/loader/locateplus pure, self-tested helpers. It is imported bydoctor.mjsandbuild_perf_map.mjs, and CLI-guarded.doctor.mjs:pageToolsaxis and config key, a 3p flag check, and a provider pin check.check_invariants.mjs: provider pin, 3p flag, andpageToolsin the mirrored-config-key check (checkDepPulseKeys→checkConfigKeys).SKILL.md, newreferences/page-tools.md,tools.md,presets.md,measurement.md,senior-audit.md,architectural-perf-catalog.md,perf-map.md, framework catalogs, README,CONTRIBUTING.md,commands/browsergnome.md.Steps to reproduce or test
Development
npm test: all self-tests (newpage-tools:test, 41 checks) plus the invariants check pass.build_perf_map.mjswith the--rendersfixture pair.claude plugin validate . --strictpasses with the CI-pinned CLI (2.1.226).chrome-devtools-mcp@1.6.0 --categoryExperimentalThirdPartywith the real injection, React 19:src/Filter.jsxapp/Filter.tsxmemoon the list row took Vite from 803 → 469 (deterministic).stats.mjs→ KEEP.QA
node doctor.mjs. It should reportpage tools: reactand the dev script./browsergnome this list re-renders on every key. It should route tore-renders, inject without touching the target repo, and stop the dev server afterwards (lsofon its port should be empty).Checklist
Breaking Changeif it applies.package.json.Deploy notes
Existing installs pick up the new dependency on their next session start: the SessionStart hook's guard now checks for
node_modules/react-devtools-cdt-mcp. The provider is experimental; bumping its pin means re-running the verification inreferences/page-tools.md.