@dbalabka/chrome-wsl 0.1.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.
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/package.json +29 -0
- package/start_chrome_wsl.sh +223 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Dmitry Balabka
|
|
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,62 @@
|
|
|
1
|
+
# Chrome Start From WSL Helper for MCP
|
|
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.
|
|
14
|
+
|
|
15
|
+
## 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
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
```sh
|
|
22
|
+
./start_chrome_wsl.sh
|
|
23
|
+
```
|
|
24
|
+
- If portproxy/firewall entries are missing, run the printed admin PowerShell commands on Windows, then rerun the script.
|
|
25
|
+
- The script logs `socat` output to `/tmp/socat-9222.log`.
|
|
26
|
+
- To stop the `socat` forwarder:
|
|
27
|
+
```sh
|
|
28
|
+
./start_chrome_wsl.sh --stop
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Installation (one-liner)
|
|
32
|
+
```sh
|
|
33
|
+
sudo install -m 755 start_chrome_wsl.sh /usr/local/bin/start-chrome-wsl
|
|
34
|
+
```
|
|
35
|
+
- Uses the local script (no curl/wget download needed). If you cloned the repo elsewhere, run from that path.
|
|
36
|
+
- Adjust `WINDOWS_CHROME_PATH` or `PORT` inside the script if needed.
|
|
37
|
+
- If `apt` is blocked, preinstall `socat` via your allowed package source.
|
|
38
|
+
|
|
39
|
+
## Installation via npx
|
|
40
|
+
```sh
|
|
41
|
+
npx start-chrome-wsl
|
|
42
|
+
```
|
|
43
|
+
- Runs directly via npm without cloning; exposes the `start-chrome-wsl` binary.
|
|
44
|
+
- Use `npm install -g start-chrome-wsl` to keep it available without npx.
|
|
45
|
+
|
|
46
|
+
## Installation via pipx
|
|
47
|
+
```sh
|
|
48
|
+
pipx install start-chrome-wsl
|
|
49
|
+
```
|
|
50
|
+
- Installs the wrapper that invokes the same `start_chrome_wsl.sh` script.
|
|
51
|
+
- Alternatively, run without installing globally:
|
|
52
|
+
```sh
|
|
53
|
+
pipx run start-chrome-wsl --stop
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Notes
|
|
57
|
+
- Portproxy check expects forwarding from the detected Windows host IP to `127.0.0.1:9222`.
|
|
58
|
+
- Chrome launch is skipped when port 9222 already listens on Windows (assumed active remote-debug session).
|
|
59
|
+
- For a different remote debugging port or Chrome path, edit `PORT` or `WINDOWS_CHROME_PATH` in `start_chrome_wsl.sh`.
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
MIT License. See `LICENSE` for details.
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dbalabka/chrome-wsl",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "WSL helper to start Windows Chrome with remote debugging and socat port forwarding.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"start-chrome-wsl": "start_chrome_wsl.sh"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"start_chrome_wsl.sh",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"wsl",
|
|
14
|
+
"chrome",
|
|
15
|
+
"socat",
|
|
16
|
+
"remote-debugging",
|
|
17
|
+
"mcp"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/dbalabka/wsl-chrome-portproxy-launcher.git"
|
|
23
|
+
},
|
|
24
|
+
"author": "Dmitry Balabka",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/dbalabka/wsl-chrome-portproxy-launcher/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/dbalabka/wsl-chrome-portproxy-launcher#readme"
|
|
29
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Compatible with bash and zsh.
|
|
3
|
+
set -e
|
|
4
|
+
set -u
|
|
5
|
+
if command -v setopt >/dev/null 2>&1; then
|
|
6
|
+
setopt pipefail
|
|
7
|
+
else
|
|
8
|
+
set -o pipefail 2>/dev/null || true
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
PORT=9222
|
|
12
|
+
WINDOWS_CHROME_PATH='C:\Program Files\Google\Chrome\Application\chrome.exe'
|
|
13
|
+
FIREWALL_RULE_NAME='Chrome Remote Debug'
|
|
14
|
+
PID_FILE="/tmp/start-chrome-wsl.pids"
|
|
15
|
+
OK_MARK="✅"
|
|
16
|
+
ERR_MARK="❌"
|
|
17
|
+
|
|
18
|
+
ok() {
|
|
19
|
+
echo "${OK_MARK} $*"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
err() {
|
|
23
|
+
echo "${ERR_MARK} $*" >&2
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
set_pid() {
|
|
27
|
+
# Stores or updates a PID value in the temp PID file.
|
|
28
|
+
local key=$1
|
|
29
|
+
local value=$2
|
|
30
|
+
[[ -z "${value:-}" ]] && return
|
|
31
|
+
touch "$PID_FILE"
|
|
32
|
+
if grep -q "^${key}=" "$PID_FILE" 2>/dev/null; then
|
|
33
|
+
sed -i.bak "s/^${key}=.*/${key}=${value}/" "$PID_FILE" && rm -f "${PID_FILE}.bak"
|
|
34
|
+
else
|
|
35
|
+
echo "${key}=${value}" >>"$PID_FILE"
|
|
36
|
+
fi
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get_pid() {
|
|
40
|
+
local key=$1
|
|
41
|
+
[[ -f "$PID_FILE" ]] || return 0
|
|
42
|
+
sed -n "s/^${key}=//p" "$PID_FILE" | head -n1
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
clear_pid() {
|
|
46
|
+
local key=$1
|
|
47
|
+
[[ -f "$PID_FILE" ]] || return 0
|
|
48
|
+
sed -i.bak "/^${key}=/d" "$PID_FILE"
|
|
49
|
+
rm -f "${PID_FILE}.bak"
|
|
50
|
+
if [[ ! -s "$PID_FILE" ]]; then
|
|
51
|
+
rm -f "$PID_FILE"
|
|
52
|
+
fi
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
stop_socat() {
|
|
56
|
+
local pattern="socat TCP-LISTEN:${PORT},fork,reuseaddr"
|
|
57
|
+
if pgrep -f "$pattern" >/dev/null 2>&1; then
|
|
58
|
+
pkill -f "$pattern" || true
|
|
59
|
+
ok "Stopped socat forwarding for port ${PORT}."
|
|
60
|
+
clear_pid "SOCAT_PID"
|
|
61
|
+
else
|
|
62
|
+
ok "No socat forwarding for port ${PORT} is running."
|
|
63
|
+
fi
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
run_powershell() {
|
|
67
|
+
# Runs a PowerShell command from WSL.
|
|
68
|
+
powershell.exe -NoLogo -NoProfile -NonInteractive -Command "$@"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
chrome_running() {
|
|
72
|
+
run_powershell "if (Get-Process -Name chrome -ErrorAction SilentlyContinue) { exit 0 } else { exit 1 }"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
port_listening_by_chrome() {
|
|
76
|
+
local attempts=5
|
|
77
|
+
local delay=1
|
|
78
|
+
local i
|
|
79
|
+
for ((i=1; i<=attempts; i++)); do
|
|
80
|
+
if run_powershell "if (Get-NetTCPConnection -LocalPort ${PORT} -ErrorAction SilentlyContinue | Where-Object { \$p = Get-Process -Id \$_.OwningProcess -ErrorAction SilentlyContinue; \$p -and \$p.Name -eq 'chrome' }) { exit 0 } else { exit 1 }"; then
|
|
81
|
+
return 0
|
|
82
|
+
fi
|
|
83
|
+
sleep "$delay"
|
|
84
|
+
done
|
|
85
|
+
return 1
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
port_listening_info() {
|
|
89
|
+
run_powershell "\$conns = Get-NetTCPConnection -LocalPort ${PORT} -ErrorAction SilentlyContinue | Select-Object -Property LocalAddress,LocalPort,RemoteAddress,RemotePort,State,OwningProcess; foreach (\$c in \$conns) { \$p = Get-Process -Id \$c.OwningProcess -ErrorAction SilentlyContinue; \$name = if (\$p) { \$p.Name } else { 'unknown' }; Write-Output (\"{0}:{1} owner={2} pid={3} state={4}\" -f \$c.LocalAddress, \$c.LocalPort, \$name, \$c.OwningProcess, \$c.State) }"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get_wsl_host_ip() {
|
|
93
|
+
local host_ip
|
|
94
|
+
host_ip=$(ip route | awk '/^default via / {print $3; exit}')
|
|
95
|
+
if [[ -z "${host_ip:-}" ]]; then
|
|
96
|
+
err "Could not determine Windows host IP from default route."
|
|
97
|
+
return 1
|
|
98
|
+
fi
|
|
99
|
+
printf '%s' "$host_ip"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
check_portproxy() {
|
|
103
|
+
local host_ip=$1
|
|
104
|
+
local output regex
|
|
105
|
+
output=$(run_powershell "netsh interface portproxy show all" | tr -d '\r')
|
|
106
|
+
regex="${host_ip//./\\.}[[:space:]]+${PORT}[[:space:]]+127\\.0\\.0\\.1[[:space:]]+${PORT}"
|
|
107
|
+
if echo "$output" | grep -Eq "$regex"; then
|
|
108
|
+
ok "Portproxy ${host_ip}:${PORT} -> 127.0.0.1:${PORT} is configured."
|
|
109
|
+
return 0
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
cat <<EOF
|
|
113
|
+
${ERR_MARK} Portproxy on ${host_ip}:${PORT} is missing.
|
|
114
|
+
Run this in an **admin PowerShell** window:
|
|
115
|
+
netsh interface portproxy add v4tov4 listenaddress=${host_ip} listenport=${PORT} connectaddress=127.0.0.1 connectport=${PORT}
|
|
116
|
+
EOF
|
|
117
|
+
return 1
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
check_firewall_rule() {
|
|
121
|
+
if run_powershell "\$rule='${FIREWALL_RULE_NAME}'; if (Get-NetFirewallRule -DisplayName \$rule -ErrorAction SilentlyContinue) { exit 0 } else { exit 1 }"; then
|
|
122
|
+
ok "Firewall rule \"${FIREWALL_RULE_NAME}\" exists."
|
|
123
|
+
return 0
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
cat <<EOF
|
|
127
|
+
${ERR_MARK} Firewall rule "${FIREWALL_RULE_NAME}" is missing.
|
|
128
|
+
Run this in an **admin PowerShell** window:
|
|
129
|
+
New-NetFirewallRule -DisplayName "${FIREWALL_RULE_NAME}" -Direction Inbound -LocalPort ${PORT} -Protocol TCP -Action Allow
|
|
130
|
+
EOF
|
|
131
|
+
return 1
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
ensure_socat() {
|
|
135
|
+
if command -v socat >/dev/null 2>&1; then
|
|
136
|
+
ok "socat is already installed."
|
|
137
|
+
return 0
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
err "socat not found. Installing via apt..."
|
|
141
|
+
sudo apt-get update
|
|
142
|
+
sudo apt-get install -y socat
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
start_socat() {
|
|
146
|
+
local host_ip=$1
|
|
147
|
+
if pgrep -f "socat TCP-LISTEN:${PORT},fork,reuseaddr TCP:${host_ip}:${PORT}" >/dev/null 2>&1; then
|
|
148
|
+
ok "socat forwarding for port ${PORT} already running."
|
|
149
|
+
return 0
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
nohup socat "TCP-LISTEN:${PORT},fork,reuseaddr" "TCP:${host_ip}:${PORT}" >/tmp/socat-9222.log 2>&1 &
|
|
153
|
+
set_pid "SOCAT_PID" "$!"
|
|
154
|
+
ok "Started socat (logging to /tmp/socat-9222.log)."
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
stop_chrome() {
|
|
158
|
+
local chrome_pid
|
|
159
|
+
chrome_pid=$(get_pid "CHROME_PID")
|
|
160
|
+
if [[ -z "${chrome_pid:-}" ]]; then
|
|
161
|
+
ok "No tracked Chrome PID found; skipping Chrome stop."
|
|
162
|
+
return 0
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
if run_powershell "if (Get-Process -Id ${chrome_pid} -ErrorAction SilentlyContinue) { Stop-Process -Id ${chrome_pid} -Force; exit 0 } else { exit 1 }"; then
|
|
166
|
+
ok "Stopped tracked Chrome process (pid ${chrome_pid})."
|
|
167
|
+
else
|
|
168
|
+
ok "Tracked Chrome PID ${chrome_pid} is not running."
|
|
169
|
+
fi
|
|
170
|
+
clear_pid "CHROME_PID"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
start_chrome() {
|
|
174
|
+
local chrome_cmd
|
|
175
|
+
chrome_cmd="\$args = @(\"--remote-debugging-port=${PORT}\", \"--no-first-run\", \"--no-default-browser-check\", \"--user-data-dir=\$env:TEMP\\chrome-profile-stable\"); \$p = Start-Process -FilePath \"${WINDOWS_CHROME_PATH}\" -ArgumentList \$args -PassThru; Write-Output \$p.Id"
|
|
176
|
+
|
|
177
|
+
if [[ -n "$(get_pid "CHROME_PID")" ]]; then
|
|
178
|
+
if port_listening_by_chrome; then
|
|
179
|
+
ok "Port ${PORT} already listening on Windows (owned by chrome); assuming ready. Skipping launch (tracked pid $(get_pid "CHROME_PID"))."
|
|
180
|
+
return 0
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
if chrome_running; then
|
|
184
|
+
err "Chrome is running (tracked pid $(get_pid "CHROME_PID")), but port ${PORT} is not listening. You may need to start Chrome with --remote-debugging-port=${PORT}."
|
|
185
|
+
fi
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
local chrome_pid
|
|
189
|
+
chrome_pid=$(run_powershell "$chrome_cmd" | tr -d '\r' | head -n 1)
|
|
190
|
+
if [[ -n "${chrome_pid:-}" ]]; then
|
|
191
|
+
set_pid "CHROME_PID" "$chrome_pid"
|
|
192
|
+
ok "Launched Chrome (pid ${chrome_pid}) with remote debugging."
|
|
193
|
+
else
|
|
194
|
+
err "Launched Chrome but could not determine PID."
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
if port_listening_by_chrome; then
|
|
198
|
+
ok "Chrome is listening on port ${PORT}."
|
|
199
|
+
else
|
|
200
|
+
err "Chrome launch did not open port ${PORT}; verify remote-debugging flag or check for conflicts."
|
|
201
|
+
port_listening_info
|
|
202
|
+
fi
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
main() {
|
|
206
|
+
if [[ "${1-}" == "--stop" ]]; then
|
|
207
|
+
stop_chrome
|
|
208
|
+
stop_socat
|
|
209
|
+
exit 0
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
local host_ip
|
|
213
|
+
host_ip=$(get_wsl_host_ip)
|
|
214
|
+
ok "Detected Windows host IP: ${host_ip}"
|
|
215
|
+
|
|
216
|
+
check_portproxy "$host_ip" || exit 1
|
|
217
|
+
check_firewall_rule || exit 1
|
|
218
|
+
ensure_socat
|
|
219
|
+
start_socat "$host_ip"
|
|
220
|
+
start_chrome
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
main "$@"
|