browser-debugger-cli 0.6.6 → 0.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -269
- package/dist/commands/__tests__/console.contract.test.d.ts +9 -0
- package/dist/commands/__tests__/console.contract.test.d.ts.map +1 -0
- package/dist/commands/__tests__/console.contract.test.js +118 -0
- package/dist/commands/__tests__/console.contract.test.js.map +1 -0
- package/dist/commands/__tests__/helpJson.contract.test.d.ts +12 -0
- package/dist/commands/__tests__/helpJson.contract.test.d.ts.map +1 -0
- package/dist/commands/__tests__/helpJson.contract.test.js +121 -0
- package/dist/commands/__tests__/helpJson.contract.test.js.map +1 -0
- package/dist/commands/__tests__/machineReadableHelp.contract.test.js +26 -7
- package/dist/commands/__tests__/machineReadableHelp.contract.test.js.map +1 -1
- package/dist/commands/cdp.d.ts.map +1 -1
- package/dist/commands/cdp.js.map +1 -1
- package/dist/commands/cleanup.d.ts.map +1 -1
- package/dist/commands/cleanup.js +17 -91
- package/dist/commands/cleanup.js.map +1 -1
- package/dist/commands/console.d.ts +17 -0
- package/dist/commands/console.d.ts.map +1 -1
- package/dist/commands/console.js +158 -56
- package/dist/commands/console.js.map +1 -1
- package/dist/commands/details.d.ts.map +1 -1
- package/dist/commands/details.js +3 -1
- package/dist/commands/details.js.map +1 -1
- package/dist/commands/dom/DomElementResolver.d.ts +138 -0
- package/dist/commands/dom/DomElementResolver.d.ts.map +1 -0
- package/dist/commands/dom/DomElementResolver.js +173 -0
- package/dist/commands/dom/DomElementResolver.js.map +1 -0
- package/dist/commands/dom/a11y.d.ts.map +1 -1
- package/dist/commands/dom/a11y.js +4 -28
- package/dist/commands/dom/a11y.js.map +1 -1
- package/dist/commands/dom/evalHelpers.d.ts.map +1 -1
- package/dist/commands/dom/evalHelpers.js +1 -1
- package/dist/commands/dom/evalHelpers.js.map +1 -1
- package/dist/commands/dom/formFillHelpers.d.ts.map +1 -1
- package/dist/commands/dom/formFillHelpers.js +11 -11
- package/dist/commands/dom/formFillHelpers.js.map +1 -1
- package/dist/commands/dom/formInteraction.d.ts.map +1 -1
- package/dist/commands/dom/formInteraction.js +5 -5
- package/dist/commands/dom/formInteraction.js.map +1 -1
- package/dist/commands/dom/helpers.d.ts +0 -50
- package/dist/commands/dom/helpers.d.ts.map +1 -1
- package/dist/commands/dom/helpers.js +2 -56
- package/dist/commands/dom/helpers.js.map +1 -1
- package/dist/commands/dom/index.d.ts.map +1 -1
- package/dist/commands/dom/index.js +50 -44
- package/dist/commands/dom/index.js.map +1 -1
- package/dist/commands/dom/keyMapping.d.ts +0 -6
- package/dist/commands/dom/keyMapping.d.ts.map +1 -1
- package/dist/commands/dom/keyMapping.js +0 -8
- package/dist/commands/dom/keyMapping.js.map +1 -1
- package/dist/commands/dom/reactEventHelpers.d.ts +12 -18
- package/dist/commands/dom/reactEventHelpers.d.ts.map +1 -1
- package/dist/commands/dom/reactEventHelpers.js +21 -70
- package/dist/commands/dom/reactEventHelpers.js.map +1 -1
- package/dist/commands/helpJson.d.ts +165 -0
- package/dist/commands/helpJson.d.ts.map +1 -0
- package/dist/commands/helpJson.js +252 -0
- package/dist/commands/helpJson.js.map +1 -0
- package/dist/commands/machineReadableHelp.d.ts +21 -2
- package/dist/commands/machineReadableHelp.d.ts.map +1 -1
- package/dist/commands/machineReadableHelp.js +95 -60
- package/dist/commands/machineReadableHelp.js.map +1 -1
- package/dist/commands/network.d.ts.map +1 -1
- package/dist/commands/network.js.map +1 -1
- package/dist/commands/peek.d.ts.map +1 -1
- package/dist/commands/peek.js +5 -7
- package/dist/commands/peek.js.map +1 -1
- package/dist/commands/shared/CommandRunner.d.ts +4 -10
- package/dist/commands/shared/CommandRunner.d.ts.map +1 -1
- package/dist/commands/shared/CommandRunner.js +2 -2
- package/dist/commands/shared/CommandRunner.js.map +1 -1
- package/dist/commands/shared/commonOptions.d.ts +0 -15
- package/dist/commands/shared/commonOptions.d.ts.map +1 -1
- package/dist/commands/shared/commonOptions.js +0 -32
- package/dist/commands/shared/commonOptions.js.map +1 -1
- package/dist/commands/shared/optionTypes.d.ts +247 -0
- package/dist/commands/shared/optionTypes.d.ts.map +1 -0
- package/dist/commands/shared/optionTypes.js +20 -0
- package/dist/commands/shared/optionTypes.js.map +1 -0
- package/dist/commands/shared/startHelpers.d.ts.map +1 -1
- package/dist/commands/shared/startHelpers.js +3 -3
- package/dist/commands/shared/startHelpers.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +8 -6
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/stop.d.ts.map +1 -1
- package/dist/commands/stop.js +17 -43
- package/dist/commands/stop.js.map +1 -1
- package/dist/commands/tail.d.ts.map +1 -1
- package/dist/commands/tail.js +49 -59
- package/dist/commands/tail.js.map +1 -1
- package/dist/connection/types.d.ts +2 -1
- package/dist/connection/types.d.ts.map +1 -1
- package/dist/constants.d.ts +14 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +39 -0
- package/dist/constants.js.map +1 -1
- package/dist/daemon/handlers/responseHandler.d.ts.map +1 -1
- package/dist/daemon/handlers/responseHandler.js +1 -0
- package/dist/daemon/handlers/responseHandler.js.map +1 -1
- package/dist/daemon/ipcServer.js +8 -8
- package/dist/daemon/ipcServer.js.map +1 -1
- package/dist/daemon/lifecycle/signalHandlers.d.ts.map +1 -1
- package/dist/daemon/lifecycle/signalHandlers.js +19 -3
- package/dist/daemon/lifecycle/signalHandlers.js.map +1 -1
- package/dist/daemon/lifecycle/workerCleanup.d.ts.map +1 -1
- package/dist/daemon/lifecycle/workerCleanup.js +5 -2
- package/dist/daemon/lifecycle/workerCleanup.js.map +1 -1
- package/dist/daemon/patternDefinitions.d.ts +0 -13
- package/dist/daemon/patternDefinitions.d.ts.map +1 -1
- package/dist/daemon/patternDefinitions.js +0 -17
- package/dist/daemon/patternDefinitions.js.map +1 -1
- package/dist/daemon/worker/commandRegistry.d.ts.map +1 -1
- package/dist/daemon/worker/commandRegistry.js +3 -0
- package/dist/daemon/worker/commandRegistry.js.map +1 -1
- package/dist/index.js +34 -2
- package/dist/index.js.map +1 -1
- package/dist/ipc/protocol/commands.d.ts +2 -0
- package/dist/ipc/protocol/commands.d.ts.map +1 -1
- package/dist/ipc/protocol/commands.js.map +1 -1
- package/dist/ipc/session/queries.d.ts +2 -0
- package/dist/ipc/session/queries.d.ts.map +1 -1
- package/dist/ipc/utils/responseValidator.d.ts +7 -1
- package/dist/ipc/utils/responseValidator.d.ts.map +1 -1
- package/dist/ipc/utils/responseValidator.js +6 -1
- package/dist/ipc/utils/responseValidator.js.map +1 -1
- package/dist/session/QueryCacheManager.d.ts +140 -0
- package/dist/session/QueryCacheManager.d.ts.map +1 -0
- package/dist/session/QueryCacheManager.js +233 -0
- package/dist/session/QueryCacheManager.js.map +1 -0
- package/dist/session/cleanup.d.ts +63 -1
- package/dist/session/cleanup.d.ts.map +1 -1
- package/dist/session/cleanup.js +191 -65
- package/dist/session/cleanup.js.map +1 -1
- package/dist/session/queryCache.d.ts +25 -14
- package/dist/session/queryCache.d.ts.map +1 -1
- package/dist/session/queryCache.js +31 -60
- package/dist/session/queryCache.js.map +1 -1
- package/dist/telemetry/__tests__/roleInference.unit.test.d.ts +9 -0
- package/dist/telemetry/__tests__/roleInference.unit.test.d.ts.map +1 -0
- package/dist/telemetry/__tests__/roleInference.unit.test.js +138 -0
- package/dist/telemetry/__tests__/roleInference.unit.test.js.map +1 -0
- package/dist/telemetry/console.d.ts.map +1 -1
- package/dist/telemetry/console.js +29 -17
- package/dist/telemetry/console.js.map +1 -1
- package/dist/telemetry/dom.d.ts +1 -0
- package/dist/telemetry/dom.d.ts.map +1 -1
- package/dist/telemetry/dom.js +9 -4
- package/dist/telemetry/dom.js.map +1 -1
- package/dist/telemetry/filters.d.ts +3 -0
- package/dist/telemetry/filters.d.ts.map +1 -1
- package/dist/telemetry/filters.js +25 -3
- package/dist/telemetry/filters.js.map +1 -1
- package/dist/telemetry/network.d.ts.map +1 -1
- package/dist/telemetry/network.js +35 -6
- package/dist/telemetry/network.js.map +1 -1
- package/dist/telemetry/remoteObject.d.ts +58 -0
- package/dist/telemetry/remoteObject.d.ts.map +1 -0
- package/dist/telemetry/remoteObject.js +134 -0
- package/dist/telemetry/remoteObject.js.map +1 -0
- package/dist/telemetry/roleInference.d.ts +50 -0
- package/dist/telemetry/roleInference.d.ts.map +1 -0
- package/dist/telemetry/roleInference.js +163 -0
- package/dist/telemetry/roleInference.js.map +1 -0
- package/dist/telemetry/utils.d.ts +0 -57
- package/dist/telemetry/utils.d.ts.map +1 -1
- package/dist/telemetry/utils.js +0 -71
- package/dist/telemetry/utils.js.map +1 -1
- package/dist/types/dom.d.ts +2 -0
- package/dist/types/dom.d.ts.map +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/formatters/a11y.d.ts +0 -9
- package/dist/ui/formatters/a11y.d.ts.map +1 -1
- package/dist/ui/formatters/a11y.js +0 -45
- package/dist/ui/formatters/a11y.js.map +1 -1
- package/dist/ui/formatters/console.d.ts +131 -0
- package/dist/ui/formatters/console.d.ts.map +1 -0
- package/dist/ui/formatters/console.js +400 -0
- package/dist/ui/formatters/console.js.map +1 -0
- package/dist/ui/formatters/preview.d.ts.map +1 -1
- package/dist/ui/formatters/preview.js +2 -39
- package/dist/ui/formatters/preview.js.map +1 -1
- package/dist/ui/logging/index.d.ts +1 -1
- package/dist/ui/logging/index.d.ts.map +1 -1
- package/dist/ui/logging/index.js +1 -1
- package/dist/ui/logging/index.js.map +1 -1
- package/dist/ui/logging/logger.d.ts +21 -0
- package/dist/ui/logging/logger.d.ts.map +1 -1
- package/dist/ui/logging/logger.js +24 -6
- package/dist/ui/logging/logger.js.map +1 -1
- package/dist/ui/messages/commands.d.ts +0 -14
- package/dist/ui/messages/commands.d.ts.map +1 -1
- package/dist/ui/messages/commands.js +0 -18
- package/dist/ui/messages/commands.js.map +1 -1
- package/dist/ui/messages/consoleMessages.d.ts +12 -27
- package/dist/ui/messages/consoleMessages.d.ts.map +1 -1
- package/dist/ui/messages/consoleMessages.js +16 -31
- package/dist/ui/messages/consoleMessages.js.map +1 -1
- package/dist/ui/messages/errors.d.ts +0 -16
- package/dist/ui/messages/errors.d.ts.map +1 -1
- package/dist/ui/messages/errors.js +0 -18
- package/dist/ui/messages/errors.js.map +1 -1
- package/dist/ui/messages/hints.d.ts +0 -10
- package/dist/ui/messages/hints.d.ts.map +1 -1
- package/dist/ui/messages/hints.js +0 -12
- package/dist/ui/messages/hints.js.map +1 -1
- package/dist/utils/decisionTrees.d.ts +0 -17
- package/dist/utils/decisionTrees.d.ts.map +1 -1
- package/dist/utils/decisionTrees.js +17 -23
- package/dist/utils/decisionTrees.js.map +1 -1
- package/dist/utils/errorMapping.d.ts +60 -0
- package/dist/utils/errorMapping.d.ts.map +1 -0
- package/dist/utils/errorMapping.js +97 -0
- package/dist/utils/errorMapping.js.map +1 -0
- package/dist/utils/file.d.ts +27 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +37 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/levenshtein.d.ts +0 -17
- package/dist/utils/levenshtein.d.ts.map +1 -1
- package/dist/utils/levenshtein.js +0 -31
- package/dist/utils/levenshtein.js.map +1 -1
- package/dist/utils/strings.d.ts +14 -0
- package/dist/utils/strings.d.ts.map +1 -0
- package/dist/utils/strings.js +23 -0
- package/dist/utils/strings.js.map +1 -0
- package/dist/utils/taskMappings.d.ts +0 -17
- package/dist/utils/taskMappings.d.ts.map +1 -1
- package/dist/utils/taskMappings.js +18 -24
- package/dist/utils/taskMappings.js.map +1 -1
- package/dist/utils/typeGuards.d.ts +62 -0
- package/dist/utils/typeGuards.d.ts.map +1 -0
- package/dist/utils/typeGuards.js +94 -0
- package/dist/utils/typeGuards.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,307 +5,86 @@
|
|
|
5
5
|
[](https://github.com/szymdzum/browser-debugger-cli/actions/workflows/security.yml)
|
|
6
6
|
[](https://www.npmjs.com/package/browser-debugger-cli)
|
|
7
7
|
|
|
8
|
-
Chrome DevTools Protocol in your terminal.
|
|
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.
|
|
9
9
|
|
|
10
|
-
## Why
|
|
11
|
-
Puppeteer is great but heavy. CDP is powerful but raw. This tool sits in between: direct protocol access with session management and a few helpful wrappers. No abstractions hiding what's actually happening.
|
|
12
|
-
Built for debugging web apps and scripting browser automation without spinning up a full testing framework.
|
|
10
|
+
## Why bdg?
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
- **Raw CDP access** - All [644 protocol methods](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
|
|
15
16
|
|
|
16
|
-
**
|
|
17
|
+
**When to use alternatives:**
|
|
18
|
+
- **Puppeteer/Playwright**: Complex multi-step scripts, mature testing ecosystem
|
|
19
|
+
- **Chrome DevTools MCP**: Already invested in MCP infrastructure
|
|
17
20
|
|
|
18
|
-
**
|
|
21
|
+
**Built for agents:** Self-discovery (`--list`, `--search`), semantic exit codes, structured errors, case-insensitive commands, token-efficient output.
|
|
19
22
|
|
|
20
|
-
##
|
|
23
|
+
## Install
|
|
21
24
|
|
|
22
25
|
```bash
|
|
23
26
|
npm install -g browser-debugger-cli@alpha
|
|
24
27
|
```
|
|
25
28
|
|
|
26
29
|
**Platform Support:**
|
|
27
|
-
- ✅ macOS and Linux
|
|
28
|
-
- ✅ Windows via WSL
|
|
29
|
-
- ❌ PowerShell
|
|
30
|
-
|
|
31
|
-
The CLI uses Unix domain sockets for inter-process communication. Windows users should run bdg inside WSL for full compatibility.
|
|
30
|
+
- ✅ macOS and Linux
|
|
31
|
+
- ✅ Windows via WSL
|
|
32
|
+
- ❌ PowerShell/Git Bash (not yet)
|
|
32
33
|
|
|
33
34
|
## Quick Start
|
|
34
35
|
|
|
35
36
|
```bash
|
|
36
|
-
# Start
|
|
37
|
-
bdg
|
|
38
|
-
|
|
39
|
-
#
|
|
40
|
-
bdg
|
|
41
|
-
bdg cdp Network --list # List Network methods
|
|
42
|
-
bdg cdp --search cookie # Search by keyword
|
|
43
|
-
|
|
44
|
-
# Run any CDP command
|
|
45
|
-
bdg cdp Network.getCookies
|
|
46
|
-
bdg cdp Runtime.evaluate --params '{"expression":"document.title","returnByValue":true}'
|
|
47
|
-
|
|
48
|
-
# Check what's running
|
|
49
|
-
bdg status
|
|
50
|
-
|
|
51
|
-
# Done
|
|
52
|
-
bdg stop
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## What You Can Do
|
|
56
|
-
|
|
57
|
-
### Discover CDP Commands (53 Domains, 300+ Methods)
|
|
58
|
-
|
|
59
|
-
Built-in introspection helps you find what you need without reading docs:
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
# What can I do with this browser?
|
|
63
|
-
bdg cdp --list
|
|
64
|
-
# Returns: 53 domains (Network, DOM, Page, Runtime, Storage, etc.)
|
|
65
|
-
|
|
66
|
-
# What Network operations exist?
|
|
67
|
-
bdg cdp Network --list
|
|
68
|
-
# Returns: 39 methods with descriptions and parameter counts
|
|
69
|
-
|
|
70
|
-
# How do I use this method?
|
|
71
|
-
bdg cdp Network.getCookies --describe
|
|
72
|
-
# Returns: Full schema with parameters, types, examples
|
|
73
|
-
|
|
74
|
-
# Find cookie-related methods
|
|
75
|
-
bdg cdp --search cookie
|
|
76
|
-
# Returns: 14 methods across domains (Network.getCookies, Storage.getCookies, etc.)
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
All discovery commands output JSON for easy parsing. Perfect for AI agents building automation on the fly.
|
|
80
|
-
|
|
81
|
-
### Run Any CDP Command
|
|
82
|
-
|
|
83
|
-
All 300+ methods from [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) work out of the box:
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
# Get cookies and filter with jq
|
|
87
|
-
bdg cdp Network.getCookies | jq '.cookies[] | select(.httpOnly)'
|
|
88
|
-
|
|
89
|
-
# Execute JavaScript in the page
|
|
90
|
-
bdg cdp Runtime.evaluate --params '{"expression":"document.querySelectorAll(\"a\").length","returnByValue":true}'
|
|
91
|
-
|
|
92
|
-
# Monitor memory usage
|
|
93
|
-
bdg cdp Performance.getMetrics | jq '.metrics[] | select(.name == "JSHeapUsedSize")'
|
|
94
|
-
|
|
95
|
-
# Capture a screenshot
|
|
96
|
-
bdg cdp Page.captureScreenshot | jq -r '.data' | base64 -d > screenshot.png
|
|
37
|
+
bdg example.com # Start session
|
|
38
|
+
bdg cdp --search cookie # Discover commands
|
|
39
|
+
bdg cdp Network.getCookies # Run any CDP method
|
|
40
|
+
bdg dom query "button" # High-level helpers
|
|
41
|
+
bdg stop # End session
|
|
97
42
|
```
|
|
98
43
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
### Pipe Everything
|
|
102
|
-
|
|
103
|
-
Output is JSON by default. Use it with `jq`, `grep`, `awk` - whatever works:
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
# Find all failed network requests
|
|
107
|
-
bdg peek --network --json | jq '.data.network[] | select(.status >= 400)'
|
|
108
|
-
|
|
109
|
-
# Extract every link on the page
|
|
110
|
-
bdg cdp Runtime.evaluate --params '{
|
|
111
|
-
"expression": "Array.from(document.querySelectorAll(\"a\")).map(a => ({text: a.textContent.trim(), href: a.href}))",
|
|
112
|
-
"returnByValue": true
|
|
113
|
-
}' | jq '.result.value'
|
|
114
|
-
|
|
115
|
-
# Count console errors
|
|
116
|
-
bdg peek --console --json | jq '[.data.console[] | select(.level == "error")] | length'
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### For AI Agents
|
|
120
|
-
|
|
121
|
-
**Self-documenting CDP discovery** - agents can explore 300+ browser capabilities without external docs:
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
# Agent discovers what's possible
|
|
125
|
-
bdg cdp --list # 53 domains available
|
|
126
|
-
bdg cdp --search screenshot # Find relevant methods
|
|
127
|
-
bdg cdp Page.captureScreenshot --describe # Learn parameters
|
|
128
|
-
bdg cdp Page.captureScreenshot --params '{"format":"png"}' # Execute
|
|
129
|
-
|
|
130
|
-
# All commands return structured JSON for easy parsing
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
**Why this matters for agents:**
|
|
134
|
-
- No need to memorize CDP docs (1000+ pages)
|
|
135
|
-
- Discover → Learn → Execute in one tool
|
|
136
|
-
- Search by keyword (`--search`)
|
|
137
|
-
- Case-insensitive execution (forgiving for LLM outputs)
|
|
138
|
-
- Semantic exit codes for error handling
|
|
139
|
-
|
|
140
|
-
Claude skill included at `.claude/skills/bdg/` with working automation patterns:
|
|
141
|
-
|
|
142
|
-
- Common CDP workflows (scraping, polling, navigation)
|
|
143
|
-
- Exit codes and error handling
|
|
144
|
-
- Troubleshooting reference
|
|
145
|
-
|
|
146
|
-
The `--help --json` flag outputs the complete CLI schema for programmatic discovery:
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
bdg --help --json | jq '.command.subcommands[].name'
|
|
150
|
-
bdg --help --json | jq '.exitCodes'
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Debug Live Apps
|
|
154
|
-
|
|
155
|
-
Point at localhost, monitor what's happening:
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
bdg localhost:3000 --headless
|
|
159
|
-
bdg tail --console # Stream console output
|
|
160
|
-
bdg tail --network # Watch requests in real-time
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Helpful for catching issues during development without opening DevTools.
|
|
164
|
-
|
|
165
|
-
### Automate Browser Tasks
|
|
166
|
-
|
|
167
|
-
Poll for elements, click buttons, extract data:
|
|
168
|
-
|
|
169
|
-
```bash
|
|
170
|
-
# Wait for an element to appear
|
|
171
|
-
while ! bdg cdp Runtime.evaluate --params '{"expression":"document.querySelector(\"#target\") !== null","returnByValue":true}' | jq -e '.result.value'; do
|
|
172
|
-
sleep 0.5
|
|
173
|
-
done
|
|
174
|
-
|
|
175
|
-
# Click it
|
|
176
|
-
bdg cdp Runtime.evaluate --params '{"expression":"document.querySelector(\"#target\").click()"}'
|
|
177
|
-
|
|
178
|
-
# Get the result
|
|
179
|
-
bdg cdp Runtime.evaluate --params '{"expression":"document.querySelector(\".result\").textContent","returnByValue":true}'
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
Check `.claude/skills/bdg/WORKFLOWS.md` for more complete examples (GitHub scraper, form automation, etc).
|
|
183
|
-
|
|
184
|
-
## Session Management
|
|
185
|
-
|
|
186
|
-
Sessions persist until you stop them. Chrome stays open, data keeps collecting:
|
|
187
|
-
|
|
188
|
-
```bash
|
|
189
|
-
bdg example.com # Opens Chrome, starts daemon
|
|
190
|
-
bdg status # Check what's running
|
|
191
|
-
bdg status --verbose # Show Chrome process details
|
|
192
|
-
bdg stop # Kill everything
|
|
193
|
-
bdg cleanup # Remove stale files
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
## Helper Commands
|
|
197
|
-
|
|
198
|
-
A few convenience wrappers for common operations. Most work still happens through `bdg cdp`:
|
|
199
|
-
|
|
200
|
-
```bash
|
|
201
|
-
# Query DOM
|
|
202
|
-
bdg dom query "button.primary" # Find elements
|
|
203
|
-
bdg dom get "button.primary" # Get HTML
|
|
204
|
-
bdg dom eval "document.title" # Run JavaScript
|
|
205
|
-
bdg dom highlight ".navbar" # Visual debugging
|
|
206
|
-
|
|
207
|
-
# Accessibility inspection
|
|
208
|
-
bdg dom a11y tree # View full accessibility tree
|
|
209
|
-
bdg dom a11y query role=button # Find elements by ARIA role
|
|
210
|
-
bdg dom a11y describe "#login" # Get a11y info for element
|
|
211
|
-
|
|
212
|
-
# Inspect collected data
|
|
213
|
-
bdg peek # Quick snapshot (shows resource types)
|
|
214
|
-
bdg peek --network # Just network data
|
|
215
|
-
bdg peek --type Document # Filter by resource type
|
|
216
|
-
bdg peek --type XHR,Fetch # Multiple types (AJAX requests)
|
|
217
|
-
bdg tail # Stream like tail -f
|
|
218
|
-
|
|
219
|
-
# Export network data
|
|
220
|
-
bdg network har # Export as HAR 1.2 format
|
|
221
|
-
bdg network har myfile.har # Custom filename
|
|
222
|
-
```
|
|
44
|
+
## Current State
|
|
223
45
|
|
|
224
|
-
|
|
46
|
+
**Raw CDP access is complete.** All 644 protocol methods (53 domains) work now. High-level wrappers (`bdg dom`, `bdg network`) are being added for common operations. See [Commands](https://github.com/szymdzum/browser-debugger-cli/wiki/Commands) for full reference.
|
|
225
47
|
|
|
226
|
-
|
|
48
|
+
## Agent Discovery Pattern
|
|
227
49
|
|
|
228
50
|
```bash
|
|
229
|
-
#
|
|
230
|
-
bdg
|
|
231
|
-
bdg
|
|
232
|
-
bdg
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
#
|
|
238
|
-
bdg dom a11y tree # View first 50 nodes
|
|
239
|
-
bdg dom a11y tree --json # Complete tree in JSON
|
|
240
|
-
|
|
241
|
-
# Find unlabeled buttons
|
|
242
|
-
bdg dom a11y query role=button --json | jq '.nodes[] | select(.name == null)'
|
|
243
|
-
|
|
244
|
-
# Verify form labels
|
|
245
|
-
bdg dom a11y query role=textbox --json | jq '.nodes[] | {id: .nodeId, label: .name}'
|
|
246
|
-
|
|
247
|
-
# Check landmark structure
|
|
248
|
-
bdg dom a11y query role=main --json | jq '.count' # Should be 1
|
|
249
|
-
|
|
250
|
-
# Audit specific element
|
|
251
|
-
bdg dom a11y describe "button#submit" --json | jq '{role, name, focusable, disabled}'
|
|
51
|
+
# Agent explores what's possible (no docs needed)
|
|
52
|
+
bdg cdp --list # 53 domains
|
|
53
|
+
bdg cdp Network --list # 39 methods
|
|
54
|
+
bdg cdp Network.getCookies --describe # Full schema + examples
|
|
55
|
+
bdg cdp Network.getCookies # Execute
|
|
56
|
+
|
|
57
|
+
# Search across all domains
|
|
58
|
+
bdg cdp --search screenshot # Find relevant methods
|
|
59
|
+
bdg cdp --search cookie # 14 results
|
|
252
60
|
```
|
|
253
61
|
|
|
254
|
-
|
|
255
|
-
- Simple button: 82% reduction (41 chars vs 233 chars HTML)
|
|
256
|
-
- Search input: 85% reduction (42 chars vs 278 chars HTML)
|
|
257
|
-
- Navigation: 99.5% reduction (19 chars vs 4,218 chars HTML)
|
|
258
|
-
|
|
259
|
-
Use cases:
|
|
260
|
-
- **AI agents**: Massive token savings for LLM-based automation
|
|
261
|
-
- **Automated testing**: Verify all interactive elements have accessible names
|
|
262
|
-
- **CI/CD integration**: Catch accessibility regressions before deployment
|
|
263
|
-
- **Screen reader simulation**: See what assistive tech sees
|
|
264
|
-
- **ARIA validation**: Check landmark roles and ARIA attributes
|
|
265
|
-
|
|
266
|
-
## Page Readiness
|
|
267
|
-
|
|
268
|
-
By default, `bdg` waits for pages to fully load using three signals:
|
|
269
|
-
|
|
270
|
-
1. Browser's `window.onload` fires
|
|
271
|
-
2. Network goes quiet (200ms without new requests)
|
|
272
|
-
3. DOM stops changing (300ms without mutations)
|
|
273
|
-
|
|
274
|
-
Catches server-rendered HTML, client hydration, and lazy-loaded content. Works with Next.js, React, Vue, whatever. Times out after 5 seconds if something hangs.
|
|
275
|
-
|
|
276
|
-
Skip it with `--no-wait` if you want immediate connection.
|
|
277
|
-
|
|
278
|
-
## Architecture
|
|
279
|
-
|
|
280
|
-
Three processes:
|
|
62
|
+
## Documentation
|
|
281
63
|
|
|
282
|
-
|
|
283
|
-
- **Daemon** manages Chrome and routes commands
|
|
284
|
-
- **Worker** holds the WebSocket to CDP
|
|
64
|
+
📖 **[Wiki](https://github.com/szymdzum/browser-debugger-cli/wiki)** - Guides, command reference, recipes
|
|
285
65
|
|
|
286
|
-
|
|
66
|
+
- [Getting Started](https://github.com/szymdzum/browser-debugger-cli/wiki/Getting-Started)
|
|
67
|
+
- [Commands](https://github.com/szymdzum/browser-debugger-cli/wiki/Commands)
|
|
68
|
+
- [For AI Agents](https://github.com/szymdzum/browser-debugger-cli/wiki/For-AI-Agents)
|
|
69
|
+
- [Recipes](https://github.com/szymdzum/browser-debugger-cli/wiki/Recipes)
|
|
70
|
+
- [Quick Reference](https://github.com/szymdzum/browser-debugger-cli/wiki/Quick-Reference)
|
|
71
|
+
- [Architecture](https://github.com/szymdzum/browser-debugger-cli/wiki/Architecture)
|
|
72
|
+
- [Troubleshooting](https://github.com/szymdzum/browser-debugger-cli/wiki/Troubleshooting)
|
|
287
73
|
|
|
288
74
|
## Design Principles
|
|
289
75
|
|
|
290
|
-
This tool
|
|
291
|
-
|
|
292
|
-
**[Self-Documenting Systems](docs/principles/SELF_DOCUMENTING_SYSTEMS.md)** - Tools should teach agents how to use them through progressive discovery, not external documentation. The `--list`, `--describe`, and `--search` commands implement this philosophy.
|
|
76
|
+
This tool implements [Agent-Friendly Tools](docs/principles/AGENT_FRIENDLY_TOOLS.md):
|
|
293
77
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
## Documentation
|
|
299
|
-
|
|
300
|
-
- **[Roadmap](docs/roadmap/ROADMAP.md)** - Product vision, milestones, and priorities
|
|
301
|
-
- **[Implementation Status](docs/roadmap/IMPLEMENTATION_STATUS.md)** - Feature completion tracking
|
|
302
|
-
- **[CLI Reference](docs/CLI_REFERENCE.md)** - Complete command documentation
|
|
303
|
-
- **[Agent Guide](docs/principles/AGENT_FRIENDLY_TOOLS.md)** - Building tools for AI agents
|
|
304
|
-
- **[Self-Documenting Systems](docs/principles/SELF_DOCUMENTING_SYSTEMS.md)** - Design philosophy
|
|
78
|
+
- **Self-documenting** - Tools teach themselves via `--list`, `--describe`
|
|
79
|
+
- **Semantic exit codes** - Machine-parseable error handling
|
|
80
|
+
- **Structured output** - JSON by default, human-readable optional
|
|
81
|
+
- **Progressive disclosure** - Simple commands, deep capabilities
|
|
305
82
|
|
|
306
83
|
## Contributing
|
|
307
84
|
|
|
308
|
-
|
|
85
|
+
[Issues](https://github.com/szymdzum/browser-debugger-cli/issues) for bugs, [Discussions](https://github.com/szymdzum/browser-debugger-cli/discussions) for ideas. PRs welcome.
|
|
86
|
+
|
|
87
|
+
See `docs/` for architecture and contributor guides.
|
|
309
88
|
|
|
310
89
|
## License
|
|
311
90
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for console command navigation filtering.
|
|
3
|
+
*
|
|
4
|
+
* Tests the public behavior of filterByCurrentNavigation:
|
|
5
|
+
* - Given messages from multiple page loads, returns only current navigation
|
|
6
|
+
* - Handles edge cases (empty, single navigation, missing IDs)
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=console.contract.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.contract.test.d.ts","sourceRoot":"","sources":["../../../src/commands/__tests__/console.contract.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for console command navigation filtering.
|
|
3
|
+
*
|
|
4
|
+
* Tests the public behavior of filterByCurrentNavigation:
|
|
5
|
+
* - Given messages from multiple page loads, returns only current navigation
|
|
6
|
+
* - Handles edge cases (empty, single navigation, missing IDs)
|
|
7
|
+
*/
|
|
8
|
+
import assert from 'node:assert';
|
|
9
|
+
import { describe, test } from 'node:test';
|
|
10
|
+
import { filterByCurrentNavigation } from '../../commands/console.js';
|
|
11
|
+
/**
|
|
12
|
+
* Create a test console message with minimal required fields.
|
|
13
|
+
*/
|
|
14
|
+
function createMessage(text, navigationId, type = 'log') {
|
|
15
|
+
const msg = {
|
|
16
|
+
text,
|
|
17
|
+
type,
|
|
18
|
+
timestamp: Date.now(),
|
|
19
|
+
};
|
|
20
|
+
if (navigationId !== undefined) {
|
|
21
|
+
msg.navigationId = navigationId;
|
|
22
|
+
}
|
|
23
|
+
return msg;
|
|
24
|
+
}
|
|
25
|
+
describe('filterByCurrentNavigation contract', () => {
|
|
26
|
+
describe('filters to current (most recent) navigation', () => {
|
|
27
|
+
test('returns only messages from highest navigationId', () => {
|
|
28
|
+
const messages = [
|
|
29
|
+
createMessage('old error', 1),
|
|
30
|
+
createMessage('old warning', 1),
|
|
31
|
+
createMessage('current error', 2),
|
|
32
|
+
createMessage('current log', 2),
|
|
33
|
+
];
|
|
34
|
+
const result = filterByCurrentNavigation(messages);
|
|
35
|
+
assert.strictEqual(result.length, 2);
|
|
36
|
+
assert.ok(result.every((m) => m.navigationId === 2));
|
|
37
|
+
assert.ok(result.some((m) => m.text === 'current error'));
|
|
38
|
+
assert.ok(result.some((m) => m.text === 'current log'));
|
|
39
|
+
});
|
|
40
|
+
test('handles three navigations correctly', () => {
|
|
41
|
+
const messages = [
|
|
42
|
+
createMessage('nav1', 1),
|
|
43
|
+
createMessage('nav2', 2),
|
|
44
|
+
createMessage('nav3-a', 3),
|
|
45
|
+
createMessage('nav3-b', 3),
|
|
46
|
+
];
|
|
47
|
+
const result = filterByCurrentNavigation(messages);
|
|
48
|
+
assert.strictEqual(result.length, 2);
|
|
49
|
+
assert.ok(result.every((m) => m.navigationId === 3));
|
|
50
|
+
});
|
|
51
|
+
test('preserves message order within navigation', () => {
|
|
52
|
+
const messages = [
|
|
53
|
+
createMessage('first', 2),
|
|
54
|
+
createMessage('second', 2),
|
|
55
|
+
createMessage('third', 2),
|
|
56
|
+
];
|
|
57
|
+
const result = filterByCurrentNavigation(messages);
|
|
58
|
+
assert.strictEqual(result.length, 3);
|
|
59
|
+
assert.strictEqual(result.at(0)?.text, 'first');
|
|
60
|
+
assert.strictEqual(result.at(1)?.text, 'second');
|
|
61
|
+
assert.strictEqual(result.at(2)?.text, 'third');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('edge cases', () => {
|
|
65
|
+
test('returns empty array for empty input', () => {
|
|
66
|
+
const result = filterByCurrentNavigation([]);
|
|
67
|
+
assert.strictEqual(result.length, 0);
|
|
68
|
+
});
|
|
69
|
+
test('returns all messages when single navigation', () => {
|
|
70
|
+
const messages = [
|
|
71
|
+
createMessage('a', 1),
|
|
72
|
+
createMessage('b', 1),
|
|
73
|
+
createMessage('c', 1),
|
|
74
|
+
];
|
|
75
|
+
const result = filterByCurrentNavigation(messages);
|
|
76
|
+
assert.strictEqual(result.length, 3);
|
|
77
|
+
});
|
|
78
|
+
test('handles messages without navigationId', () => {
|
|
79
|
+
const messages = [
|
|
80
|
+
createMessage('no-nav', undefined),
|
|
81
|
+
createMessage('with-nav', 1),
|
|
82
|
+
];
|
|
83
|
+
const result = filterByCurrentNavigation(messages);
|
|
84
|
+
// Messages without navigationId should be excluded (navigationId !== maxId)
|
|
85
|
+
assert.strictEqual(result.length, 1);
|
|
86
|
+
assert.strictEqual(result.at(0)?.text, 'with-nav');
|
|
87
|
+
});
|
|
88
|
+
test('handles all messages without navigationId', () => {
|
|
89
|
+
const messages = [
|
|
90
|
+
createMessage('no-nav-1', undefined),
|
|
91
|
+
createMessage('no-nav-2', undefined),
|
|
92
|
+
];
|
|
93
|
+
const result = filterByCurrentNavigation(messages);
|
|
94
|
+
// All have navigationId=undefined, max of [0,0] = 0, filter where navId === 0
|
|
95
|
+
// Since undefined !== 0, returns empty
|
|
96
|
+
assert.strictEqual(result.length, 0);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe('message types preserved', () => {
|
|
100
|
+
test('preserves all console message types', () => {
|
|
101
|
+
const messages = [
|
|
102
|
+
createMessage('error msg', 1, 'error'),
|
|
103
|
+
createMessage('warning msg', 1, 'warning'),
|
|
104
|
+
createMessage('log msg', 1, 'log'),
|
|
105
|
+
createMessage('info msg', 1, 'info'),
|
|
106
|
+
createMessage('debug msg', 1, 'debug'),
|
|
107
|
+
];
|
|
108
|
+
const result = filterByCurrentNavigation(messages);
|
|
109
|
+
assert.strictEqual(result.length, 5);
|
|
110
|
+
assert.ok(result.some((m) => m.type === 'error'));
|
|
111
|
+
assert.ok(result.some((m) => m.type === 'warning'));
|
|
112
|
+
assert.ok(result.some((m) => m.type === 'log'));
|
|
113
|
+
assert.ok(result.some((m) => m.type === 'info'));
|
|
114
|
+
assert.ok(result.some((m) => m.type === 'debug'));
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=console.contract.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.contract.test.js","sourceRoot":"","sources":["../../../src/commands/__tests__/console.contract.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for machine-readable help generation.
|
|
3
|
+
*
|
|
4
|
+
* Tests the contract that dynamic capability counts match actual implementation:
|
|
5
|
+
* - CDP domain count matches protocol
|
|
6
|
+
* - CDP method count matches total across all domains
|
|
7
|
+
* - High-level command count matches task mappings
|
|
8
|
+
*
|
|
9
|
+
* These tests prevent drift between hardcoded values and reality.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=helpJson.contract.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpJson.contract.test.d.ts","sourceRoot":"","sources":["../../../src/commands/__tests__/helpJson.contract.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for machine-readable help generation.
|
|
3
|
+
*
|
|
4
|
+
* Tests the contract that dynamic capability counts match actual implementation:
|
|
5
|
+
* - CDP domain count matches protocol
|
|
6
|
+
* - CDP method count matches total across all domains
|
|
7
|
+
* - High-level command count matches task mappings
|
|
8
|
+
*
|
|
9
|
+
* These tests prevent drift between hardcoded values and reality.
|
|
10
|
+
*/
|
|
11
|
+
import assert from 'node:assert';
|
|
12
|
+
import { describe, test, beforeEach } from 'node:test';
|
|
13
|
+
import { Command } from 'commander';
|
|
14
|
+
import { getAllDomainSummaries } from '../../cdp/schema.js';
|
|
15
|
+
import { generateMachineReadableHelp } from '../../commands/helpJson.js';
|
|
16
|
+
import { getAllTaskMappings } from '../../utils/taskMappings.js';
|
|
17
|
+
describe('Machine-readable help capabilities', () => {
|
|
18
|
+
let program;
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
program = new Command();
|
|
21
|
+
program.name('bdg').version('0.0.0-test');
|
|
22
|
+
program.command('test').description('Test command');
|
|
23
|
+
});
|
|
24
|
+
describe('CDP capabilities', () => {
|
|
25
|
+
test('cdp.domains matches actual CDP domain count', () => {
|
|
26
|
+
const help = generateMachineReadableHelp(program);
|
|
27
|
+
const actualDomains = getAllDomainSummaries();
|
|
28
|
+
assert.strictEqual(help.capabilities.cdp.domains, actualDomains.length);
|
|
29
|
+
});
|
|
30
|
+
test('cdp.methods matches total CDP method count across all domains', () => {
|
|
31
|
+
const help = generateMachineReadableHelp(program);
|
|
32
|
+
const domainSummaries = getAllDomainSummaries();
|
|
33
|
+
const totalMethods = domainSummaries.reduce((sum, domain) => sum + domain.commandCount, 0);
|
|
34
|
+
assert.strictEqual(parseInt(help.capabilities.cdp.methods, 10), totalMethods);
|
|
35
|
+
});
|
|
36
|
+
test('cdp.methods is a valid numeric string', () => {
|
|
37
|
+
const help = generateMachineReadableHelp(program);
|
|
38
|
+
assert.strictEqual(typeof help.capabilities.cdp.methods, 'string');
|
|
39
|
+
assert.ok(parseInt(help.capabilities.cdp.methods, 10) > 0);
|
|
40
|
+
assert.strictEqual(isNaN(parseInt(help.capabilities.cdp.methods, 10)), false);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('high-level command capabilities', () => {
|
|
44
|
+
test('highLevel.commands contains all unique commands from task mappings', () => {
|
|
45
|
+
const help = generateMachineReadableHelp(program);
|
|
46
|
+
const taskMappings = getAllTaskMappings();
|
|
47
|
+
const expectedCommands = new Set(Object.values(taskMappings).flatMap((mapping) => mapping.commands));
|
|
48
|
+
assert.ok(Array.isArray(help.capabilities.highLevel.commands));
|
|
49
|
+
assert.strictEqual(help.capabilities.highLevel.commands.length, expectedCommands.size);
|
|
50
|
+
for (const cmd of expectedCommands) {
|
|
51
|
+
assert.ok(help.capabilities.highLevel.commands.includes(cmd), `Expected commands to include "${cmd}"`);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
test('highLevel.coverage includes expected domains', () => {
|
|
55
|
+
const help = generateMachineReadableHelp(program);
|
|
56
|
+
const expectedDomains = ['dom', 'network', 'console', 'session', 'monitoring'];
|
|
57
|
+
for (const domain of expectedDomains) {
|
|
58
|
+
assert.ok(help.capabilities.highLevel.coverage.includes(domain), `Expected coverage to include ${domain}`);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('capability counts are realistic', () => {
|
|
63
|
+
test('CDP domain count is greater than 50', () => {
|
|
64
|
+
const help = generateMachineReadableHelp(program);
|
|
65
|
+
assert.ok(help.capabilities.cdp.domains > 50);
|
|
66
|
+
});
|
|
67
|
+
test('CDP method count is greater than 600', () => {
|
|
68
|
+
const help = generateMachineReadableHelp(program);
|
|
69
|
+
const methodCount = parseInt(help.capabilities.cdp.methods, 10);
|
|
70
|
+
assert.ok(methodCount > 600);
|
|
71
|
+
});
|
|
72
|
+
test('high-level command list has more than 10 commands', () => {
|
|
73
|
+
const help = generateMachineReadableHelp(program);
|
|
74
|
+
assert.ok(help.capabilities.highLevel.commands.length > 10);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('dynamic calculation prevents drift', () => {
|
|
78
|
+
test('command list updates when task mappings change', () => {
|
|
79
|
+
const help = generateMachineReadableHelp(program);
|
|
80
|
+
const taskMappings = getAllTaskMappings();
|
|
81
|
+
const expectedCommands = new Set(Object.values(taskMappings).flatMap((mapping) => mapping.commands));
|
|
82
|
+
assert.strictEqual(help.capabilities.highLevel.commands.length, expectedCommands.size);
|
|
83
|
+
});
|
|
84
|
+
test('CDP counts change if protocol changes', () => {
|
|
85
|
+
const help = generateMachineReadableHelp(program);
|
|
86
|
+
const domainSummaries = getAllDomainSummaries();
|
|
87
|
+
const calculatedTotal = domainSummaries.reduce((sum, domain) => sum + domain.commandCount, 0);
|
|
88
|
+
const reportedTotal = parseInt(help.capabilities.cdp.methods, 10);
|
|
89
|
+
assert.strictEqual(reportedTotal, calculatedTotal);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('help structure includes capabilities', () => {
|
|
93
|
+
test('capabilities object exists in help output', () => {
|
|
94
|
+
const help = generateMachineReadableHelp(program);
|
|
95
|
+
assert.ok(help.capabilities);
|
|
96
|
+
assert.ok(help.capabilities.cdp);
|
|
97
|
+
assert.ok(help.capabilities.highLevel);
|
|
98
|
+
});
|
|
99
|
+
test('capabilities structure matches expected shape', () => {
|
|
100
|
+
const help = generateMachineReadableHelp(program);
|
|
101
|
+
assert.strictEqual(typeof help.capabilities.cdp.domains, 'number');
|
|
102
|
+
assert.strictEqual(typeof help.capabilities.cdp.methods, 'string');
|
|
103
|
+
assert.ok(Array.isArray(help.capabilities.highLevel.commands));
|
|
104
|
+
assert.ok(Array.isArray(help.capabilities.highLevel.coverage));
|
|
105
|
+
});
|
|
106
|
+
test('highLevel.commands contains only strings', () => {
|
|
107
|
+
const help = generateMachineReadableHelp(program);
|
|
108
|
+
for (const cmd of help.capabilities.highLevel.commands) {
|
|
109
|
+
assert.strictEqual(typeof cmd, 'string');
|
|
110
|
+
assert.ok(cmd.length > 0, 'Command should not be empty');
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
test('highLevel.commands is sorted alphabetically', () => {
|
|
114
|
+
const help = generateMachineReadableHelp(program);
|
|
115
|
+
const commands = help.capabilities.highLevel.commands;
|
|
116
|
+
const sorted = [...commands].sort();
|
|
117
|
+
assert.deepStrictEqual(commands, sorted);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
//# sourceMappingURL=helpJson.contract.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpJson.contract.test.js","sourceRoot":"","sources":["../../../src/commands/__tests__/helpJson.contract.test.ts"],"names":[],"mappings":"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"}
|