@romanmatena/browsermonitor 2.0.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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +558 -0
  3. package/package.json +53 -0
  4. package/src/agents.llm/browser-monitor-section.md +18 -0
  5. package/src/cli.mjs +202 -0
  6. package/src/http-server.mjs +536 -0
  7. package/src/init.mjs +162 -0
  8. package/src/intro.mjs +36 -0
  9. package/src/logging/LogBuffer.mjs +178 -0
  10. package/src/logging/constants.mjs +19 -0
  11. package/src/logging/dump.mjs +207 -0
  12. package/src/logging/index.mjs +13 -0
  13. package/src/logging/timestamps.mjs +13 -0
  14. package/src/monitor/README.md +10 -0
  15. package/src/monitor/index.mjs +18 -0
  16. package/src/monitor/interactive-mode.mjs +275 -0
  17. package/src/monitor/join-mode.mjs +654 -0
  18. package/src/monitor/open-mode.mjs +889 -0
  19. package/src/monitor/page-monitoring.mjs +199 -0
  20. package/src/monitor/tab-selection.mjs +53 -0
  21. package/src/monitor.mjs +39 -0
  22. package/src/os/README.md +4 -0
  23. package/src/os/wsl/chrome.mjs +503 -0
  24. package/src/os/wsl/detect.mjs +68 -0
  25. package/src/os/wsl/diagnostics.mjs +729 -0
  26. package/src/os/wsl/index.mjs +45 -0
  27. package/src/os/wsl/port-proxy.mjs +190 -0
  28. package/src/settings.mjs +101 -0
  29. package/src/templates/api-help.mjs +212 -0
  30. package/src/templates/cli-commands.mjs +51 -0
  31. package/src/templates/interactive-keys.mjs +33 -0
  32. package/src/templates/ready-help.mjs +33 -0
  33. package/src/templates/section-heading.mjs +141 -0
  34. package/src/templates/table-helper.mjs +73 -0
  35. package/src/templates/wait-for-chrome.mjs +19 -0
  36. package/src/utils/ask.mjs +49 -0
  37. package/src/utils/chrome-profile-path.mjs +37 -0
  38. package/src/utils/colors.mjs +49 -0
  39. package/src/utils/env.mjs +30 -0
  40. package/src/utils/profile-id.mjs +23 -0
  41. package/src/utils/status-line.mjs +47 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 info@romanmatena.cz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,558 @@
1
+ <div align="center">
2
+
3
+ ![Browser Monitor](docs/banner.png)
4
+
5
+ # Browser Monitor
6
+
7
+ [![CI](https://github.com/romanmatena/browsermonitor/actions/workflows/ci.yml/badge.svg)](https://github.com/romanmatena/browsermonitor/actions/workflows/ci.yml)
8
+ [![npm](https://img.shields.io/npm/v/browsermonitor.svg)](https://www.npmjs.com/package/browsermonitor)
9
+ [![npm downloads](https://img.shields.io/npm/dm/browsermonitor.svg)](https://www.npmjs.com/package/browsermonitor)
10
+ [![Node](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen)](https://nodejs.org/)
11
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
12
+ [![GitHub](https://img.shields.io/badge/GitHub-romanmatena%2Fbrowsermonitor-24292e?logo=github)](https://github.com/romanmatena/browsermonitor)
13
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](CONTRIBUTING.md)
14
+
15
+ Browser console, network, DOM, and screenshot monitoring for debugging and LLM workflows.
16
+
17
+ **[npm](https://www.npmjs.com/package/browsermonitor)** · **[GitHub](https://github.com/romanmatena/browsermonitor)**
18
+
19
+ [Installation](#installation) · [Quick Start](#quick-start) · [HTTP API](#http-api) · [Contributing](CONTRIBUTING.md)
20
+
21
+ </div>
22
+
23
+ **What it is:** Browser Monitor lets you capture the live state of a browser—console output, network requests, cookies, screenshot, and the current page DOM—and write it all to files. You (or an LLM agent) can then read those files instead of asking someone to copy-paste from DevTools or the browser.
24
+
25
+ **Why it's useful:** When debugging a frontend app or feeding context to an AI assistant, you need the real console, the real DOM, and the real network traffic. Manual copy-paste is slow and error-prone. This tool connects to Chrome via Puppeteer, records everything in one place, and exposes a simple "dump" so the next step is always "read the files" instead of "please open the browser and copy this."
26
+
27
+ **Who needs it:** Frontend and full-stack developers who debug in the browser; teams using LLM coding agents that need up-to-date DOM and network data; anyone who wants a repeatable way to snapshot browser state for logs, tests, or AI context. If you've ever asked a colleague to "send me what you see in the console" or "paste the HTML of that element," you need this. Without it, getting a reliable, one-command snapshot of the live browser is much harder.
28
+
29
+ **Entry point:** `browsermonitor` (global CLI). Run it in any project directory.
30
+
31
+ ### Features
32
+
33
+ - **Console, network, DOM, cookies, screenshot** – capture full browser state in one dump
34
+ - **Screenshot** – each dump writes `.browsermonitor/.puppeteer/screenshot.png` (current tab viewport); ideal for LLM vision or quick visual checks
35
+ - **HTTP REST API** – trigger dump, status, clear, tab switch via `curl` (ideal for LLM agents)
36
+ - **Multiple modes** – Interactive (menu), Open (launch Chrome), Join (attach to existing)
37
+ - **WSL + Windows** – Chrome on Windows, app in WSL with automatic port proxy
38
+ - **Native Linux** – run with GUI on Ubuntu or headless
39
+ - **Lazy or realtime** – buffer in memory or write logs immediately
40
+
41
+ ## Screenshots (demo)
42
+
43
+ | Interactive mode | Open mode / Dump output |
44
+ |------------------|--------------------------|
45
+ | ![Interactive](docs/Screenshot_1.png) | ![Output](docs/Screenshot_2.png) |
46
+
47
+ ## Installation
48
+
49
+ Install globally from [npm](https://www.npmjs.com/package/browsermonitor):
50
+
51
+ ```bash
52
+ # Using npm
53
+ npm install -g browsermonitor
54
+
55
+ # Or pnpm
56
+ pnpm add -g browsermonitor
57
+ ```
58
+
59
+ **Note:** Chromium download is skipped — browsermonitor uses your system Chrome/Chromium. No extra 300 MB download.
60
+
61
+ **First run:** When you run `browsermonitor` in a project directory for the first time, it auto-creates `.browsermonitor/` with `settings.json` and optionally updates agent files (`CLAUDE.md`, `AGENTS.md`, `memory.md`).
62
+
63
+ **Manual setup:** Run `browsermonitor init` to re-run the setup wizard.
64
+
65
+ ## Quick Start
66
+
67
+ ```bash
68
+ browsermonitor # Interactive: menu → o (open) or j (join)
69
+ browsermonitor --open # Open mode: launch new Chrome and monitor
70
+ browsermonitor --join=9222 # Join mode: attach to existing Chrome on port 9222
71
+ ```
72
+
73
+ ## Modes
74
+
75
+ | Mode | How to run | When to use |
76
+ |------------|--------------------------|-------------|
77
+ | **Interactive** | `browsermonitor` (no flags) | Menu asks for project root, then: **o** = open Chrome, **j** = join running Chrome, **q** = quit. |
78
+ | **Open** | `browsermonitor --open [url]` | Launch a new Chrome and monitor it. Uses current dir for logs. |
79
+ | **Join** | `browsermonitor --join=PORT` | Attach to an existing Chrome with remote debugging on PORT (e.g. 9222). Port is required. |
80
+
81
+ ---
82
+
83
+ ## Windows (native)
84
+
85
+ **When to use:** You develop directly on Windows using IIS, XAMPP, or other local server.
86
+
87
+ ```powershell
88
+ cd C:\Projects\my-app
89
+ browsermonitor --open https://localhost:5173/
90
+ ```
91
+
92
+ Open mode launches Chrome via Puppeteer. No port proxy or firewall setup needed.
93
+
94
+ ---
95
+
96
+ ## Windows + WSL
97
+
98
+ **When to use:** Your app runs in WSL (Node.js, Python, etc.) but you want Chrome on Windows for GPU/WebGL.
99
+
100
+ **Usage:** Run from WSL:
101
+
102
+ ```bash
103
+ cd /srv/project
104
+ browsermonitor --open https://localhost:5173/
105
+ ```
106
+
107
+ **How it works:** Open mode detects WSL and launches Chrome Canary on Windows, sets up port proxy (0.0.0.0:9222 → Chrome), and connects from WSL via the Windows gateway IP. Port proxy requires Administrator (one-time) on first run.
108
+
109
+ **Join mode** (attach to existing Chrome): Start Chrome manually with `--remote-debugging-port=9222`, then `browsermonitor --join=9222` from WSL. For port proxy, run in PowerShell (Admin): `netsh interface portproxy add v4tov4 listenport=9222 listenaddress=0.0.0.0 connectport=9222 connectaddress=127.0.0.1`
110
+
111
+ ---
112
+
113
+ ## Linux (Ubuntu) with GUI
114
+
115
+ **When to use:** You develop on native Linux (Ubuntu, etc.) with a display. Chrome/Chromium runs with GUI on the same machine.
116
+
117
+ ```bash
118
+ browsermonitor --open https://localhost:5173/
119
+ ```
120
+
121
+ Chrome/Chromium is started via Puppeteer with `--remote-debugging-port`. No port proxy needed; direct localhost connection.
122
+
123
+ **Requirements:**
124
+ - Chrome or Chromium installed: `apt install chromium-browser` or install Google Chrome
125
+ - Display available (X11 or Wayland)
126
+
127
+ For **join mode** (attach to existing Chrome): start Chrome manually with `--remote-debugging-port=9222`, then `browsermonitor --join=9222`.
128
+
129
+ ---
130
+
131
+ ## Chrome Profile
132
+
133
+ Each project gets its own Chrome profile:
134
+ - **WSL:** `%LOCALAPPDATA%\browsermonitor\{project}_{hash}` (Windows path)
135
+ - **Native:** `.browsermonitor-profile/` in project dir
136
+
137
+ Separate cookies and logins per project; won't interfere with your regular Chrome.
138
+
139
+ ---
140
+
141
+ ## Chrome Canary (Required)
142
+
143
+ browsermonitor **requires Chrome Canary** for launching Chrome (`--open` and `--join` when no Chrome is running). Regular Chrome cannot be used because Chrome is a singleton — all instances bind to the first launched process. If your regular Chrome is already open, a new Chrome with `--remote-debugging-port` would just open a window in the existing process and the debug port would be ignored.
144
+
145
+ Chrome Canary runs as a completely **separate process** from regular Chrome (different singleton, different profile directory), so:
146
+ - Your regular Chrome stays completely untouched
147
+ - Debug port is guaranteed to work
148
+ - No singleton hijacking issues
149
+
150
+ **Installation:**
151
+ 1. Download from: https://www.google.com/chrome/canary/
152
+ 2. Install (goes to `%LOCALAPPDATA%\Google\Chrome SxS\`)
153
+ 3. browsermonitor will detect it automatically
154
+
155
+ **Note:** If you already have Chrome running with `--remote-debugging-port` (e.g. started manually), you can connect to it with `browsermonitor --join=PORT` regardless of whether it's Canary or regular Chrome.
156
+
157
+ ---
158
+
159
+ ## Project Directory Structure
160
+
161
+ When browsermonitor runs in a project directory, it creates:
162
+
163
+ ```
164
+ <project-root>/
165
+ ├── .browsermonitor/
166
+ │ ├── settings.json # Project config (defaultUrl, httpPort, etc.)
167
+ │ ├── browsermonitor.pid # PID file for recovery
168
+ │ └── .puppeteer/ # All dump outputs
169
+ │ ├── console.log
170
+ │ ├── network.log
171
+ │ ├── network-log/ # Per-request JSON files
172
+ │ ├── cookies/ # Per-domain cookie JSONs
173
+ │ ├── dom.html
174
+ │ └── screenshot.png
175
+ └── .browsermonitor-profile/ # Chrome profile (native) or
176
+ # %LOCALAPPDATA%\browsermonitor\ (WSL)
177
+ ```
178
+
179
+ ## Keyboard Controls (open/join mode)
180
+
181
+ | Key | Action |
182
+ |-----|--------|
183
+ | `d` | Dump logs, cookies, screenshot, and current page HTML to files |
184
+ | `c` | Clear in-memory buffer |
185
+ | `s` | Show status (buffer counts, URLs) |
186
+ | `p` | Pause/resume recording (stop/start collecting) |
187
+ | `t` | Switch monitored tab |
188
+ | `h` | Full help (incl. LLM instructions and HTTP API) |
189
+ | `k` | Kill Chrome and exit [open] / kill Chrome and quit [join] |
190
+ | `q` | Quit (Chrome stays open) [open] / disconnect only [join] |
191
+
192
+ ## Output Files
193
+
194
+ | File | Description |
195
+ |------|-------------|
196
+ | `.browsermonitor/.puppeteer/console.log` | Console output |
197
+ | `.browsermonitor/.puppeteer/network.log` | Network requests |
198
+ | `.browsermonitor/.puppeteer/network-log/` | Detailed request/response JSON |
199
+ | `.browsermonitor/.puppeteer/cookies/` | Cookies per domain |
200
+ | `.browsermonitor/.puppeteer/dom.html` | Current page HTML (JS-modified element tree). **LLM: read this for the live DOM structure.** |
201
+ | `.browsermonitor/.puppeteer/screenshot.png` | Screenshot of the current tab viewport (PNG). Written on each dump. |
202
+
203
+ All files are written on dump (key `d` or `curl …/dump`).
204
+
205
+ ## HTTP API
206
+
207
+ Use `curl` to communicate with the HTTP API over REST. Default URL: `http://localhost:60001`.
208
+
209
+ | Endpoint | Description |
210
+ |----------|-------------|
211
+ | `GET /dump` | Dump logs, DOM, cookies, screenshot to files; returns output paths |
212
+ | `GET /status` | Current status, monitored URLs, stats, output file paths |
213
+ | `GET /stop` | Pause collecting (console/network) |
214
+ | `GET /start` | Resume collecting |
215
+ | `GET /clear` | Clear in-memory buffers |
216
+ | `GET /tabs` | List all user tabs (index, url) |
217
+ | `GET /tab?index=N` | Switch monitored tab (1-based index) |
218
+ | `GET /computed-styles?selector=...` | Get computed CSS for first element matching selector (default: body) |
219
+ | `POST /puppeteer` | Call Puppeteer page method. Body: `{ "method": "page.goto", "args": ["https://..."] }` |
220
+
221
+ **Puppeteer whitelist:** `content`, `click`, `focus`, `goto`, `hover`, `pdf`, `screenshot`, `select`, `setDefaultNavigationTimeout`, `setDefaultTimeout`, `setViewport`, `title`, `type`, `url`, `waitForSelector`, `waitForTimeout`
222
+
223
+ ```bash
224
+ curl http://localhost:60001/dump # Dump to files
225
+ curl http://localhost:60001/status # Check status
226
+ curl http://localhost:60001/clear # Clear buffers
227
+ curl http://localhost:60001/tabs # List tabs
228
+ curl "http://localhost:60001/tab?index=2" # Switch to tab 2
229
+ curl "http://localhost:60001/computed-styles?selector=.my-class" # Get computed CSS
230
+ curl -X POST http://localhost:60001/puppeteer -H "Content-Type: application/json" \
231
+ -d '{"method":"page.goto","args":["https://example.com"]}' # Navigate via API
232
+ ```
233
+
234
+ ## CLI Options
235
+
236
+ | Option | Description |
237
+ |--------|-------------|
238
+ | `--open` | Go directly to open mode (launch new Chrome) |
239
+ | `--join=PORT` | Go directly to join mode; attach to Chrome at PORT (port required) |
240
+ | `--port=PORT` | HTTP API port (default: from settings or 60001) |
241
+ | `--headless` | Run Chrome without GUI |
242
+ | `--realtime` | Write logs immediately (default: lazy buffer) |
243
+ | `--timeout=MS` | Hard timeout in ms; process exits after (0 = disabled) |
244
+ | `--nav-timeout=MS` | Navigation timeout in ms (default: from settings, 0 = no limit) |
245
+
246
+ **Config (`.browsermonitor/settings.json`):** `defaultUrl`, `headless`, `navigationTimeout`, `ignorePatterns`, `httpPort`, `realtime`
247
+
248
+ ---
249
+
250
+ ## Troubleshooting WSL
251
+
252
+ ### Connection refused from WSL
253
+
254
+ 1. **Verify Chrome is listening:**
255
+ ```powershell
256
+ netstat -ano | findstr "127.0.0.1:9222.*LISTEN"
257
+ ```
258
+
259
+ 2. **Verify port proxy:**
260
+ ```powershell
261
+ netsh interface portproxy show v4tov4 | findstr 9222
262
+ ```
263
+ Should show: `0.0.0.0 9222 127.0.0.1 9222`
264
+
265
+ 3. **Test from WSL:**
266
+ ```bash
267
+ curl -s http://$(ip route | grep default | awk '{print $3}'):9222/json/version
268
+ ```
269
+
270
+ ### Chrome won't start with debug port
271
+
272
+ Port proxy blocks port 9222 during Chrome startup. Open mode handles this automatically; if it fails, run PowerShell as Administrator so the port proxy can be configured.
273
+
274
+ ### Manual reset
275
+
276
+ ```powershell
277
+ # 1. Remove port proxy (both types)
278
+ netsh interface portproxy delete v4tov4 listenport=9222 listenaddress=0.0.0.0
279
+ netsh interface portproxy delete v4tov6 listenport=9222 listenaddress=0.0.0.0
280
+
281
+ # 2. Kill ONLY browsermonitor Chrome (NOT your regular browser!)
282
+ Get-WmiObject Win32_Process -Filter "name='chrome.exe'" | Where-Object { $_.CommandLine -match 'browsermonitor' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }
283
+
284
+ # 3. Start Chrome Canary (recommended - isolated from regular Chrome)
285
+ Start-Process "$env:LOCALAPPDATA\Google\Chrome SxS\Application\chrome.exe" -ArgumentList "--remote-debugging-port=9222","--user-data-dir=$env:LOCALAPPDATA\browsermonitor\manual"
286
+
287
+ # 4. Wait 5s, check binding, add appropriate proxy
288
+ Start-Sleep 5
289
+ # Check if IPv4 or IPv6:
290
+ netstat -ano | findstr "9222.*LISTEN"
291
+ # If 127.0.0.1:9222:
292
+ netsh interface portproxy add v4tov4 listenport=9222 listenaddress=0.0.0.0 connectport=9222 connectaddress=127.0.0.1
293
+ # If [::1]:9222:
294
+ netsh interface portproxy add v4tov6 listenport=9222 listenaddress=0.0.0.0 connectport=9222 connectaddress=::1
295
+ ```
296
+
297
+ **WARNING:** Never use `Stop-Process -Name chrome -Force` - it kills ALL Chrome including your personal browser!
298
+
299
+ ---
300
+
301
+ ## For Developers: WSL→Windows Chrome Internals
302
+
303
+ This section documents the technical details of connecting to Chrome from WSL2 when Chrome runs on Windows.
304
+
305
+ ### WSL2 Network Architecture
306
+
307
+ WSL2 runs in a lightweight Hyper-V virtual machine with its own network stack:
308
+
309
+ ```
310
+ ┌─────────────────────────────────────────────────────────┐
311
+ │ Windows Host │
312
+ │ Chrome: 127.0.0.1:9222 (localhost only by default) │
313
+ │ │
314
+ │ ┌─────────────────────────────────────────────────┐ │
315
+ │ │ WSL2 VM (e.g., 172.29.100.50) │ │
316
+ │ │ │ │
317
+ │ │ browsermonitor trying to connect... │ │
318
+ │ │ → 127.0.0.1:9222 ❌ (WSL's own localhost) │ │
319
+ │ │ → 172.29.96.1:9222 ✅ (Windows gateway) │ │
320
+ │ └─────────────────────────────────────────────────┘ │
321
+ └─────────────────────────────────────────────────────────┘
322
+ ```
323
+
324
+ **Key insight:** `localhost` in WSL2 refers to WSL's own network, not Windows. To reach Windows services, WSL must connect via the Windows gateway IP (typically `172.x.x.1`).
325
+
326
+ ### Chrome Singleton Behavior
327
+
328
+ Chrome uses a singleton pattern - only one instance runs per user profile:
329
+
330
+ ```
331
+ First launch: chrome.exe --remote-debugging-port=9222 --user-data-dir=X
332
+ → Starts Chrome, listens on port 9222 ✅
333
+
334
+ Second launch: chrome.exe --remote-debugging-port=9223 --user-data-dir=Y
335
+ → If Chrome is already running, the new process:
336
+ 1. Sends command to existing Chrome via IPC
337
+ 2. Opens new window in EXISTING process
338
+ 3. New process exits immediately
339
+ 4. --remote-debugging-port=9223 is IGNORED! ❌
340
+ ```
341
+
342
+ **Consequence:** If user has Chrome open for regular browsing, launching a new Chrome with debug flags does nothing - the existing Chrome (without debugging) handles it.
343
+
344
+ **Detection method (used in monitor.mjs):**
345
+ ```bash
346
+ # From WSL, query Windows WMI for Chrome processes:
347
+ wmic.exe process where "name='chrome.exe'" get processid,commandline
348
+
349
+ # Parse output to find --remote-debugging-port=XXXX
350
+ # Multiple subprocesses report same port - deduplicate with Set
351
+ ```
352
+
353
+ ### Remote Debugging Address Binding
354
+
355
+ **Important: Chrome M113+ Security Change**
356
+
357
+ Since Chrome M113 (May 2023), Chrome **ignores** the `--remote-debugging-address=0.0.0.0` flag for security reasons. Chrome always binds to `127.0.0.1` only.
358
+
359
+ Sources:
360
+ - [Chromium Issue #40261787](https://issues.chromium.org/issues/40261787)
361
+ - [Docker Chromium CDP Port Guide](https://www.ytyng.com/en/blog/docker-chromium-cdp-port/)
362
+
363
+ | Flag | Binding | Accessible from |
364
+ |------|---------|-----------------|
365
+ | `--remote-debugging-port=9222` | 127.0.0.1:9222 | Windows localhost only |
366
+ | `--remote-debugging-port=9222 --remote-debugging-address=0.0.0.0` | 127.0.0.1:9222 | **IGNORED since Chrome M113** |
367
+
368
+ **For WSL access, port proxy is REQUIRED** - there is no way to make Chrome bind to 0.0.0.0.
369
+
370
+ ### Port Proxy Mechanism
371
+
372
+ Windows `netsh` port proxy forwards connections from one address to another.
373
+
374
+ **IPv4 vs IPv6 Binding:**
375
+
376
+ Chrome may bind to either IPv4 (`127.0.0.1`) or IPv6 (`[::1]`) depending on system configuration. The monitor automatically detects which address Chrome uses and configures the appropriate proxy type:
377
+
378
+ | Chrome Binds To | Proxy Type | Command |
379
+ |-----------------|------------|---------|
380
+ | `127.0.0.1:9222` | v4tov4 | `netsh interface portproxy add v4tov4 ... connectaddress=127.0.0.1` |
381
+ | `[::1]:9222` | v4tov6 | `netsh interface portproxy add v4tov6 ... connectaddress=::1` |
382
+
383
+ **Detection logic (used in open mode):**
384
+ ```javascript
385
+ // Check netstat output for Chrome's binding
386
+ const netstatOutput = execSync('netstat.exe -ano', { encoding: 'utf8' });
387
+ const lines = netstatOutput.split('\n').filter(l => l.includes(':9222') && l.includes('LISTEN'));
388
+ // Parse for 127.0.0.1:9222 or [::1]:9222
389
+ ```
390
+
391
+ **Manual proxy commands:**
392
+
393
+ ```powershell
394
+ # IPv4 proxy: forward 0.0.0.0:9222 → 127.0.0.1:9222
395
+ netsh interface portproxy add v4tov4 listenport=9222 listenaddress=0.0.0.0 connectport=9222 connectaddress=127.0.0.1
396
+
397
+ # IPv6 proxy: forward 0.0.0.0:9222 → [::1]:9222
398
+ netsh interface portproxy add v4tov6 listenport=9222 listenaddress=0.0.0.0 connectport=9222 connectaddress=::1
399
+
400
+ # List existing proxies (check both types!)
401
+ netsh interface portproxy show v4tov4
402
+ netsh interface portproxy show v4tov6
403
+
404
+ # Remove proxy
405
+ netsh interface portproxy delete v4tov4 listenport=9222 listenaddress=0.0.0.0
406
+ netsh interface portproxy delete v4tov6 listenport=9222 listenaddress=0.0.0.0
407
+ ```
408
+
409
+ **How it works:**
410
+ ```
411
+ WSL (172.29.100.50) → Windows gateway (172.29.96.1:9222)
412
+ ↓ port proxy (v4tov4 or v4tov6)
413
+ Windows (127.0.0.1:9222 or [::1]:9222)
414
+
415
+ Chrome DevTools Protocol
416
+ ```
417
+
418
+ **Important:** Port proxy requires Administrator privileges to configure.
419
+
420
+ ### Windows Firewall
421
+
422
+ Inbound connections to port 9222 require a firewall rule that allows WSL subnet:
423
+
424
+ ```powershell
425
+ # Check existing rules
426
+ Get-NetFirewallRule -DisplayName "*Chrome*" | Get-NetFirewallPortFilter
427
+
428
+ # Add rule with WSL subnet (one-time, persists across reboots)
429
+ # 172.16.0.0/12 covers the WSL2 dynamic IP range
430
+ New-NetFirewallRule -DisplayName "Chrome Debug (browsermonitor)" -Direction Inbound -LocalPort 9222-9299 -Protocol TCP -Action Allow -RemoteAddress LocalSubnet,172.16.0.0/12
431
+
432
+ # Update existing rule if it doesn't include WSL subnet
433
+ Set-NetFirewallRule -DisplayName "Chrome Remote Debugging" -RemoteAddress LocalSubnet,172.16.0.0/12
434
+ ```
435
+
436
+ **Note:** If firewall rule exists but connections still timeout, check that `RemoteAddress` includes the WSL subnet (172.x.x.x range).
437
+
438
+ ### The 7-Step Diagnostic Process
439
+
440
+ The `runWslDiagnostics()` function performs:
441
+
442
+ | Step | Check | Method |
443
+ |------|-------|--------|
444
+ | 1 | Chrome instances on Windows | `wmic.exe process where "name='chrome.exe'"` |
445
+ | 2 | Network bindings | `netstat.exe -ano \| findstr 9222` |
446
+ | 3 | Port configuration | Parse `--remote-debugging-port` (note: `--remote-debugging-address` is ignored since Chrome M113) |
447
+ | 4 | Windows Firewall | `netsh.exe advfirewall firewall show rule name=all` |
448
+ | 5 | Port proxy config | `netsh.exe interface portproxy show v4tov4` |
449
+ | 6 | Scan port range | Check 9222-9299 for existing proxies |
450
+ | 7 | Connectivity test | `fetch('http://gateway:port/json/version')` |
451
+
452
+ ### Automatic Chrome Detection Flow
453
+
454
+ ```
455
+ ┌──────────────────────────────────────────────────────────────┐
456
+ │ browsermonitor --join=9222 │
457
+ └──────────────────────────────────────────────────────────────┘
458
+
459
+
460
+ ┌───────────────────────────────┐
461
+ │ Detect Windows gateway IP │
462
+ │ (ip route | grep default) │
463
+ └───────────────────────────────┘
464
+
465
+
466
+ ┌───────────────────────────────┐
467
+ │ Try connect to gateway:9222 │
468
+ └───────────────────────────────┘
469
+
470
+ ┌─────────┴─────────┐
471
+ │ │
472
+ Success Fail
473
+ │ │
474
+ ▼ ▼
475
+ ┌───────────┐ ┌───────────────────┐
476
+ │ Connected │ │ Run diagnostics │
477
+ └───────────┘ └───────────────────┘
478
+
479
+
480
+ ┌───────────────────┐
481
+ │ Chrome running │
482
+ │ with debug port? │
483
+ └───────────────────┘
484
+
485
+ ┌─────────┴─────────┐
486
+ │ │
487
+ Yes No
488
+ │ │
489
+ ▼ ▼
490
+ ┌──────────────────┐ ┌──────────────────┐
491
+ │ Offer port proxy │ │ Show how to │
492
+ │ setup (admin) │ │ start Chrome │
493
+ └──────────────────┘ └──────────────────┘
494
+ ```
495
+
496
+ ### Common Issues and Solutions
497
+
498
+ | Symptom | Cause | Solution |
499
+ |---------|-------|----------|
500
+ | Connection refused | Chrome binds to 127.0.0.1 only | Set up port proxy |
501
+ | Connection timeout | Chrome binds to IPv6 (`[::1]`) but proxy forwards to IPv4 | Use `v4tov6` proxy instead of `v4tov4` |
502
+ | New Chrome ignores debug flags | Singleton joined existing process | Close all Chrome windows first, or use port proxy to existing debug port |
503
+ | Port proxy won't start | Chrome already listening on 0.0.0.0 | Remove proxy, start Chrome, re-add proxy |
504
+ | "Access denied" from WSL | Firewall blocking | Add inbound rule for port 9222 |
505
+
506
+ **IPv6 Troubleshooting:**
507
+
508
+ If connection times out after Chrome starts, check what address Chrome is listening on:
509
+
510
+ ```powershell
511
+ # Check Chrome's binding
512
+ netstat -ano | findstr "9222.*LISTEN"
513
+
514
+ # If you see [::1]:9222 (IPv6), you need v4tov6 proxy:
515
+ netsh interface portproxy delete v4tov4 listenport=9222 listenaddress=0.0.0.0
516
+ netsh interface portproxy add v4tov6 listenport=9222 listenaddress=0.0.0.0 connectport=9222 connectaddress=::1
517
+
518
+ # If you see 127.0.0.1:9222 (IPv4), use v4tov4 proxy:
519
+ netsh interface portproxy add v4tov4 listenport=9222 listenaddress=0.0.0.0 connectport=9222 connectaddress=127.0.0.1
520
+ ```
521
+
522
+ ### Environment Detection
523
+
524
+ The monitor detects WSL environment via:
525
+
526
+ ```javascript
527
+ const isWsl = process.platform === 'linux' &&
528
+ (process.env.WSL_DISTRO_NAME ||
529
+ fs.existsSync('/proc/sys/fs/binfmt_misc/WSLInterop'));
530
+ ```
531
+
532
+ ### Debugging Tips
533
+
534
+ ```bash
535
+ # From WSL: Get Windows gateway IP
536
+ ip route | grep default | awk '{print $3}'
537
+ # Result: 172.29.96.1
538
+
539
+ # From WSL: Test Chrome DevTools endpoint
540
+ curl -s http://172.29.96.1:9222/json/version | jq
541
+
542
+ # From WSL: Query Windows processes
543
+ wmic.exe process where "name='chrome.exe'" get processid,commandline
544
+
545
+ # From WSL: Check Windows netstat
546
+ netstat.exe -ano | grep 9222
547
+
548
+ # From Windows: Check what's listening
549
+ netstat -ano | findstr "9222.*LISTEN"
550
+ ```
551
+
552
+ ### Code References
553
+
554
+ - **Entry point:** [cli.mjs](src/cli.mjs) – argument parsing, mode dispatch
555
+ - **Settings:** [settings.mjs](src/settings.mjs) – project paths, config loading
556
+ - **Modes:** [monitor.mjs](src/monitor.mjs) re-exports; implementations in [monitor/join-mode.mjs](src/monitor/join-mode.mjs), [monitor/open-mode.mjs](src/monitor/open-mode.mjs), [monitor/interactive-mode.mjs](src/monitor/interactive-mode.mjs)
557
+ - **WSL:** [os/wsl/index.mjs](src/os/wsl/index.mjs) – `runWslDiagnostics()`, `scanChromeInstances()`, Chrome launch and port proxy helpers
558
+ - **Chrome launch (WSL):** [os/wsl/chrome.mjs](src/os/wsl/chrome.mjs) – `startChromeOnWindows()`, port proxy, profile path
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@romanmatena/browsermonitor",
3
+ "version": "2.0.0",
4
+ "description": "Browser console, network, DOM monitoring for debugging and LLM workflows. Captures console, network, cookies, screenshot, DOM. HTTP API for LLM/scripts. WSL+Windows, Linux, Open/Join modes.",
5
+ "type": "module",
6
+ "bin": {
7
+ "browsermonitor": "./src/cli.mjs"
8
+ },
9
+ "main": "./src/monitor.mjs",
10
+ "files": [
11
+ "src"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18.0.0"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/romanmatena/browsermonitor.git"
19
+ },
20
+ "author": "24gate",
21
+ "license": "MIT",
22
+ "dependencies": {
23
+ "boxen": "^8.0.1",
24
+ "cli-table3": "^0.6.5",
25
+ "puppeteer": "^24.36.1"
26
+ },
27
+ "puppeteer": {
28
+ "skipDownload": true
29
+ },
30
+ "packageManager": "pnpm@10.25.0+sha512.5e82639027af37cf832061bcc6d639c219634488e0f2baebe785028a793de7b525ffcd3f7ff574f5e9860654e098fe852ba8ac5dd5cefe1767d23a020a92f501",
31
+ "homepage": "https://github.com/romanmatena/browsermonitor#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/romanmatena/browsermonitor/issues"
34
+ },
35
+ "keywords": [
36
+ "browser",
37
+ "browsermonitor",
38
+ "chrome",
39
+ "console",
40
+ "debugging",
41
+ "devtools",
42
+ "dom",
43
+ "llm",
44
+ "monitoring",
45
+ "network",
46
+ "puppeteer",
47
+ "screenshot",
48
+ "wsl"
49
+ ],
50
+ "publishConfig": {
51
+ "access": "public"
52
+ }
53
+ }
@@ -0,0 +1,18 @@
1
+ <!-- BEGIN browser-monitor-llm-section - LLM: do not remove this block; required for automatic section updates -->
2
+ ## Browser Monitor (for LLM agent)
3
+
4
+ **Why use this:** Do not ask the user to copy or paste content from the browser (DOM, console, network). You can obtain the current page state yourself: the project has browsermonitor; after a dump you read the generated files.
5
+
6
+ **What to do when you need the live page (elements, console, requests):**
7
+ 1. Trigger a dump: `curl -s http://localhost:60001/dump` (monitor must be running; user runs `browsermonitor` or `browsermonitor --open` / `--join=9222` to start it).
8
+ 2. Read the written files in `.browsermonitor/.puppeteer/`:
9
+ - **.browsermonitor/.puppeteer/dom.html** – current page HTML (JS-modified DOM). Use this for the element tree and structure.
10
+ - **.browsermonitor/.puppeteer/screenshot.png** – screenshot of the current tab viewport.
11
+ - **.browsermonitor/.puppeteer/console.log** – browser console output.
12
+ - **.browsermonitor/.puppeteer/network.log** and **.browsermonitor/.puppeteer/network-log/*.json** – network requests and responses.
13
+ - **.browsermonitor/.puppeteer/cookies/** – cookies per domain (JSON files).
14
+ 3. Optional: `curl -s http://localhost:60001/status` for buffer status.
15
+ 4. Optional: `curl -s http://localhost:60001/tabs` to list tabs; `curl -s "http://localhost:60001/tab?index=2"` to switch tab.
16
+ 5. Optional: `curl -s http://localhost:60001/clear` to clear buffers.
17
+
18
+ <!-- END browser-monitor-llm-section - LLM: do not remove this block; required for automatic section updates -->