browser-tools 0.1.0__tar.gz
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.
- browser_tools-0.1.0/.gitignore +29 -0
- browser_tools-0.1.0/LICENSE +21 -0
- browser_tools-0.1.0/PKG-INFO +153 -0
- browser_tools-0.1.0/README.md +121 -0
- browser_tools-0.1.0/pyproject.toml +107 -0
- browser_tools-0.1.0/src/browser_tools/__init__.py +22 -0
- browser_tools-0.1.0/src/browser_tools/attach_chrome.sh +124 -0
- browser_tools-0.1.0/src/browser_tools/browser_state.py +157 -0
- browser_tools-0.1.0/src/browser_tools/browser_tools_session.py +1132 -0
- browser_tools-0.1.0/src/browser_tools/camoufox_session.py +332 -0
- browser_tools-0.1.0/src/browser_tools/cdp_client.py +253 -0
- browser_tools-0.1.0/src/browser_tools/cdp_constants.py +152 -0
- browser_tools-0.1.0/src/browser_tools/cdp_handler.py +1555 -0
- browser_tools-0.1.0/src/browser_tools/chrome_config.py +415 -0
- browser_tools-0.1.0/src/browser_tools/chrome_utils.py +559 -0
- browser_tools-0.1.0/src/browser_tools/daemon_client.py +125 -0
- browser_tools-0.1.0/src/browser_tools/detect_interstitial.js +267 -0
- browser_tools-0.1.0/src/browser_tools/frame_manager.py +408 -0
- browser_tools-0.1.0/src/browser_tools/interstitial.py +202 -0
- browser_tools-0.1.0/src/browser_tools/mcp_daemon.py +753 -0
- browser_tools-0.1.0/src/browser_tools/mcp_session.py +202 -0
- browser_tools-0.1.0/src/browser_tools/persistent-session-template.mjs +132 -0
- browser_tools-0.1.0/src/browser_tools/persistent_browser.py +1309 -0
- browser_tools-0.1.0/src/browser_tools/process_utils.py +373 -0
- browser_tools-0.1.0/src/browser_tools/profiler.py +289 -0
- browser_tools-0.1.0/src/browser_tools/screenshot_utils.py +126 -0
- browser_tools-0.1.0/src/browser_tools/stealth.js +179 -0
- browser_tools-0.1.0/tests/conftest.py +95 -0
- browser_tools-0.1.0/tests/test_attach_browser.py +706 -0
- browser_tools-0.1.0/tests/test_browser_tools.py +418 -0
- browser_tools-0.1.0/tests/test_camoufox.py +257 -0
- browser_tools-0.1.0/tests/test_cdp_client.py +359 -0
- browser_tools-0.1.0/tests/test_e2e_camoufox.py +118 -0
- browser_tools-0.1.0/tests/test_frame_manager.py +293 -0
- browser_tools-0.1.0/tests/test_inspect_mode.py +141 -0
- browser_tools-0.1.0/tests/test_interstitial.py +490 -0
- browser_tools-0.1.0/tests/test_mcp_daemon.py +228 -0
- browser_tools-0.1.0/tests/test_new_tools.py +864 -0
- browser_tools-0.1.0/tests/test_persistent_browser.py +499 -0
- browser_tools-0.1.0/tests/test_profiles.py +186 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
*.egg
|
|
7
|
+
|
|
8
|
+
# Virtual environments
|
|
9
|
+
.venv/
|
|
10
|
+
venv/
|
|
11
|
+
|
|
12
|
+
# Test / coverage
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
htmlcov/
|
|
16
|
+
|
|
17
|
+
# Ruff
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
|
|
20
|
+
# IDE
|
|
21
|
+
.vscode/
|
|
22
|
+
.idea/
|
|
23
|
+
|
|
24
|
+
# OS
|
|
25
|
+
.DS_Store
|
|
26
|
+
Thumbs.db
|
|
27
|
+
|
|
28
|
+
# Build
|
|
29
|
+
*.whl
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Browser Tools 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.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: browser-tools
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Browser automation, debugging, and anti-detect browsing CLI
|
|
5
|
+
Project-URL: Homepage, https://github.com/dungle-scrubs/browser-tools
|
|
6
|
+
Project-URL: Repository, https://github.com/dungle-scrubs/browser-tools
|
|
7
|
+
Project-URL: Issues, https://github.com/dungle-scrubs/browser-tools/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/dungle-scrubs/browser-tools/blob/main/CHANGELOG.md
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: anti-detect,browser-automation,camoufox,cdp,chrome-devtools,mcp,playwright,web-scraping
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: MacOS
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: Software Development :: Testing
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.13
|
|
27
|
+
Requires-Dist: aiohttp>=3.14.1
|
|
28
|
+
Requires-Dist: camoufox[geoip]>=0.4.11
|
|
29
|
+
Requires-Dist: pillow>=10.0.0
|
|
30
|
+
Requires-Dist: websockets>=14.0
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# Browser Tools
|
|
34
|
+
|
|
35
|
+
[](https://github.com/dungle-scrubs/browser-tools/actions/workflows/ci.yml)
|
|
36
|
+
[](https://www.python.org/downloads/)
|
|
37
|
+
[](https://opensource.org/licenses/MIT)
|
|
38
|
+
[](https://docs.astral.sh/ruff/)
|
|
39
|
+
|
|
40
|
+
Browser automation, debugging, and anti-detect browsing CLI. Provides:
|
|
41
|
+
|
|
42
|
+
- **Chrome DevTools MCP wrapper** — Snapshot-based page automation via
|
|
43
|
+
[chrome-devtools-mcp](https://github.com/anthropics/chrome-devtools-mcp)
|
|
44
|
+
- **Persistent browser sessions** — Long-lived Chrome instances with named profiles,
|
|
45
|
+
daemon-based MCP reuse, and attach-to-running-browser support
|
|
46
|
+
- **Frame-aware tools** — Iframe/CDP frame tree management, execution context
|
|
47
|
+
resolution, and storage inspection
|
|
48
|
+
- **Interstitial detection** — Multi-signal heuristic detection for Cloudflare,
|
|
49
|
+
DataDome, Akamai, PerimeterX, Imperva, AWS WAF, and other challenge pages
|
|
50
|
+
- **Camoufox anti-detect browsing** — Fingerprint-injected Firefox-based
|
|
51
|
+
browsing for bot-protected sites
|
|
52
|
+
- **CPU profiling** — Direct CDP-based JavaScript CPU profiling with
|
|
53
|
+
threshold-triggered capture
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
### Installation
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Using uv (recommended)
|
|
61
|
+
uv tool install browser-tools
|
|
62
|
+
|
|
63
|
+
# Or with pip
|
|
64
|
+
pip install browser-tools
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Usage
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Run the CLI
|
|
71
|
+
browser-tools --help
|
|
72
|
+
|
|
73
|
+
# Take a snapshot of a page
|
|
74
|
+
browser-tools --headless navigate --url https://example.com
|
|
75
|
+
browser-tools --headless take-snapshot
|
|
76
|
+
|
|
77
|
+
# Use a persistent profile
|
|
78
|
+
browser-tools --profile dev navigate --url https://example.com
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Development setup
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Clone and install in editable mode
|
|
85
|
+
git clone https://github.com/dungle-scrubs/browser-tools.git
|
|
86
|
+
cd browser-tools
|
|
87
|
+
uv sync
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Runtime requirements:
|
|
91
|
+
|
|
92
|
+
- **Chrome** or **Chrome Canary** for DevTools automation
|
|
93
|
+
- **Node.js** (>=18) for `chrome-devtools-mcp`
|
|
94
|
+
- **Camoufox** (`camoufox fetch`) for anti-detect Firefox workflows
|
|
95
|
+
|
|
96
|
+
## Architecture
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
browser_tools_session.py CLI entry point
|
|
100
|
+
|
|
|
101
|
+
+-- chrome_config.py Tool schemas & validation
|
|
102
|
+
+-- chrome_utils.py MCP subprocess invocation, formatting
|
|
103
|
+
+-- persistent_browser.py Chrome lifecycle, daemon, profiles
|
|
104
|
+
| +-- browser_state.py Persisted state dataclasses
|
|
105
|
+
| +-- mcp_session.py Short-lived MCP session wrapper
|
|
106
|
+
| +-- daemon_client.py Unix socket client
|
|
107
|
+
| +-- process_utils.py Chrome process/port utilities
|
|
108
|
+
| +-- mcp_daemon.py Long-lived MCP daemon
|
|
109
|
+
| +-- cdp_handler.py CDP tool implementations
|
|
110
|
+
| +-- cdp_constants.py CDP toolset definitions
|
|
111
|
+
| +-- cdp_client.py CDP WebSocket client
|
|
112
|
+
| +-- frame_manager.py Frame tree management
|
|
113
|
+
| +-- interstitial.py Challenge detection
|
|
114
|
+
| +-- screenshot_utils.py Blank-frame detection
|
|
115
|
+
+-- camoufox_session.py Camoufox anti-detect wrapper
|
|
116
|
+
+-- profiler.py Standalone CPU profiler
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Development
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
uv sync
|
|
123
|
+
uv run ruff check src/ tests/
|
|
124
|
+
uv run pytest
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Project Configuration
|
|
128
|
+
|
|
129
|
+
Place a `.browser-tools.json` in your project root:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"preferredSession": {
|
|
134
|
+
"mode": "headed-auth",
|
|
135
|
+
"profile": "dev"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This auto-selects a persistent headed browser session using the named profile.
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT — see [LICENSE](LICENSE).
|
|
145
|
+
|
|
146
|
+
## Contributing
|
|
147
|
+
|
|
148
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
|
|
149
|
+
All contributors are expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
150
|
+
|
|
151
|
+
## Security
|
|
152
|
+
|
|
153
|
+
Found a vulnerability? See [SECURITY.md](SECURITY.md) for responsible disclosure.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Browser Tools
|
|
2
|
+
|
|
3
|
+
[](https://github.com/dungle-scrubs/browser-tools/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://docs.astral.sh/ruff/)
|
|
7
|
+
|
|
8
|
+
Browser automation, debugging, and anti-detect browsing CLI. Provides:
|
|
9
|
+
|
|
10
|
+
- **Chrome DevTools MCP wrapper** — Snapshot-based page automation via
|
|
11
|
+
[chrome-devtools-mcp](https://github.com/anthropics/chrome-devtools-mcp)
|
|
12
|
+
- **Persistent browser sessions** — Long-lived Chrome instances with named profiles,
|
|
13
|
+
daemon-based MCP reuse, and attach-to-running-browser support
|
|
14
|
+
- **Frame-aware tools** — Iframe/CDP frame tree management, execution context
|
|
15
|
+
resolution, and storage inspection
|
|
16
|
+
- **Interstitial detection** — Multi-signal heuristic detection for Cloudflare,
|
|
17
|
+
DataDome, Akamai, PerimeterX, Imperva, AWS WAF, and other challenge pages
|
|
18
|
+
- **Camoufox anti-detect browsing** — Fingerprint-injected Firefox-based
|
|
19
|
+
browsing for bot-protected sites
|
|
20
|
+
- **CPU profiling** — Direct CDP-based JavaScript CPU profiling with
|
|
21
|
+
threshold-triggered capture
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Using uv (recommended)
|
|
29
|
+
uv tool install browser-tools
|
|
30
|
+
|
|
31
|
+
# Or with pip
|
|
32
|
+
pip install browser-tools
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Usage
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Run the CLI
|
|
39
|
+
browser-tools --help
|
|
40
|
+
|
|
41
|
+
# Take a snapshot of a page
|
|
42
|
+
browser-tools --headless navigate --url https://example.com
|
|
43
|
+
browser-tools --headless take-snapshot
|
|
44
|
+
|
|
45
|
+
# Use a persistent profile
|
|
46
|
+
browser-tools --profile dev navigate --url https://example.com
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Development setup
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Clone and install in editable mode
|
|
53
|
+
git clone https://github.com/dungle-scrubs/browser-tools.git
|
|
54
|
+
cd browser-tools
|
|
55
|
+
uv sync
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Runtime requirements:
|
|
59
|
+
|
|
60
|
+
- **Chrome** or **Chrome Canary** for DevTools automation
|
|
61
|
+
- **Node.js** (>=18) for `chrome-devtools-mcp`
|
|
62
|
+
- **Camoufox** (`camoufox fetch`) for anti-detect Firefox workflows
|
|
63
|
+
|
|
64
|
+
## Architecture
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
browser_tools_session.py CLI entry point
|
|
68
|
+
|
|
|
69
|
+
+-- chrome_config.py Tool schemas & validation
|
|
70
|
+
+-- chrome_utils.py MCP subprocess invocation, formatting
|
|
71
|
+
+-- persistent_browser.py Chrome lifecycle, daemon, profiles
|
|
72
|
+
| +-- browser_state.py Persisted state dataclasses
|
|
73
|
+
| +-- mcp_session.py Short-lived MCP session wrapper
|
|
74
|
+
| +-- daemon_client.py Unix socket client
|
|
75
|
+
| +-- process_utils.py Chrome process/port utilities
|
|
76
|
+
| +-- mcp_daemon.py Long-lived MCP daemon
|
|
77
|
+
| +-- cdp_handler.py CDP tool implementations
|
|
78
|
+
| +-- cdp_constants.py CDP toolset definitions
|
|
79
|
+
| +-- cdp_client.py CDP WebSocket client
|
|
80
|
+
| +-- frame_manager.py Frame tree management
|
|
81
|
+
| +-- interstitial.py Challenge detection
|
|
82
|
+
| +-- screenshot_utils.py Blank-frame detection
|
|
83
|
+
+-- camoufox_session.py Camoufox anti-detect wrapper
|
|
84
|
+
+-- profiler.py Standalone CPU profiler
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Development
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv sync
|
|
91
|
+
uv run ruff check src/ tests/
|
|
92
|
+
uv run pytest
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Project Configuration
|
|
96
|
+
|
|
97
|
+
Place a `.browser-tools.json` in your project root:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"preferredSession": {
|
|
102
|
+
"mode": "headed-auth",
|
|
103
|
+
"profile": "dev"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
This auto-selects a persistent headed browser session using the named profile.
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT — see [LICENSE](LICENSE).
|
|
113
|
+
|
|
114
|
+
## Contributing
|
|
115
|
+
|
|
116
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
|
|
117
|
+
All contributors are expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
118
|
+
|
|
119
|
+
## Security
|
|
120
|
+
|
|
121
|
+
Found a vulnerability? See [SECURITY.md](SECURITY.md) for responsible disclosure.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "browser-tools"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Browser automation, debugging, and anti-detect browsing CLI"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
requires-python = ">=3.13"
|
|
8
|
+
keywords = [
|
|
9
|
+
"browser-automation",
|
|
10
|
+
"chrome-devtools",
|
|
11
|
+
"cdp",
|
|
12
|
+
"anti-detect",
|
|
13
|
+
"camoufox",
|
|
14
|
+
"playwright",
|
|
15
|
+
"web-scraping",
|
|
16
|
+
"mcp",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Environment :: Console",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Operating System :: MacOS",
|
|
24
|
+
"Operating System :: POSIX :: Linux",
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
28
|
+
"Topic :: Internet :: WWW/HTTP :: Browsers",
|
|
29
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
30
|
+
"Topic :: Software Development :: Testing",
|
|
31
|
+
"Topic :: Utilities",
|
|
32
|
+
"Typing :: Typed",
|
|
33
|
+
]
|
|
34
|
+
dependencies = [
|
|
35
|
+
"camoufox[geoip]>=0.4.11",
|
|
36
|
+
"pillow>=10.0.0",
|
|
37
|
+
"websockets>=14.0",
|
|
38
|
+
# Security overrides for transitive dependencies.
|
|
39
|
+
# camoufox pulls in aiohttp 3.13.x which has 11 known CVEs (PYSEC-2026-237, etc.).
|
|
40
|
+
# Force >=3.14.1 until camoufox updates its own pin.
|
|
41
|
+
"aiohttp>=3.14.1",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/dungle-scrubs/browser-tools"
|
|
46
|
+
Repository = "https://github.com/dungle-scrubs/browser-tools"
|
|
47
|
+
Issues = "https://github.com/dungle-scrubs/browser-tools/issues"
|
|
48
|
+
Changelog = "https://github.com/dungle-scrubs/browser-tools/blob/main/CHANGELOG.md"
|
|
49
|
+
|
|
50
|
+
[project.scripts]
|
|
51
|
+
browser-tools = "browser_tools.browser_tools_session:main"
|
|
52
|
+
browser-tools-profiler = "browser_tools.profiler:main"
|
|
53
|
+
|
|
54
|
+
[build-system]
|
|
55
|
+
requires = ["hatchling"]
|
|
56
|
+
build-backend = "hatchling.build"
|
|
57
|
+
|
|
58
|
+
[tool.hatch.build.targets.wheel]
|
|
59
|
+
packages = ["src/browser_tools"]
|
|
60
|
+
artifacts = [
|
|
61
|
+
"src/browser_tools/*.js",
|
|
62
|
+
"src/browser_tools/*.mjs",
|
|
63
|
+
"src/browser_tools/*.sh",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[tool.hatch.build.targets.sdist]
|
|
67
|
+
include = [
|
|
68
|
+
"src/browser_tools",
|
|
69
|
+
"tests",
|
|
70
|
+
"README.md",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[dependency-groups]
|
|
74
|
+
dev = [
|
|
75
|
+
"pyright>=1.1.0",
|
|
76
|
+
"pytest>=8.0.0",
|
|
77
|
+
"pytest-asyncio>=1.3.0",
|
|
78
|
+
"ruff>=0.8.0",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
[tool.pyright]
|
|
82
|
+
typeCheckingMode = "strict"
|
|
83
|
+
pythonVersion = "3.13"
|
|
84
|
+
reportMissingTypeStubs = false
|
|
85
|
+
reportUnknownMemberType = false
|
|
86
|
+
reportUnknownArgumentType = false
|
|
87
|
+
reportUnknownVariableType = false
|
|
88
|
+
reportUnknownParameterType = false
|
|
89
|
+
|
|
90
|
+
[tool.ruff]
|
|
91
|
+
line-length = 100
|
|
92
|
+
target-version = "py313"
|
|
93
|
+
|
|
94
|
+
[tool.ruff.lint]
|
|
95
|
+
select = [
|
|
96
|
+
"E", "W", "F", "I", # pycodestyle + pyflakes + isort
|
|
97
|
+
"B", # flake8-bugbear
|
|
98
|
+
"C4", # flake8-comprehensions
|
|
99
|
+
"RUF", # ruff-specific rules
|
|
100
|
+
"SIM", # flake8-simplify
|
|
101
|
+
"TCH", # flake8-type-checking
|
|
102
|
+
"UP", # pyupgrade
|
|
103
|
+
]
|
|
104
|
+
ignore = ["E501", "E731", "F841"]
|
|
105
|
+
|
|
106
|
+
[tool.ruff.lint.isort]
|
|
107
|
+
known-first-party = ["browser_tools"]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Browser Tools automation package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .browser_state import ActiveAttachConfig, BrowserState, ProjectBrowserConfig
|
|
6
|
+
from .camoufox_session import CamoufoxSession
|
|
7
|
+
from .cdp_client import CDPClient, CDPError
|
|
8
|
+
from .frame_manager import FrameManager
|
|
9
|
+
from .persistent_browser import PersistentChromeController
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"ActiveAttachConfig",
|
|
13
|
+
"BrowserState",
|
|
14
|
+
"CDPClient",
|
|
15
|
+
"CDPError",
|
|
16
|
+
"CamoufoxSession",
|
|
17
|
+
"FrameManager",
|
|
18
|
+
"PersistentChromeController",
|
|
19
|
+
"ProjectBrowserConfig",
|
|
20
|
+
"__version__",
|
|
21
|
+
]
|
|
22
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# attach-chrome.sh — Launch Chrome with remote debugging for browser-tools attach
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# ./attach-chrome.sh [--port PORT] [--profile PROFILE] [URL]
|
|
6
|
+
#
|
|
7
|
+
# Examples:
|
|
8
|
+
# ./attach-chrome.sh # Default port 9222
|
|
9
|
+
# ./attach-chrome.sh --port 9333 # Custom port
|
|
10
|
+
# ./attach-chrome.sh --profile dev # Named profile
|
|
11
|
+
# ./attach-chrome.sh https://myapp.localhost # Open specific URL
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
PORT=9222
|
|
16
|
+
PROFILE=""
|
|
17
|
+
URL=""
|
|
18
|
+
CHROME_CANARY="/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"
|
|
19
|
+
CHROME_STABLE="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
20
|
+
|
|
21
|
+
while [[ $# -gt 0 ]]; do
|
|
22
|
+
case "$1" in
|
|
23
|
+
--port)
|
|
24
|
+
PORT="$2"
|
|
25
|
+
shift 2
|
|
26
|
+
;;
|
|
27
|
+
--profile)
|
|
28
|
+
PROFILE="$2"
|
|
29
|
+
shift 2
|
|
30
|
+
;;
|
|
31
|
+
--help|-h)
|
|
32
|
+
echo "Usage: $0 [--port PORT] [--profile PROFILE] [URL]"
|
|
33
|
+
echo ""
|
|
34
|
+
echo "Launch Chrome with remote debugging enabled for browser-tools."
|
|
35
|
+
echo ""
|
|
36
|
+
echo "Options:"
|
|
37
|
+
echo " --port PORT Remote debugging port (default: 9222)"
|
|
38
|
+
echo " --profile NAME Named profile for persistent sessions"
|
|
39
|
+
echo " URL URL to open on launch"
|
|
40
|
+
echo ""
|
|
41
|
+
echo "Then in your agent, use:"
|
|
42
|
+
echo ' attach_browser(endpoint="http://127.0.0.1:PORT")'
|
|
43
|
+
exit 0
|
|
44
|
+
;;
|
|
45
|
+
*)
|
|
46
|
+
URL="$1"
|
|
47
|
+
shift
|
|
48
|
+
;;
|
|
49
|
+
esac
|
|
50
|
+
done
|
|
51
|
+
|
|
52
|
+
# Find Chrome executable
|
|
53
|
+
CHROME=""
|
|
54
|
+
if [[ -x "$CHROME_CANARY" ]]; then
|
|
55
|
+
CHROME="$CHROME_CANARY"
|
|
56
|
+
elif [[ -x "$CHROME_STABLE" ]]; then
|
|
57
|
+
CHROME="$CHROME_STABLE"
|
|
58
|
+
elif command -v google-chrome &>/dev/null; then
|
|
59
|
+
CHROME="google-chrome"
|
|
60
|
+
elif command -v chromium &>/dev/null; then
|
|
61
|
+
CHROME="chromium"
|
|
62
|
+
else
|
|
63
|
+
echo "Error: Chrome not found. Install Chrome or Chrome Canary." >&2
|
|
64
|
+
exit 1
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# Build user-data-dir path
|
|
68
|
+
CACHE_DIR="$HOME/.cache/tool-proxy/browser-tools"
|
|
69
|
+
if [[ -n "$PROFILE" ]]; then
|
|
70
|
+
USER_DATA_DIR="$CACHE_DIR/profiles/$PROFILE"
|
|
71
|
+
else
|
|
72
|
+
USER_DATA_DIR="$CACHE_DIR/profiles/attach-$PORT"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
mkdir -p "$USER_DATA_DIR"
|
|
76
|
+
chmod 700 "$USER_DATA_DIR"
|
|
77
|
+
|
|
78
|
+
echo "Launching Chrome with remote debugging on port $PORT..."
|
|
79
|
+
echo " Executable: $CHROME"
|
|
80
|
+
echo " Profile: $USER_DATA_DIR"
|
|
81
|
+
|
|
82
|
+
ARGS=(
|
|
83
|
+
"--remote-debugging-port=$PORT"
|
|
84
|
+
"--user-data-dir=$USER_DATA_DIR"
|
|
85
|
+
"--no-first-run"
|
|
86
|
+
"--no-default-browser-check"
|
|
87
|
+
"--disable-sync"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if [[ -n "$URL" ]]; then
|
|
91
|
+
ARGS+=("$URL")
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Detach Chrome into a new session so it survives if our parent shell is
|
|
95
|
+
# killed (e.g. an agent's Bash tool call hits its timeout). nohup alone is
|
|
96
|
+
# not enough on macOS: when the shell's process group is signaled, the
|
|
97
|
+
# child dies with it. Python's start_new_session=True calls os.setsid()
|
|
98
|
+
# in the child before exec, putting Chrome in its own session/process group.
|
|
99
|
+
python3 - "$CHROME" "${ARGS[@]}" <<'PY'
|
|
100
|
+
import subprocess, sys
|
|
101
|
+
subprocess.Popen(
|
|
102
|
+
sys.argv[1:],
|
|
103
|
+
stdin=subprocess.DEVNULL,
|
|
104
|
+
stdout=subprocess.DEVNULL,
|
|
105
|
+
stderr=subprocess.DEVNULL,
|
|
106
|
+
start_new_session=True,
|
|
107
|
+
)
|
|
108
|
+
PY
|
|
109
|
+
|
|
110
|
+
# Wait for the remote debugging endpoint to become reachable so the caller
|
|
111
|
+
# can attach immediately on return.
|
|
112
|
+
for _ in $(seq 1 60); do
|
|
113
|
+
if curl -fsS "http://127.0.0.1:$PORT/json/version" >/dev/null 2>&1; then
|
|
114
|
+
echo ""
|
|
115
|
+
echo "Chrome ready on http://127.0.0.1:$PORT"
|
|
116
|
+
echo "Connect with: attach_browser(endpoint=\"http://127.0.0.1:$PORT\")"
|
|
117
|
+
exit 0
|
|
118
|
+
fi
|
|
119
|
+
sleep 0.5
|
|
120
|
+
done
|
|
121
|
+
|
|
122
|
+
echo "Error: Chrome did not become ready on port $PORT within 30s." >&2
|
|
123
|
+
echo "If another Chrome is already using $USER_DATA_DIR, kill it first or use --profile NAME." >&2
|
|
124
|
+
exit 1
|