browser-ctl 0.2.2__tar.gz → 0.2.4__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_ctl-0.2.2 → browser_ctl-0.2.4}/PKG-INFO +1 -1
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/cli.py +34 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/extension/background.js +11 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/extension/manifest.json +1 -1
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl.egg-info/PKG-INFO +1 -1
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/pyproject.toml +1 -1
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/LICENSE +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/README.md +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/SKILL.md +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/__init__.py +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/__main__.py +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/client.py +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/extension/icon-128.png +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/extension/icon-16.png +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/extension/icon-32.png +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/extension/icon-48.png +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl/server.py +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl.egg-info/SOURCES.txt +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl.egg-info/dependency_links.txt +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl.egg-info/entry_points.txt +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl.egg-info/requires.txt +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/browser_ctl.egg-info/top_level.txt +0 -0
- {browser_ctl-0.2.2 → browser_ctl-0.2.4}/setup.cfg +0 -0
|
@@ -440,6 +440,28 @@ def _get_extension_source_dir() -> str | None:
|
|
|
440
440
|
return None
|
|
441
441
|
|
|
442
442
|
|
|
443
|
+
def _get_package_version() -> str:
|
|
444
|
+
"""Get the package version. Tries pyproject.toml first (dev), then importlib.metadata (pip)."""
|
|
445
|
+
# 1. Read from pyproject.toml (always up-to-date in source checkouts)
|
|
446
|
+
try:
|
|
447
|
+
pkg_dir = os.path.dirname(os.path.abspath(__file__))
|
|
448
|
+
toml_path = os.path.join(os.path.dirname(pkg_dir), "pyproject.toml")
|
|
449
|
+
if os.path.exists(toml_path):
|
|
450
|
+
with open(toml_path) as f:
|
|
451
|
+
for line in f:
|
|
452
|
+
if line.strip().startswith("version"):
|
|
453
|
+
return line.split("=", 1)[1].strip().strip('"').strip("'")
|
|
454
|
+
except Exception:
|
|
455
|
+
pass
|
|
456
|
+
# 2. importlib.metadata (works for pip-installed packages)
|
|
457
|
+
try:
|
|
458
|
+
from importlib.metadata import version
|
|
459
|
+
return version("browser-ctl")
|
|
460
|
+
except Exception:
|
|
461
|
+
pass
|
|
462
|
+
return "0.0.0"
|
|
463
|
+
|
|
464
|
+
|
|
443
465
|
def _install_extension() -> str | None:
|
|
444
466
|
"""Copy extension to ~/.browser-ctl/extension/ and try to open Chrome extensions page."""
|
|
445
467
|
src = _get_extension_source_dir()
|
|
@@ -451,6 +473,18 @@ def _install_extension() -> str | None:
|
|
|
451
473
|
shutil.rmtree(dest)
|
|
452
474
|
shutil.copytree(src, dest)
|
|
453
475
|
|
|
476
|
+
# Sync manifest.json version with the Python package version
|
|
477
|
+
manifest_path = os.path.join(dest, "manifest.json")
|
|
478
|
+
try:
|
|
479
|
+
with open(manifest_path, "r") as f:
|
|
480
|
+
manifest = json.load(f)
|
|
481
|
+
manifest["version"] = _get_package_version()
|
|
482
|
+
with open(manifest_path, "w") as f:
|
|
483
|
+
json.dump(manifest, f, indent=2)
|
|
484
|
+
f.write("\n")
|
|
485
|
+
except Exception:
|
|
486
|
+
pass # Non-fatal: extension still works with mismatched version
|
|
487
|
+
|
|
454
488
|
# Try to open Chrome extensions page
|
|
455
489
|
system = platform.system()
|
|
456
490
|
try:
|
|
@@ -792,6 +792,17 @@ async function contentScriptHandler(commands) {
|
|
|
792
792
|
case "click": {
|
|
793
793
|
const el = qs(params.selector, params.index, params.text);
|
|
794
794
|
el.scrollIntoView({ block: "center", behavior: "instant" });
|
|
795
|
+
// Dispatch full pointer/mouse sequence first for Vue/React SPA compatibility,
|
|
796
|
+
// then call native el.click() which produces a trusted (isTrusted:true) event
|
|
797
|
+
// that sites like GitHub require.
|
|
798
|
+
const rect = el.getBoundingClientRect();
|
|
799
|
+
const cx = rect.left + rect.width / 2;
|
|
800
|
+
const cy = rect.top + rect.height / 2;
|
|
801
|
+
const mOpts = { bubbles: true, cancelable: true, clientX: cx, clientY: cy, button: 0 };
|
|
802
|
+
el.dispatchEvent(new PointerEvent("pointerdown", { ...mOpts, pointerId: 1 }));
|
|
803
|
+
el.dispatchEvent(new MouseEvent("mousedown", mOpts));
|
|
804
|
+
el.dispatchEvent(new PointerEvent("pointerup", { ...mOpts, pointerId: 1 }));
|
|
805
|
+
el.dispatchEvent(new MouseEvent("mouseup", mOpts));
|
|
795
806
|
el.click();
|
|
796
807
|
const total = params.selector ? document.querySelectorAll(params.selector).length : 1;
|
|
797
808
|
return { clicked: params.selector || "body", index: params.index ?? 0, total, text: params.text || null };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Browser-Ctl",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.4",
|
|
5
5
|
"description": "Developer tool for CLI-driven browser automation. Control Chrome via command-line — navigate, click, type, query DOM, capture screenshots, and download files, all through a local WebSocket bridge.",
|
|
6
6
|
"permissions": [
|
|
7
7
|
"tabs",
|
|
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
|