browser-debugger-cli 0.11.0 → 0.12.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 (98) hide show
  1. package/README.md +142 -79
  2. package/dist/commands/css.d.ts +13 -0
  3. package/dist/commands/css.js +53 -0
  4. package/dist/commands/dom/audit.d.ts +14 -0
  5. package/dist/commands/dom/audit.js +87 -0
  6. package/dist/commands/dom/formInteraction.js +36 -6
  7. package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
  8. package/dist/commands/dom/helpers/keyAttributes.js +6 -4
  9. package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
  10. package/dist/commands/dom/helpers/screenshot.js +158 -38
  11. package/dist/commands/dom/index.js +4 -1
  12. package/dist/commands/dom/screenshot.js +10 -6
  13. package/dist/commands/dom/wait.js +5 -3
  14. package/dist/commands/helpJson.js +1 -1
  15. package/dist/commands/optionBehaviors.js +21 -6
  16. package/dist/commands/page.js +7 -4
  17. package/dist/commands/peek.d.ts +7 -0
  18. package/dist/commands/peek.js +65 -23
  19. package/dist/commands/shared/optionTypes.d.ts +5 -1
  20. package/dist/commands/start.d.ts +13 -0
  21. package/dist/commands/start.js +19 -2
  22. package/dist/commands/tail.d.ts +7 -1
  23. package/dist/commands/tail.js +13 -62
  24. package/dist/commands.js +2 -0
  25. package/dist/daemon/session/commandRegistry.js +7 -1
  26. package/dist/daemon/session/plugins.js +4 -52
  27. package/dist/daemon.js +7986 -6848
  28. package/dist/errors/messages.d.ts +34 -4
  29. package/dist/errors/messages.js +68 -5
  30. package/dist/index.js +610 -186
  31. package/dist/ipc/client.d.ts +4 -0
  32. package/dist/ipc/client.js +8 -0
  33. package/dist/ipc/protocol/auditTypes.d.ts +129 -0
  34. package/dist/ipc/protocol/auditTypes.js +6 -0
  35. package/dist/ipc/protocol/commands.d.ts +23 -0
  36. package/dist/ipc/protocol/commands.js +2 -0
  37. package/dist/ipc/protocol/domTypes.d.ts +4 -0
  38. package/dist/ipc/protocol/inspectTypes.d.ts +71 -8
  39. package/dist/runtime/css/search.d.ts +39 -0
  40. package/dist/runtime/css/search.js +122 -0
  41. package/dist/runtime/dom/actionEffects.d.ts +4 -1
  42. package/dist/runtime/dom/actionEffects.js +8 -4
  43. package/dist/runtime/dom/audit.d.ts +19 -0
  44. package/dist/runtime/dom/audit.js +36 -0
  45. package/dist/runtime/dom/auditModel.d.ts +45 -0
  46. package/dist/runtime/dom/auditModel.js +215 -0
  47. package/dist/runtime/dom/auditScripts.d.ts +107 -0
  48. package/dist/runtime/dom/auditScripts.js +112 -0
  49. package/dist/runtime/dom/elementGeometry.d.ts +8 -2
  50. package/dist/runtime/dom/elementGeometry.js +24 -8
  51. package/dist/runtime/dom/elementInfo.d.ts +3 -2
  52. package/dist/runtime/dom/elementInfo.js +8 -2
  53. package/dist/runtime/dom/formFillHelpers/fill.js +2 -2
  54. package/dist/runtime/dom/inspect.d.ts +7 -0
  55. package/dist/runtime/dom/inspect.js +88 -23
  56. package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
  57. package/dist/runtime/dom/inspectAllStyles.js +89 -7
  58. package/dist/runtime/dom/inspectCascade.d.ts +19 -2
  59. package/dist/runtime/dom/inspectCascade.js +214 -44
  60. package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
  61. package/dist/runtime/dom/inspectCascadeModel.js +108 -34
  62. package/dist/runtime/dom/inspectHints.d.ts +26 -3
  63. package/dist/runtime/dom/inspectHints.js +125 -9
  64. package/dist/runtime/dom/inspectModel.d.ts +3 -0
  65. package/dist/runtime/dom/inspectModel.js +30 -7
  66. package/dist/runtime/dom/inspectPaintModel.d.ts +48 -22
  67. package/dist/runtime/dom/inspectPaintModel.js +180 -68
  68. package/dist/runtime/dom/inspectRules.d.ts +19 -0
  69. package/dist/runtime/dom/inspectRules.js +21 -5
  70. package/dist/runtime/dom/inspectScripts.d.ts +85 -12
  71. package/dist/runtime/dom/inspectScripts.js +314 -28
  72. package/dist/runtime/dom/inspectTree.js +10 -2
  73. package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
  74. package/dist/runtime/dom/inspectWhyModel.js +52 -10
  75. package/dist/runtime/dom/layout.js +31 -9
  76. package/dist/runtime/dom/reactEventHelpers.d.ts +7 -0
  77. package/dist/runtime/dom/reactEventHelpers.js +27 -9
  78. package/dist/runtime/page/emulation.d.ts +13 -4
  79. package/dist/runtime/page/emulation.js +69 -4
  80. package/dist/runtime/page/userAgent.d.ts +17 -0
  81. package/dist/runtime/page/userAgent.js +57 -0
  82. package/dist/types.d.ts +4 -0
  83. package/dist/ui/formatters/audit.d.ts +19 -0
  84. package/dist/ui/formatters/audit.js +106 -0
  85. package/dist/ui/formatters/dom.d.ts +1 -1
  86. package/dist/ui/formatters/dom.js +6 -3
  87. package/dist/ui/formatters/inspect.js +42 -15
  88. package/dist/ui/formatters/status.js +1 -1
  89. package/dist/ui/messages/commands.d.ts +44 -7
  90. package/dist/ui/messages/commands.js +83 -11
  91. package/dist/ui/messages/preview.d.ts +6 -0
  92. package/dist/ui/messages/preview.js +9 -1
  93. package/dist/utils/cssValues.js +36 -4
  94. package/dist/utils/decisionTrees.js +0 -5
  95. package/dist/utils/suggestions.d.ts +4 -2
  96. package/dist/utils/suggestions.js +7 -5
  97. package/dist/utils/taskMappings.js +1 -1
  98. package/package.json +3 -2
package/README.md CHANGED
@@ -1,127 +1,190 @@
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 cdp --search cookie # 13 matching methods across all CDP domains, each with an example call
85
+ bdg cdp Network.getCookies --describe # Parameters, return types, an example
37
86
  ```
38
87
 
39
- **Requirements:** Node.js 22.12+ and Chrome (or Chromium).
88
+ And when it gets something wrong, bdg tells it what it meant:
89
+
90
+ ```console
91
+ $ bdg dom clik "a"
92
+ error: unknown command 'clik'
93
+ (Did you mean click?)
94
+
95
+ $ bdg cdp Network.getCookie
96
+ "error": "Method 'Network.getCookie' not found",
97
+ "suggestion": "... Did you mean: Network.getCookies, Network.setCookie, Network.setCookies"
98
+ ```
99
+
100
+ 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.
101
+
102
+ ## Benchmark: CLI vs MCP
103
+
104
+ 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
105
 
41
- **Platform Support:**
42
- - ✅ macOS and Linux
43
- - ✅ Windows via WSL
44
- - ❌ PowerShell/Git Bash (not yet)
106
+ | | bdg | Chrome DevTools MCP |
107
+ |---|---|---|
108
+ | **Score** | **77 / 100** | 60 / 100 |
109
+ | **Token efficiency** | **202** | 152 |
110
+ | Tokens used | ~38.1K | ~39.4K |
45
111
 
46
- ## Use with Claude Code and Other Agents
112
+ 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
113
 
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.
114
+ ## Use it with your agent
115
+
116
+ bdg ships an agent skill that teaches the workflow: start once, act, read what changed, inspect without screenshots, check network and console.
49
117
 
50
118
  ```bash
51
- bdg install-skill # ~/.claude/skills/bdg (Claude Code) + ~/.agents/skills/bdg (Codex, Gemini CLI, ...)
119
+ bdg install-skill # Claude Code (~/.claude/skills) + Codex, Gemini CLI, ... (~/.agents/skills)
52
120
  bdg install-skill --claude # Claude Code only
53
121
  ```
54
122
 
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`.
123
+ 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
124
 
57
- ## Quick Start
125
+ ## Quick start
58
126
 
59
127
  ```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"
128
+ bdg example.com # Start a session (the browser stays open)
129
+ bdg dom fill 'input[name="q"]' "shoes" # Interact
67
130
  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
131
+ bdg dom wait "#result" --visible # Wait for an element instead of sleeping
132
+ bdg network list --preset errors # Failed requests
133
+ bdg console # Console messages
134
+ bdg dom layout "#save" # Where is it? Visible? Covered?
135
+ bdg dom inspect "#save" --why color # Which CSS rule sets the color
136
+ bdg dom audit contrast # Page-wide: text below WCAG AA, weakest first
137
+ bdg css search -- --brand # Where a token is set, in every stylesheet
138
+ bdg dom listeners "#save" # Which event listeners run
139
+ bdg page emulate --viewport 900x700 # Responsive check mid-session (--mobile for a phone)
140
+ bdg eval "document.title" # Run JavaScript (--frame for iframes)
141
+ bdg cdp Network.getCookies # Any CDP method
142
+ bdg stop # End the session
79
143
  ```
80
144
 
81
- ## Current State
145
+ 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
146
 
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.
147
+ ## What it covers
84
148
 
85
- ## Agent Discovery Pattern
149
+ | Area | Commands |
150
+ |---|---|
151
+ | **Page** | navigate, reload, back/forward, viewport, phone (`--mobile`) and color-scheme emulation |
152
+ | **Interaction** | click (double, right), fill (React-compatible, file inputs), hover, keys, forms, scroll, wait; shadow DOM and iframes included |
153
+ | **Inspection** | element styles with the CSS cascade, layout and visibility, page-wide audits (contrast, overflow, layers, animations), stylesheet search, accessibility tree, event listeners, screenshots |
154
+ | **Telemetry** | network requests and headers (incl. `Authorization`), HAR export, cookies (incl. `HttpOnly`), console messages, live `peek --follow` |
155
+ | **Accessibility** | accessibility tree, semantic queries (`role:button name:Submit`), contrast checks |
156
+ | **Performance** | metrics, CPU and heap profiling, tracing, CPU and network throttling (raw CDP) |
157
+ | **Sessions** | several named sessions side by side, or attach to a browser you already have open (`--chrome-ws-url`) |
158
+ | **Everything else** | raw CDP: `bdg cdp --list`, `--search`, `--describe` |
86
159
 
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
- ```
160
+ The [CLI reference](docs/CLI_REFERENCE.md) documents every command. `bdg --help --json` gives agents the machine-readable version.
161
+
162
+ ## Install
98
163
 
99
- ## Documentation
164
+ **Requirements:** Node.js 22.12+ and a Chromium-based browser: Chrome, Chromium or Microsoft Edge.
100
165
 
101
- 📖 **[Wiki](https://github.com/szymdzum/browser-debugger-cli/wiki)** - Guides, command reference, recipes
166
+ **Platforms:** macOS, Linux and Windows via WSL. Native PowerShell and Git Bash are not supported yet.
102
167
 
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)
168
+ **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
169
 
111
- ## Design Principles
170
+ ```bash
171
+ CHROME_PATH="/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" bdg example.com # macOS
172
+ CHROME_PATH=/usr/bin/microsoft-edge bdg example.com # Linux
173
+ bdg example.com --chrome-ws-url 9222 # Attach to a running browser
174
+ ```
112
175
 
113
- This tool implements [Agent-Friendly Tools](docs/principles/AGENT_FRIENDLY_TOOLS.md):
176
+ Firefox and Safari are not supported: bdg speaks the Chrome DevTools Protocol, which they do not implement.
114
177
 
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
178
+ ## When to use something else
119
179
 
120
- ## Contributing
180
+ - **Playwright / Puppeteer**: long scripted test suites and a mature testing ecosystem.
181
+ - **Chrome DevTools MCP**: if your setup is already built around MCP servers.
121
182
 
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.
183
+ 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.
184
+
185
+ ## Contributing
123
186
 
124
- See `docs/` for architecture and contributor guides.
187
+ [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
188
 
126
189
  ## License
127
190
 
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `bdg css search <text>` - find text in the page's stylesheets, including
3
+ * cross-origin ones that page scripts cannot read: where a token is set, which
4
+ * rules use `oklch(`, a class or a custom property.
5
+ */
6
+ import type { Command } from 'commander';
7
+ /**
8
+ * Register the `css` command group.
9
+ *
10
+ * @param program - Root command
11
+ */
12
+ export declare function registerCssCommands(program: Command): void;
13
+ //# sourceMappingURL=css.d.ts.map
@@ -0,0 +1,53 @@
1
+ /**
2
+ * `bdg css search <text>` - find text in the page's stylesheets, including
3
+ * cross-origin ones that page scripts cannot read: where a token is set, which
4
+ * rules use `oklch(`, a class or a custom property.
5
+ */
6
+ import { runCommand } from './shared/CommandRunner.js';
7
+ import { jsonOption } from './shared/commonOptions.js';
8
+ import { integerOption } from './shared/validation.js';
9
+ import { cssSearch } from '../ipc/client.js';
10
+ import { formatCssSearch } from '../ui/formatters/audit.js';
11
+ import { CSS_SEARCH_HELP_EXAMPLES } from '../ui/messages/commands.js';
12
+ import { EXIT_CODES } from '../utils/exitCodes.js';
13
+ /**
14
+ * Register the `css` command group.
15
+ *
16
+ * @param program - Root command
17
+ */
18
+ export function registerCssCommands(program) {
19
+ const css = program.command('css').description("The page's stylesheets: search <text>");
20
+ css
21
+ .command('search')
22
+ .description('Find text in every stylesheet of the page (cross-origin ones too), with the rule and file:line')
23
+ .argument('<text>', 'Text to find (case-insensitive), e.g. oklch( or .btn-primary; put -- before one that starts with - (-- --brand)')
24
+ .option('--limit <n>', 'Matches listed (default: 20)', integerOption(1, 500))
25
+ .addOption(jsonOption())
26
+ .addHelpText('after', CSS_SEARCH_HELP_EXAMPLES)
27
+ .action(async (text, options) => {
28
+ await runCommand(() => search(text, options), options, formatCssSearch);
29
+ });
30
+ }
31
+ /**
32
+ * Ask the daemon to search the stylesheets.
33
+ *
34
+ * @param text - Text to find
35
+ * @param options - Limit
36
+ * @returns Command result
37
+ */
38
+ async function search(text, options) {
39
+ const response = await cssSearch({
40
+ query: text,
41
+ ...(options.limit !== undefined && { limit: options.limit }),
42
+ });
43
+ if (response.status === 'error' || !response.data) {
44
+ return {
45
+ success: false,
46
+ error: response.error ?? 'Failed to search the stylesheets',
47
+ exitCode: response.exitCode ?? EXIT_CODES.CDP_CONNECTION_FAILURE,
48
+ ...(response.suggestion && { errorContext: { suggestion: response.suggestion } }),
49
+ };
50
+ }
51
+ return { success: true, data: response.data };
52
+ }
53
+ //# sourceMappingURL=css.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `bdg dom audit [check...]` - page-wide checks without a screenshot or
3
+ * `dom eval`: text below a WCAG contrast level, what makes the page scroll
4
+ * sideways and cut-off text and scaled images, fixed and sticky layers, and
5
+ * running animations.
6
+ */
7
+ import type { Command } from 'commander';
8
+ /**
9
+ * Register `bdg dom audit`.
10
+ *
11
+ * @param dom - The `dom` command group
12
+ */
13
+ export declare function registerAuditCommand(dom: Command): void;
14
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1,87 @@
1
+ /**
2
+ * `bdg dom audit [check...]` - page-wide checks without a screenshot or
3
+ * `dom eval`: text below a WCAG contrast level, what makes the page scroll
4
+ * sideways and cut-off text and scaled images, fixed and sticky layers, and
5
+ * running animations.
6
+ */
7
+ import { InvalidArgumentError } from 'commander';
8
+ import { runCommand } from '../shared/CommandRunner.js';
9
+ import { jsonOption } from '../shared/commonOptions.js';
10
+ import { integerOption } from '../shared/validation.js';
11
+ import { unknownAuditCheckMessage } from '../../errors/messages.js';
12
+ import { domAudit } from '../../ipc/client.js';
13
+ import { AUDIT_CHECKS } from '../../ipc/protocol/auditTypes.js';
14
+ import { formatAudit } from '../../ui/formatters/audit.js';
15
+ import { AUDIT_HELP_EXAMPLES } from '../../ui/messages/commands.js';
16
+ import { EXIT_CODES } from '../../utils/exitCodes.js';
17
+ import { findSimilar } from '../../utils/suggestions.js';
18
+ /**
19
+ * Register `bdg dom audit`.
20
+ *
21
+ * @param dom - The `dom` command group
22
+ */
23
+ export function registerAuditCommand(dom) {
24
+ dom
25
+ .command('audit')
26
+ .description('Page-wide checks: text below WCAG contrast, sideways scroll and cut-off text, scaled images, fixed/sticky layers, animations')
27
+ .argument('[checks...]', `Checks to run: ${AUDIT_CHECKS.join(', ')} (default: all)`, checkList)
28
+ .option('--level <level>', 'WCAG level text must reach: AA or AAA (default: AA)', levelOption)
29
+ .option('--limit <n>', 'Findings listed per check (default: 20)', integerOption(1, 500))
30
+ .addOption(jsonOption())
31
+ .addHelpText('after', AUDIT_HELP_EXAMPLES)
32
+ .action(async (checks, options) => {
33
+ await runCommand(() => audit(checks, options), options, formatAudit);
34
+ });
35
+ }
36
+ /**
37
+ * Parse the checks, rejecting unknown names with the closest one.
38
+ *
39
+ * @param value - One check name
40
+ * @param previous - Checks so far
41
+ * @returns Checks
42
+ * @throws InvalidArgumentError for an unknown name
43
+ */
44
+ function checkList(value, previous = []) {
45
+ const check = AUDIT_CHECKS.find((name) => name === value.trim().toLowerCase());
46
+ if (!check) {
47
+ throw new InvalidArgumentError(unknownAuditCheckMessage(value, findSimilar(value, [...AUDIT_CHECKS]), AUDIT_CHECKS));
48
+ }
49
+ return previous.includes(check) ? previous : [...previous, check];
50
+ }
51
+ /**
52
+ * Parse `--level`.
53
+ *
54
+ * @param value - Level
55
+ * @returns AA or AAA
56
+ * @throws InvalidArgumentError for another value
57
+ */
58
+ function levelOption(value) {
59
+ const level = value.trim().toUpperCase();
60
+ if (level === 'AA' || level === 'AAA')
61
+ return level;
62
+ throw new InvalidArgumentError('Use AA or AAA');
63
+ }
64
+ /**
65
+ * Ask the daemon to audit the page.
66
+ *
67
+ * @param checks - Checks given (all when none)
68
+ * @param options - Level and limit
69
+ * @returns Command result
70
+ */
71
+ async function audit(checks, options) {
72
+ const response = await domAudit({
73
+ checks: checks && checks.length > 0 ? checks : [...AUDIT_CHECKS],
74
+ ...(options.level && { level: options.level }),
75
+ ...(options.limit !== undefined && { limit: options.limit }),
76
+ });
77
+ if (response.status === 'error' || !response.data) {
78
+ return {
79
+ success: false,
80
+ error: response.error ?? 'Failed to audit the page',
81
+ exitCode: response.exitCode ?? EXIT_CODES.CDP_CONNECTION_FAILURE,
82
+ ...(response.suggestion && { errorContext: { suggestion: response.suggestion } }),
83
+ };
84
+ }
85
+ return { success: true, data: response.data };
86
+ }
87
+ //# sourceMappingURL=audit.js.map
@@ -12,12 +12,12 @@ import { runCommand } from '../shared/CommandRunner.js';
12
12
  import { jsonOption, SELECTOR_OR_INDEX_ARGUMENT } from '../shared/commonOptions.js';
13
13
  import { integerOption } from '../shared/validation.js';
14
14
  import { CommandError } from '../../errors/index.js';
15
- import { VIA_LABEL_SUFFIX, conflictingOptionsMessage, indexSourceText, internalError, scrollOptionsError, } from '../../errors/messages.js';
16
- import { domClick, domFill, domPressKey, domScroll, domSubmit } from '../../ipc/client.js';
15
+ import { VIA_LABEL_SUFFIX, conflictingOptionsMessage, hoverOffWithTargetError, missingArgumentError, indexSourceText, internalError, scrollOptionsError, } from '../../errors/messages.js';
16
+ import { callCDP, domClick, domFill, domPressKey, domScroll, domSubmit } from '../../ipc/client.js';
17
17
  import { findUnknownModifiers } from '../../runtime/dom/keyMapping.js';
18
18
  import { formatTriggeredRequestLines, formatTriggeredRequestsTitle, } from '../../ui/formatters/triggeredRequests.js';
19
19
  import { OutputFormatter } from '../../ui/formatting.js';
20
- import { CLICK_RESULT_WAIT_HELP, POINTER_ACTION_DONE, POINTER_ACTION_NOUN, actionStatusLine, dialogConsoleText, newMessageText, pageNavigationText, shownElementText, stillChangingNote, } from '../../ui/messages/commands.js';
20
+ import { CLICK_RESULT_WAIT_HELP, HOVER_OFF_DONE, HOVER_USAGE, POINTER_ACTION_DONE, POINTER_ACTION_NOUN, actionStatusLine, dialogConsoleText, moreMessagesText, newMessageText, pageNavigationText, shownElementText, stillChangingNote, } from '../../ui/messages/commands.js';
21
21
  import { sessionCommand } from '../../ui/messages/sessionCommand.js';
22
22
  import { EXIT_CODES } from '../../utils/exitCodes.js';
23
23
  /** Help of `--strict` on click and hover */
@@ -96,13 +96,18 @@ export function registerFormInteractionCommands(program) {
96
96
  });
97
97
  domCommand
98
98
  .command('hover')
99
- .description('Move the mouse over an element (shows hover menus and tooltips)')
100
- .argument('<selectorOrIndex>', SELECTOR_OR_INDEX_ARGUMENT)
99
+ .description('Move the mouse over an element (shows hover menus and tooltips); --off moves it off the page')
100
+ .argument('[selectorOrIndex]', SELECTOR_OR_INDEX_ARGUMENT)
101
101
  .option('--index <n>', 'Element index if selector matches multiple (0-based)', integerOption(0))
102
+ .option('--off', 'Move the mouse off the page instead (closes menus that open on hover)')
102
103
  .option('--strict', STRICT_OPTION_HELP)
103
104
  .option('--no-wait', 'Skip waiting for network stability after hovering')
104
105
  .addOption(jsonOption())
105
106
  .action(async (selectorOrIndex, options) => {
107
+ if (options.off || selectorOrIndex === undefined) {
108
+ await hoverOff(selectorOrIndex, options);
109
+ return;
110
+ }
106
111
  await runPointerCommand(selectorOrIndex, options, 'hover');
107
112
  });
108
113
  domCommand
@@ -260,6 +265,28 @@ function scrollOptionsProblem(selector, options) {
260
265
  * @param options - Command options
261
266
  * @param action - Pointer action
262
267
  */
268
+ /**
269
+ * `bdg dom hover --off`: move the mouse off the page, so `mouseleave` and
270
+ * `:hover` end and menus that open on hover close.
271
+ *
272
+ * @param selectorOrIndex - Must be absent with --off
273
+ * @param options - Command options
274
+ */
275
+ async function hoverOff(selectorOrIndex, options) {
276
+ await runCommand(async () => {
277
+ if (!options.off || selectorOrIndex !== undefined || options.index !== undefined) {
278
+ const err = options.off ? hoverOffWithTargetError() : missingArgumentError(HOVER_USAGE);
279
+ return {
280
+ success: false,
281
+ error: err.message,
282
+ exitCode: EXIT_CODES.INVALID_ARGUMENTS,
283
+ errorContext: { suggestion: err.suggestion },
284
+ };
285
+ }
286
+ await callCDP('Input.dispatchMouseEvent', { type: 'mouseMoved', x: -1, y: -1 });
287
+ return { success: true, data: { pointer: 'off' } };
288
+ }, options, () => HOVER_OFF_DONE);
289
+ }
263
290
  async function runPointerCommand(selectorOrIndex, options, action) {
264
291
  await runCommand(() => options.double && options.right
265
292
  ? Promise.resolve({
@@ -316,7 +343,10 @@ function formatActionOutput(done, details, result, options = {}) {
316
343
  fmt.keyValueList(details, keyWidth);
317
344
  if (result.navigation)
318
345
  fmt.keyValue('Page', pageNavigationText(result.navigation), keyWidth);
319
- listRows(fmt, 'New text', (result.messages ?? []).map(newMessageText), keyWidth);
346
+ listRows(fmt, 'New text', [
347
+ ...(result.messages ?? []).map(newMessageText),
348
+ ...(result.moreMessages ? [moreMessagesText(result.moreMessages)] : []),
349
+ ], keyWidth);
320
350
  listRows(fmt, 'Shown', (result.shown ?? []).map(shownElementText), keyWidth);
321
351
  const omitted = result.triggeredRequestsOmitted;
322
352
  const requests = formatTriggeredRequestLines(result.triggeredRequests ?? [], omitted);
@@ -5,8 +5,9 @@
5
5
  */
6
6
  import type { ElementState, KeyAttributes } from '../../../types.js';
7
7
  /**
8
- * The key attributes of an element: the identifying attributes of its type
9
- * that are set (empty ones left out) and the live state of a form control
8
+ * The key attributes of an element: its shadow `part` name (how a page's CSS
9
+ * reaches it with `::part()`), the identifying attributes of its type that
10
+ * are set (empty ones left out) and the live state of a form control
10
11
  * (type, current value, checked, selected options). Values arrive masked
11
12
  * from the page (`ELEMENT_STATE_JS`); a hidden input's value is never read,
12
13
  * and a sensitive field's value is masked here again in case it was not.
@@ -16,8 +16,9 @@ const ATTRIBUTES_BY_TAG = {
16
16
  form: ['action', 'method'],
17
17
  };
18
18
  /**
19
- * The key attributes of an element: the identifying attributes of its type
20
- * that are set (empty ones left out) and the live state of a form control
19
+ * The key attributes of an element: its shadow `part` name (how a page's CSS
20
+ * reaches it with `::part()`), the identifying attributes of its type that
21
+ * are set (empty ones left out) and the live state of a form control
21
22
  * (type, current value, checked, selected options). Values arrive masked
22
23
  * from the page (`ELEMENT_STATE_JS`); a hidden input's value is never read,
23
24
  * and a sensitive field's value is masked here again in case it was not.
@@ -29,9 +30,10 @@ const ATTRIBUTES_BY_TAG = {
29
30
  */
30
31
  export function keyAttributes(tag, attributes, state = {}) {
31
32
  const names = ATTRIBUTES_BY_TAG[tag];
33
+ const part = attributes['part'];
32
34
  if (!names)
33
- return undefined;
34
- const result = {};
35
+ return part ? { part } : undefined;
36
+ const result = part ? { part } : {};
35
37
  const type = state.type ?? attributes['type'];
36
38
  if (type)
37
39
  result['type'] = type;
@@ -29,5 +29,6 @@ export declare function captureElementScreenshot(outputPath: string, ref: NodeRe
29
29
  format?: 'png' | 'jpeg';
30
30
  quality?: number;
31
31
  noResize?: boolean;
32
+ padding?: number;
32
33
  }): Promise<ScreenshotResult>;
33
34
  //# sourceMappingURL=screenshot.d.ts.map