cdpilot 0.9.0 → 0.9.2
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 +61 -21
- package/bin/cdpilot.js +35 -6
- package/package.json +7 -3
- package/src/cdpilot.py +853 -118
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ npx cdpilot <command>
|
|
|
76
76
|
npm i -g cdpilot
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
**Requirements:** Node.js 18
|
|
79
|
+
**Requirements:** Node.js 18+, Python 3.10+, and one of: Brave Browser, Google Chrome, or Chromium. (The Python `websockets` module is auto-installed by the pre-flight wizard on first launch.)
|
|
80
80
|
|
|
81
81
|
### First-time setup
|
|
82
82
|
|
|
@@ -124,7 +124,7 @@ See [CHANGELOG.md](CHANGELOG.md) for the full list with rationale.
|
|
|
124
124
|
### Navigation & Content
|
|
125
125
|
|
|
126
126
|
```bash
|
|
127
|
-
cdpilot go <url> # Navigate to URL
|
|
127
|
+
cdpilot go <url> # Navigate to URL (alias: open <url>)
|
|
128
128
|
cdpilot content # Get page text content
|
|
129
129
|
cdpilot html # Get page HTML
|
|
130
130
|
cdpilot shot [file] # Take screenshot (PNG)
|
|
@@ -537,11 +537,26 @@ cdpilot profile warm # age the profile for reCAPTCHA v3 score
|
|
|
537
537
|
which nudges reCAPTCHA v3's behavioral score upward over time. Slow by
|
|
538
538
|
design — run it ahead of a session, not inline.
|
|
539
539
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
540
|
+
Public bot-detection panels, measured 2026-09-27, **headless** Brave (Chrome 154)
|
|
541
|
+
([method and raw results](.claude/docs/stealth-panel-olcumu-2026-09-27.md)):
|
|
542
|
+
|
|
543
|
+
| `mode` | bot.sannysoft.com (31 rows) | incolumitas intoli | incolumitas fpscanner | incolumitas new-tests |
|
|
544
|
+
|---|---|---|---|---|
|
|
545
|
+
| `regular` (no patches, default) | 28 pass / 3 fail | 5/6 | 17 ok / 3 fail / 1 warn | all ok |
|
|
546
|
+
| `stealth` | 31 pass | 6/6 | 19 ok / 1 fail / 1 warn | all ok |
|
|
547
|
+
| `undetected` | 31 pass | 6/6 | 19 ok / 1 fail / 1 warn | all ok |
|
|
548
|
+
|
|
549
|
+
- The remaining fpscanner fail is `'webdriver' in navigator`, which is true in every modern
|
|
550
|
+
Chrome; faking it away would make cdpilot the odd one out.
|
|
551
|
+
- `regular`'s fails all come from the `HeadlessChrome` user agent. `stealth`/`undetected`
|
|
552
|
+
rewrite it for the page load that `go` starts; a later, separate command in the same page
|
|
553
|
+
can still read `HeadlessChrome`.
|
|
554
|
+
- new-tests: every key is ok; `connectionRTT` is reported as unknown in all tiers.
|
|
555
|
+
- nowsecure.nl and areyouheadless could not be measured (a fixed always-interactive
|
|
556
|
+
Turnstile test key; HTTP 502).
|
|
557
|
+
|
|
558
|
+
Earlier figures on this page (sannysoft 24/24, intoli 6/6) were measured on v0.4.x in April
|
|
559
|
+
2026; they are replaced by the table above.
|
|
545
560
|
|
|
546
561
|
### Reliability
|
|
547
562
|
|
|
@@ -559,23 +574,45 @@ until cdpilot health >/dev/null; do cdpilot launch; sleep 2; done
|
|
|
559
574
|
Surfaces today's Brave crash count from `~/Library/Logs/DiagnosticReports/`
|
|
560
575
|
on macOS — spot degradation before your automation silently stalls.
|
|
561
576
|
|
|
577
|
+
**Auto-launch.** A page command (`go`, `content`, `click`, `shot`, …) that finds
|
|
578
|
+
the browser not running starts it the same way `cdpilot launch` does (same
|
|
579
|
+
profile, same headless/visible setting), then carries on, printing one line to
|
|
580
|
+
stderr: `cdpilot: browser was not running — launched it (CDPILOT_NO_AUTOLAUNCH=1 to disable)`.
|
|
581
|
+
Lifecycle, status and configuration commands (`launch`, `stop`, `close`,
|
|
582
|
+
`close-tab`, `stop-all`, `project-stop`, `session-close`, `status`, `health`,
|
|
583
|
+
`tabs`, `sessions`, `projects`, `headless`, `proxy`, `browser`, `extensions`,
|
|
584
|
+
`mcp`, `serve`, …) never launch. `CDPILOT_NO_AUTOLAUNCH=1` restores the old
|
|
585
|
+
"CDP connection error. Is the browser running?" error and exit code 1.
|
|
586
|
+
|
|
587
|
+
**Timeouts.** Any command takes `--timeout <seconds>`, before or after the
|
|
588
|
+
command name, or a default from `CDPILOT_TIMEOUT` (the flag wins; `0`
|
|
589
|
+
disables). It bounds the whole command's wall-clock: on expiry cdpilot prints
|
|
590
|
+
`cdpilot: timed out after <N>s (<command>)` to stderr, kills the child processes
|
|
591
|
+
it started and exits with code **124** (like GNU `timeout`). A browser that was
|
|
592
|
+
already up and registered is left running.
|
|
593
|
+
|
|
594
|
+
```bash
|
|
595
|
+
cdpilot --timeout 10 click "#submit" # before the command...
|
|
596
|
+
cdpilot shot page.png --timeout 30 # ...or after it
|
|
597
|
+
CDPILOT_TIMEOUT=60 cdpilot run flow.cdp # default for every command (and each script line)
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
For `mcp` and `serve` the value is not applied to the long-running server
|
|
601
|
+
itself; it is passed on to every tool call / request it runs.
|
|
602
|
+
|
|
562
603
|
### Scaling & Workstation Use
|
|
563
604
|
|
|
564
605
|
```bash
|
|
565
|
-
CDPILOT_POOL_SIZE=4 cdpilot launch # 4 separate browser processes
|
|
566
606
|
CDPILOT_OFFSCREEN=1 cdpilot launch # headed, but no window on your screen
|
|
567
607
|
```
|
|
568
608
|
|
|
569
|
-
- **Multi-instance pool** (`CDPILOT_POOL_SIZE=N`) starts N independent browser
|
|
570
|
-
processes and dispatches work to the least-loaded one, for `N × per-instance`
|
|
571
|
-
parallelism. Default is `1` — single instance, no change for existing users.
|
|
572
609
|
- **Off-screen mode** (`CDPILOT_OFFSCREEN=1`) keeps the browser headed (real
|
|
573
610
|
rendering, no headless fingerprint) but positions the window where it can't
|
|
574
611
|
steal focus — meant for automating on a workstation you're also using.
|
|
575
|
-
- **
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
612
|
+
- **Multi-instance pool** (`CDPILOT_POOL_SIZE`) — planned, not shipped yet.
|
|
613
|
+
See [Roadmap](#coming-soon).
|
|
614
|
+
- **Docker + Xvfb harness** — used in a separate, private benchmark
|
|
615
|
+
repo (`cdpilot-bench`), not part of this package.
|
|
579
616
|
|
|
580
617
|
## Use with AI Agents
|
|
581
618
|
|
|
@@ -624,7 +661,8 @@ print(result.stdout)
|
|
|
624
661
|
| `BROWSER_SESSION` | Auto | Session identifier |
|
|
625
662
|
| `CDPILOT_MODE` | `regular` | Stealth tier override (`regular`/`stealth`/`undetected`) |
|
|
626
663
|
| `CDPILOT_OFFSCREEN` | `0` | Headed but render off-screen — no window steals focus |
|
|
627
|
-
| `
|
|
664
|
+
| `CDPILOT_TIMEOUT` | unset | Default `--timeout` in seconds for every command (flag wins, `0` disables); expiry exits 124 |
|
|
665
|
+
| `CDPILOT_NO_AUTOLAUNCH` | `0` | `1` = page commands fail with the old "Is the browser running?" error instead of launching the browser |
|
|
628
666
|
|
|
629
667
|
## How It Works
|
|
630
668
|
|
|
@@ -636,7 +674,7 @@ print(result.stdout)
|
|
|
636
674
|
│ │
|
|
637
675
|
│ Zero dependencies │ Isolated profile
|
|
638
676
|
│ Pure HTTP + WebSocket │ Separate from your
|
|
639
|
-
│
|
|
677
|
+
│ single file, stdlib + websockets │ personal browser
|
|
640
678
|
└────────────────────────────────────────┘
|
|
641
679
|
```
|
|
642
680
|
|
|
@@ -694,8 +732,8 @@ The full adaptive layer is bench-neutral vs baseline (30/80 vs 30/80) for Stealt
|
|
|
694
732
|
|
|
695
733
|
| Feature | cdpilot | Puppeteer | Playwright | Selenium |
|
|
696
734
|
|---------|-----------|-----------|------------|----------|
|
|
697
|
-
| Install size |
|
|
698
|
-
| Dependencies | **0** | 50+ | 30+ | Java + drivers |
|
|
735
|
+
| Install size | **one Python file + a small Node launcher, no node_modules** | 400MB+ | 200MB+ | 100MB+ |
|
|
736
|
+
| Dependencies | **0 npm** (Python: `websockets`, auto-installed) | 50+ | 30+ | Java + drivers |
|
|
699
737
|
| Setup time | **instant** | minutes | minutes | painful |
|
|
700
738
|
| AI-agent ready | **yes** | manual | manual | manual |
|
|
701
739
|
| Browser download | **no** | yes (Chromium) | yes (3 browsers) | no |
|
|
@@ -753,7 +791,8 @@ The only browser MCP with built-in test assertions. Here's what we've shipped an
|
|
|
753
791
|
- [x] 70+ CLI commands (navigate, click, fill, screenshot, PDF, console, network, video understanding, friction ladder...)
|
|
754
792
|
- [x] MCP server for AI agent integration (Claude Code, Cursor, etc.)
|
|
755
793
|
- [x] **10 built-in test assertions** — assert, assert-url, assert-title, assert-count, assert-value, assert-attr, assert-visible/hidden, wait-for, check (batch), screenshot-diff
|
|
756
|
-
- [x]
|
|
794
|
+
- [x] **`test` runner + `trace` viewer** — `cdpilot test [--watch]` runs `*.cdpt.js` files; `cdpilot trace open <run>` opens a time-travel trace viewer for a run
|
|
795
|
+
- [x] **Accessibility tree snapshot** (`a11y-snapshot`) — structured text with @ref handles the agent can act on directly, no vision model needed; 1.4–42× smaller than the page's raw HTML on the four pages we measured (2026-09-27). Not always cheaper than a screenshot: link-heavy pages produce more text than a small screenshot costs
|
|
757
796
|
- [x] **Token-efficient screenshots** — element-level crop (13x smaller), JPEG quality control, format selection
|
|
758
797
|
- [x] **Vision fallback** (`describe`) — a11y + screenshot + text in one call
|
|
759
798
|
- [x] **Annotated screenshots** — @N badge overlays on interactive elements
|
|
@@ -780,7 +819,7 @@ The only browser MCP with built-in test assertions. Here's what we've shipped an
|
|
|
780
819
|
- [x] **Three-tier stealth mode** (`mode regular|stealth|undetected`) — single switch over fingerprint surface, with per-host adaptive tier learning
|
|
781
820
|
- [x] **Press-and-hold solver** (`press-hold`) — humanized press → hold → release gesture (Gaussian 3–7s + micro-jitter) for PerimeterX/HUMAN behavioral challenges; `captcha-solve` auto-routes here
|
|
782
821
|
- [x] **Image CAPTCHA + profile warming** — offline Amazon image OCR (optional `amazoncaptcha` lib) + BYOK image-to-text (capsolver/2captcha); `profile warm` ages the profile for reCAPTCHA v3 score
|
|
783
|
-
- [x] **
|
|
822
|
+
- [x] **Off-screen mode** (`CDPILOT_OFFSCREEN`) — headed rendering without stealing window focus
|
|
784
823
|
- [x] **Data extraction** (`extract`) — structured DOM data in text, JSON, or list format
|
|
785
824
|
- [x] **Page observation** (`observe`) — list all interactive elements with available actions
|
|
786
825
|
- [x] **Script runner** (`run`) — execute `.cdp` script files with pass/fail reporting
|
|
@@ -788,6 +827,7 @@ The only browser MCP with built-in test assertions. Here's what we've shipped an
|
|
|
788
827
|
### Coming Soon
|
|
789
828
|
|
|
790
829
|
- [ ] **iframe** support — interact with elements inside iframes (Shadow DOM traversal already shipped in smart commands)
|
|
830
|
+
- [ ] **Multi-instance pool** (`CDPILOT_POOL_SIZE`) — N independent browser processes with least-loaded dispatch
|
|
791
831
|
- [ ] **Session recording & replay** — record browser sessions and replay them deterministically
|
|
792
832
|
- [ ] **Stealth mode** *(Pro)* — human-like mouse/typing, anti-fingerprint, CAPTCHA solving
|
|
793
833
|
- [ ] **cdpilot Cloud** — hosted browser sessions API, REST + WebSocket MCP endpoint
|
package/bin/cdpilot.js
CHANGED
|
@@ -321,7 +321,14 @@ function showHelp() {
|
|
|
321
321
|
cdpilot v${VERSION} — Zero-dependency browser automation
|
|
322
322
|
|
|
323
323
|
USAGE
|
|
324
|
-
cdpilot <command> [args]
|
|
324
|
+
cdpilot [--timeout <s>] <command> [args]
|
|
325
|
+
|
|
326
|
+
GLOBAL OPTIONS
|
|
327
|
+
--timeout <s> Abort the command after <s> seconds (exit 124). Before or
|
|
328
|
+
after the command; env CDPILOT_TIMEOUT sets a default
|
|
329
|
+
(the flag wins, 0 disables).
|
|
330
|
+
Page commands start the browser if it is not running
|
|
331
|
+
(set CDPILOT_NO_AUTOLAUNCH=1 to get an error instead).
|
|
325
332
|
|
|
326
333
|
SETUP
|
|
327
334
|
setup Auto-detect browser, create isolated profile
|
|
@@ -332,7 +339,7 @@ function showHelp() {
|
|
|
332
339
|
if no user tabs remain (--force quits anyway, --keep never quits)
|
|
333
340
|
|
|
334
341
|
NAVIGATION
|
|
335
|
-
go <url> Navigate to URL
|
|
342
|
+
go <url> Navigate to URL (alias: open)
|
|
336
343
|
content Get page text content
|
|
337
344
|
html Get page HTML
|
|
338
345
|
shot [file] Take screenshot
|
|
@@ -590,8 +597,23 @@ if (process.argv.includes('--internal-test-runner')) {
|
|
|
590
597
|
return; // runAll() is async, this exits via process.exit
|
|
591
598
|
}
|
|
592
599
|
|
|
600
|
+
// Global flags may precede the command name (`cdpilot --timeout 10 click "#x"`).
|
|
601
|
+
// src/cdpilot.py parses and validates them (it is also run directly, without
|
|
602
|
+
// this launcher); here they only have to be skipped to find the command that
|
|
603
|
+
// the launcher answers itself (help / --version / setup / status). args are
|
|
604
|
+
// passed to Python unchanged.
|
|
605
|
+
function commandIndex(argv) {
|
|
606
|
+
let i = 0;
|
|
607
|
+
while (i < argv.length) {
|
|
608
|
+
if (argv[i] === '--timeout') { i += 2; continue; }
|
|
609
|
+
if (argv[i].startsWith('--timeout=')) { i += 1; continue; }
|
|
610
|
+
break;
|
|
611
|
+
}
|
|
612
|
+
return i;
|
|
613
|
+
}
|
|
614
|
+
|
|
593
615
|
const args = process.argv.slice(2);
|
|
594
|
-
const cmd = args[
|
|
616
|
+
const cmd = args[commandIndex(args)];
|
|
595
617
|
|
|
596
618
|
if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
597
619
|
showHelp();
|
|
@@ -620,7 +642,7 @@ if (cmd === 'status') {
|
|
|
620
642
|
// Delegate to Python
|
|
621
643
|
const python = findPython();
|
|
622
644
|
if (!python) {
|
|
623
|
-
console.error('Error: Python 3.
|
|
645
|
+
console.error('Error: Python 3.10+ required. Install: https://www.python.org/downloads/');
|
|
624
646
|
process.exit(1);
|
|
625
647
|
}
|
|
626
648
|
|
|
@@ -650,7 +672,14 @@ if (cmd === 'status') {
|
|
|
650
672
|
env,
|
|
651
673
|
});
|
|
652
674
|
|
|
653
|
-
child.
|
|
654
|
-
|
|
675
|
+
// A child killed by a signal reports code === null. `code || 0` turned that
|
|
676
|
+
// into success, so an OOM-killed or SIGKILLed run looked fine to scripts
|
|
677
|
+
// and agents. Use the shell convention 128 + signal number instead.
|
|
678
|
+
child.on('close', (code, signal) => {
|
|
679
|
+
if (code === null && signal) {
|
|
680
|
+
console.error(`cdpilot: python was terminated by ${signal}`);
|
|
681
|
+
process.exit(128 + (os.constants.signals[signal] || 0));
|
|
682
|
+
}
|
|
683
|
+
process.exit(code ?? 0);
|
|
655
684
|
});
|
|
656
685
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cdpilot",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
|
+
"mcpName": "io.github.mehmetnadir/cdpilot",
|
|
4
5
|
"description": "Zero-dependency browser automation CLI. Raw CDP, 70+ commands, friction ladder, 3-tier stealth, CAPTCHA + press-and-hold solvers, proxy pools, MCP server. No Puppeteer/Playwright/Selenium.",
|
|
5
6
|
"bin": {
|
|
6
7
|
"cdpilot": "./bin/cdpilot.js",
|
|
@@ -48,15 +49,18 @@
|
|
|
48
49
|
"shadow-dom",
|
|
49
50
|
"perimeterx",
|
|
50
51
|
"press-and-hold",
|
|
51
|
-
"progressive-resilience"
|
|
52
|
-
"multi-instance"
|
|
52
|
+
"progressive-resilience"
|
|
53
53
|
],
|
|
54
54
|
"author": "Mehmet Nadir",
|
|
55
55
|
"license": "MIT",
|
|
56
|
+
"homepage": "https://cdpilot.ndr.ist",
|
|
56
57
|
"repository": {
|
|
57
58
|
"type": "git",
|
|
58
59
|
"url": "https://github.com/mehmetnadir/cdpilot"
|
|
59
60
|
},
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/mehmetnadir/cdpilot/issues"
|
|
63
|
+
},
|
|
60
64
|
"engines": {
|
|
61
65
|
"node": ">=18.0.0"
|
|
62
66
|
},
|