cdpilot 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) 2026 browserctl contributors
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,283 @@
1
+ # browserctl
2
+
3
+ > Zero-dependency browser automation from your terminal. One command, full control.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/browserctl.svg)](https://www.npmjs.com/package/browserctl)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
7
+
8
+ <!-- Demo GIF will be added after first release -->
9
+
10
+ ## Quick Start
11
+
12
+ ```bash
13
+ npx browserctl launch # Start browser with CDP
14
+ npx browserctl go https://example.com
15
+ npx browserctl shot # Take screenshot
16
+ ```
17
+
18
+ No config files. No boilerplate. Just `npx` and go.
19
+
20
+ ## Why browserctl?
21
+
22
+ AI agents and developers need browser control that **just works**:
23
+
24
+ - **Zero config** — `npx browserctl launch` starts an isolated browser session
25
+ - **Zero dependency** — No Puppeteer, no Playwright, no Selenium. Pure CDP over HTTP
26
+ - **40+ commands** — Navigate, click, type, screenshot, network, console, accessibility, and more
27
+ - **AI-agent friendly** — Designed for Claude, GPT, Gemini, and any LLM tool-use workflow
28
+ - **Isolated sessions** — Your personal browser stays untouched. browserctl runs in its own profile
29
+ - **Privacy-first** — Everything runs locally. No data leaves your machine
30
+
31
+ ### Why Brave?
32
+
33
+ browserctl uses [Brave Browser](https://brave.com) as its engine. Here's why:
34
+
35
+ | Feature | Brave | Chrome | Why it matters |
36
+ |---------|-------|--------|---------------|
37
+ | **Built-in ad blocker** | Shields (native) | Extension needed | Pages load faster, less noise in DOM |
38
+ | **Tracker blocking** | Default on | Manual config | Cleaner network logs for debugging |
39
+ | **Fingerprint protection** | Native | None | Better privacy for automated sessions |
40
+ | **Chromium-based** | Full CDP support | Full CDP support | Same DevTools Protocol, same power |
41
+ | **Open source** | Yes (MPL 2.0) | Chromium yes, Chrome no | Transparent, auditable |
42
+ | **Resource usage** | Lower memory | Higher memory | Better for running alongside your work |
43
+
44
+ **TL;DR:** Brave = Chrome's power + built-in privacy + less bloat. Perfect for automation.
45
+
46
+ > browserctl also works with Chrome and Chromium as fallback. Brave is recommended, not required.
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ # Use directly (no install needed)
52
+ npx browserctl <command>
53
+
54
+ # Or install globally
55
+ npm i -g browserctl
56
+ ```
57
+
58
+ **Requirements:** Node.js 18+ and one of: Brave Browser, Google Chrome, or Chromium.
59
+
60
+ ### First-time setup
61
+
62
+ ```bash
63
+ npx browserctl setup # Auto-detect browser, create isolated profile
64
+ npx browserctl launch # Start browser with CDP enabled
65
+ npx browserctl status # Check connection
66
+ ```
67
+
68
+ ## Commands
69
+
70
+ ### Navigation & Content
71
+
72
+ ```bash
73
+ browserctl go <url> # Navigate to URL
74
+ browserctl content # Get page text content
75
+ browserctl html # Get page HTML
76
+ browserctl shot [file] # Take screenshot (PNG)
77
+ browserctl pdf [file] # Save page as PDF
78
+ ```
79
+
80
+ ### Interaction
81
+
82
+ ```bash
83
+ browserctl click <selector> # Click element
84
+ browserctl type <selector> <text># Type into input
85
+ browserctl fill <selector> <val> # Set input value (React-compatible)
86
+ browserctl submit <form> # Submit form
87
+ browserctl hover <selector> # Hover element
88
+ browserctl keys <combo> # Keyboard shortcut (ctrl+a, enter, etc.)
89
+ browserctl scroll-to <selector> # Scroll element into view
90
+ browserctl drag <from> <to> # Drag and drop
91
+ ```
92
+
93
+ ### Debugging
94
+
95
+ ```bash
96
+ browserctl console [url] # Capture console logs
97
+ browserctl network [url] # Monitor network requests
98
+ browserctl debug [url] # Full diagnostic (console+network+perf+shot)
99
+ browserctl perf # Performance metrics
100
+ browserctl eval <js> # Execute JavaScript
101
+ ```
102
+
103
+ ### Tab Management
104
+
105
+ ```bash
106
+ browserctl tabs # List open tabs
107
+ browserctl new-tab [url] # Open new tab
108
+ browserctl switch-tab <id> # Switch to tab
109
+ browserctl close-tab [id] # Close tab
110
+ browserctl close # Close active tab
111
+ ```
112
+
113
+ ### Network Control
114
+
115
+ ```bash
116
+ browserctl throttle slow3g # Simulate slow 3G
117
+ browserctl throttle fast3g # Simulate fast 3G
118
+ browserctl throttle offline # Go offline
119
+ browserctl throttle off # Back to normal
120
+ browserctl proxy <url> # Set proxy
121
+ browserctl proxy off # Remove proxy
122
+ ```
123
+
124
+ ### Request Interception
125
+
126
+ ```bash
127
+ browserctl intercept block <pattern> # Block requests
128
+ browserctl intercept mock <pattern> <json-file> # Mock responses
129
+ browserctl intercept headers <pattern> <header:value> # Add headers
130
+ browserctl intercept list # List active rules
131
+ browserctl intercept clear # Clear all rules
132
+ ```
133
+
134
+ ### Device Emulation
135
+
136
+ ```bash
137
+ browserctl emulate iphone # iPhone emulation
138
+ browserctl emulate ipad # iPad emulation
139
+ browserctl emulate android # Android emulation
140
+ browserctl emulate reset # Back to desktop
141
+ ```
142
+
143
+ ### Geolocation
144
+
145
+ ```bash
146
+ browserctl geo istanbul # Set location to Istanbul
147
+ browserctl geo london # Set location to London
148
+ browserctl geo 41.01 28.97 # Custom coordinates
149
+ browserctl geo off # Remove override
150
+ ```
151
+
152
+ ### Accessibility
153
+
154
+ ```bash
155
+ browserctl a11y # Full accessibility tree
156
+ browserctl a11y summary # Quick summary
157
+ browserctl a11y find <role> # Find elements by ARIA role
158
+ ```
159
+
160
+ ### Session Management
161
+
162
+ ```bash
163
+ browserctl session # Current session info
164
+ browserctl sessions # List all sessions
165
+ browserctl session-close [id] # Close session
166
+ ```
167
+
168
+ ### Advanced
169
+
170
+ ```bash
171
+ browserctl cookies [domain] # List cookies
172
+ browserctl storage # localStorage contents
173
+ browserctl upload <sel> <file> # Upload file to input
174
+ browserctl multi-eval <js> # Execute JS in all tabs
175
+ browserctl headless [on|off] # Toggle headless mode
176
+ browserctl frame list # List iframes
177
+ browserctl dialog auto-accept # Auto-accept dialogs
178
+ browserctl permission grant geo # Grant geolocation
179
+ ```
180
+
181
+ ## Use with AI Agents
182
+
183
+ browserctl is designed to be called by AI agents as a tool:
184
+
185
+ ### Claude Code (MCP)
186
+
187
+ ```json
188
+ {
189
+ "mcpServers": {
190
+ "browserctl": {
191
+ "command": "npx",
192
+ "args": ["browserctl", "mcp"]
193
+ }
194
+ }
195
+ }
196
+ ```
197
+
198
+ ### Any LLM (tool-use)
199
+
200
+ ```json
201
+ {
202
+ "name": "browser",
203
+ "description": "Control a browser via CDP",
204
+ "parameters": {
205
+ "command": "go https://example.com"
206
+ }
207
+ }
208
+ ```
209
+
210
+ ### Python (subprocess)
211
+
212
+ ```python
213
+ import subprocess
214
+ result = subprocess.run(["npx", "browserctl", "go", url], capture_output=True, text=True)
215
+ print(result.stdout)
216
+ ```
217
+
218
+ ## Environment Variables
219
+
220
+ | Variable | Default | Description |
221
+ |----------|---------|-------------|
222
+ | `CDP_PORT` | `9222` | CDP debugging port |
223
+ | `CHROME_BIN` | Auto-detect | Browser binary path |
224
+ | `BROWSERCTL_PROFILE` | `~/.browserctl/profile` | Isolated browser profile |
225
+ | `BROWSER_SESSION` | Auto | Session identifier |
226
+
227
+ ## How It Works
228
+
229
+ ```
230
+ ┌─────────────┐ HTTP/WebSocket ┌──────────────┐
231
+ │ browserctl │ ◄──────────────────────► │ Brave/Chrome │
232
+ │ (CLI) │ Chrome DevTools │ (CDP mode) │
233
+ └─────────────┘ Protocol └──────────────┘
234
+ │ │
235
+ │ Zero dependencies │ Isolated profile
236
+ │ Pure HTTP + WebSocket │ Separate from your
237
+ │ ~2500 lines, single file │ personal browser
238
+ └────────────────────────────────────────┘
239
+ ```
240
+
241
+ **No Puppeteer. No Playwright. No Selenium.** Just direct CDP communication.
242
+
243
+ ## Comparison
244
+
245
+ | Feature | browserctl | Puppeteer | Playwright | Selenium |
246
+ |---------|-----------|-----------|------------|----------|
247
+ | Install size | **~50KB** | 400MB+ | 200MB+ | 100MB+ |
248
+ | Dependencies | **0** | 50+ | 30+ | Java + drivers |
249
+ | Setup time | **instant** | minutes | minutes | painful |
250
+ | AI-agent ready | **yes** | manual | manual | manual |
251
+ | Browser download | **no** | yes (Chromium) | yes (3 browsers) | no |
252
+ | CLI-first | **yes** | no (library) | no (library) | no |
253
+ | MCP support | **yes** | no | no | no |
254
+
255
+ ## Monetization / Pro (Coming Soon)
256
+
257
+ browserctl CLI is and will always be **free and open source** (MIT).
258
+
259
+ Future paid offerings:
260
+ - **browserctl cloud** — Remote browser instances, no local browser needed
261
+ - **Team dashboard** — Shared sessions, audit logs, usage analytics
262
+ - **Priority support** — Direct help for enterprise integrations
263
+
264
+ ## Contributing
265
+
266
+ ```bash
267
+ git clone https://github.com/user/browserctl.git
268
+ cd browserctl
269
+ npm install
270
+ npm test
271
+ ```
272
+
273
+ PRs welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) first.
274
+
275
+ ## License
276
+
277
+ MIT — do whatever you want.
278
+
279
+ ---
280
+
281
+ <p align="center">
282
+ Built with the <a href="https://github.com/nicedoc/browserctl">browserctl</a> mindset: one tool, one job, done right.
283
+ </p>
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * browserctl — Zero-dependency browser automation CLI
5
+ * Entry point: detects Python, finds browser, delegates to browserctl.py
6
+ */
7
+
8
+ const { execSync, spawn } = require('child_process');
9
+ const path = require('path');
10
+ const fs = require('fs');
11
+ const os = require('os');
12
+
13
+ const SCRIPT = path.join(__dirname, '..', 'src', 'browserctl.py');
14
+ const VERSION = require('../package.json').version;
15
+
16
+ // ── Browser Detection ──
17
+
18
+ function findBrowser() {
19
+ // User override
20
+ if (process.env.CHROME_BIN) {
21
+ if (fs.existsSync(process.env.CHROME_BIN)) return process.env.CHROME_BIN;
22
+ }
23
+
24
+ const platform = os.platform();
25
+ const candidates = [];
26
+
27
+ if (platform === 'darwin') {
28
+ candidates.push(
29
+ '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser',
30
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
31
+ '/Applications/Chromium.app/Contents/MacOS/Chromium',
32
+ );
33
+ } else if (platform === 'linux') {
34
+ candidates.push(
35
+ 'brave-browser',
36
+ 'brave',
37
+ 'google-chrome',
38
+ 'google-chrome-stable',
39
+ 'chromium-browser',
40
+ 'chromium',
41
+ );
42
+ } else if (platform === 'win32') {
43
+ const programFiles = process.env['PROGRAMFILES'] || 'C:\\Program Files';
44
+ const programFilesX86 = process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)';
45
+ const localAppData = process.env.LOCALAPPDATA || '';
46
+ candidates.push(
47
+ path.join(programFiles, 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'),
48
+ path.join(programFilesX86, 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'),
49
+ path.join(localAppData, 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'),
50
+ path.join(programFiles, 'Google', 'Chrome', 'Application', 'chrome.exe'),
51
+ path.join(programFilesX86, 'Google', 'Chrome', 'Application', 'chrome.exe'),
52
+ path.join(localAppData, 'Google', 'Chrome', 'Application', 'chrome.exe'),
53
+ );
54
+ }
55
+
56
+ for (const bin of candidates) {
57
+ if (bin.startsWith('/') || bin.includes('\\')) {
58
+ if (fs.existsSync(bin)) return bin;
59
+ } else {
60
+ try {
61
+ execSync(`which ${bin} 2>/dev/null`, { stdio: 'pipe' });
62
+ return bin;
63
+ } catch {}
64
+ }
65
+ }
66
+ return null;
67
+ }
68
+
69
+ // ── Python Detection ──
70
+
71
+ function findPython() {
72
+ for (const cmd of ['python3', 'python']) {
73
+ try {
74
+ const ver = execSync(`${cmd} --version 2>&1`, { stdio: 'pipe' }).toString().trim();
75
+ const match = ver.match(/(\d+)\.(\d+)/);
76
+ if (match && parseInt(match[1]) >= 3 && parseInt(match[2]) >= 8) {
77
+ return cmd;
78
+ }
79
+ } catch {}
80
+ }
81
+ return null;
82
+ }
83
+
84
+ // ── Setup Command ──
85
+
86
+ function runSetup() {
87
+ const browser = findBrowser();
88
+ const profileDir = process.env.BROWSERCTL_PROFILE
89
+ || path.join(os.homedir(), '.browserctl', 'profile');
90
+ const port = process.env.CDP_PORT || '9222';
91
+
92
+ console.log('\n browserctl setup\n');
93
+ console.log(` Browser: ${browser || '❌ Not found'}`);
94
+ console.log(` Profile: ${profileDir}`);
95
+ console.log(` CDP Port: ${port}`);
96
+ console.log(` Python: ${findPython() || '❌ Not found'}`);
97
+
98
+ if (!browser) {
99
+ console.log('\n ❌ No compatible browser found.');
100
+ console.log(' Install Brave (recommended): https://brave.com/download/');
101
+ console.log(' Or Google Chrome: https://www.google.com/chrome/\n');
102
+ process.exit(1);
103
+ }
104
+
105
+ if (!findPython()) {
106
+ console.log('\n ❌ Python 3.8+ not found.');
107
+ console.log(' Install: https://www.python.org/downloads/\n');
108
+ process.exit(1);
109
+ }
110
+
111
+ // Create profile directory
112
+ if (!fs.existsSync(profileDir)) {
113
+ fs.mkdirSync(profileDir, { recursive: true });
114
+ console.log(`\n ✓ Created profile: ${profileDir}`);
115
+ } else {
116
+ console.log(`\n ✓ Profile exists: ${profileDir}`);
117
+ }
118
+
119
+ console.log(' ✓ Setup complete! Run: browserctl launch\n');
120
+ }
121
+
122
+ // ── Status Command ──
123
+
124
+ function runStatus() {
125
+ const port = process.env.CDP_PORT || '9222';
126
+ console.log(`\n browserctl status (port ${port})\n`);
127
+
128
+ try {
129
+ const http = require('http');
130
+ const req = http.get(`http://127.0.0.1:${port}/json/version`, { timeout: 2000 }, (res) => {
131
+ let data = '';
132
+ res.on('data', (chunk) => data += chunk);
133
+ res.on('end', () => {
134
+ try {
135
+ const info = JSON.parse(data);
136
+ console.log(` ✓ Connected`);
137
+ console.log(` Browser: ${info.Browser || 'Unknown'}`);
138
+ console.log(` Protocol: ${info['Protocol-Version'] || 'Unknown'}`);
139
+ console.log(` WebSocket: ${info.webSocketDebuggerUrl || 'N/A'}\n`);
140
+ } catch {
141
+ console.log(' ✓ CDP responding but version info unavailable\n');
142
+ }
143
+ });
144
+ });
145
+ req.on('error', () => {
146
+ console.log(' ❌ No browser connected on this port.');
147
+ console.log(' Run: browserctl launch\n');
148
+ });
149
+ req.on('timeout', () => {
150
+ req.destroy();
151
+ console.log(' ❌ Connection timeout.');
152
+ console.log(' Run: browserctl launch\n');
153
+ });
154
+ } catch {
155
+ console.log(' ❌ Could not check status.\n');
156
+ }
157
+ }
158
+
159
+ // ── Version ──
160
+
161
+ function showVersion() {
162
+ console.log(`browserctl v${VERSION}`);
163
+ }
164
+
165
+ // ── Help ──
166
+
167
+ function showHelp() {
168
+ console.log(`
169
+ browserctl v${VERSION} — Zero-dependency browser automation
170
+
171
+ USAGE
172
+ browserctl <command> [args]
173
+
174
+ SETUP
175
+ setup Auto-detect browser, create isolated profile
176
+ launch Start browser with CDP enabled
177
+ status Check browser connection
178
+ stop Stop browser
179
+
180
+ NAVIGATION
181
+ go <url> Navigate to URL
182
+ content Get page text content
183
+ html Get page HTML
184
+ shot [file] Take screenshot
185
+ pdf [file] Save page as PDF
186
+
187
+ INTERACTION
188
+ click <sel> Click element
189
+ type <sel> <text> Type into input
190
+ fill <sel> <val> Set input value (React-compatible)
191
+ submit <form> Submit form
192
+ hover <sel> Hover element
193
+ keys <combo> Keyboard shortcut
194
+
195
+ DEBUGGING
196
+ console [url] Capture console logs
197
+ network [url] Monitor network requests
198
+ debug [url] Full diagnostic
199
+ eval <js> Execute JavaScript
200
+
201
+ TABS
202
+ tabs List open tabs
203
+ new-tab [url] Open new tab
204
+ close-tab [id] Close tab
205
+
206
+ More: https://github.com/user/browserctl#commands
207
+ `);
208
+ }
209
+
210
+ // ── Main ──
211
+
212
+ const args = process.argv.slice(2);
213
+ const cmd = args[0];
214
+
215
+ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
216
+ showHelp();
217
+ process.exit(0);
218
+ }
219
+
220
+ if (cmd === '--version' || cmd === '-v') {
221
+ showVersion();
222
+ process.exit(0);
223
+ }
224
+
225
+ if (cmd === 'setup') {
226
+ runSetup();
227
+ process.exit(0);
228
+ }
229
+
230
+ if (cmd === 'status') {
231
+ runStatus();
232
+ // Don't exit immediately — let http callback complete
233
+ } else {
234
+ // Delegate to Python
235
+ const python = findPython();
236
+ if (!python) {
237
+ console.error('Error: Python 3.8+ required. Install: https://www.python.org/downloads/');
238
+ process.exit(1);
239
+ }
240
+
241
+ const browser = findBrowser();
242
+ const profileDir = process.env.BROWSERCTL_PROFILE
243
+ || path.join(os.homedir(), '.browserctl', 'profile');
244
+ const port = process.env.CDP_PORT || '9222';
245
+
246
+ const env = {
247
+ ...process.env,
248
+ CDP_PORT: port,
249
+ BROWSERCTL_PROFILE: profileDir,
250
+ };
251
+
252
+ if (browser && !process.env.CHROME_BIN) {
253
+ env.CHROME_BIN = browser;
254
+ }
255
+
256
+ const child = spawn(python, [SCRIPT, ...args], {
257
+ stdio: 'inherit',
258
+ env,
259
+ });
260
+
261
+ child.on('close', (code) => {
262
+ process.exit(code || 0);
263
+ });
264
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "cdpilot",
3
+ "version": "0.1.0",
4
+ "description": "Zero-dependency browser automation from your terminal. One command, full control.",
5
+ "bin": {
6
+ "bctl": "./bin/browserctl.js",
7
+ "browserctl": "./bin/browserctl.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node test/test.js",
11
+ "start": "node bin/browserctl.js"
12
+ },
13
+ "keywords": [
14
+ "browser",
15
+ "automation",
16
+ "cdp",
17
+ "chrome-devtools-protocol",
18
+ "cli",
19
+ "devtools",
20
+ "headless",
21
+ "screenshot",
22
+ "testing",
23
+ "web-scraping",
24
+ "ai-agent",
25
+ "mcp",
26
+ "claude",
27
+ "brave"
28
+ ],
29
+ "author": "",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/user/browserctl"
34
+ },
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ },
38
+ "files": [
39
+ "bin/",
40
+ "src/",
41
+ "README.md",
42
+ "LICENSE"
43
+ ]
44
+ }