{"_id":"@adamancyzhang/agent-reacttools","_rev":"2-603cfac9e1329dda05b2b151f1317ecf","name":"@adamancyzhang/agent-reacttools","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@adamancyzhang/agent-reacttools","version":"0.1.0","keywords":["react","cdp","devtools","cli","agent","inspect","browser","fiber"],"license":"MIT","_id":"@adamancyzhang/agent-reacttools@0.1.0","maintainers":[{"name":"adamancyzhang","email":"adamancyzhang@163.com"}],"homepage":"https://github.com/adamancyzhang/agent-reacttools#readme","bugs":{"url":"https://github.com/adamancyzhang/agent-reacttools/issues"},"bin":{"agent-reacttools":"dist/cli.js"},"dist":{"shasum":"e6ae50823468dba299f1f1b1f0597249dd465b57","tarball":"https://registry.npmjs.org/@adamancyzhang/agent-reacttools/-/agent-reacttools-0.1.0.tgz","fileCount":6,"integrity":"sha512-yD5tFCxegcklfSh/HVr9CVQLP2YUW0hWiJu5bvnHxGNJGQXQJbK4qTmrwNak6XMHjw7LSv5TU+CgSKzZgJFSzg==","signatures":[{"sig":"MEQCIGnfHZtWetAAYYTYVnF+DZ8dRXAyKmg7B+md32Jvf3w+AiBWJ4Go/v+v9+yjvLby49eZvKJ09CuH6bzay3mDzLEYaQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88247},"type":"module","engines":{"node":">=18"},"gitHead":"08afcf7d6b8a9247264875011b3b1fb972134f18","scripts":{"test":"vitest run test/unit","build":"npm run typecheck && node scripts/build.mjs","test:e2e":"npm run build && vitest run test/e2e","typecheck":"tsc --noEmit","fixture:serve":"vite dev test/fixtures/react-app --port 4173 --strictPort","prepublishOnly":"npm run build"},"_npmUser":{"name":"adamancyzhang","email":"adamancyzhang@163.com"},"repository":{"url":"git+https://github.com/adamancyzhang/agent-reacttools.git","type":"git"},"_npmVersion":"11.19.0","description":"Inspect React component tree, props and hook state in a live browser over CDP — no react-devtools extension needed.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.0","jsdom":"^26.0.0","react":"^18.3.1","vitest":"^3.0.0","esbuild":"^0.25.0","@types/ws":"^8.5.13","react-dom":"^18.3.1","typescript":"^5.7.0","@types/node":"^22.10.0","@types/react":"^18.3.0","@types/react-dom":"^18.3.0","@vitejs/plugin-react":"^4.3.0"},"_npmOperationalInternal":{"tmp":"tmp/agent-reacttools_0.1.0_1788410419919_0.21258760307112112","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@adamancyzhang/agent-reacttools","version":"0.1.1","description":"Inspect React component tree, props and hook state in a live browser over CDP — no react-devtools extension needed.","type":"module","bin":{"agent-reacttools":"dist/cli.js"},"engines":{"node":">=18"},"repository":{"type":"git","url":"git+https://github.com/adamancyzhang/agent-reacttools.git"},"license":"MIT","keywords":["react","cdp","devtools","cli","agent","inspect","browser","fiber"],"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"scripts":{"prepublishOnly":"npm run build","build":"npm run typecheck && node scripts/build.mjs","typecheck":"tsc --noEmit","test":"vitest run test/unit","test:e2e":"npm run build && vitest run test/e2e","fixture:serve":"vite dev test/fixtures/react-app --port 4173 --strictPort"},"dependencies":{"ws":"^8.18.0"},"devDependencies":{"@types/node":"^22.10.0","@types/react":"^18.3.0","@types/react-dom":"^18.3.0","@types/ws":"^8.5.13","@vitejs/plugin-react":"^4.3.0","esbuild":"^0.25.0","jsdom":"^26.0.0","react":"^18.3.1","react-dom":"^18.3.1","typescript":"^5.7.0","vite":"^6.0.0","vitest":"^3.0.0"},"gitHead":"8b9afa1c6d5441de2bb91fec135cce690b49cd31","_id":"@adamancyzhang/agent-reacttools@0.1.1","bugs":{"url":"https://github.com/adamancyzhang/agent-reacttools/issues"},"homepage":"https://github.com/adamancyzhang/agent-reacttools#readme","_nodeVersion":"22.21.1","_npmVersion":"11.19.0","dist":{"integrity":"sha512-BaEqL/cdyR2eQdQ5MUejGemvoc8XWhKXYENV9sijiJ4Nrmg1ZdvTN6Qz21d1uY+kSIKXZvY1iKDDRlpbiHOcxQ==","shasum":"ae381ac0c1f2af601fbc28ec947c9b4072458fe7","tarball":"https://registry.npmjs.org/@adamancyzhang/agent-reacttools/-/agent-reacttools-0.1.1.tgz","fileCount":6,"unpackedSize":88247,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDhaklT3GgEGCuij0Blp3hOreUcDuTFnJjhTEK30KBOrAiEA46zuIdtHscM1CbgiOe6cAeMN1YUmpUt57LXKGRzPqm4="}]},"_npmUser":{"name":"adamancyzhang","email":"adamancyzhang@163.com"},"directories":{},"maintainers":[{"name":"adamancyzhang","email":"adamancyzhang@163.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/agent-reacttools_0.1.1_1788410762307_0.01745671491416445"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-03T04:40:19.742Z","modified":"2026-09-03T04:46:02.624Z","0.1.0":"2026-09-03T04:40:20.049Z","0.1.1":"2026-09-03T04:46:02.453Z"},"bugs":{"url":"https://github.com/adamancyzhang/agent-reacttools/issues"},"license":"MIT","homepage":"https://github.com/adamancyzhang/agent-reacttools#readme","keywords":["react","cdp","devtools","cli","agent","inspect","browser","fiber"],"repository":{"type":"git","url":"git+https://github.com/adamancyzhang/agent-reacttools.git"},"description":"Inspect React component tree, props and hook state in a live browser over CDP — no react-devtools extension needed.","maintainers":[{"name":"adamancyzhang","email":"adamancyzhang@163.com"}],"readme":"# agent-reacttools\n\nInspect React components in a live browser over CDP — no react-devtools extension needed. Built for AI agents: stable machine-readable output, plus a human-readable text format.\n\n[![npm version](https://img.shields.io/npm/v/%40adamancyzhang%2Fagent-reacttools)](https://www.npmjs.com/package/@adamancyzhang/agent-reacttools)\n[![license](https://img.shields.io/npm/l/%40adamancyzhang%2Fagent-reacttools)](LICENSE)\n[![node](https://img.shields.io/badge/node-%3E%3D18-green)](package.json)\n\n## What it does\n\nThe React runtime marks every rendered DOM node with internal expando properties — `__reactContainer$…` on containers, `__reactFiber$…` on elements (React 17/18/19), `__reactInternalInstance$…` (React 16). agent-reacttools connects to the browser via the Chrome DevTools Protocol (CDP), injects a probe script that walks the fiber tree (`child`/`sibling` pointers → `memoizedProps` / hooks `memoizedState` / `_debugSource`), serializes cycle-safely in-page, and returns the result as JSON or a text tree.\n\n```bash\nagent-reacttools tree                      # component tree of the page\nagent-reacttools inspect Counter --json    # props, hook state, memo of one component\nagent-reacttools query '//button[contains(@class, \"nav\")]'   # collect DOM matches + owning components\nagent-reacttools style '#submit-btn'       # computed style of an element\n```\n\n## Installation\n\n### Global (recommended)\n\n```bash\nnpm install -g @adamancyzhang/agent-reacttools\n```\n\nRequires Node >= 18. No other dependencies — the only runtime dependency is `ws`.\n\n### From source\n\n```bash\ngit clone https://github.com/adamancyzhang/agent-reacttools.git\ncd agent-reacttools\nnpm install\nnpm run build\nnpm link\n```\n\n### Requirements\n\nA Chrome/Edge with a debugging port (default `127.0.0.1:9222`):\n\n```bash\n\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\" --remote-debugging-port=9222\n```\n\nThat's it. Open your React page (dev server recommended for the richest output) and run any command.\n\n## Quick Start\n\n```bash\nagent-reacttools tree                        # component tree\nagent-reacttools inspect Counter             # deep-dive by component name\nagent-reacttools inspect src/components/     # by source path substring\nagent-reacttools inspect \"#submit-btn\"       # by CSS selector\nagent-reacttools inspect '//*[text()[contains(., \"Submit\")]]'   # by XPath\nagent-reacttools inspect \"Back to list\"      # by visible text\nagent-reacttools find NavLink                # locate + parent chains\nagent-reacttools query '.nav a' --limit 20   # collect DOM matches\nagent-reacttools style '.ant-btn-primary'    # computed style + full class\n```\n\n## Commands\n\n### tree\n\n```\nagent-reacttools tree [--depth N] [--fields ...] [--compact] [--json]\n```\n\nPrints the component + element tree. Component nodes carry a `[DOM]` bracket, prop values, a hooks summary, and the source path (dev builds).\n\n| Flag | Description |\n|---|---|\n| `--depth <n>` | Max tree depth. Default 8, no upper limit (5000-node cap still applies) |\n| `--fields <list>` | Comma-separated: `props,hooks,memo,context,state,file,dom` (default: `props,hooks,file,dom`) |\n| `--compact` | Name and DOM only |\n\n```\n# 2 React apps found on this page\n└─ StrictMode [DIV#app]\n   └─ App {hooks: useState=\"agent-reacttools fixture\", useState (1)=3, useMemo=6} [DIV#app-root.app-shell] (src/main.tsx)\n      ├─ h1 [H1] \"agent-reacttools fixture\"\n      ├─ Counter {step: 1, count: 3, label: \"Count\"} {hooks: useState=7, useMemo=6} [DIV#counter-box] (src/App.tsx)\n      ├─ ItemList [UL#item-list] (src/App.tsx)\n      │  └─ li [LI.item] \"alpha\"\n      ├─ MultiRoot [P#mr-1] \"root one\"\n      │  └─ p [P#mr-2] \"root two\"\n      └─ ThemeBox [BUTTON#theme-btn] \"dark\" (src/App.tsx)\n```\n\nA component's own root-element line is elided (its DOM is already in the bracket); unkeyed React fragments are transparent, so multi-root components' elements render at the component's level.\n\n### inspect\n\n```\nagent-reacttools inspect <query> [--fields ...] [--json]\n```\n\nDeep-dives one component. Resolution order: **component name** → **source path substring** (case-insensitive) → **CSS selector** → **XPath expression** → **visible text**.\n\nOutput: resolved props (+ `defaultProps` defaults when declared), hook state (useState/useReducer/useRef/useContext values; useMemo/useCallback results), memo, class component state, context provider values, and the parent chain.\n\n```\nCounter (src/App.tsx)\n  DOM: <div#counter-box>\n  Parent chain: App\n\n  props:\n    step: 1\n    count: 3\n    label: \"Count\"\n\n  hooks:\n    useState: 7\n    useMemo: 6\n\n  memo:\n    useMemo: 6\n```\n\n### find\n\n```\nagent-reacttools find <name|path-substring>\n```\n\nLocates components in the tree and prints each match with its parent chain:\n\n```\nNavLink (src/App.tsx)\n  at: App → Header → NavLink\n```\n\n### query\n\n```\nagent-reacttools query <xpath|css> [--limit N] [--json]\n```\n\nCollects DOM elements (XPath expression or CSS selector). Each match reports the element descriptor plus its owning component (name/source, or null for plain DOM). Capped at 50 matches by default. Works on non-React pages too.\n\n```\n# 2 of 2 matches for \"//button[contains(@class, \"q-btn\")]\"\n[BUTTON#q-btn-1.q-btn] \"Submit order\" — QueryApp\n[BUTTON#q-btn-2.q-btn] \"Cancel\" — QueryApp\n```\n\n### style\n\n```\nagent-reacttools style <xpath|css> [--all] [--json]\n```\n\nDumps an element's computed style (a curated ~40 layout/typography/color properties by default, `--all` for every property), inline style, and explicit `tag` / `id` / **full untruncated `class`** / `text` fields — the class attribute is the primary hook for style debugging. Works on non-React pages too.\n\n```\ntag: button\nclass: \"ant-btn ant-btn-primary\"\ntext: \"Submit order\"\ncomputed style:\n  display: inline-flex\n  position: relative\n  width: 74px\n```\n\n### Selectors\n\n`inspect` resolves its query in a fixed chain (name → source path → CSS → XPath → visible text); `query` and `style` accept XPath or CSS directly. XPath expressions are evaluated by the browser's native engine (XPath 1.0).\n\n> Visible-text search first tries direct text nodes; React splits interpolated text into sibling text nodes, so it then falls back to the element's complete text content, keeping only the deepest matches. `contains(text(), 'q')` in your own XPath only checks the **first** text node — to match any direct text node, use `//*[text()[contains(., 'q')]]`. See [skills/agent-reacttools/references/xpath.md](skills/agent-reacttools/references/xpath.md) for the full XPath reference.\n\n## Agent Mode\n\n`--json` prints a single-line envelope on stdout — errors included:\n\n```json\n{\"ok\":true,\"command\":\"tree\",\"page\":{\"title\":\"…\",\"url\":\"…\"},\n \"react\":{\"version\":\"18+\",\"apps\":1,\"truncated\":false},\n \"data\":{\"roots\":[{\"name\":\"App\",\"kind\":\"component\",\"file\":\"src/App.tsx\",\"dom\":{\"tag\":\"div\",\"id\":\"app\"},\n   \"props\":{\"msg\":\"hi\"},\"hooks\":{\"useState\":3},\"children\":[…]}]}}\n```\n\nError envelope: `{\"ok\":false,\"error\":{\"code\":\"…\",\"message\":\"…\",\"hint\":\"…\"}}` with a stable `code`:\n\n| Code | Meaning |\n|---|---|\n| `no-react` | No React app on the selected page (may still be loading — retry) |\n| `not-found` | No component/element matches the query |\n| `bad-query` | Invalid XPath / CSS expression |\n| `no-browser` | No reachable CDP endpoint |\n| `ambiguous-tab` | Multiple tabs, none selected — error lists them |\n| `bad-tab` | `--tab` selector matched nothing |\n\nExit codes: `0` success / `1` runtime error / `2` usage error. With `--json`, the error JSON goes to stdout and the human-readable explanation to stderr.\n\n## Connecting\n\n1. **`--cdp <port|host:port|http(s)://url|ws(s)://url>`** — explicit debugging endpoint\n2. **Fallback probe of `127.0.0.1:9222`**\n\nMultiple tabs: pick with `--tab` (`t1`/`t2`… 1-based, exact title, or URL substring). Prefer URL substrings — `Target.getTargets` order is not guaranteed. With multiple tabs and no `--tab`, the CLI errors and lists the options.\n\n## Browser operations\n\nagent-reacttools inspects but never drives the page. For browser control — opening URLs, clicking, filling forms, screenshots — pair it with [agent-browser](https://github.com/vercel-labs/agent-browser), which manages a Chrome instance over the same CDP protocol:\n\n```bash\nnpm i -g agent-browser\nagent-browser install                  # first time only\nagent-browser open http://localhost:5173\n\nagent-reacttools tree --cdp \"$(agent-browser get cdp-url)\"   # inspect its browser\nagent-browser click \"#submit\"                               # drive the UI\nagent-reacttools inspect SubmitButton --cdp \"$(agent-browser get cdp-url)\" --fields props,hooks,memo\n```\n\n`agent-browser get cdp-url` bridges the two tools: it prints the ws URL of agent-browser's Chrome, which agent-reacttools accepts directly via `--cdp`.\n\n## Limits & Caveats\n\n- **React 16/17/18/19** (the probe reads the fiber tree through the DOM markers each major ships).\n- **Production builds** lose `_debugSource` paths, hook names (keys degrade to `h0..hN`), and often component names (minified to `Anonymous`) — the same limits react-devtools has. Dev builds give the richest output.\n- `_debugSource` records the **JSX site that renders** a component (the react-devtools source-panel location), not its definition file — this differs from Vue's `__file`, which points at the definition.\n- **Version reporting**: the runtime exposes no version field; the probe reports `window.React.version` for UMD builds and otherwise the major inferred from DOM markers (`18+` / `17` / `16`).\n- **iframes**: main frame only. **Suspense** shows the committed branch; **unkeyed fragments** are transparent (React flattens them in the fiber tree), keyed fragments appear as nodes.\n- **Huge pages**: tree caps at 5000 nodes (`truncated: true`). For deep content, use `inspect`/`query` with XPath or text targeting instead of the tree.\n- Reading hook values triggers their getters (side-effect-free by convention — standard for component inspection tools).\n\n## Skill for AI Coding Assistants\n\nInstall the agent-reacttools skill with the [skills](https://skills.sh) CLI, directly from GitHub:\n\n```bash\nnpx skills add adamancyzhang/agent-reacttools\n```\n\nThe skill is fetched from this repository (`skills/agent-reacttools/SKILL.md`), so it stays up to date automatically. Works with Claude Code, Codex, Cursor, Gemini CLI, and other skills-aware assistants. Do not copy `SKILL.md` from `node_modules` — it will become stale.\n\nManual install for Claude Code:\n\n```bash\nmkdir -p .claude/skills\ncp -r skills/agent-reacttools .claude/skills/\n```\n\n## Development\n\n```bash\nnpm install\nnpm run build          # typecheck + esbuild bundle to dist/cli.js\nnpm run test           # unit tests (ws.Server for the CDP layer; jsdom + React DOM for the probe)\nnpm run test:e2e       # E2E: real headless Chrome + Vite dev fixture (requires local Chrome)\nnpm run fixture:serve  # serve the fixture dev server manually (port 4173)\n```\n\nLayout: `src/cdp/` (minimal CDP client, endpoint discovery, tab attach) · `src/probe/probe.js` (the injected page probe, embedded into the bundle as a string at build time) · `src/commands/` (tree/inspect/find/query/style) · `src/output/text.ts` (text rendering) · `test/fixtures/react-app/` (Vite + React 18 fixture) · `skills/` (agent skill docs).\n\n## Roadmap\n\n- iframe / shadow DOM traversal\n- Hook change stream (live re-inspection loop)\n- MCP server mode\n\n## License\n\n[MIT](LICENSE) © 2026 Adamancy Zhang\n","readmeFilename":"README.md"}