@dbalabka/chrome-wsl 0.4.0 → 0.5.1

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 (3) hide show
  1. package/README.md +24 -15
  2. package/chrome-wsl +135 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,22 +1,29 @@
1
1
  # Chrome Start From WSL Helper for MCP
2
2
 
3
- A small WSL helper to open Google Chrome on Windows with remote debugging (port 9222) while bridging traffic from WSL via `socat`. It checks/prints the required Windows portproxy and firewall setup, ensures `socat` is installed, starts the tunnel, and launches Chrome with a temporary profile.
4
-
5
- ## Features
6
- - Detects Windows host IP automatically from WSL.
7
- - Verifies Windows portproxy forwarding (9222) and shows admin PowerShell commands if missing.
8
- - Verifies the Windows firewall rule for port 9222 and shows the admin command if missing.
9
- - Ensures `socat` is installed on WSL, installs via `apt` when needed.
10
- - Starts a background `socat` bridge WSL→Windows (logs to `/tmp/socat-9222.log`).
11
- - Launches Windows Chrome with `--remote-debugging-port=9222` and a temp profile.
12
- - Skips launching if port 9222 is already listening on Windows; warns if Chrome is running without the debug port.
13
- - Works under bash or zsh; includes `--stop` to kill the `socat` forwarder.
3
+ A lightweight shell script that **automates Chrome DevTools MCP setup** from **WSL** by launching **Windows Chrome** with remote debugging enabled and transparently proxying traffic from WSL using `socat`.
4
+
5
+ No Linux Chrome, no gWSL, no manual Windows networking setup.
6
+
7
+ ## What It Does
8
+
9
+ * 🤖 Automatically bridges **WSL Windows Chrome DevTools (9222)** using `socat`
10
+ * Validates required **Windows portproxy and firewall rules**
11
+ * 🚀 Launches **existing Windows Chrome** with remote debugging and a temporary profile
12
+ * 🧹 Cleans up easily with a stop command and leaves no permanent system changes
13
+
14
+ ## Key Features
15
+
16
+ * **Fully automated**: one command to get Chrome DevTools MCP working from WSL
17
+ * **Lightweight**: simple, readable shell script
18
+ * **Uses your existing Windows Chrome** — no Linux Chrome or gWSL required
19
+ * **Clean & reversible**: minimal system changes, easy to uninstall
14
20
 
15
21
  ## Prerequisites
16
- - WSL with `powershell.exe` available.
17
- - Windows Chrome installed at `C:\Program Files\Google\Chrome\Application\chrome.exe` (adjust the path in the script if different).
18
- - Network/apt access to install `socat` on first run (or preinstall manually).
19
- - Run the script from inside WSL; non-WSL Linux is not supported (Docker has limited proxy-only support, see below).
22
+
23
+ * Windows Chrome already installed
24
+ * WSL environment
25
+ * The script will install one small dependency (`socat`) automatically for port proxying
26
+
20
27
 
21
28
  ## Usage
22
29
 
@@ -36,6 +43,8 @@ npx @dbalabka/chrome-wsl
36
43
  ```
37
44
  - Runs directly via npm without cloning; default entrypoint is `chrome-wsl` (matching the package name).
38
45
 
46
+ > ℹ️️ Note: Must be run from WSL. Docker is supported only for proxying (no Chrome launch).
47
+
39
48
  #### Example
40
49
  ```sh
41
50
  ❯ npx @dbalabka/chrome-wsl
package/chrome-wsl CHANGED
@@ -74,6 +74,66 @@ stop_socat() {
74
74
  fi
75
75
  }
76
76
 
77
+ debug_socat_info() {
78
+ echo "socat status:"
79
+ if command -v socat >/dev/null 2>&1; then
80
+ echo " version: $(socat -V 2>&1 | head -n 1)"
81
+ else
82
+ echo " version: not installed"
83
+ fi
84
+
85
+ local pattern="socat TCP-LISTEN:${PORT},fork,reuseaddr"
86
+ if pgrep -af "$pattern" >/dev/null 2>&1; then
87
+ pgrep -af "$pattern" | while read -r line; do
88
+ echo " process: ${line}"
89
+ done
90
+ else
91
+ echo " process: not running"
92
+ fi
93
+
94
+ local socat_pid
95
+ socat_pid=$(get_pid "SOCAT_PID")
96
+ if [[ -n "${socat_pid:-}" ]]; then
97
+ echo " tracked pid: ${socat_pid}"
98
+ else
99
+ echo " tracked pid: none"
100
+ fi
101
+
102
+ if [[ -f /tmp/socat-9222.log ]]; then
103
+ echo " log: /tmp/socat-9222.log"
104
+ else
105
+ echo " log: not found"
106
+ fi
107
+ }
108
+
109
+ debug_linux_listeners() {
110
+ echo "Linux listeners on port ${PORT}:"
111
+ if command -v ss >/dev/null 2>&1; then
112
+ if ss -lntp 2>/dev/null | awk -v port=":${PORT}" '$0 ~ port {print " " $0}' | head -n 50; then
113
+ return 0
114
+ fi
115
+ fi
116
+ if command -v lsof >/dev/null 2>&1; then
117
+ if lsof -nP -iTCP:"${PORT}" -sTCP:LISTEN 2>/dev/null | awk 'NR==1 {print " " $0; next} {print " " $0}'; then
118
+ return 0
119
+ fi
120
+ fi
121
+ echo " unavailable (no permissions or tools)"
122
+ }
123
+
124
+ debug_windows_listeners() {
125
+ echo "Windows listeners on port ${PORT}:"
126
+ run_powershell "netstat -ano | Select-String -Pattern \"LISTENING\" | Select-String -Pattern \":${PORT}\" | ForEach-Object { \" \" + \$_.Line }"
127
+ run_powershell "if (-not (netstat -ano | Select-String -Pattern \"LISTENING\" | Select-String -Pattern \":${PORT}\")) { Write-Output ' none' }"
128
+ }
129
+
130
+ debug_windows_rules() {
131
+ echo "Portproxy rules for port ${PORT}:"
132
+ run_powershell "\$lines = netsh interface portproxy show all | Select-String -SimpleMatch '${PORT}' | ForEach-Object { \$_.Line }; if (\$lines) { \$lines } else { ' none' }"
133
+ echo "Firewall rules for port ${PORT}:"
134
+ run_powershell "\$port='${PORT}'; \$rules = Get-NetFirewallRule -ErrorAction SilentlyContinue | Where-Object { \$filter = Get-NetFirewallPortFilter -AssociatedNetFirewallRule \$_ -ErrorAction SilentlyContinue; \$filter -and (\$filter.LocalPort -contains \$port) }; if (\$rules) { \$rules | ForEach-Object { \" {0} enabled={1} direction={2} action={3} profile={4}\" -f \$_.DisplayName, \$_.Enabled, \$_.Direction, \$_.Action, \$_.Profile } } else { ' none' }"
135
+ }
136
+
77
137
  run_powershell() {
78
138
  # Runs a PowerShell command from WSL. If RUN_AS_ADMIN=1, invoke via Start-Process -Verb RunAs
79
139
  # and capture output through a temp script/output file to mirror direct execution.
@@ -106,7 +166,11 @@ confirm() {
106
166
  local prompt=$1
107
167
  local reply
108
168
  local prefix="${CONTAINER_LABEL:+[${CONTAINER_LABEL}] }"
109
- read -r -p "${CONFIRM_MARK} ${prefix}${prompt} [y/N] " reply
169
+ if [[ -r /dev/tty ]]; then
170
+ read -r -p "${CONFIRM_MARK} ${prefix}${prompt} [y/N] " reply </dev/tty
171
+ else
172
+ read -r -p "${CONFIRM_MARK} ${prefix}${prompt} [y/N] " reply
173
+ fi
110
174
  [[ "${reply}" =~ ^[Yy]$ ]]
111
175
  }
112
176
 
@@ -145,6 +209,38 @@ get_browser_version() {
145
209
  | head -n 1
146
210
  }
147
211
 
212
+ get_protocol_version() {
213
+ local host_ip=${1:-$HOST_IP}
214
+ [[ -z "${host_ip:-}" ]] && return 0
215
+ curl -s "http://${host_ip}:${PORT}/json/version" \
216
+ | sed -n "s/.*\"Protocol-Version\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" \
217
+ | head -n 1
218
+ }
219
+
220
+ check_devtools_access_wsl() {
221
+ local url_local="http://127.0.0.1:${PORT}/json/version"
222
+ local url_host="http://${HOST_IP}:${PORT}/json/version"
223
+ local json browser protocol
224
+
225
+ json=$(curl -s --max-time 2 "$url_local" || true)
226
+ if [[ -z "${json:-}" ]]; then
227
+ warn "Chrome DevTools not reachable at ${url_local} from WSL."
228
+ json=$(curl -s --max-time 2 "$url_host" || true)
229
+ if [[ -z "${json:-}" ]]; then
230
+ err "Chrome DevTools not reachable at ${url_host} from WSL."
231
+ return 1
232
+ fi
233
+ fi
234
+
235
+ browser=$(echo "$json" | sed -n "s/.*\"Browser\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" | head -n 1)
236
+ protocol=$(echo "$json" | sed -n "s/.*\"Protocol-Version\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" | head -n 1)
237
+ if [[ -n "${browser:-}" || -n "${protocol:-}" ]]; then
238
+ ok "DevTools reachable from WSL: ${browser:-unknown} (Protocol ${protocol:-unknown})."
239
+ else
240
+ warn "DevTools reachable from WSL, but version info was not parsed."
241
+ fi
242
+ }
243
+
148
244
  get_wsl_host_ip() {
149
245
  local host_ip
150
246
  host_ip=$(ip route | awk '/^default via / {print $3; exit}')
@@ -158,8 +254,23 @@ get_wsl_host_ip() {
158
254
  check_portproxy() {
159
255
  local host_ip=$1
160
256
  local output regex
161
- output=$(run_powershell "netsh interface portproxy show all" | tr -d '
162
- ')
257
+ output=$(run_powershell "netsh interface portproxy show all" | tr -d '\r')
258
+
259
+ echo "$output" | awk 'NF>=4 && $2 ~ /^[0-9]+$/ {print $1, $2, $3, $4}' | while read -r listen_addr listen_port connect_addr connect_port; do
260
+ if [[ "$listen_port" == "$PORT" && "$listen_addr" != "$host_ip" ]]; then
261
+ if confirm "Remove portproxy ${listen_addr}:${listen_port} -> ${connect_addr}:${connect_port} (conflicts with ${host_ip}:${PORT})?"; then
262
+ if RUN_AS_ADMIN=1 run_powershell "netsh interface portproxy delete v4tov4 listenaddress=${listen_addr} listenport=${listen_port}"; then
263
+ ok "Removed conflicting portproxy ${listen_addr}:${listen_port}."
264
+ else
265
+ warn "Failed to remove conflicting portproxy ${listen_addr}:${listen_port}."
266
+ fi
267
+ else
268
+ warn "Keeping conflicting portproxy ${listen_addr}:${listen_port}."
269
+ fi
270
+ fi
271
+ done
272
+
273
+ output=$(run_powershell "netsh interface portproxy show all" | tr -d '\r')
163
274
  regex="${host_ip//./\.}[[:space:]]+${PORT}[[:space:]]+127\.0\.0\.1[[:space:]]+${PORT}"
164
275
  if echo "$output" | grep -Eq "$regex"; then
165
276
  ok "Portproxy ${host_ip}:${PORT} -> 127.0.0.1:${PORT} is configured."
@@ -388,12 +499,13 @@ ensure_wsl() {
388
499
  }
389
500
 
390
501
  main() {
391
- local container="" uninstall_flag=0 stop_flag=0
502
+ local container="" uninstall_flag=0 stop_flag=0 debug_flag=0
392
503
  for arg in "$@"; do
393
504
  case "$arg" in
394
505
  --container=*) container=${arg#*=} ;;
395
506
  --uninstall) uninstall_flag=1 ;;
396
507
  --stop) stop_flag=1 ;;
508
+ --debug) debug_flag=1 ;;
397
509
  esac
398
510
  done
399
511
 
@@ -408,6 +520,11 @@ main() {
408
520
  fi
409
521
 
410
522
  if is_docker; then
523
+ if [[ $debug_flag -eq 1 ]]; then
524
+ debug_socat_info
525
+ exit 0
526
+ fi
527
+
411
528
  if [[ $uninstall_flag -eq 1 ]]; then
412
529
  uninstall_socat
413
530
  exit 0
@@ -431,6 +548,17 @@ main() {
431
548
 
432
549
  ensure_wsl
433
550
 
551
+ if [[ $debug_flag -eq 1 ]]; then
552
+ debug_windows_rules
553
+ debug_windows_listeners
554
+ debug_linux_listeners
555
+ debug_socat_info
556
+ if [[ -n "$container" ]]; then
557
+ container_exec "$container" --debug
558
+ fi
559
+ exit 0
560
+ fi
561
+
434
562
  if [[ $uninstall_flag -eq 1 ]]; then
435
563
  uninstall_portproxy
436
564
  uninstall_firewall_rule
@@ -456,13 +584,14 @@ main() {
456
584
 
457
585
  check_portproxy "$host_ip" || exit 1
458
586
  check_firewall_rule || exit 1
587
+ start_chrome
459
588
  ensure_socat
460
589
  start_socat "$host_ip"
461
- start_chrome
590
+ check_devtools_access_wsl || true
462
591
 
463
592
  if [[ -n "$container" ]]; then
464
593
  container_exec "$container"
465
594
  fi
466
595
  }
467
596
 
468
- main "$@"
597
+ main "$@"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbalabka/chrome-wsl",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "WSL helper to start Windows Chrome with remote debugging and socat port forwarding.",
5
5
  "bin": "./chrome-wsl",
6
6
  "files": [