camoufox-cli 0.7.0__tar.gz → 0.7.2__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.

Files changed (119) hide show
  1. camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1/.claude-plugin/marketplace.json +20 -0
  2. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/README.md +1 -0
  3. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/cli.ts +18 -0
  4. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tests/cli.test.ts +10 -1
  5. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/skills/camoufox-cli/SKILL.md +1 -0
  6. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/skills/camoufox-cli/references/commands.md +1 -0
  7. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/cli.py +17 -0
  8. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/test_cli.py +17 -1
  9. camoufox_cli-0.7.2/.gitignore +30 -0
  10. camoufox_cli-0.7.2/LICENSE +21 -0
  11. camoufox_cli-0.7.2/Makefile +30 -0
  12. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2}/PKG-INFO +4 -3
  13. camoufox_cli-0.7.2/README.md +272 -0
  14. camoufox_cli-0.7.2/js/.gitignore +2 -0
  15. camoufox_cli-0.7.2/js/LICENSE +21 -0
  16. camoufox_cli-0.7.2/js/package-lock.json +2785 -0
  17. camoufox_cli-0.7.2/js/package.json +47 -0
  18. camoufox_cli-0.7.2/js/pnpm-lock.yaml +1599 -0
  19. camoufox_cli-0.7.2/js/scripts/postinstall.js +11 -0
  20. camoufox_cli-0.7.2/js/src/browser.ts +401 -0
  21. camoufox_cli-0.7.2/js/src/cli.ts +588 -0
  22. camoufox_cli-0.7.2/js/src/commands.ts +364 -0
  23. camoufox_cli-0.7.2/js/src/config.ts +140 -0
  24. camoufox_cli-0.7.2/js/src/daemon.ts +27 -0
  25. camoufox_cli-0.7.2/js/src/identity.ts +206 -0
  26. camoufox_cli-0.7.2/js/src/install.ts +179 -0
  27. camoufox_cli-0.7.2/js/src/protocol.ts +32 -0
  28. camoufox_cli-0.7.2/js/src/proxy.ts +40 -0
  29. camoufox_cli-0.7.2/js/src/refs.ts +65 -0
  30. camoufox_cli-0.7.2/js/src/server.ts +214 -0
  31. camoufox_cli-0.7.2/js/tests/browser.test.ts +122 -0
  32. camoufox_cli-0.7.2/js/tests/cli.test.ts +475 -0
  33. camoufox_cli-0.7.2/js/tests/commands.test.ts +189 -0
  34. camoufox_cli-0.7.2/js/tests/e2e.test.ts +294 -0
  35. camoufox_cli-0.7.2/js/tests/install.test.ts +205 -0
  36. camoufox_cli-0.7.2/js/tests/protocol.test.ts +98 -0
  37. camoufox_cli-0.7.2/js/tests/proxy.test.ts +55 -0
  38. camoufox_cli-0.7.2/js/tests/refs.test.ts +150 -0
  39. camoufox_cli-0.7.2/js/tests/server.test.ts +300 -0
  40. camoufox_cli-0.7.2/js/tsconfig.json +14 -0
  41. camoufox_cli-0.7.2/js/vitest.config.ts +7 -0
  42. camoufox_cli-0.7.2/pyproject.toml +51 -0
  43. camoufox_cli-0.7.2/skills/camoufox-cli/SKILL.md +386 -0
  44. camoufox_cli-0.7.2/skills/camoufox-cli/references/commands.md +150 -0
  45. camoufox_cli-0.7.2/skills/camoufox-cli/references/snapshot-refs.md +221 -0
  46. camoufox_cli-0.7.2/src/camoufox_cli/__init__.py +0 -0
  47. camoufox_cli-0.7.2/src/camoufox_cli/__main__.py +38 -0
  48. camoufox_cli-0.7.2/src/camoufox_cli/browser.py +316 -0
  49. camoufox_cli-0.7.2/src/camoufox_cli/cli.py +590 -0
  50. camoufox_cli-0.7.2/src/camoufox_cli/commands.py +406 -0
  51. camoufox_cli-0.7.2/src/camoufox_cli/config.py +130 -0
  52. camoufox_cli-0.7.2/src/camoufox_cli/identity.py +215 -0
  53. camoufox_cli-0.7.2/src/camoufox_cli/install.py +167 -0
  54. camoufox_cli-0.7.2/src/camoufox_cli/protocol.py +24 -0
  55. camoufox_cli-0.7.2/src/camoufox_cli/proxy.py +30 -0
  56. camoufox_cli-0.7.2/src/camoufox_cli/refs.py +83 -0
  57. camoufox_cli-0.7.2/src/camoufox_cli/server.py +189 -0
  58. camoufox_cli-0.7.2/tests/__init__.py +0 -0
  59. camoufox_cli-0.7.2/tests/fixture.html +22 -0
  60. camoufox_cli-0.7.2/tests/test_cli.py +418 -0
  61. camoufox_cli-0.7.2/tests/test_commands.py +556 -0
  62. camoufox_cli-0.7.2/tests/test_e2e.py +302 -0
  63. camoufox_cli-0.7.2/tests/test_install.py +201 -0
  64. camoufox_cli-0.7.2/tests/test_protocol.py +63 -0
  65. camoufox_cli-0.7.2/tests/test_proxy.py +37 -0
  66. camoufox_cli-0.7.2/tests/test_refs.py +112 -0
  67. camoufox_cli-0.7.2/tests/test_server.py +101 -0
  68. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/.gitignore +0 -0
  69. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/LICENSE +0 -0
  70. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/Makefile +0 -0
  71. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/.gitignore +0 -0
  72. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/LICENSE +0 -0
  73. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/package-lock.json +0 -0
  74. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/package.json +0 -0
  75. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/pnpm-lock.yaml +0 -0
  76. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/scripts/postinstall.js +0 -0
  77. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/browser.ts +0 -0
  78. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/commands.ts +0 -0
  79. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/config.ts +0 -0
  80. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/daemon.ts +0 -0
  81. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/identity.ts +0 -0
  82. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/install.ts +0 -0
  83. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/protocol.ts +0 -0
  84. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/proxy.ts +0 -0
  85. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/refs.ts +0 -0
  86. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/src/server.ts +0 -0
  87. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tests/browser.test.ts +0 -0
  88. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tests/commands.test.ts +0 -0
  89. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tests/e2e.test.ts +0 -0
  90. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tests/install.test.ts +0 -0
  91. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tests/protocol.test.ts +0 -0
  92. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tests/proxy.test.ts +0 -0
  93. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tests/refs.test.ts +0 -0
  94. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tests/server.test.ts +0 -0
  95. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/tsconfig.json +0 -0
  96. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/js/vitest.config.ts +0 -0
  97. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/pyproject.toml +0 -0
  98. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/skills/camoufox-cli/references/snapshot-refs.md +0 -0
  99. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/__init__.py +0 -0
  100. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/__main__.py +0 -0
  101. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/browser.py +0 -0
  102. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/commands.py +0 -0
  103. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/config.py +0 -0
  104. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/identity.py +0 -0
  105. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/install.py +0 -0
  106. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/protocol.py +0 -0
  107. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/proxy.py +0 -0
  108. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/refs.py +0 -0
  109. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/src/camoufox_cli/server.py +0 -0
  110. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/__init__.py +0 -0
  111. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/fixture.html +0 -0
  112. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/test_commands.py +0 -0
  113. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/test_e2e.py +0 -0
  114. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/test_install.py +0 -0
  115. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/test_protocol.py +0 -0
  116. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/test_proxy.py +0 -0
  117. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/test_refs.py +0 -0
  118. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2/.claude/worktrees/cli-version-command-8852a1}/tests/test_server.py +0 -0
  119. {camoufox_cli-0.7.0 → camoufox_cli-0.7.2}/.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
+ }
@@ -174,6 +174,7 @@ camoufox-cli cookies export file.json # Export cookies
174
174
  --proxy <url> Proxy server (http:// or https://; auth: http://user:pass@host:port)
175
175
  --no-geoip Disable automatic GeoIP spoofing (auto-enabled with --proxy)
176
176
  --locale <tag> Force browser locale (e.g. "en-US" or "en-US,zh-CN")
177
+ --version Print version and exit
177
178
  ```
178
179
 
179
180
  ## Config File
@@ -97,6 +97,16 @@ export function listSessions(): string[] {
97
97
  return sessions.sort();
98
98
  }
99
99
 
100
+ export function getVersion(): string {
101
+ // package.json ships in the npm package and sits one level above both src/ and dist/.
102
+ try {
103
+ const pkgPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
104
+ return JSON.parse(fs.readFileSync(pkgPath, "utf8")).version ?? "unknown";
105
+ } catch {
106
+ return "unknown";
107
+ }
108
+ }
109
+
100
110
  // ---------------------------------------------------------------------------
101
111
  // Arg parsing
102
112
  // ---------------------------------------------------------------------------
@@ -379,6 +389,13 @@ function installSystemDeps(): void {
379
389
 
380
390
  async function main() {
381
391
  const argv = process.argv.slice(2);
392
+
393
+ // Short-circuit before parseArgs: --version has no command and needs no daemon.
394
+ if (argv.includes("--version")) {
395
+ console.log(getVersion());
396
+ return;
397
+ }
398
+
382
399
  const { flags, command } = parseArgs(argv);
383
400
 
384
401
  // Resolve default persistent path
@@ -505,6 +522,7 @@ Flags:
505
522
  --proxy <url> Proxy server (e.g. http://host:port or https://host:443)
506
523
  --no-geoip Disable automatic GeoIP spoofing (auto-enabled with --proxy)
507
524
  --locale <tag> Force browser locale (e.g. "en-US" or "en-US,zh-CN")
525
+ --version Print version and exit
508
526
 
509
527
  Config file:
510
528
  ~/.camoufox-cli/config.json sets defaults for the flags above (override the
@@ -2,7 +2,8 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
2
  import * as fs from "node:fs";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
- import { buildCommand, getSocketPath, parseArgs } from "../src/cli.js";
5
+ import { fileURLToPath } from "node:url";
6
+ import { buildCommand, getSocketPath, getVersion, parseArgs } from "../src/cli.js";
6
7
  import { loadDefaults } from "../src/config.js";
7
8
 
8
9
  // buildCommand calls process.exit on error; mock it to throw instead
@@ -316,6 +317,14 @@ describe("getSocketPath", () => {
316
317
  });
317
318
  });
318
319
 
320
+ describe("getVersion", () => {
321
+ it("returns the version from package.json", () => {
322
+ const pkgPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
323
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
324
+ expect(getVersion()).toBe(pkg.version);
325
+ });
326
+ });
327
+
319
328
  describe("config file", () => {
320
329
  let dir: string;
321
330
  let cfg: string;
@@ -354,6 +354,7 @@ camoufox-cli snapshot -i
354
354
  --proxy <url> Proxy server (http:// or https://; auth: http://user:pass@host:port)
355
355
  --no-geoip Disable automatic GeoIP spoofing (auto-enabled with --proxy)
356
356
  --locale <tag> Force browser locale (e.g. "en-US" or "en-US,zh-CN")
357
+ --version Print version and exit
357
358
  ```
358
359
 
359
360
  **Config file (optional).** To avoid repeating flags, set defaults in `~/.camoufox-cli/config.json` (override path with `$CAMOUFOX_CLI_CONFIG`): a `default` block applies to all sessions, and an optional `sessions.<name>` block layers extra overrides on top whenever you run `--session <name>` (the name is just whatever you pass to `--session` — sessions are never pre-registered). Settable keys: `proxy`, `locale`, `geoip`, `persistent` (`true`/`false`/path), `headed`, `timeout`, `json`. Command-line flags always win over the file. Config is read only when a session's daemon first launches.
@@ -131,6 +131,7 @@ camoufox-cli --persistent [path] ... # Persistent identity — reuse the same fi
131
131
  camoufox-cli --proxy <url> ... # Proxy server (e.g. http://host:port or http://user:pass@host:port)
132
132
  camoufox-cli --no-geoip ... # Disable automatic GeoIP spoofing (auto-enabled with --proxy)
133
133
  camoufox-cli --locale <tag> ... # Force browser locale (e.g. "en-US" or "en-US,zh-CN")
134
+ camoufox-cli --version # Print version and exit
134
135
  ```
135
136
 
136
137
  ### `--persistent` in detail
@@ -91,6 +91,16 @@ def ensure_daemon(session: str, headed: bool, timeout: int, persistent: str | No
91
91
  spawn_daemon(session, headed, timeout, persistent, proxy, geoip, locale)
92
92
 
93
93
 
94
+ def get_version() -> str:
95
+ """Version from installed package metadata; pyproject isn't shipped in the wheel."""
96
+ from importlib.metadata import version, PackageNotFoundError
97
+
98
+ try:
99
+ return version("camoufox-cli")
100
+ except PackageNotFoundError:
101
+ return "unknown"
102
+
103
+
94
104
  def list_sessions() -> list[str]:
95
105
  sessions = []
96
106
  try:
@@ -401,6 +411,12 @@ def _install_system_deps() -> None:
401
411
 
402
412
  def main():
403
413
  args = sys.argv[1:]
414
+
415
+ # Short-circuit before parse_args: --version has no command and needs no daemon.
416
+ if "--version" in args:
417
+ print(get_version())
418
+ return
419
+
404
420
  flags, command = parse_args(args)
405
421
 
406
422
  # Resolve default persistent path
@@ -526,6 +542,7 @@ Flags:
526
542
  --proxy <url> Proxy server (e.g. http://host:port or https://host:443)
527
543
  --no-geoip Disable automatic GeoIP spoofing (auto-enabled with --proxy)
528
544
  --locale <tag> Force browser locale (e.g. "en-US" or "en-US,zh-CN")
545
+ --version Print version and exit
529
546
 
530
547
  Config file:
531
548
  ~/.camoufox-cli/config.json sets defaults for the flags above (override the
@@ -1,11 +1,12 @@
1
1
  """Tests for CLI argument parsing and command building."""
2
2
 
3
3
  import json
4
+ import re
4
5
 
5
6
  import pytest
6
7
 
7
8
  from camoufox_cli import config
8
- from camoufox_cli.cli import build_command, parse_args, list_sessions, get_socket_path
9
+ from camoufox_cli.cli import build_command, parse_args, list_sessions, get_socket_path, get_version
9
10
 
10
11
 
11
12
  @pytest.fixture(autouse=True)
@@ -282,6 +283,21 @@ class TestGetSocketPath:
282
283
  assert get_socket_path("my-session") == "/tmp/camoufox-cli-my-session.sock"
283
284
 
284
285
 
286
+ class TestGetVersion:
287
+ def test_returns_semver(self):
288
+ # The package is installed in the dev/test venv, so metadata resolves.
289
+ assert re.match(r"^\d+\.\d+\.\d+", get_version())
290
+
291
+ def test_unknown_when_not_installed(self, monkeypatch):
292
+ import importlib.metadata
293
+
294
+ def _raise(name):
295
+ raise importlib.metadata.PackageNotFoundError(name)
296
+
297
+ monkeypatch.setattr(importlib.metadata, "version", _raise)
298
+ assert get_version() == "unknown"
299
+
300
+
285
301
  class TestConfigFile:
286
302
  # --- config.load_defaults ---
287
303
  def test_absent_file(self):
@@ -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.7.0
3
+ Version: 0.7.2
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
@@ -15,7 +15,7 @@ Classifier: Intended Audience :: Developers
15
15
  Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
16
16
  Classifier: Topic :: Software Development :: Testing
17
17
  Requires-Python: >=3.10
18
- Requires-Dist: camoufox[geoip]
18
+ Requires-Dist: camoufox[geoip]==0.4.11
19
19
  Requires-Dist: pillow
20
20
  Requires-Dist: playwright==1.52.0
21
21
  Description-Content-Type: text/markdown
@@ -45,7 +45,7 @@ Tell your AI agent (e.g. OpenClaw):
45
45
  Or install manually:
46
46
 
47
47
  ```bash
48
- npm install -g camoufox-cli
48
+ npm install -g camoufox-cli # Requires Node.js 20.10+
49
49
  camoufox-cli install # Download browser
50
50
  ```
51
51
 
@@ -196,6 +196,7 @@ camoufox-cli cookies export file.json # Export cookies
196
196
  --proxy <url> Proxy server (http:// or https://; auth: http://user:pass@host:port)
197
197
  --no-geoip Disable automatic GeoIP spoofing (auto-enabled with --proxy)
198
198
  --locale <tag> Force browser locale (e.g. "en-US" or "en-US,zh-CN")
199
+ --version Print version and exit
199
200
  ```
200
201
 
201
202
  ## Config File
@@ -0,0 +1,272 @@
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 # Requires Node.js 20.10+
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
+ The browser is downloaded from GitHub releases. If the anonymous GitHub API
44
+ rate limit is exhausted (common on shared server/CI IPs), the installer
45
+ automatically falls back to scraping github.com release pages.
46
+
47
+ ### Agent Skill
48
+
49
+ ```bash
50
+ # Add skills for AI agents (Claude Code, Cursor, Codex, etc.)
51
+ npx skills add Bin-Huang/camoufox-cli
52
+ ```
53
+
54
+ ## Quick Start
55
+
56
+ ```bash
57
+ camoufox-cli open https://example.com # Launch browser & navigate
58
+ camoufox-cli snapshot -i # Interactive elements only
59
+ # - link "More information..." [ref=e1]
60
+ camoufox-cli click @e1 # Click by ref
61
+ camoufox-cli close # Done
62
+ ```
63
+
64
+ ## Commands
65
+
66
+ ### Navigation
67
+
68
+ ```bash
69
+ camoufox-cli open <url> # Navigate to URL (starts daemon if needed)
70
+ camoufox-cli back # Go back
71
+ camoufox-cli forward # Go forward
72
+ camoufox-cli reload # Reload page
73
+ camoufox-cli url # Print current URL
74
+ camoufox-cli title # Print page title
75
+ camoufox-cli close # Close your tab (browser exits when the last tab closes)
76
+ ```
77
+
78
+ ### Snapshot
79
+
80
+ ```bash
81
+ camoufox-cli snapshot # Full accessibility tree
82
+ camoufox-cli snapshot -i # Interactive elements only
83
+ camoufox-cli snapshot -s "css-selector" # Scoped to CSS selector
84
+ ```
85
+
86
+ Output format:
87
+
88
+ ```
89
+ - heading "Example Domain" [level=1] [ref=e1]
90
+ - paragraph [ref=e2]
91
+ - link "More information..." [ref=e3]
92
+ ```
93
+
94
+ ### Interaction
95
+
96
+ ```bash
97
+ camoufox-cli click @e1 # Click element
98
+ camoufox-cli fill @e3 "search query" # Clear + type into input
99
+ camoufox-cli type @e3 "append text" # Type without clearing
100
+ camoufox-cli select @e5 "option text" # Select dropdown option
101
+ camoufox-cli check @e6 # Toggle checkbox
102
+ camoufox-cli hover @e2 # Hover over element
103
+ camoufox-cli press Enter # Press keyboard key
104
+ camoufox-cli press "Control+a" # Key combination
105
+ ```
106
+
107
+ ### Data Extraction
108
+
109
+ ```bash
110
+ camoufox-cli text @e1 # Get text content of element
111
+ camoufox-cli text body # Get all page text
112
+ camoufox-cli eval "document.title" # Execute JavaScript
113
+ camoufox-cli screenshot # Screenshot (JSON with base64)
114
+ camoufox-cli screenshot page.png # Screenshot to file
115
+ camoufox-cli screenshot --full page.png # Full page screenshot
116
+ ```
117
+
118
+ ### Scroll & Wait
119
+
120
+ ```bash
121
+ camoufox-cli scroll down # Scroll down 500px
122
+ camoufox-cli scroll up 1000 # Scroll up 1000px
123
+ camoufox-cli wait 2000 # Wait milliseconds
124
+ camoufox-cli wait @e1 # Wait for element to appear
125
+ camoufox-cli wait --url "*/dashboard" # Wait for URL pattern
126
+ ```
127
+
128
+ ### Tabs
129
+
130
+ ```bash
131
+ camoufox-cli tabs # List open tabs (with owner names)
132
+ camoufox-cli switch 2 # Switch to tab by index
133
+ ```
134
+
135
+ Named tabs let concurrent agents share one browser — same fingerprint, same cookies/login state — while each keeps its own page, element refs, and history. Tabs share one browser process (commands from different tabs may queue behind a slow one); separate sessions run as independent processes in parallel:
136
+
137
+ ```bash
138
+ camoufox-cli --tab inbox-scan-x4q open https://app.example.com/a
139
+ camoufox-cli --tab report-pull-9kf open https://app.example.com/b
140
+ camoufox-cli --tab inbox-scan-x4q snapshot -i # refs are per tab
141
+ camoufox-cli --tab inbox-scan-x4q close # frees only this tab; browser exits when the last tab closes
142
+ ```
143
+
144
+ Tab names must be unique per agent (nothing enforces this): use a task slug plus a short shell-generated random suffix (e.g. `price-scan-$(openssl rand -hex 2)`), chosen once and reused.
145
+
146
+ ### Sessions
147
+
148
+ Each named session is a separate browser process with its own randomly-generated fingerprint and its own cookies. Use sessions for isolated identities, named tabs (above) for cheap parallelism under one identity. For real multi-account isolation, combine sessions with a per-session proxy (config file) and `--persistent` — see Persistent Identity below:
149
+
150
+ ```bash
151
+ camoufox-cli sessions # List active sessions
152
+ camoufox-cli --session work open <url> # Use named session
153
+ camoufox-cli close --all # Force-close all sessions
154
+ ```
155
+
156
+ ### Cookies
157
+
158
+ ```bash
159
+ camoufox-cli cookies # Dump cookies as JSON
160
+ camoufox-cli cookies import file.json # Import cookies
161
+ camoufox-cli cookies export file.json # Export cookies
162
+ ```
163
+
164
+ ## Flags
165
+
166
+ ```
167
+ --session <name> Named session (default: "default")
168
+ --tab <name> Named tab within the session's shared browser: same fingerprint and
169
+ cookies/login, independent page/refs/history (default: "default")
170
+ --headed Show browser window (default: headless)
171
+ --timeout <seconds> Daemon idle timeout (default: 1800)
172
+ --json Output as JSON
173
+ --persistent [path] Persistent identity (see below); default path: ~/.camoufox-cli/profiles/<session>
174
+ --proxy <url> Proxy server (http:// or https://; auth: http://user:pass@host:port)
175
+ --no-geoip Disable automatic GeoIP spoofing (auto-enabled with --proxy)
176
+ --locale <tag> Force browser locale (e.g. "en-US" or "en-US,zh-CN")
177
+ --version Print version and exit
178
+ ```
179
+
180
+ ## Config File
181
+
182
+ Tired of repeating the same flags on every call? Put defaults in `~/.camoufox-cli/config.json` (override the path with `$CAMOUFOX_CLI_CONFIG`):
183
+
184
+ ```json
185
+ {
186
+ "default": {
187
+ "persistent": true,
188
+ "timeout": 3600,
189
+ "proxy": "http://user:pass@host:8080"
190
+ },
191
+ "sessions": {
192
+ "<your-session-name>": {
193
+ "proxy": "socks5://127.0.0.1:1080",
194
+ "locale": "zh-CN"
195
+ }
196
+ }
197
+ }
198
+ ```
199
+
200
+ - **`default`** applies to every session.
201
+ - **`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.
202
+ - **Command-line flags always win** over the file, which in turn wins over built-in defaults.
203
+ - 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.
204
+ - A broken config never blocks a command — it's ignored with a warning on stderr.
205
+ - 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.
206
+
207
+ ## Persistent Identity
208
+
209
+ 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.
210
+
211
+ ```bash
212
+ # First launch: generates + stores identity
213
+ camoufox-cli --persistent ~/.camoufox-cli/profiles/alice open https://example.com
214
+
215
+ # Every subsequent launch: same fingerprint, same cookies, same device
216
+ camoufox-cli --persistent ~/.camoufox-cli/profiles/alice open https://example.com
217
+ ```
218
+
219
+ **Frozen** — generated on the first launch, permanent until the directory is deleted:
220
+
221
+ - Fingerprint (UA, canvas, WebGL, fonts, navigator properties)
222
+ - OS (defaults to host OS)
223
+ - Canvas/font noise seeds
224
+
225
+ **Persisted** — stored in the file, refreshed whenever you pass the flag:
226
+
227
+ - `--locale`: sets the stored locale; pass it again to change it, omit it to keep the stored value.
228
+ - 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.
229
+
230
+ **Per-launch** — never stored; pass on every launch for it to apply:
231
+
232
+ - `--proxy`: proxies rotate or expire; re-specify each launch to avoid silently running through a stale one.
233
+ - `--no-geoip`: follows the current `--proxy`.
234
+
235
+ **Multiple identities in parallel.** Each persistent path is a distinct identity. Combine with `--session` for concurrent daemons:
236
+
237
+ ```bash
238
+ camoufox-cli --session a --persistent ~/.camoufox-cli/profiles/alice open https://...
239
+ camoufox-cli --session b --persistent ~/.camoufox-cli/profiles/bob open https://...
240
+ ```
241
+
242
+ **Resetting an identity.** Just delete the directory (`rm -rf ~/.camoufox-cli/profiles/alice`). The next launch generates a fresh one.
243
+
244
+ ## Architecture
245
+
246
+ ```
247
+ CLI (camoufox-cli) ──Unix socket──▶ Daemon (Python) ──Playwright──▶ Camoufox (Firefox)
248
+ ```
249
+
250
+ 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.
251
+
252
+ ## Related
253
+
254
+ - [google-analytics-cli](https://github.com/Bin-Huang/google-analytics-cli) -- Google Analytics CLI & Skills for AI agents (and humans)
255
+ - [google-search-console-cli](https://github.com/Bin-Huang/google-search-console-cli) -- Google Search Console CLI & Skills for AI agents (and humans)
256
+ - [youtube-analytics-cli](https://github.com/Bin-Huang/youtube-analytics-cli) -- YouTube Analytics CLI & Skills for AI agents (and humans)
257
+ - [x-analytics-cli](https://github.com/Bin-Huang/x-analytics-cli) -- X Analytics CLI & Skills for AI agents (and humans)
258
+ - [google-ads-open-cli](https://github.com/Bin-Huang/google-ads-open-cli) -- Google Ads CLI & Skills for AI agents (and humans)
259
+ - [meta-ads-open-cli](https://github.com/Bin-Huang/meta-ads-open-cli) -- Meta Ads CLI & Skills for AI agents (and humans)
260
+ - [microsoft-ads-cli](https://github.com/Bin-Huang/microsoft-ads-cli) -- Microsoft Ads CLI & Skills for AI agents (and humans)
261
+ - [amazon-ads-open-cli](https://github.com/Bin-Huang/amazon-ads-open-cli) -- Amazon Ads CLI & Skills for AI agents (and humans)
262
+ - [tiktok-ads-cli](https://github.com/Bin-Huang/tiktok-ads-cli) -- TikTok Ads CLI & Skills for AI agents (and humans)
263
+ - [linkedin-ads-cli](https://github.com/Bin-Huang/linkedin-ads-cli) -- LinkedIn Ads CLI & Skills for AI agents (and humans)
264
+ - [x-ads-cli](https://github.com/Bin-Huang/x-ads-cli) -- X Ads CLI & Skills for AI agents (and humans)
265
+ - [snapchat-ads-cli](https://github.com/Bin-Huang/snapchat-ads-cli) -- Snapchat Ads CLI & Skills for AI agents (and humans)
266
+ - [pinterest-ads-cli](https://github.com/Bin-Huang/pinterest-ads-cli) -- Pinterest Ads CLI & Skills for AI agents (and humans)
267
+ - [reddit-ads-cli](https://github.com/Bin-Huang/reddit-ads-cli) -- Reddit Ads CLI & Skills for AI agents (and humans)
268
+ - [spotify-ads-cli](https://github.com/Bin-Huang/spotify-ads-cli) -- Spotify Ads CLI & Skills for AI agents (and humans)
269
+ - [apple-ads-cli](https://github.com/Bin-Huang/apple-ads-cli) -- Apple Ads CLI & Skills for AI agents (and humans)
270
+ ## License
271
+
272
+ MIT
@@ -0,0 +1,2 @@
1
+ node_modules/
2
+ dist/
@@ -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.