chrome-cli-bridge 0.1.0 → 0.1.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 +315 -0
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# chrome-cli-bridge
|
|
2
|
+
|
|
3
|
+
> Connect any CLI tool or AI agent to a **live Chrome tab** — bypass auth walls, anti-bot detection, and SPAs that defeat headless browsers.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install -g chrome-cli-bridge
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
Headless browsers and `curl` can't handle pages protected by:
|
|
14
|
+
|
|
15
|
+
- OAuth / SSO / MFA login flows
|
|
16
|
+
- Cloudflare Turnstile, CAPTCHA, fingerprinting
|
|
17
|
+
- Client-side rendered SPAs that only show data after login
|
|
18
|
+
|
|
19
|
+
`chrome-cli-bridge` connects to a **real Chrome tab you already have open** and exposes it to any terminal tool — AI coding assistants, shell scripts, Node.js SDKs, pipelines. All traffic stays on localhost.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
┌──────────────────────┐ WebSocket + JSON-RPC ┌─────────────────────┐
|
|
23
|
+
│ Chrome Extension │ ◄───────────────────────► │ Local Relay Server │
|
|
24
|
+
│ (your live tab) │ session token │ chrome-bridge CLI │
|
|
25
|
+
└──────────────────────┘ └──────────┬──────────┘
|
|
26
|
+
│
|
|
27
|
+
┌─────────────▼────────────┐
|
|
28
|
+
│ Copilot CLI · Claude │
|
|
29
|
+
│ Code · shell scripts · │
|
|
30
|
+
│ Node.js SDK · pipelines │
|
|
31
|
+
└──────────────────────────┘
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
### 1 — Install the CLI
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
npm install -g chrome-cli-bridge
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Requires **Node.js ≥ 18**.
|
|
45
|
+
|
|
46
|
+
### 2 — Load the Chrome extension
|
|
47
|
+
|
|
48
|
+
The companion extension is what actually acts in the browser.
|
|
49
|
+
|
|
50
|
+
1. Download the extension from the [GitHub releases page](https://github.com/nestormata/chrome-bridge/releases)
|
|
51
|
+
2. Open **chrome://extensions** in Chrome
|
|
52
|
+
3. Enable **Developer mode** (top-right toggle)
|
|
53
|
+
4. Click **Load unpacked** → select the `extension/` folder
|
|
54
|
+
|
|
55
|
+
### 3 — Start the relay and connect
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
chrome-bridge start
|
|
59
|
+
# ✔ Relay started on ws://localhost:9876
|
|
60
|
+
# ✔ Session token: a1b2c3d4-… (saved to ~/.chrome-cli-bridge.token)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Click the extension icon in Chrome, paste the token, click **Connect**. The bridge is live.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Commands
|
|
68
|
+
|
|
69
|
+
### Navigation & tabs
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
chrome-bridge tabs # list all open tabs
|
|
73
|
+
chrome-bridge tabs --select 42 # select tab by ID
|
|
74
|
+
chrome-bridge tabs --select active # select the focused tab
|
|
75
|
+
|
|
76
|
+
chrome-bridge navigate --url https://example.com # navigate and await load
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Inspect the page
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
chrome-bridge query --selector "h1" # query DOM elements
|
|
83
|
+
chrome-bridge query --html # full page HTML
|
|
84
|
+
|
|
85
|
+
chrome-bridge snapshot # full outerHTML snapshot
|
|
86
|
+
chrome-bridge snapshot --styles # with inline computed styles
|
|
87
|
+
|
|
88
|
+
chrome-bridge exec --code "document.title"
|
|
89
|
+
chrome-bridge exec --code "fetch('/api/me').then(r => r.json())"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Screenshot
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
chrome-bridge screenshot # prints base64 PNG
|
|
96
|
+
chrome-bridge screenshot --output shot.png # saves to file
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Storage
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
chrome-bridge storage --type local # read all localStorage
|
|
103
|
+
chrome-bridge storage --type local --key token # read one key
|
|
104
|
+
chrome-bridge storage --type local --key x --set val # write a key
|
|
105
|
+
chrome-bridge storage --type session # sessionStorage
|
|
106
|
+
chrome-bridge storage --type cookies # cookies for tab origin
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Wait for elements
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
chrome-bridge wait --selector "#app" # wait up to 5 s
|
|
113
|
+
chrome-bridge wait --selector ".loaded" --timeout 10000
|
|
114
|
+
# exits with code 1 on timeout
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Logs & network
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
chrome-bridge logs # buffered console logs
|
|
121
|
+
chrome-bridge logs --level error # filter by level
|
|
122
|
+
chrome-bridge logs --watch # stream in real time (Ctrl+C stops)
|
|
123
|
+
chrome-bridge logs --network # captured HTTP requests
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Interact with the page
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
chrome-bridge trigger --selector "#btn" --event click # dispatch DOM event
|
|
130
|
+
chrome-bridge type --selector "#search" --text "hello world"
|
|
131
|
+
chrome-bridge click --selector "button.submit"
|
|
132
|
+
chrome-bridge hover --selector ".dropdown-trigger"
|
|
133
|
+
chrome-bridge inject --file ./patch.js # inject a local JS file
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Interactive REPL
|
|
137
|
+
|
|
138
|
+
```sh
|
|
139
|
+
chrome-bridge repl
|
|
140
|
+
# chrome-bridge REPL — JavaScript in the selected tab
|
|
141
|
+
# > document.title
|
|
142
|
+
# "My Page"
|
|
143
|
+
# > document.querySelectorAll('a').length
|
|
144
|
+
# 42
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### DevTools data
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
chrome-bridge devtools performance # runtime metrics
|
|
151
|
+
chrome-bridge devtools memory --output snap.heapsnapshot
|
|
152
|
+
chrome-bridge devtools coverage --duration 5000 # JS coverage, 5 s
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Pipeline / stdin mode
|
|
158
|
+
|
|
159
|
+
Output is always JSON when stdout is not a TTY — pipe freely:
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
chrome-bridge tabs | jq '.[0].id'
|
|
163
|
+
chrome-bridge exec --code "document.title" | jq -r '.result'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**NDJSON batch mode** — send one command per line, get one result per line:
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
echo '{"command":"exec","code":"document.title"}' | chrome-bridge
|
|
170
|
+
|
|
171
|
+
cat <<EOF | chrome-bridge
|
|
172
|
+
{"command":"navigate","url":"https://example.com"}
|
|
173
|
+
{"command":"wait","selector":"#content"}
|
|
174
|
+
{"command":"snapshot"}
|
|
175
|
+
EOF
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Force pipe mode in environments that look like a TTY:
|
|
179
|
+
|
|
180
|
+
```sh
|
|
181
|
+
chrome-bridge --pipe < commands.ndjson
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Node.js SDK
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
import { ChromeBridge } from 'chrome-cli-bridge';
|
|
190
|
+
|
|
191
|
+
const bridge = new ChromeBridge();
|
|
192
|
+
await bridge.connect();
|
|
193
|
+
|
|
194
|
+
const tabs = await bridge.tabs();
|
|
195
|
+
await bridge.selectTab(tabs[0].id);
|
|
196
|
+
|
|
197
|
+
// Navigate & inspect
|
|
198
|
+
await bridge.navigate({ url: 'https://example.com' });
|
|
199
|
+
await bridge.wait({ selector: '#app', timeout: 8000 });
|
|
200
|
+
const snap = await bridge.snapshot();
|
|
201
|
+
|
|
202
|
+
// Execute JS
|
|
203
|
+
const { result } = await bridge.exec({ code: 'document.title' });
|
|
204
|
+
|
|
205
|
+
// Interact
|
|
206
|
+
await bridge.type({ selector: '#q', text: 'search term' });
|
|
207
|
+
await bridge.click({ selector: 'button[type=submit]' });
|
|
208
|
+
|
|
209
|
+
// Screenshot
|
|
210
|
+
const { dataUrl } = await bridge.screenshot();
|
|
211
|
+
|
|
212
|
+
// Storage
|
|
213
|
+
const store = await bridge.storage({ type: 'local' });
|
|
214
|
+
const cookies = await bridge.storage({ type: 'cookies' });
|
|
215
|
+
|
|
216
|
+
// Real-time logs
|
|
217
|
+
const unsub = bridge.streamLogs((entry) => console.log(entry));
|
|
218
|
+
// ... later:
|
|
219
|
+
unsub();
|
|
220
|
+
|
|
221
|
+
// DevTools
|
|
222
|
+
const metrics = await bridge.devtools.performance();
|
|
223
|
+
|
|
224
|
+
await bridge.disconnect();
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Usage with AI coding assistants
|
|
230
|
+
|
|
231
|
+
`chrome-cli-bridge` is designed to be a tool layer for AI agents working in the terminal.
|
|
232
|
+
|
|
233
|
+
### GitHub Copilot CLI
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
you> read the current page title from my browser
|
|
237
|
+
copilot> chrome-bridge exec --code "document.title"
|
|
238
|
+
{"result":"Checkout — My Store"}
|
|
239
|
+
|
|
240
|
+
you> get all the product names on the page
|
|
241
|
+
copilot> chrome-bridge exec --code "
|
|
242
|
+
[...document.querySelectorAll('.product-title')].map(el => el.textContent.trim())
|
|
243
|
+
"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Claude Code / Claude.ai
|
|
247
|
+
|
|
248
|
+
Add this to your system prompt or project context:
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
You have access to a live Chrome tab via chrome-cli-bridge.
|
|
252
|
+
Use `chrome-bridge <command>` to read the DOM, run JavaScript,
|
|
253
|
+
capture screenshots, navigate, or interact with the page.
|
|
254
|
+
All output is JSON.
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Then Claude can autonomously scrape, test, or automate flows:
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
claude> I'll check the current state of the checkout form.
|
|
261
|
+
$ chrome-bridge snapshot
|
|
262
|
+
$ chrome-bridge exec --code "document.querySelector('#cart-total').textContent"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Shell script automation
|
|
266
|
+
|
|
267
|
+
```sh
|
|
268
|
+
#!/bin/bash
|
|
269
|
+
# Scrape a page that requires login (you're already logged in via Chrome)
|
|
270
|
+
|
|
271
|
+
chrome-bridge navigate --url "https://myapp.com/dashboard"
|
|
272
|
+
chrome-bridge wait --selector "#data-table"
|
|
273
|
+
|
|
274
|
+
DATA=$(chrome-bridge exec --code "
|
|
275
|
+
[...document.querySelectorAll('#data-table tr')]
|
|
276
|
+
.slice(1)
|
|
277
|
+
.map(r => r.cells[0].textContent + ',' + r.cells[1].textContent)
|
|
278
|
+
.join('\n')
|
|
279
|
+
")
|
|
280
|
+
|
|
281
|
+
echo "$DATA" | jq -r '.result' > output.csv
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Automated testing of authenticated pages
|
|
285
|
+
|
|
286
|
+
```js
|
|
287
|
+
import { ChromeBridge } from 'chrome-cli-bridge';
|
|
288
|
+
|
|
289
|
+
// You're already logged in — no need to re-auth in the test
|
|
290
|
+
const bridge = new ChromeBridge();
|
|
291
|
+
await bridge.connect();
|
|
292
|
+
|
|
293
|
+
await bridge.navigate({ url: 'https://app.example.com/orders' });
|
|
294
|
+
await bridge.wait({ selector: '.order-list' });
|
|
295
|
+
|
|
296
|
+
const count = await bridge.exec({ code: 'document.querySelectorAll(".order-row").length' });
|
|
297
|
+
console.assert(count.result > 0, 'Expected orders to be visible');
|
|
298
|
+
|
|
299
|
+
const shot = await bridge.screenshot({ output: 'test-screenshot.png' });
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Security
|
|
305
|
+
|
|
306
|
+
- Relay **only listens on `127.0.0.1`** — zero external exposure
|
|
307
|
+
- **UUID v4 session token** rotated on every `chrome-bridge start`, stored at `~/.chrome-cli-bridge.token` (mode `0600`)
|
|
308
|
+
- Extension rejects connections without a valid token (WS close code `4001`)
|
|
309
|
+
- Network / DevTools access requires explicit commands and shows Chrome's "DevTools connected" banner — nothing is captured passively
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
MIT © [Nestor Mata](https://github.com/nestormata)
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-cli-bridge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Connect CLI tools and AI agents to a live Chrome tab via WebSocket bridge",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"chrome-bridge": "
|
|
8
|
+
"chrome-bridge": "bin/chrome-bridge.js"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./src/index.js"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"repository": {
|
|
37
37
|
"type": "git",
|
|
38
|
-
"url": "https://github.com/nestormata/chrome-bridge.git"
|
|
38
|
+
"url": "git+https://github.com/nestormata/chrome-bridge.git"
|
|
39
39
|
},
|
|
40
40
|
"homepage": "https://github.com/nestormata/chrome-bridge#readme",
|
|
41
41
|
"bugs": {
|