camoufox-cli 0.4.0__tar.gz → 0.5.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.
Potentially problematic release.
This version of camoufox-cli might be problematic. Click here for more details.
- camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0/.claude-plugin/marketplace.json +20 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/browser.ts +5 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/browser.py +6 -0
- camoufox_cli-0.5.0/.gitignore +30 -0
- camoufox_cli-0.5.0/LICENSE +21 -0
- camoufox_cli-0.5.0/Makefile +30 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0}/PKG-INFO +28 -1
- camoufox_cli-0.5.0/README.md +253 -0
- camoufox_cli-0.5.0/js/.gitignore +2 -0
- camoufox_cli-0.5.0/js/LICENSE +21 -0
- camoufox_cli-0.5.0/js/package-lock.json +2719 -0
- camoufox_cli-0.5.0/js/package.json +47 -0
- camoufox_cli-0.5.0/js/pnpm-lock.yaml +1599 -0
- camoufox_cli-0.5.0/js/scripts/postinstall.js +11 -0
- camoufox_cli-0.5.0/js/src/browser.ts +192 -0
- camoufox_cli-0.5.0/js/src/cli.ts +505 -0
- camoufox_cli-0.5.0/js/src/commands.ts +352 -0
- camoufox_cli-0.5.0/js/src/config.ts +140 -0
- camoufox_cli-0.5.0/js/src/daemon.ts +27 -0
- camoufox_cli-0.5.0/js/src/identity.ts +206 -0
- camoufox_cli-0.5.0/js/src/protocol.ts +32 -0
- camoufox_cli-0.5.0/js/src/proxy.ts +40 -0
- camoufox_cli-0.5.0/js/src/refs.ts +65 -0
- camoufox_cli-0.5.0/js/src/server.ts +131 -0
- camoufox_cli-0.5.0/js/tests/browser.test.ts +61 -0
- camoufox_cli-0.5.0/js/tests/cli.test.ts +455 -0
- camoufox_cli-0.5.0/js/tests/commands.test.ts +194 -0
- camoufox_cli-0.5.0/js/tests/e2e.test.ts +216 -0
- camoufox_cli-0.5.0/js/tests/protocol.test.ts +98 -0
- camoufox_cli-0.5.0/js/tests/proxy.test.ts +55 -0
- camoufox_cli-0.5.0/js/tests/refs.test.ts +150 -0
- camoufox_cli-0.5.0/js/tests/server.test.ts +193 -0
- camoufox_cli-0.5.0/js/tsconfig.json +14 -0
- camoufox_cli-0.5.0/js/vitest.config.ts +7 -0
- camoufox_cli-0.5.0/pyproject.toml +46 -0
- camoufox_cli-0.5.0/skills/camoufox-cli/SKILL.md +351 -0
- camoufox_cli-0.5.0/skills/camoufox-cli/references/commands.md +143 -0
- camoufox_cli-0.5.0/skills/camoufox-cli/references/snapshot-refs.md +221 -0
- camoufox_cli-0.5.0/src/camoufox_cli/__init__.py +0 -0
- camoufox_cli-0.5.0/src/camoufox_cli/__main__.py +38 -0
- camoufox_cli-0.5.0/src/camoufox_cli/browser.py +190 -0
- camoufox_cli-0.5.0/src/camoufox_cli/cli.py +518 -0
- camoufox_cli-0.5.0/src/camoufox_cli/commands.py +390 -0
- camoufox_cli-0.5.0/src/camoufox_cli/config.py +130 -0
- camoufox_cli-0.5.0/src/camoufox_cli/identity.py +215 -0
- camoufox_cli-0.5.0/src/camoufox_cli/protocol.py +24 -0
- camoufox_cli-0.5.0/src/camoufox_cli/proxy.py +30 -0
- camoufox_cli-0.5.0/src/camoufox_cli/refs.py +83 -0
- camoufox_cli-0.5.0/src/camoufox_cli/server.py +145 -0
- camoufox_cli-0.5.0/tests/__init__.py +0 -0
- camoufox_cli-0.5.0/tests/fixture.html +22 -0
- camoufox_cli-0.5.0/tests/test_cli.py +392 -0
- camoufox_cli-0.5.0/tests/test_commands.py +556 -0
- camoufox_cli-0.5.0/tests/test_e2e.py +217 -0
- camoufox_cli-0.5.0/tests/test_protocol.py +63 -0
- camoufox_cli-0.5.0/tests/test_proxy.py +37 -0
- camoufox_cli-0.5.0/tests/test_refs.py +112 -0
- camoufox_cli-0.4.0/.claude/settings.local.json +0 -20
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/.gitignore +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/LICENSE +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/Makefile +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/README.md +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/.gitignore +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/LICENSE +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/package-lock.json +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/package.json +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/pnpm-lock.yaml +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/scripts/postinstall.js +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/cli.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/commands.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/daemon.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/identity.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/protocol.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/proxy.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/refs.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/server.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/tests/browser.test.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/tests/cli.test.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/tests/commands.test.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/tests/e2e.test.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/tests/protocol.test.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/tests/proxy.test.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/tests/refs.test.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/tests/server.test.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/tsconfig.json +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/vitest.config.ts +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/pyproject.toml +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/skills/camoufox-cli/SKILL.md +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/skills/camoufox-cli/references/commands.md +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/skills/camoufox-cli/references/snapshot-refs.md +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/__init__.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/__main__.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/cli.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/commands.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/identity.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/protocol.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/proxy.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/refs.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/src/camoufox_cli/server.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/tests/__init__.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/tests/fixture.html +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/tests/test_cli.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/tests/test_commands.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/tests/test_e2e.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/tests/test_protocol.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/tests/test_proxy.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/tests/test_refs.py +0 -0
- {camoufox_cli-0.4.0 → camoufox_cli-0.5.0}/.claude-plugin/marketplace.json +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "camoufox-cli",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Benn Huang"
|
|
5
|
+
},
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "Anti-detect browser automation CLI & Skills for AI agents, powered by Camoufox",
|
|
8
|
+
"version": "0.1.0"
|
|
9
|
+
},
|
|
10
|
+
"plugins": [
|
|
11
|
+
{
|
|
12
|
+
"name": "camoufox-cli",
|
|
13
|
+
"description": "Anti-detect browser automation skill with fingerprint spoofing for AI agents",
|
|
14
|
+
"source": "./",
|
|
15
|
+
"skills": [
|
|
16
|
+
"./skills/camoufox-cli"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
{camoufox_cli-0.4.0 → camoufox_cli-0.5.0/.claude/worktrees/hungry-mclaren-0aa1c0}/js/src/browser.ts
RENAMED
|
@@ -8,6 +8,8 @@ import { loadOrCreate, toLaunchOptions } from "./identity.js";
|
|
|
8
8
|
import { parseProxySettings } from "./proxy.js";
|
|
9
9
|
import { RefRegistry } from "./refs.js";
|
|
10
10
|
|
|
11
|
+
const MAX_HISTORY = 200;
|
|
12
|
+
|
|
11
13
|
function ensureBrowserInstalled(): void {
|
|
12
14
|
try {
|
|
13
15
|
execFileSync("npx", ["camoufox-js", "path"], { stdio: "pipe" });
|
|
@@ -147,6 +149,9 @@ export class BrowserManager {
|
|
|
147
149
|
pushHistory(url: string): void {
|
|
148
150
|
this.history = this.history.slice(0, this.historyIndex + 1);
|
|
149
151
|
this.history.push(url);
|
|
152
|
+
if (this.history.length > MAX_HISTORY) {
|
|
153
|
+
this.history = this.history.slice(-MAX_HISTORY);
|
|
154
|
+
}
|
|
150
155
|
this.historyIndex = this.history.length - 1;
|
|
151
156
|
}
|
|
152
157
|
|
|
@@ -13,6 +13,9 @@ from .proxy import parse_proxy_settings
|
|
|
13
13
|
from .refs import RefRegistry
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
_MAX_HISTORY = 200
|
|
17
|
+
|
|
18
|
+
|
|
16
19
|
def _ensure_browser_installed() -> None:
|
|
17
20
|
"""Check that the Camoufox browser binary is installed, raise if not."""
|
|
18
21
|
try:
|
|
@@ -147,6 +150,9 @@ class BrowserManager:
|
|
|
147
150
|
# Truncate forward history when navigating to a new page
|
|
148
151
|
self._history = self._history[:self._history_index + 1]
|
|
149
152
|
self._history.append(url)
|
|
153
|
+
# Cap history to avoid unbounded growth in long-lived daemons.
|
|
154
|
+
if len(self._history) > _MAX_HISTORY:
|
|
155
|
+
self._history = self._history[-_MAX_HISTORY:]
|
|
150
156
|
self._history_index = len(self._history) - 1
|
|
151
157
|
|
|
152
158
|
def go_back(self) -> str | None:
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.venv/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
uv.lock
|
|
11
|
+
|
|
12
|
+
# Node
|
|
13
|
+
node_modules/
|
|
14
|
+
js/README.md
|
|
15
|
+
|
|
16
|
+
# IDE
|
|
17
|
+
.idea/
|
|
18
|
+
.vscode/
|
|
19
|
+
*.swp
|
|
20
|
+
*.swo
|
|
21
|
+
|
|
22
|
+
# OS
|
|
23
|
+
.DS_Store
|
|
24
|
+
|
|
25
|
+
# Env
|
|
26
|
+
.env
|
|
27
|
+
|
|
28
|
+
# Runtime
|
|
29
|
+
*.sock
|
|
30
|
+
*.pid
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Benn Huang
|
|
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,30 @@
|
|
|
1
|
+
.PHONY: test test-unit test-integration test-e2e build publish publish-pip publish-npm clean
|
|
2
|
+
|
|
3
|
+
test:
|
|
4
|
+
python -m pytest tests/ -v
|
|
5
|
+
|
|
6
|
+
test-unit:
|
|
7
|
+
python -m pytest tests/ -v -m "not integration"
|
|
8
|
+
|
|
9
|
+
test-integration:
|
|
10
|
+
python -m pytest tests/ -v -m integration
|
|
11
|
+
|
|
12
|
+
test-e2e:
|
|
13
|
+
python -m pytest tests/test_e2e.py -v
|
|
14
|
+
cd js && npx vitest run tests/e2e.test.ts
|
|
15
|
+
|
|
16
|
+
build: clean
|
|
17
|
+
uv build
|
|
18
|
+
cd js && npm run build
|
|
19
|
+
|
|
20
|
+
publish: publish-pip publish-npm
|
|
21
|
+
|
|
22
|
+
publish-pip: build
|
|
23
|
+
uvx twine upload dist/*
|
|
24
|
+
|
|
25
|
+
publish-npm: build
|
|
26
|
+
cd js && npm publish --access public
|
|
27
|
+
|
|
28
|
+
clean:
|
|
29
|
+
rm -rf dist/
|
|
30
|
+
rm -rf js/dist/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: camoufox-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Anti-detect browser CLI & Skills for AI agents, powered by Camoufox
|
|
5
5
|
Project-URL: Homepage, https://github.com/Bin-Huang/camoufox-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/Bin-Huang/camoufox-cli
|
|
@@ -180,6 +180,33 @@ camoufox-cli cookies export file.json # Export cookies
|
|
|
180
180
|
--locale <tag> Force browser locale (e.g. "en-US" or "en-US,zh-CN")
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
+
## Config File
|
|
184
|
+
|
|
185
|
+
Tired of repeating the same flags on every call? Put defaults in `~/.camoufox-cli/config.json` (override the path with `$CAMOUFOX_CLI_CONFIG`):
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"default": {
|
|
190
|
+
"persistent": true,
|
|
191
|
+
"timeout": 3600,
|
|
192
|
+
"proxy": "http://user:pass@host:8080"
|
|
193
|
+
},
|
|
194
|
+
"sessions": {
|
|
195
|
+
"<your-session-name>": {
|
|
196
|
+
"proxy": "socks5://127.0.0.1:1080",
|
|
197
|
+
"locale": "zh-CN"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
- **`default`** applies to every session.
|
|
204
|
+
- **`sessions` is optional.** You never pre-register sessions — the name is just whatever you pass to `--session`. A `sessions.<name>` block only kicks in when you happen to run `--session <name>`, layering its keys on top of `default`; any other session (or no `--session` at all) just uses `default`. Above, `camoufox-cli --session <your-session-name> open <url>` swaps in that block's proxy + locale, while every other session keeps the `default` proxy.
|
|
205
|
+
- **Command-line flags always win** over the file, which in turn wins over built-in defaults.
|
|
206
|
+
- Settable keys: `proxy`, `locale`, `geoip`, `persistent` (`true` / `false` / path string), `headed`, `timeout`, `json`. `session` is command-line only (it selects which block to apply), and per-command options like `--full` or `-i` are never read from config.
|
|
207
|
+
- A broken config never blocks a command — it's ignored with a warning on stderr.
|
|
208
|
+
- Config is read when a session's daemon **first launches**. If one is already running for that session, run `camoufox-cli --session <name> close` first for changes to take effect.
|
|
209
|
+
|
|
183
210
|
## Persistent Identity
|
|
184
211
|
|
|
185
212
|
Without `--persistent`, every launch gets a fresh random fingerprint. With `--persistent`, a `camoufox-cli.json` file is written next to the browser's user data. Fingerprint, OS, and canvas/font seeds are generated on the first launch and frozen afterwards; locale and proxy-derived timezone/geolocation are also saved but track whatever you pass on the command line. Every subsequent launch with the same path reloads the identity, so sites see the same device on every visit.
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# camoufox-cli
|
|
2
|
+
|
|
3
|
+
Anti-detect browser CLI & Skills for AI agents, powered by [Camoufox](https://github.com/daijro/camoufox).
|
|
4
|
+
|
|
5
|
+
### Highlights
|
|
6
|
+
|
|
7
|
+
- C++-level fingerprint spoofing via Camoufox (canvas, WebGL, audio, screen metrics, fonts)
|
|
8
|
+
- Persistent identities: stable fingerprint, OS, and locale across launches with `--persistent`
|
|
9
|
+
- Accessibility-tree snapshots with `@ref` element targeting
|
|
10
|
+
- Session isolation with cookie import/export
|
|
11
|
+
- Shell commands, no code generation
|
|
12
|
+
|
|
13
|
+
### Works with
|
|
14
|
+
|
|
15
|
+
OpenClaw, Claude Code, Cursor, Codex, and any agent that can run shell commands.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
Tell your AI agent (e.g. OpenClaw):
|
|
20
|
+
|
|
21
|
+
> Install this CLI and skills from https://github.com/Bin-Huang/camoufox-cli
|
|
22
|
+
|
|
23
|
+
Or install manually:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g camoufox-cli
|
|
27
|
+
camoufox-cli install # Download browser
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or with pip:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pipx install camoufox-cli
|
|
34
|
+
camoufox-cli install # Download browser
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
On Linux, install system dependencies with:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
camoufox-cli install --with-deps
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Agent Skill
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Add skills for AI agents (Claude Code, Cursor, Codex, etc.)
|
|
47
|
+
npx skills add Bin-Huang/camoufox-cli
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
camoufox-cli open https://example.com # Launch browser & navigate
|
|
54
|
+
camoufox-cli snapshot -i # Interactive elements only
|
|
55
|
+
# - link "More information..." [ref=e1]
|
|
56
|
+
camoufox-cli click @e1 # Click by ref
|
|
57
|
+
camoufox-cli close # Done
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Commands
|
|
61
|
+
|
|
62
|
+
### Navigation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
camoufox-cli open <url> # Navigate to URL (starts daemon if needed)
|
|
66
|
+
camoufox-cli back # Go back
|
|
67
|
+
camoufox-cli forward # Go forward
|
|
68
|
+
camoufox-cli reload # Reload page
|
|
69
|
+
camoufox-cli url # Print current URL
|
|
70
|
+
camoufox-cli title # Print page title
|
|
71
|
+
camoufox-cli close # Close browser and stop daemon
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Snapshot
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
camoufox-cli snapshot # Full accessibility tree
|
|
78
|
+
camoufox-cli snapshot -i # Interactive elements only
|
|
79
|
+
camoufox-cli snapshot -s "css-selector" # Scoped to CSS selector
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Output format:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
- heading "Example Domain" [level=1] [ref=e1]
|
|
86
|
+
- paragraph [ref=e2]
|
|
87
|
+
- link "More information..." [ref=e3]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Interaction
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
camoufox-cli click @e1 # Click element
|
|
94
|
+
camoufox-cli fill @e3 "search query" # Clear + type into input
|
|
95
|
+
camoufox-cli type @e3 "append text" # Type without clearing
|
|
96
|
+
camoufox-cli select @e5 "option text" # Select dropdown option
|
|
97
|
+
camoufox-cli check @e6 # Toggle checkbox
|
|
98
|
+
camoufox-cli hover @e2 # Hover over element
|
|
99
|
+
camoufox-cli press Enter # Press keyboard key
|
|
100
|
+
camoufox-cli press "Control+a" # Key combination
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Data Extraction
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
camoufox-cli text @e1 # Get text content of element
|
|
107
|
+
camoufox-cli text body # Get all page text
|
|
108
|
+
camoufox-cli eval "document.title" # Execute JavaScript
|
|
109
|
+
camoufox-cli screenshot # Screenshot (JSON with base64)
|
|
110
|
+
camoufox-cli screenshot page.png # Screenshot to file
|
|
111
|
+
camoufox-cli screenshot --full page.png # Full page screenshot
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Scroll & Wait
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
camoufox-cli scroll down # Scroll down 500px
|
|
118
|
+
camoufox-cli scroll up 1000 # Scroll up 1000px
|
|
119
|
+
camoufox-cli wait 2000 # Wait milliseconds
|
|
120
|
+
camoufox-cli wait @e1 # Wait for element to appear
|
|
121
|
+
camoufox-cli wait --url "*/dashboard" # Wait for URL pattern
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Tabs
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
camoufox-cli tabs # List open tabs
|
|
128
|
+
camoufox-cli switch 2 # Switch to tab by index
|
|
129
|
+
camoufox-cli close-tab # Close current tab
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Sessions
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
camoufox-cli sessions # List active sessions
|
|
136
|
+
camoufox-cli --session work open <url> # Use named session
|
|
137
|
+
camoufox-cli close --all # Close all sessions
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Cookies
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
camoufox-cli cookies # Dump cookies as JSON
|
|
144
|
+
camoufox-cli cookies import file.json # Import cookies
|
|
145
|
+
camoufox-cli cookies export file.json # Export cookies
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Flags
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
--session <name> Named session (default: "default")
|
|
152
|
+
--headed Show browser window (default: headless)
|
|
153
|
+
--timeout <seconds> Daemon idle timeout (default: 1800)
|
|
154
|
+
--json Output as JSON
|
|
155
|
+
--persistent [path] Persistent identity (see below); default path: ~/.camoufox-cli/profiles/<session>
|
|
156
|
+
--proxy <url> Proxy server (http:// or https://; auth: http://user:pass@host:port)
|
|
157
|
+
--no-geoip Disable automatic GeoIP spoofing (auto-enabled with --proxy)
|
|
158
|
+
--locale <tag> Force browser locale (e.g. "en-US" or "en-US,zh-CN")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Config File
|
|
162
|
+
|
|
163
|
+
Tired of repeating the same flags on every call? Put defaults in `~/.camoufox-cli/config.json` (override the path with `$CAMOUFOX_CLI_CONFIG`):
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"default": {
|
|
168
|
+
"persistent": true,
|
|
169
|
+
"timeout": 3600,
|
|
170
|
+
"proxy": "http://user:pass@host:8080"
|
|
171
|
+
},
|
|
172
|
+
"sessions": {
|
|
173
|
+
"<your-session-name>": {
|
|
174
|
+
"proxy": "socks5://127.0.0.1:1080",
|
|
175
|
+
"locale": "zh-CN"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- **`default`** applies to every session.
|
|
182
|
+
- **`sessions` is optional.** You never pre-register sessions — the name is just whatever you pass to `--session`. A `sessions.<name>` block only kicks in when you happen to run `--session <name>`, layering its keys on top of `default`; any other session (or no `--session` at all) just uses `default`. Above, `camoufox-cli --session <your-session-name> open <url>` swaps in that block's proxy + locale, while every other session keeps the `default` proxy.
|
|
183
|
+
- **Command-line flags always win** over the file, which in turn wins over built-in defaults.
|
|
184
|
+
- Settable keys: `proxy`, `locale`, `geoip`, `persistent` (`true` / `false` / path string), `headed`, `timeout`, `json`. `session` is command-line only (it selects which block to apply), and per-command options like `--full` or `-i` are never read from config.
|
|
185
|
+
- A broken config never blocks a command — it's ignored with a warning on stderr.
|
|
186
|
+
- Config is read when a session's daemon **first launches**. If one is already running for that session, run `camoufox-cli --session <name> close` first for changes to take effect.
|
|
187
|
+
|
|
188
|
+
## Persistent Identity
|
|
189
|
+
|
|
190
|
+
Without `--persistent`, every launch gets a fresh random fingerprint. With `--persistent`, a `camoufox-cli.json` file is written next to the browser's user data. Fingerprint, OS, and canvas/font seeds are generated on the first launch and frozen afterwards; locale and proxy-derived timezone/geolocation are also saved but track whatever you pass on the command line. Every subsequent launch with the same path reloads the identity, so sites see the same device on every visit.
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# First launch: generates + stores identity
|
|
194
|
+
camoufox-cli --persistent ~/.camoufox-cli/profiles/alice open https://example.com
|
|
195
|
+
|
|
196
|
+
# Every subsequent launch: same fingerprint, same cookies, same device
|
|
197
|
+
camoufox-cli --persistent ~/.camoufox-cli/profiles/alice open https://example.com
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Frozen** — generated on the first launch, permanent until the directory is deleted:
|
|
201
|
+
|
|
202
|
+
- Fingerprint (UA, canvas, WebGL, fonts, navigator properties)
|
|
203
|
+
- OS (defaults to host OS)
|
|
204
|
+
- Canvas/font noise seeds
|
|
205
|
+
|
|
206
|
+
**Persisted** — stored in the file, refreshed whenever you pass the flag:
|
|
207
|
+
|
|
208
|
+
- `--locale`: sets the stored locale; pass it again to change it, omit it to keep the stored value.
|
|
209
|
+
- Timezone / geolocation: re-derived from the current proxy's IP whenever `--proxy` is active (and `--no-geoip` isn't set), then written back. Without a proxy, the last stored values stay in effect.
|
|
210
|
+
|
|
211
|
+
**Per-launch** — never stored; pass on every launch for it to apply:
|
|
212
|
+
|
|
213
|
+
- `--proxy`: proxies rotate or expire; re-specify each launch to avoid silently running through a stale one.
|
|
214
|
+
- `--no-geoip`: follows the current `--proxy`.
|
|
215
|
+
|
|
216
|
+
**Multiple identities in parallel.** Each persistent path is a distinct identity. Combine with `--session` for concurrent daemons:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
camoufox-cli --session a --persistent ~/.camoufox-cli/profiles/alice open https://...
|
|
220
|
+
camoufox-cli --session b --persistent ~/.camoufox-cli/profiles/bob open https://...
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Resetting an identity.** Just delete the directory (`rm -rf ~/.camoufox-cli/profiles/alice`). The next launch generates a fresh one.
|
|
224
|
+
|
|
225
|
+
## Architecture
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
CLI (camoufox-cli) ──Unix socket──▶ Daemon (Python) ──Playwright──▶ Camoufox (Firefox)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The CLI sends JSON commands to a long-running daemon process via Unix socket. The daemon manages the Camoufox browser instance and maintains the ref registry between commands. The daemon auto-starts on the first command and auto-stops after 30 minutes of inactivity.
|
|
232
|
+
|
|
233
|
+
## Related
|
|
234
|
+
|
|
235
|
+
- [google-analytics-cli](https://github.com/Bin-Huang/google-analytics-cli) -- Google Analytics CLI & Skills for AI agents (and humans)
|
|
236
|
+
- [google-search-console-cli](https://github.com/Bin-Huang/google-search-console-cli) -- Google Search Console CLI & Skills for AI agents (and humans)
|
|
237
|
+
- [youtube-analytics-cli](https://github.com/Bin-Huang/youtube-analytics-cli) -- YouTube Analytics CLI & Skills for AI agents (and humans)
|
|
238
|
+
- [x-analytics-cli](https://github.com/Bin-Huang/x-analytics-cli) -- X Analytics CLI & Skills for AI agents (and humans)
|
|
239
|
+
- [google-ads-open-cli](https://github.com/Bin-Huang/google-ads-open-cli) -- Google Ads CLI & Skills for AI agents (and humans)
|
|
240
|
+
- [meta-ads-open-cli](https://github.com/Bin-Huang/meta-ads-open-cli) -- Meta Ads CLI & Skills for AI agents (and humans)
|
|
241
|
+
- [microsoft-ads-cli](https://github.com/Bin-Huang/microsoft-ads-cli) -- Microsoft Ads CLI & Skills for AI agents (and humans)
|
|
242
|
+
- [amazon-ads-open-cli](https://github.com/Bin-Huang/amazon-ads-open-cli) -- Amazon Ads CLI & Skills for AI agents (and humans)
|
|
243
|
+
- [tiktok-ads-cli](https://github.com/Bin-Huang/tiktok-ads-cli) -- TikTok Ads CLI & Skills for AI agents (and humans)
|
|
244
|
+
- [linkedin-ads-cli](https://github.com/Bin-Huang/linkedin-ads-cli) -- LinkedIn Ads CLI & Skills for AI agents (and humans)
|
|
245
|
+
- [x-ads-cli](https://github.com/Bin-Huang/x-ads-cli) -- X Ads CLI & Skills for AI agents (and humans)
|
|
246
|
+
- [snapchat-ads-cli](https://github.com/Bin-Huang/snapchat-ads-cli) -- Snapchat Ads CLI & Skills for AI agents (and humans)
|
|
247
|
+
- [pinterest-ads-cli](https://github.com/Bin-Huang/pinterest-ads-cli) -- Pinterest Ads CLI & Skills for AI agents (and humans)
|
|
248
|
+
- [reddit-ads-cli](https://github.com/Bin-Huang/reddit-ads-cli) -- Reddit Ads CLI & Skills for AI agents (and humans)
|
|
249
|
+
- [spotify-ads-cli](https://github.com/Bin-Huang/spotify-ads-cli) -- Spotify Ads CLI & Skills for AI agents (and humans)
|
|
250
|
+
- [apple-ads-cli](https://github.com/Bin-Huang/apple-ads-cli) -- Apple Ads CLI & Skills for AI agents (and humans)
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
MIT
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Benn Huang
|
|
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.
|