browser-debugger-cli 0.11.0 → 0.13.0

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.
Files changed (222) hide show
  1. package/.claude/skills/bdg/SKILL.md +4 -4
  2. package/README.md +143 -79
  3. package/dist/commands/cdp.d.ts +22 -1
  4. package/dist/commands/cdp.js +100 -43
  5. package/dist/commands/console.d.ts +12 -0
  6. package/dist/commands/console.js +62 -12
  7. package/dist/commands/css.d.ts +13 -0
  8. package/dist/commands/css.js +53 -0
  9. package/dist/commands/dom/DomElementResolver.d.ts +3 -1
  10. package/dist/commands/dom/DomElementResolver.js +10 -3
  11. package/dist/commands/dom/a11y.js +3 -2
  12. package/dist/commands/dom/audit.d.ts +14 -0
  13. package/dist/commands/dom/audit.js +87 -0
  14. package/dist/commands/dom/eval.d.ts +3 -2
  15. package/dist/commands/dom/eval.js +11 -5
  16. package/dist/commands/dom/form.js +10 -9
  17. package/dist/commands/dom/formInteraction.js +42 -11
  18. package/dist/commands/dom/get.js +8 -8
  19. package/dist/commands/dom/helpers/index.d.ts +1 -1
  20. package/dist/commands/dom/helpers/index.js +1 -1
  21. package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
  22. package/dist/commands/dom/helpers/keyAttributes.js +6 -4
  23. package/dist/commands/dom/helpers/query.d.ts +27 -3
  24. package/dist/commands/dom/helpers/query.js +152 -64
  25. package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
  26. package/dist/commands/dom/helpers/screenshot.js +169 -49
  27. package/dist/commands/dom/index.js +7 -2
  28. package/dist/commands/dom/query.d.ts +19 -2
  29. package/dist/commands/dom/query.js +37 -6
  30. package/dist/commands/dom/screenshot.js +12 -7
  31. package/dist/commands/dom/semanticUtils.d.ts +3 -2
  32. package/dist/commands/dom/semanticUtils.js +40 -9
  33. package/dist/commands/dom/wait.js +5 -3
  34. package/dist/commands/helpJson.d.ts +82 -19
  35. package/dist/commands/helpJson.js +112 -41
  36. package/dist/commands/helpTopic.d.ts +16 -1
  37. package/dist/commands/helpTopic.js +59 -1
  38. package/dist/commands/installSkill.d.ts +15 -5
  39. package/dist/commands/installSkill.js +86 -16
  40. package/dist/commands/network/list.js +22 -12
  41. package/dist/commands/optionBehaviors.js +53 -16
  42. package/dist/commands/page.js +7 -4
  43. package/dist/commands/peek.d.ts +7 -0
  44. package/dist/commands/peek.js +65 -23
  45. package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
  46. package/dist/commands/shared/daemonErrorHandler.js +20 -9
  47. package/dist/commands/shared/dataFetcher.d.ts +12 -4
  48. package/dist/commands/shared/dataFetcher.js +12 -4
  49. package/dist/commands/shared/followMode.d.ts +9 -1
  50. package/dist/commands/shared/followMode.js +22 -4
  51. package/dist/commands/shared/optionTypes.d.ts +9 -2
  52. package/dist/commands/shared/outputFile.js +6 -1
  53. package/dist/commands/start.d.ts +20 -5
  54. package/dist/commands/start.js +84 -23
  55. package/dist/commands/stop.d.ts +11 -0
  56. package/dist/commands/stop.js +24 -1
  57. package/dist/commands/tail.d.ts +7 -1
  58. package/dist/commands/tail.js +13 -62
  59. package/dist/commands.js +2 -0
  60. package/dist/connection/cdp.d.ts +7 -0
  61. package/dist/connection/cdp.js +9 -0
  62. package/dist/connection/launcher.js +3 -2
  63. package/dist/daemon/SessionController.js +6 -1
  64. package/dist/daemon/launcher.d.ts +3 -2
  65. package/dist/daemon/launcher.js +47 -3
  66. package/dist/daemon/session/Session.d.ts +4 -1
  67. package/dist/daemon/session/Session.js +33 -2
  68. package/dist/daemon/session/TelemetryStore.d.ts +8 -1
  69. package/dist/daemon/session/TelemetryStore.js +13 -1
  70. package/dist/daemon/session/commandRegistry.js +36 -14
  71. package/dist/daemon/session/interactions.d.ts +2 -1
  72. package/dist/daemon/session/interactions.js +13 -1
  73. package/dist/daemon/session/plugins.js +19 -53
  74. package/dist/daemon/session/teardown.js +1 -1
  75. package/dist/daemon.js +9234 -7222
  76. package/dist/errors/messages.d.ts +88 -15
  77. package/dist/errors/messages.js +177 -27
  78. package/dist/index.js +19322 -13961
  79. package/dist/ipc/client.d.ts +22 -2
  80. package/dist/ipc/client.js +34 -5
  81. package/dist/ipc/protocol/auditTypes.d.ts +135 -0
  82. package/dist/ipc/protocol/auditTypes.js +6 -0
  83. package/dist/ipc/protocol/commands.d.ts +35 -0
  84. package/dist/ipc/protocol/commands.js +2 -0
  85. package/dist/ipc/protocol/domTypes.d.ts +16 -0
  86. package/dist/ipc/protocol/inspectTypes.d.ts +73 -8
  87. package/dist/ipc/session/types.d.ts +2 -0
  88. package/dist/runtime/css/search.d.ts +39 -0
  89. package/dist/runtime/css/search.js +122 -0
  90. package/dist/runtime/dom/actionEffects.d.ts +9 -2
  91. package/dist/runtime/dom/actionEffects.js +30 -14
  92. package/dist/runtime/dom/audit.d.ts +19 -0
  93. package/dist/runtime/dom/audit.js +37 -0
  94. package/dist/runtime/dom/auditModel.d.ts +45 -0
  95. package/dist/runtime/dom/auditModel.js +220 -0
  96. package/dist/runtime/dom/auditScripts.d.ts +113 -0
  97. package/dist/runtime/dom/auditScripts.js +148 -0
  98. package/dist/runtime/dom/elementGeometry.d.ts +16 -3
  99. package/dist/runtime/dom/elementGeometry.js +49 -10
  100. package/dist/runtime/dom/elementInfo.d.ts +74 -17
  101. package/dist/runtime/dom/elementInfo.js +187 -34
  102. package/dist/runtime/dom/evalHelpers.d.ts +12 -2
  103. package/dist/runtime/dom/evalHelpers.js +67 -7
  104. package/dist/runtime/dom/formDiscovery.d.ts +6 -2
  105. package/dist/runtime/dom/formDiscovery.js +20 -3
  106. package/dist/runtime/dom/formFillHelpers/fill.js +8 -12
  107. package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
  108. package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
  109. package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
  110. package/dist/runtime/dom/formSubmitHelpers.js +4 -3
  111. package/dist/runtime/dom/frameLayout.js +1 -0
  112. package/dist/runtime/dom/inspect.d.ts +7 -0
  113. package/dist/runtime/dom/inspect.js +92 -28
  114. package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
  115. package/dist/runtime/dom/inspectAllStyles.js +90 -7
  116. package/dist/runtime/dom/inspectCascade.d.ts +19 -2
  117. package/dist/runtime/dom/inspectCascade.js +214 -44
  118. package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
  119. package/dist/runtime/dom/inspectCascadeModel.js +108 -34
  120. package/dist/runtime/dom/inspectHints.d.ts +26 -3
  121. package/dist/runtime/dom/inspectHints.js +125 -9
  122. package/dist/runtime/dom/inspectModel.d.ts +5 -1
  123. package/dist/runtime/dom/inspectModel.js +37 -10
  124. package/dist/runtime/dom/inspectPaintModel.d.ts +50 -22
  125. package/dist/runtime/dom/inspectPaintModel.js +182 -68
  126. package/dist/runtime/dom/inspectRules.d.ts +19 -0
  127. package/dist/runtime/dom/inspectRules.js +21 -5
  128. package/dist/runtime/dom/inspectScripts.d.ts +112 -12
  129. package/dist/runtime/dom/inspectScripts.js +357 -32
  130. package/dist/runtime/dom/inspectTree.js +10 -2
  131. package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
  132. package/dist/runtime/dom/inspectWhyModel.js +52 -10
  133. package/dist/runtime/dom/layout.js +40 -16
  134. package/dist/runtime/dom/reactEventHelpers.d.ts +21 -4
  135. package/dist/runtime/dom/reactEventHelpers.js +90 -36
  136. package/dist/runtime/dom/targetNode.d.ts +18 -5
  137. package/dist/runtime/dom/targetNode.js +268 -8
  138. package/dist/runtime/dom/wait.js +2 -1
  139. package/dist/runtime/page/bdgWorld.d.ts +57 -0
  140. package/dist/runtime/page/bdgWorld.js +180 -0
  141. package/dist/runtime/page/emulation.d.ts +13 -4
  142. package/dist/runtime/page/emulation.js +69 -4
  143. package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
  144. package/dist/runtime/page/replacedBuiltins.js +136 -0
  145. package/dist/runtime/page/userAgent.d.ts +17 -0
  146. package/dist/runtime/page/userAgent.js +57 -0
  147. package/dist/session/QueryCacheManager.d.ts +4 -1
  148. package/dist/session/QueryCacheManager.js +5 -2
  149. package/dist/session/chrome.d.ts +4 -1
  150. package/dist/session/chrome.js +7 -1
  151. package/dist/session/cleanup/staleSession.d.ts +21 -4
  152. package/dist/session/cleanup/staleSession.js +79 -9
  153. package/dist/session/cleanup/userCommands.d.ts +4 -1
  154. package/dist/session/cleanup/userCommands.js +10 -5
  155. package/dist/session/daemonSocket.d.ts +10 -0
  156. package/dist/session/daemonSocket.js +22 -0
  157. package/dist/session/lastSession.d.ts +6 -3
  158. package/dist/session/lastSession.js +11 -5
  159. package/dist/session/paths.d.ts +3 -1
  160. package/dist/session/paths.js +5 -5
  161. package/dist/session/portClaims.js +4 -3
  162. package/dist/session/sessionList.d.ts +13 -5
  163. package/dist/session/sessionList.js +31 -7
  164. package/dist/telemetry/a11y.js +2 -2
  165. package/dist/telemetry/console.d.ts +2 -1
  166. package/dist/telemetry/console.js +30 -21
  167. package/dist/telemetry/pageCrash.d.ts +26 -0
  168. package/dist/telemetry/pageCrash.js +53 -0
  169. package/dist/types.d.ts +20 -0
  170. package/dist/ui/formatters/audit.d.ts +19 -0
  171. package/dist/ui/formatters/audit.js +115 -0
  172. package/dist/ui/formatters/cdp.d.ts +138 -0
  173. package/dist/ui/formatters/cdp.js +131 -0
  174. package/dist/ui/formatters/console/chronological.js +3 -1
  175. package/dist/ui/formatters/console/follow.d.ts +2 -1
  176. package/dist/ui/formatters/console/follow.js +2 -2
  177. package/dist/ui/formatters/console/json.d.ts +2 -2
  178. package/dist/ui/formatters/console/json.js +11 -5
  179. package/dist/ui/formatters/console/shared.d.ts +30 -0
  180. package/dist/ui/formatters/console/shared.js +16 -0
  181. package/dist/ui/formatters/console/summarize.d.ts +9 -2
  182. package/dist/ui/formatters/console/summarize.js +40 -9
  183. package/dist/ui/formatters/console.d.ts +2 -1
  184. package/dist/ui/formatters/console.js +7 -5
  185. package/dist/ui/formatters/details.js +3 -1
  186. package/dist/ui/formatters/dom.d.ts +2 -2
  187. package/dist/ui/formatters/dom.js +10 -8
  188. package/dist/ui/formatters/helpFormatters.js +1 -1
  189. package/dist/ui/formatters/inspect.js +50 -17
  190. package/dist/ui/formatters/installSkill.d.ts +9 -1
  191. package/dist/ui/formatters/installSkill.js +32 -6
  192. package/dist/ui/formatters/layout.js +2 -1
  193. package/dist/ui/formatters/networkList.d.ts +1 -1
  194. package/dist/ui/formatters/networkList.js +1 -2
  195. package/dist/ui/formatters/preview.d.ts +2 -0
  196. package/dist/ui/formatters/preview.js +17 -7
  197. package/dist/ui/formatters/sessions.d.ts +2 -2
  198. package/dist/ui/formatters/sessions.js +9 -2
  199. package/dist/ui/formatters/status.js +1 -1
  200. package/dist/ui/logging/logger.d.ts +1 -1
  201. package/dist/ui/messages/commands.d.ts +168 -11
  202. package/dist/ui/messages/commands.js +245 -18
  203. package/dist/ui/messages/consoleMessages.d.ts +24 -0
  204. package/dist/ui/messages/consoleMessages.js +32 -0
  205. package/dist/ui/messages/preview.d.ts +12 -0
  206. package/dist/ui/messages/preview.js +18 -2
  207. package/dist/ui/messages/session.d.ts +13 -2
  208. package/dist/ui/messages/session.js +22 -3
  209. package/dist/utils/cssValues.js +36 -4
  210. package/dist/utils/decisionTrees.js +0 -5
  211. package/dist/utils/directories.d.ts +34 -0
  212. package/dist/utils/directories.js +88 -0
  213. package/dist/utils/display.d.ts +16 -0
  214. package/dist/utils/display.js +42 -0
  215. package/dist/utils/exitCodes.d.ts +1 -0
  216. package/dist/utils/exitCodes.js +6 -0
  217. package/dist/utils/process.d.ts +12 -0
  218. package/dist/utils/process.js +25 -0
  219. package/dist/utils/suggestions.d.ts +4 -2
  220. package/dist/utils/suggestions.js +7 -5
  221. package/dist/utils/taskMappings.js +1 -1
  222. package/package.json +3 -2
@@ -16,8 +16,8 @@ bdg stop # End session
16
16
  ## Session Management
17
17
 
18
18
  ```bash
19
- bdg <url> # Start session (1920x1080, headless if no display)
20
- bdg <url> --headless # Force headless mode
19
+ bdg <url> # Start session (a window on a Mac or Linux desktop; headless over SSH, with CI set, on servers)
20
+ bdg <url> --headless # Force headless mode (do this when running unattended)
21
21
  bdg <url> --no-headless # Force visible browser window
22
22
  bdg status # Check session status
23
23
  bdg peek # Preview collected telemetry
@@ -98,7 +98,7 @@ Selectors search open shadow roots and same-origin iframes, and accept `:has-tex
98
98
  ### Look Without a Screenshot
99
99
 
100
100
  ```bash
101
- bdg dom inspect "button.primary" # Box, layout, rendered font, colors + WCAG contrast, borders, state (~60-100 tokens)
101
+ bdg dom inspect "button.primary" # Box, layout, rendered font, colors + WCAG contrast, borders, state (~80-130 tokens; --no-hints drops the hints)
102
102
  bdg dom inspect ".card" --why color # Which CSS rule set a property, and what it overrode
103
103
  bdg dom layout ".card" # Positions/sizes of every match: above/below the fold, hidden, covered
104
104
  bdg dom listeners "#save" # Event listeners that run for an element (incl. delegated, React/Preact)
@@ -176,7 +176,7 @@ bdg cdp Runtime.evaluate --params '{
176
176
 
177
177
  ## JSON Output and Exit Codes
178
178
 
179
- Add `--json` (`-j`) to any command for `{ version, success, data }` (or `{ success: false, error, exitCode, suggestion }`). `bdg --help --json` lists every command, flag and exit code.
179
+ Add `--json` (`-j`) to any command for `{ version, success, data }` (or `{ success: false, error, exitCode, suggestion }`). `bdg --help --json` lists every command, flag and exit code; `bdg <command> --help --json` describes one command in full (option behaviors, defaults, examples).
180
180
 
181
181
  | Code | Meaning | Action |
182
182
  |------|---------|--------|
package/README.md CHANGED
@@ -1,127 +1,191 @@
1
- # Browser Debugger CLI
1
+ # bdg - Browser Debugger CLI
2
2
 
3
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/szymdzum/browser-debugger-cli/pulls)
3
+ [![npm downloads](https://img.shields.io/npm/dt/browser-debugger-cli?color=blue)](https://www.npmjs.com/package/browser-debugger-cli)
4
4
  [![CI](https://github.com/szymdzum/browser-debugger-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/szymdzum/browser-debugger-cli/actions/workflows/ci.yml)
5
5
  [![Security](https://github.com/szymdzum/browser-debugger-cli/actions/workflows/security.yml/badge.svg)](https://github.com/szymdzum/browser-debugger-cli/actions/workflows/security.yml)
6
- [![npm downloads](https://img.shields.io/npm/dt/browser-debugger-cli?color=blue)](https://www.npmjs.com/package/browser-debugger-cli)
6
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/szymdzum/browser-debugger-cli/pulls)
7
7
 
8
- Chrome DevTools Protocol in your terminal. Opens a persistent connection to Chrome where commands can be executed sequentially via Unix pipes. **Designed for AI agents** and developers who want direct browser control without framework overhead.
8
+ **Give your AI agent a real browser. And the DevTools to go with it.**
9
9
 
10
- ## Why bdg?
10
+ 📖 **[Wiki](https://github.com/szymdzum/browser-debugger-cli/wiki)**: [Getting Started](https://github.com/szymdzum/browser-debugger-cli/wiki/Getting-Started) · [Commands](https://github.com/szymdzum/browser-debugger-cli/wiki/Commands) · [For AI Agents](https://github.com/szymdzum/browser-debugger-cli/wiki/For-AI-Agents) · [Recipes](https://github.com/szymdzum/browser-debugger-cli/wiki/Recipes) · [Quick Reference](https://github.com/szymdzum/browser-debugger-cli/wiki/Quick-Reference) · [Troubleshooting](https://github.com/szymdzum/browser-debugger-cli/wiki/Troubleshooting) · [CLI reference](docs/CLI_REFERENCE.md)
11
11
 
12
- - **Raw CDP access** - Every [protocol method](https://chromedevtools.github.io/devtools-protocol/) available directly
13
- - **Token efficient** - No overhead from MCP tool definitions; progressive discovery loads only what's needed
14
- - **Self-correcting** - Errors clearly exposed with semantic exit codes and suggestions
15
- - **Composable** - Unix philosophy: pipes, jq, shell scripts work naturally
12
+ bdg keeps a browser session open in the background and lets you drive it one shell command at a time. Click, fill, navigate, then read what actually happened: requests, console errors, layout and styles. It is built for coding agents like Claude Code, Codex and Gemini CLI, and it's just as handy in your own terminal. Every command is a plain process with compact output, so it pipes into `jq` and costs an agent few tokens.
16
13
 
17
- **When to use alternatives:**
18
- - **Puppeteer/Playwright**: Complex multi-step scripts, mature testing ecosystem
19
- - **Chrome DevTools MCP**: Already invested in MCP infrastructure
14
+ ```bash
15
+ npm install -g browser-debugger-cli
16
+ bdg localhost:3000
17
+ ```
20
18
 
21
- **Built for agents:** Self-discovery (`--list`, `--search`), semantic exit codes, structured errors, case-insensitive commands, token-efficient output.
19
+ ## Two ways to use it
22
20
 
23
- ## Benchmark: CLI vs MCP for AI Agents
21
+ ### Debug a page: browser telemetry on demand
24
22
 
25
- We benchmarked bdg against Chrome DevTools MCP Server on real developer debugging tasks.
23
+ ![The cart button does nothing; bdg shows the 500 response, the console error and the missing cookie](https://raw.githubusercontent.com/szymdzum/browser-debugger-cli/main/docs/assets/demo-debug.gif)
26
24
 
25
+ The cart button does nothing, and the page doesn't say why. Three commands later the agent knows: the click fired a POST that returned 500, the console says the `cart_id` cookie is missing, and the cookie jar confirms it. Network, console, cookies and the DOM are there whenever the agent asks, without a debugger UI.
27
26
 
28
- **[Full benchmark analysis →](docs/benchmarks/ARTICLE_MCP_VS_CLI_FOR_AGENTS.md)**
27
+ ### Automate without writing a script
29
28
 
30
- **Key findings:** CLI provided 33% better token efficiency through selective queries vs full accessibility tree dumps, plus capabilities MCP doesn't expose (memory profiling, HAR export, batch JS execution).
29
+ ![An agent fills a form, clicks Subscribe, reads the confirmation and inspects the button](https://raw.githubusercontent.com/szymdzum/browser-debugger-cli/main/docs/assets/demo-automate.gif)
31
30
 
31
+ No Playwright script written up front. The agent runs one command, reads what the browser reports back, and picks the next step from that: the click says which text appeared, `dom inspect` says what the button looks like. When the page does something unexpected, the agent adapts on the spot instead of failing at line 40 of a test.
32
32
 
33
- ## Install
33
+ ## More examples
34
+
35
+ ### Reuse the browser's login from the shell
36
+
37
+ ```console
38
+ $ bdg network getCookies
39
+ [1] session_id
40
+ Value: s%3A9f8e7d6c
41
+ HttpOnly: Yes
42
+ SameSite: Lax
43
+
44
+ $ bdg network headers 89565.2 --header authorization
45
+ Request Headers:
46
+ Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZGEifQ.demo
47
+
48
+ $ bdg eval "localStorage.getItem('access_token')"
49
+ eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZGEifQ.demo
50
+ ```
51
+
52
+ `HttpOnly` cookies are included, even though the page's own JavaScript can't read them. Log in once in the browser, then reuse the session from the shell:
34
53
 
35
54
  ```bash
36
- npm install -g browser-debugger-cli
55
+ COOKIES=$(bdg network getCookies --json | jq -r '[.data[] | "\(.name)=\(.value)"] | join("; ")')
56
+ curl -H "Cookie: $COOKIES" localhost:3000/api/me
57
+ ```
58
+
59
+ ### The rest of DevTools
60
+
61
+ ```console
62
+ $ bdg dom a11y tree
63
+ [RootWebArea] "My App" (focused)
64
+ [Heading] "My App"
65
+ [Button] "Sign in" (focusable)
66
+ [Image] ← no accessible name
67
+
68
+ $ bdg cdp Performance.enable
69
+ $ bdg cdp Performance.getMetrics --json | jq '.data.result.metrics | from_entries'
70
+ { "Nodes": 51, "LayoutDuration": 0.000115, "ScriptDuration": 0.000775, "JSHeapUsedSize": 772124, ... }
71
+
72
+ $ bdg cdp Emulation.setCPUThrottlingRate --params '{"rate":4}' # Slow CPU
73
+ $ bdg cdp Network.emulateNetworkConditions --params '{"offline":false,"latency":400,"downloadThroughput":50000,"uploadThroughput":20000}'
74
+ ```
75
+
76
+ Accessibility, performance metrics, CPU profiling, heap snapshots, code coverage, throttling, storage, service workers: everything Chrome DevTools can do, bdg can do too, through raw CDP. Can't find the method you need? `bdg cdp --search heap`.
77
+
78
+ ## Agents learn it on their own
79
+
80
+ No docs to paste into the prompt. The agent asks bdg:
81
+
82
+ ```bash
83
+ bdg --help --json # Every command, flag and exit code, plus "task → command" mappings
84
+ bdg dom query --help --json # One command in full: option behaviors, defaults, examples
85
+ bdg cdp --search cookie # 13 matching methods across all CDP domains, each with an example call
86
+ bdg cdp Network.getCookies --describe # Parameters, return types, an example
37
87
  ```
38
88
 
39
- **Requirements:** Node.js 22.12+ and Chrome (or Chromium).
89
+ And when it gets something wrong, bdg tells it what it meant:
90
+
91
+ ```console
92
+ $ bdg dom clik "a"
93
+ error: unknown command 'clik'
94
+ (Did you mean click?)
95
+
96
+ $ bdg cdp Network.getCookie
97
+ "error": "Method 'Network.getCookie' not found",
98
+ "suggestion": "... Did you mean: Network.getCookies, Network.setCookie, Network.setCookies"
99
+ ```
100
+
101
+ Each mistake exits with code 81 (invalid arguments), so the agent knows to fix the call rather than retry it. CDP method names are case-insensitive, and raw CDP calls point to the friendlier command when one exists. More in the [Agent-Friendly Tools](docs/principles/AGENT_FRIENDLY_TOOLS.md) principles bdg follows.
102
+
103
+ ## Benchmark: CLI vs MCP
104
+
105
+ We gave an AI agent five real debugging tasks, from a single JS error up to a memory leak, and ran each one with bdg and with the official Chrome DevTools MCP server (November 2025).
40
106
 
41
- **Platform Support:**
42
- - ✅ macOS and Linux
43
- - ✅ Windows via WSL
44
- - ❌ PowerShell/Git Bash (not yet)
107
+ | | bdg | Chrome DevTools MCP |
108
+ |---|---|---|
109
+ | **Score** | **77 / 100** | 60 / 100 |
110
+ | **Token efficiency** | **202** | 152 |
111
+ | Tokens used | ~38.1K | ~39.4K |
45
112
 
46
- ## Use with Claude Code and Other Agents
113
+ bdg scored 17 points higher on about the same token budget, so its token efficiency was 33% better. Part of the gap is reach: memory profiling, HAR export and batch JS execution have no MCP equivalent. [Read the full analysis →](docs/benchmarks/ARTICLE_MCP_VS_CLI_FOR_AGENTS.md)
47
114
 
48
- bdg ships an agent skill (`SKILL.md`) that teaches the workflow: start once, act, read what the action changed, inspect without screenshots, check network and console.
115
+ ## Use it with your agent
116
+
117
+ bdg ships an agent skill that teaches the workflow: start once, act, read what changed, inspect without screenshots, check network and console.
49
118
 
50
119
  ```bash
51
- bdg install-skill # ~/.claude/skills/bdg (Claude Code) + ~/.agents/skills/bdg (Codex, Gemini CLI, ...)
120
+ bdg install-skill # Claude Code (~/.claude/skills) + Codex, Gemini CLI, ... (~/.agents/skills)
52
121
  bdg install-skill --claude # Claude Code only
53
122
  ```
54
123
 
55
- Start a new agent session afterwards, and re-run `bdg install-skill` after upgrading bdg. In Claude Code the skill loads when a task needs a browser, or on demand with `/bdg`.
124
+ Start a new agent session afterwards. In Claude Code the skill loads when a task needs a browser, or on demand with `/bdg`. Re-run `bdg install-skill` after upgrading bdg.
56
125
 
57
- ## Quick Start
126
+ ## Quick start
58
127
 
59
128
  ```bash
60
- bdg example.com # Start session
61
- bdg https://localhost:5173 --chrome-flags="--ignore-certificate-errors" # Self-signed certs
62
- bdg https://localhost:5173 --chrome-flags="--disable-web-security" # Disable CORS
63
- bdg cdp --search cookie # Discover commands
64
- bdg cdp Network.getCookies # Run any CDP method
65
- bdg dom query "button" # High-level helpers
66
- bdg dom fill 'input[name="q"]' "shoes"
129
+ bdg example.com # Start a session (the browser stays open)
130
+ bdg dom fill 'input[name="q"]' "shoes" # Interact
67
131
  bdg dom click 'button:has-text("Search")'
68
- bdg page navigate example.com/about
69
- bdg eval "document.title" # Run JavaScript in the page (--frame for iframes)
70
- bdg network list --preset errors # Network requests, console: bdg console
71
- bdg dom listeners "#save" # Which event listeners run for an element
72
- bdg dom layout "#save" # Where it is, whether it is visible or covered
73
- bdg dom inspect "#save" # What it looks like (Figma-like styles), no screenshot
74
- bdg dom inspect "#save" --why color # Which CSS rule sets a value, and what it beats
75
- bdg page emulate --viewport 900x700 # Responsive check mid-session (or --color-scheme)
76
- bdg dom wait "#result" --visible # Wait for an element instead of sleeping
77
- bdg example.com --session agent2 --viewport 1280x800 # A second, independent session
78
- bdg stop # End session
132
+ bdg dom wait "#result" --visible # Wait for an element instead of sleeping
133
+ bdg network list --preset errors # Failed requests
134
+ bdg console # Console messages
135
+ bdg dom layout "#save" # Where is it? Visible? Covered?
136
+ bdg dom inspect "#save" --why color # Which CSS rule sets the color
137
+ bdg dom audit contrast # Page-wide: text below WCAG AA, weakest first
138
+ bdg css search -- --brand # Where a token is set, in every stylesheet
139
+ bdg dom listeners "#save" # Which event listeners run
140
+ bdg page emulate --viewport 900x700 # Responsive check mid-session (--mobile for a phone)
141
+ bdg eval "document.title" # Run JavaScript (--frame for iframes)
142
+ bdg cdp Network.getCookies # Any CDP method
143
+ bdg stop # End the session
79
144
  ```
80
145
 
81
- ## Current State
146
+ Local dev servers with self-signed certificates: `bdg https://localhost:5173 --chrome-flags="--ignore-certificate-errors"`. Need parallel sessions? `bdg example.com --session agent2`.
82
147
 
83
- **Raw CDP access is complete.** Every protocol method works now. High-level commands cover the common work: page navigation, DOM queries and interaction (click, fill, hover, keys, forms, shadow DOM and iframes), accessibility tree, screenshots, element styles with the CSS cascade (`dom inspect`: what an element looks like, which rule sets each value, and declarations that have no effect), network requests and HAR export, console messages and event listeners. Actions report what they changed (navigation, new messages, requests, or no visible effect), and several named sessions can run side by side. See the [CLI reference](docs/CLI_REFERENCE.md) for every command, and `bdg --help --json` for the machine-readable version.
148
+ ## What it covers
84
149
 
85
- ## Agent Discovery Pattern
150
+ | Area | Commands |
151
+ |---|---|
152
+ | **Page** | navigate, reload, back/forward, viewport, phone (`--mobile`) and color-scheme emulation |
153
+ | **Interaction** | click (double, right), fill (React-compatible, file inputs), hover, keys, forms, scroll, wait; shadow DOM and iframes included |
154
+ | **Inspection** | element styles with the CSS cascade, layout and visibility, page-wide audits (contrast, overflow, layers, animations), stylesheet search, accessibility tree, event listeners, screenshots |
155
+ | **Telemetry** | network requests and headers (incl. `Authorization`), HAR export, cookies (incl. `HttpOnly`), console messages, live `peek --follow` |
156
+ | **Accessibility** | accessibility tree, semantic queries (`role:button name:Submit`), contrast checks |
157
+ | **Performance** | metrics, CPU and heap profiling, tracing, CPU and network throttling (raw CDP) |
158
+ | **Sessions** | several named sessions side by side, or attach to a browser you already have open (`--chrome-ws-url`) |
159
+ | **Everything else** | raw CDP: `bdg cdp --list`, `--search`, `--describe` |
86
160
 
87
- ```bash
88
- # Agent explores what's possible (no docs needed)
89
- bdg cdp --list # All domains
90
- bdg cdp Network --list # Methods in one domain
91
- bdg cdp Network.getCookies --describe # Full schema + examples
92
- bdg cdp Network.getCookies # Execute
93
-
94
- # Search across all domains
95
- bdg cdp --search screenshot # Find relevant methods
96
- bdg cdp --search cookie # methods mentioning cookies
97
- ```
161
+ The [CLI reference](docs/CLI_REFERENCE.md) documents every command. `bdg --help --json` gives agents the machine-readable version.
162
+
163
+ ## Install
98
164
 
99
- ## Documentation
165
+ **Requirements:** Node.js 22.12+ and a Chromium-based browser: Chrome, Chromium or Microsoft Edge.
100
166
 
101
- 📖 **[Wiki](https://github.com/szymdzum/browser-debugger-cli/wiki)** - Guides, command reference, recipes
167
+ **Platforms:** macOS, Linux and Windows via WSL. Native PowerShell and Git Bash are not supported yet.
102
168
 
103
- - [Getting Started](https://github.com/szymdzum/browser-debugger-cli/wiki/Getting-Started)
104
- - [Commands](https://github.com/szymdzum/browser-debugger-cli/wiki/Commands)
105
- - [For AI Agents](https://github.com/szymdzum/browser-debugger-cli/wiki/For-AI-Agents)
106
- - [Recipes](https://github.com/szymdzum/browser-debugger-cli/wiki/Recipes)
107
- - [Quick Reference](https://github.com/szymdzum/browser-debugger-cli/wiki/Quick-Reference)
108
- - [Architecture](https://github.com/szymdzum/browser-debugger-cli/wiki/Architecture)
109
- - [Troubleshooting](https://github.com/szymdzum/browser-debugger-cli/wiki/Troubleshooting)
169
+ **Browsers:** bdg launches Chrome by default. To use Edge, point `CHROME_PATH` at its binary, or attach to an Edge you started with `--remote-debugging-port`:
110
170
 
111
- ## Design Principles
171
+ ```bash
172
+ CHROME_PATH="/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" bdg example.com # macOS
173
+ CHROME_PATH=/usr/bin/microsoft-edge bdg example.com # Linux
174
+ bdg example.com --chrome-ws-url 9222 # Attach to a running browser
175
+ ```
112
176
 
113
- This tool implements [Agent-Friendly Tools](docs/principles/AGENT_FRIENDLY_TOOLS.md):
177
+ Firefox and Safari are not supported: bdg speaks the Chrome DevTools Protocol, which they do not implement.
114
178
 
115
- - **Self-documenting** - Tools teach themselves via `--list`, `--describe`
116
- - **Semantic exit codes** - Machine-parseable error handling
117
- - **Structured output** - JSON by default, human-readable optional
118
- - **Progressive disclosure** - Simple commands, deep capabilities
179
+ ## When to use something else
119
180
 
120
- ## Contributing
181
+ - **Playwright / Puppeteer**: long scripted test suites and a mature testing ecosystem.
182
+ - **Chrome DevTools MCP**: if your setup is already built around MCP servers.
121
183
 
122
- [Issues](https://github.com/szymdzum/browser-debugger-cli/issues) for bugs, [Discussions](https://github.com/szymdzum/browser-debugger-cli/discussions) for ideas. PRs welcome.
184
+ bdg is for when an agent or a developer needs to poke at a live page, step by step, and understand what is going on.
185
+
186
+ ## Contributing
123
187
 
124
- See `docs/` for architecture and contributor guides.
188
+ [Issues](https://github.com/szymdzum/browser-debugger-cli/issues) for bugs, [Discussions](https://github.com/szymdzum/browser-debugger-cli/discussions) for ideas. PRs welcome. See the [Architecture](https://github.com/szymdzum/browser-debugger-cli/wiki/Architecture) page and `docs/` for contributor guides.
125
189
 
126
190
  ## License
127
191
 
@@ -1,4 +1,7 @@
1
- import type { Command } from 'commander';
1
+ import { type Command } from 'commander';
2
+ import { type CommandResult } from './shared/CommandRunner.js';
3
+ import type { CdpCommandOptions } from './shared/optionTypes.js';
4
+ import { type CdpExecuteData } from '../ui/formatters/cdp.js';
2
5
  /**
3
6
  * Register CDP command with full introspection support.
4
7
  *
@@ -14,4 +17,22 @@ import type { Command } from 'commander';
14
17
  * @param program - Commander.js Command instance to register commands on
15
18
  */
16
19
  export declare function registerCdpCommand(program: Command): void;
20
+ /**
21
+ * Whether the argument names a domain without a method and nothing asks to
22
+ * run it (`bdg cdp Network`): its methods are listed, as with `--list`.
23
+ *
24
+ * @param method - Method or domain argument
25
+ * @param options - Command options
26
+ * @returns True for a bare domain name
27
+ */
28
+ export declare function isBareDomain(method: string, options: CdpCommandOptions): boolean;
29
+ /**
30
+ * The page exception a method reported in its result (`Runtime.evaluate`,
31
+ * `Runtime.callFunctionOn`, ... answer a script that threw with
32
+ * `exceptionDetails`), as an error result like `dom eval`'s (exit 91).
33
+ *
34
+ * @param result - Method result
35
+ * @returns Error result, or undefined when the result has no exception
36
+ */
37
+ export declare function pageExceptionResult(result: unknown): CommandResult<CdpExecuteData> | undefined;
17
38
  //# sourceMappingURL=cdp.d.ts.map
@@ -1,10 +1,14 @@
1
+ import { Option } from 'commander';
1
2
  import { normalizeMethod } from '../cdp/protocol.js';
2
3
  import { getAllDomainSummaries, getDomainMethods, getProtocolCounts, getDomainSummary, getMethodSchema, } from '../cdp/schema.js';
3
4
  import { runCommand } from './shared/CommandRunner.js';
4
5
  import { jsonOption } from './shared/commonOptions.js';
5
6
  import { CommandError } from '../errors/index.js';
7
+ import { emptyCdpSearchError, missingArgumentError, scriptExecutionError, } from '../errors/messages.js';
6
8
  import { callCDP } from '../ipc/client.js';
7
9
  import { validateIPCResponse } from '../ipc/index.js';
10
+ import { describeException } from '../runtime/dom/evalHelpers.js';
11
+ import { formatCdpDescription, formatCdpDomainMethods, formatCdpDomains, formatCdpResult, formatCdpSearch, isEmptyCdpResult, } from '../ui/formatters/cdp.js';
8
12
  import { formatHint } from '../ui/messages/hints.js';
9
13
  import { sessionCommand } from '../ui/messages/sessionCommand.js';
10
14
  import { getErrorMessage } from '../utils/errors.js';
@@ -26,6 +30,8 @@ const DOMAIN_NOTES = {
26
30
  Tracing: 'Performance tracing. Call Tracing.start, perform actions, then Tracing.end. ' +
27
31
  'Data arrives via Tracing.dataCollected events.',
28
32
  };
33
+ /** Usage of `bdg cdp`, suggested when it gets neither a method nor a flag */
34
+ const CDP_USAGE = 'Usage: bdg cdp [method] [--params <json>] [--list] [--describe] [--search <query>]';
29
35
  /**
30
36
  * Domain and method counts of the bundled protocol, for the help text.
31
37
  *
@@ -44,18 +50,6 @@ const METHOD_NOTES = {
44
50
  'Profiler.start': 'Starts CPU profiling. Returns empty. Call Profiler.stop to get the profile data.',
45
51
  'Tracing.start': 'Starts tracing. Returns empty. Data arrives via events after Tracing.end.',
46
52
  };
47
- /**
48
- * Check if a CDP result is empty (null, undefined, or empty object).
49
- */
50
- function isEmptyResult(result) {
51
- if (result === null || result === undefined) {
52
- return true;
53
- }
54
- if (typeof result === 'object' && Object.keys(result).length === 0) {
55
- return true;
56
- }
57
- return false;
58
- }
59
53
  /**
60
54
  * Get contextual hint for a method based on domain notes and result.
61
55
  */
@@ -64,7 +58,7 @@ function getMethodHint(methodName, result) {
64
58
  return METHOD_NOTES[methodName];
65
59
  }
66
60
  const domain = methodName.split('.')[0];
67
- if (domain && DOMAIN_NOTES[domain] && isEmptyResult(result)) {
61
+ if (domain && DOMAIN_NOTES[domain] && isEmptyCdpResult(result)) {
68
62
  return DOMAIN_NOTES[domain];
69
63
  }
70
64
  return undefined;
@@ -90,35 +84,87 @@ export function registerCdpCommand(program) {
90
84
  ' Discovery: --list, --search, --describe\n' +
91
85
  ' Execution: case-insensitive (network.getcookies works)')
92
86
  .argument('[method]', 'CDP method name (e.g., Network.getCookies, network.getcookies)')
93
- .option('--params <json>', 'Method parameters as JSON')
94
- .option('--list', 'List all domains or methods in a domain')
95
- .option('--describe', 'Show method signature and parameters')
96
- .option('--search <query>', 'Search methods by keyword')
97
- .addOption(jsonOption().hideHelp())
87
+ .addOption(new Option('--params <json>', 'Method parameters as JSON'))
88
+ .addOption(new Option('--list', 'List all domains or methods in a domain').conflicts([
89
+ 'describe',
90
+ 'params',
91
+ ]))
92
+ .addOption(new Option('--describe', 'Show method signature and parameters').conflicts('params'))
93
+ .addOption(new Option('--search <query>', 'Search methods by keyword').conflicts([
94
+ 'list',
95
+ 'describe',
96
+ 'params',
97
+ ]))
98
+ .addOption(jsonOption())
98
99
  .addHelpText('after', () => `\nBundled protocol: ${cdpCountsText()}`)
99
100
  .action(async (method, options) => {
100
- await runCommand(async (opts) => {
101
- if (opts.search) {
102
- return await handleSearch(opts.search, method);
103
- }
104
- if (opts.list && !method) {
105
- return handleListDomains();
106
- }
107
- if (opts.list && method) {
108
- return handleListDomainMethods(method);
109
- }
110
- if (opts.describe && method) {
111
- return handleDescribeMethod(method);
112
- }
113
- if (method) {
114
- return await handleExecuteMethod(method, opts.params);
115
- }
116
- throw new CommandError('Missing required argument or flag', {
117
- suggestion: 'Usage: bdg cdp [method] [--params <json>] [--list] [--describe] [--search <query>]',
118
- }, EXIT_CODES.INVALID_ARGUMENTS);
119
- }, { ...options, json: true });
101
+ await runCdpCommand(method, options);
120
102
  });
121
103
  }
104
+ /**
105
+ * Run the `bdg cdp` mode the options select, with its human-readable output.
106
+ *
107
+ * @param method - Method or domain argument
108
+ * @param options - Command options (exits 81 when neither a method nor a
109
+ * discovery flag is given)
110
+ */
111
+ async function runCdpCommand(method, options) {
112
+ if (options.search !== undefined) {
113
+ const query = options.search;
114
+ return runCommand(async () => handleSearch(query, method), options, formatCdpSearch);
115
+ }
116
+ if (method && (options.list || isBareDomain(method, options))) {
117
+ return runCommand(async () => handleListDomainMethods(method), options, formatCdpDomainMethods);
118
+ }
119
+ if (options.list)
120
+ return runCommand(async () => handleListDomains(), options, formatCdpDomains);
121
+ if (options.describe && method) {
122
+ return runCommand(async () => handleDescribeMethod(method), options, formatCdpDescription);
123
+ }
124
+ if (method) {
125
+ return runCommand(async () => handleExecuteMethod(method, options.params), options, formatCdpResult);
126
+ }
127
+ return runCommand(async () => {
128
+ const err = missingArgumentError(CDP_USAGE);
129
+ throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.INVALID_ARGUMENTS);
130
+ }, options);
131
+ }
132
+ /**
133
+ * Whether the argument names a domain without a method and nothing asks to
134
+ * run it (`bdg cdp Network`): its methods are listed, as with `--list`.
135
+ *
136
+ * @param method - Method or domain argument
137
+ * @param options - Command options
138
+ * @returns True for a bare domain name
139
+ */
140
+ export function isBareDomain(method, options) {
141
+ return (!method.includes('.') &&
142
+ options.params === undefined &&
143
+ !options.describe &&
144
+ getDomainSummary(method) !== undefined);
145
+ }
146
+ /**
147
+ * The page exception a method reported in its result (`Runtime.evaluate`,
148
+ * `Runtime.callFunctionOn`, ... answer a script that threw with
149
+ * `exceptionDetails`), as an error result like `dom eval`'s (exit 91).
150
+ *
151
+ * @param result - Method result
152
+ * @returns Error result, or undefined when the result has no exception
153
+ */
154
+ export function pageExceptionResult(result) {
155
+ if (typeof result !== 'object' || result === null || !('exceptionDetails' in result)) {
156
+ return undefined;
157
+ }
158
+ const details = result
159
+ .exceptionDetails;
160
+ const err = scriptExecutionError(describeException(details));
161
+ return {
162
+ success: false,
163
+ error: err.message,
164
+ exitCode: EXIT_CODES.SCRIPT_ERROR,
165
+ errorContext: { suggestion: err.suggestion },
166
+ };
167
+ }
122
168
  /**
123
169
  * Find similar methods to suggest when a method is not found.
124
170
  * Returns up to 3 closest matches based on edit distance.
@@ -177,6 +223,15 @@ function blockedAlternative(methodName) {
177
223
  * @returns Success result with matching methods
178
224
  */
179
225
  async function handleSearch(query, domain) {
226
+ if (!query.trim()) {
227
+ const err = emptyCdpSearchError();
228
+ return {
229
+ success: false,
230
+ error: err.message,
231
+ exitCode: EXIT_CODES.INVALID_ARGUMENTS,
232
+ errorContext: { suggestion: err.suggestion },
233
+ };
234
+ }
180
235
  if (domain !== undefined && !getDomainSummary(domain)) {
181
236
  return {
182
237
  success: false,
@@ -186,11 +241,11 @@ async function handleSearch(query, domain) {
186
241
  };
187
242
  }
188
243
  const { searchMethods } = await import('../cdp/schema.js');
189
- const results = searchMethods(query).filter((m) => domain === undefined || m.domain.toLowerCase() === domain.toLowerCase());
244
+ const results = searchMethods(query.trim()).filter((m) => domain === undefined || m.domain.toLowerCase() === domain.toLowerCase());
190
245
  return {
191
246
  success: true,
192
247
  data: {
193
- query,
248
+ query: query.trim(),
194
249
  count: results.length,
195
250
  methods: results.map((m) => ({
196
251
  name: m.name,
@@ -338,6 +393,7 @@ function handleDescribeMethod(methodName) {
338
393
  };
339
394
  }
340
395
  const methodNote = METHOD_NOTES[schema.name] ?? DOMAIN_NOTES[schema.domain];
396
+ const alternative = blockedAlternative(schema.name);
341
397
  return {
342
398
  success: true,
343
399
  data: {
@@ -365,9 +421,7 @@ function handleDescribeMethod(methodName) {
365
421
  description: r.description,
366
422
  items: r.items,
367
423
  })),
368
- example: blockedAlternative(schema.name)
369
- ? { command: blockedAlternative(schema.name) }
370
- : schema.example,
424
+ example: alternative ? { command: alternative } : schema.example,
371
425
  },
372
426
  };
373
427
  }
@@ -443,6 +497,9 @@ async function handleExecuteMethod(methodName, paramsJson) {
443
497
  const response = await callCDP(normalized, params);
444
498
  validateIPCResponse(response);
445
499
  const cdpResult = response.data?.result;
500
+ const exception = pageExceptionResult(cdpResult);
501
+ if (exception)
502
+ return exception;
446
503
  const result = {
447
504
  success: true,
448
505
  data: {
@@ -22,6 +22,18 @@ export declare function listsMessages(options: Pick<ConsoleCommandOptions, 'list
22
22
  * @returns Messages of the current page (empty if it logged nothing)
23
23
  */
24
24
  export declare function filterByCurrentNavigation(messages: ConsoleMessage[], currentNavigationId?: number): ConsoleMessage[];
25
+ /**
26
+ * Dropped messages that could have been in the view: all of them with
27
+ * `--history`; for the current page only while the oldest kept message is
28
+ * that page's (else every dropped one came from an earlier page).
29
+ *
30
+ * @param messages - All kept messages, oldest first
31
+ * @param dropped - Oldest messages the session dropped at its limit
32
+ * @param options - `--history`
33
+ * @param currentNavigationId - Navigation id of the current page, if known
34
+ * @returns Dropped count to warn about (0: none of the view's)
35
+ */
36
+ export declare function droppedInView(messages: ConsoleMessage[], dropped: number, options: Pick<ConsoleCommandOptions, 'history'>, currentNavigationId?: number): number;
25
37
  export declare function filterByLevel(messages: ConsoleMessage[], level: ConsoleLevel): ConsoleMessage[];
26
38
  /**
27
39
  * Messages the filters left out between the first and the last listed