browser-agent-server 1.0.0__tar.gz → 1.0.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.
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/CHANGELOG.md +17 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/PKG-INFO +1 -1
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/pyproject.toml +1 -1
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/src/browser_agent/chrome.py +1 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/src/browser_agent/cli.py +2 -0
- browser_agent_server-1.0.2/tests/test_chrome_state_dir.py +48 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/uv.lock +1 -1
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/.github/workflows/ci.yml +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/.github/workflows/release.yml +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/.gitignore +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/AGENTS.md +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/LICENSE +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/README.md +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/docs/api.md +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/docs/architecture.md +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/docs/deployment.md +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/docs/publishing.md +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/docs/security.md +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/docs/troubleshooting.md +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/src/browser_agent/__init__.py +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/src/browser_agent/data/browser-agent.service +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/src/browser_agent/server.py +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/src/browser_agent/vision_agent.py +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/src/browser_agent/x11_input.py +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/tests/test_bezier.py +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/tests/test_cli.py +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/tests/test_client.py +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/tests/test_cloudflare.py +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/tests/test_http_api.py +0 -0
- {browser_agent_server-1.0.0 → browser_agent_server-1.0.2}/tests/test_ws_frames.py +0 -0
|
@@ -5,6 +5,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [1.0.2] - 2026-10-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `browser-agent --version` prints the installed package version (the flag was
|
|
13
|
+
missing — noticed while operating the production daemon).
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [1.0.1] - 2026-10-10
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Create the XDG state directory before opening `chrome.err`: a fresh install
|
|
21
|
+
(empty `~/.local/state/browser-agent/`) crashed the very first browser
|
|
22
|
+
launch with `FileNotFoundError`. Found during the production migration onto
|
|
23
|
+
the published package. Regression tests added.
|
|
24
|
+
|
|
8
25
|
## [1.0.0] - 2026-10-10
|
|
9
26
|
|
|
10
27
|
Initial public release. Extracted from a private production deployment where
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: browser-agent-server
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Real headful Chrome on Xvfb with a hardware-level X11 mouse, Cloudflare Turnstile auto-solve and zero-leak CDP. Localhost HTTP API + CLI + Python SDK.
|
|
5
5
|
Project-URL: Homepage, https://github.com/vernikr/browser-agent
|
|
6
6
|
Project-URL: Repository, https://github.com/vernikr/browser-agent
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "browser-agent-server"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.2"
|
|
4
4
|
description = "Real headful Chrome on Xvfb with a hardware-level X11 mouse, Cloudflare Turnstile auto-solve and zero-leak CDP. Localhost HTTP API + CLI + Python SDK."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -239,6 +239,7 @@ class RealChromeSession:
|
|
|
239
239
|
self._stop_chrome_only()
|
|
240
240
|
|
|
241
241
|
self.user_data_dir.mkdir(parents=True, exist_ok=True)
|
|
242
|
+
self._stderr_path.parent.mkdir(parents=True, exist_ok=True)
|
|
242
243
|
for lock_name in ("SingletonLock", "SingletonCookie", "SingletonSocket"):
|
|
243
244
|
lock_path = self.user_data_dir / lock_name
|
|
244
245
|
if lock_path.exists() or lock_path.is_symlink():
|
|
@@ -27,6 +27,7 @@ import urllib.request
|
|
|
27
27
|
from importlib import resources
|
|
28
28
|
from pathlib import Path
|
|
29
29
|
|
|
30
|
+
from . import __version__
|
|
30
31
|
from .chrome import find_chrome_binary, is_warp_proxy_ready
|
|
31
32
|
from .server import API_VERSION, DEFAULT_HOST, DEFAULT_IDLE_TIMEOUT, DEFAULT_PORT, serve
|
|
32
33
|
|
|
@@ -264,6 +265,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
264
265
|
common.add_argument("--port", type=int, default=DEFAULT_PORT, help="Daemon HTTP port (default: 8765)")
|
|
265
266
|
|
|
266
267
|
parser = argparse.ArgumentParser(prog="browser-agent", description="Real Chrome + X11 Mouse Agent", parents=[common])
|
|
268
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
267
269
|
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
268
270
|
|
|
269
271
|
p_serve = sub.add_parser("serve", parents=[common], help="Run the localhost HTTP daemon (127.0.0.1:8765)")
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Regression: daemon must create the XDG state dir before opening chrome.err.
|
|
2
|
+
|
|
3
|
+
Found on a fresh production install: ChromeManager.start() crashed with
|
|
4
|
+
FileNotFoundError ('~/.local/state/browser-agent/chrome.err') because the state
|
|
5
|
+
directory is only created lazily by other code paths.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import subprocess
|
|
11
|
+
|
|
12
|
+
from browser_agent import chrome as chrome_mod
|
|
13
|
+
from browser_agent.chrome import RealChromeSession
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class _FakePopen:
|
|
17
|
+
def __init__(self, args, env=None, stdout=None, stderr=None):
|
|
18
|
+
self.args = args
|
|
19
|
+
self.pid = 4242
|
|
20
|
+
self.returncode = None
|
|
21
|
+
|
|
22
|
+
def poll(self):
|
|
23
|
+
return None # pretend chrome is alive
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_start_creates_state_dir(monkeypatch, tmp_path):
|
|
27
|
+
state_home = tmp_path / "empty-state"
|
|
28
|
+
monkeypatch.setenv("XDG_STATE_HOME", str(state_home))
|
|
29
|
+
monkeypatch.setenv("HOME", str(tmp_path))
|
|
30
|
+
|
|
31
|
+
mgr = RealChromeSession(cdp_port=9223)
|
|
32
|
+
assert not mgr._stderr_path.parent.exists()
|
|
33
|
+
|
|
34
|
+
monkeypatch.setattr(mgr.x11, "start", lambda: None)
|
|
35
|
+
monkeypatch.setattr(chrome_mod, "find_chrome_binary", lambda: "/usr/bin/true")
|
|
36
|
+
monkeypatch.setattr(mgr, "_wait_for_cdp", lambda timeout=12.0: {"webSocketDebuggerUrl": "ws://x"})
|
|
37
|
+
monkeypatch.setattr(subprocess, "Popen", _FakePopen)
|
|
38
|
+
|
|
39
|
+
mgr.start() # must not raise FileNotFoundError
|
|
40
|
+
assert mgr._stderr_path.parent.is_dir()
|
|
41
|
+
mgr._stderr_file.close()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_start_respects_profile_env(monkeypatch, tmp_path):
|
|
45
|
+
monkeypatch.setenv("XDG_STATE_HOME", str(tmp_path / "state"))
|
|
46
|
+
monkeypatch.setenv("BROWSER_AGENT_PROFILE_DIR", "/tmp/browser-agent-profile")
|
|
47
|
+
mgr = RealChromeSession()
|
|
48
|
+
assert str(mgr.user_data_dir) == "/tmp/browser-agent-profile"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|