@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.
- package/README.md +24 -15
- package/chrome-wsl +135 -6
- 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
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 "$@"
|