@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 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 "$@"