browser-tools 0.2.0__tar.gz → 0.3.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.2.0 → browser_tools-0.3.0}/PKG-INFO +1 -1
- {browser_tools-0.2.0 → browser_tools-0.3.0}/pyproject.toml +1 -1
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/cli.py +52 -9
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/launcher.py +45 -8
- browser_tools-0.3.0/src/browser_tools/core/supervisor.py +858 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/curated.py +26 -63
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/events.py +16 -68
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/lifecycle.py +37 -1
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/list_verbs.py +20 -71
- browser_tools-0.3.0/src/browser_tools/one_shot.py +174 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/passthrough.py +96 -62
- browser_tools-0.3.0/src/browser_tools/user_settings.py +70 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_cli_lifecycle.py +45 -3
- browser_tools-0.3.0/tests/test_core_launcher.py +255 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_curated_verbs.py +16 -9
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_events.py +20 -4
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_list_verbs.py +20 -4
- browser_tools-0.3.0/tests/test_one_shot.py +375 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_passthrough.py +122 -13
- browser_tools-0.3.0/tests/test_supervisor_document_liveness.py +356 -0
- browser_tools-0.3.0/tests/test_supervisor_never_pauses.py +299 -0
- browser_tools-0.3.0/tests/test_window_marking.py +348 -0
- browser_tools-0.2.0/src/browser_tools/core/supervisor.py +0 -293
- browser_tools-0.2.0/tests/test_core_launcher.py +0 -128
- browser_tools-0.2.0/tests/test_window_marking.py +0 -140
- {browser_tools-0.2.0 → browser_tools-0.3.0}/.gitignore +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/LICENSE +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/NOTICE +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/README.md +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/__init__.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/attach_chrome.sh +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/automation_backend.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/browser_session.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/browser_state.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/camoufox_runner.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/camoufox_session.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/cdp_client.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/cdp_constants.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/cdp_handler.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/chrome_config.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/chrome_utils.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/__init__.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/attach.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/cdp_client.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/connection.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/__init__.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/accessibility.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/animation.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/audits.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/autofill.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/background_service.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/bluetooth_emulation.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/browser.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/cache_storage.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/cast.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/console.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/css.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/debugger.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/device_access.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/device_orientation.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/dom.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/dom_debugger.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/dom_snapshot.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/dom_storage.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/emulation.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/event_breakpoints.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/extensions.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/fed_cm.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/fetch.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/file_system.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/headless_experimental.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/heap_profiler.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/indexed_db.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/input.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/inspector.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/io.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/layer_tree.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/log.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/media.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/memory.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/network.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/overlay.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/page.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/performance.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/performance_timeline.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/preload.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/profiler.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/pwa.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/runtime.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/schema.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/security.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/service_worker.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/smart_card_emulation.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/storage.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/system_info.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/target.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/tethering.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/tracing.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/web_audio.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/domains/web_authn.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/errors.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/fingerprint.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/instance_status.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/protocol.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/registry.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/session.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/core/utils.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/daemon_client.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/daemon_supervisor.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/detect_interstitial.js +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/extras.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/frame_manager.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/interstitial.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/live_chrome.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/mcp_broker.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/mcp_daemon.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/mcp_response.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/mcp_session.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/native_interaction.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/native_snapshot.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/page_selection.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/persistent-session-template.mjs +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/persistent_browser.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/process_utils.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/profile_catalog.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/profiler.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/project_identity.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/screencast.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/screenshot_utils.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/session_layout.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/session_reaper.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/session_store.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/src/browser_tools/tool_registry.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/conftest.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/CORPUS.md +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/conftest.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/fixtures/dynamic.html +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/fixtures/form.html +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/fixtures/iframe.html +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/fixtures/iframe_child.html +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/fixtures/plain.html +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/fixtures/shadow.html +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/live_chromium.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/parity_comparison.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/parity_corpus.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/parity_engines.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/run_baseline.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/test_parity_baseline.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/test_parity_corpus.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/test_parity_engine.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/test_parity_gate.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/test_parity_native.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/test_parity_native_interaction.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/parity/test_parity_operator.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_attach_browser.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_auth_identity.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_automation_backend.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_browser_tools.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_camoufox.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_cdp_client.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_close_and_real_mode.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_daemonless_cli.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_dispatch.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_e2e_backend_seam.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_e2e_camoufox.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_frame_manager.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_inspect_mode.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_interstitial.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_live_chrome.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_mcp_daemon.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_mcp_surface_contract.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_native_backend.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_native_interaction.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_native_snapshot.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_new_tools.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_packaging.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_page_selection.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_persistent_browser.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_profile_liveness.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_profiler.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_profiles.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_session_dispatch.py +0 -0
- {browser_tools-0.2.0 → browser_tools-0.3.0}/tests/test_session_lifecycle.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: browser-tools
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Browser automation, debugging, and anti-detect browsing CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/dungle-scrubs/browser-tools
|
|
6
6
|
Project-URL: Repository, https://github.com/dungle-scrubs/browser-tools
|
|
@@ -27,7 +27,7 @@ import argparse
|
|
|
27
27
|
import json
|
|
28
28
|
import sys
|
|
29
29
|
|
|
30
|
-
from . import curated, events, lifecycle, list_verbs, passthrough
|
|
30
|
+
from . import curated, events, lifecycle, list_verbs, passthrough, user_settings
|
|
31
31
|
from .lifecycle import LifecycleError
|
|
32
32
|
from .passthrough import UsageError as PassthroughUsageError
|
|
33
33
|
|
|
@@ -48,6 +48,7 @@ _KNOWN_VERBS = {
|
|
|
48
48
|
"stop",
|
|
49
49
|
"cleanup",
|
|
50
50
|
"guide",
|
|
51
|
+
"window-border",
|
|
51
52
|
"help",
|
|
52
53
|
"attach",
|
|
53
54
|
"wait",
|
|
@@ -89,7 +90,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
89
90
|
launch.add_argument(
|
|
90
91
|
"--no-window-border",
|
|
91
92
|
action="store_true",
|
|
92
|
-
help=
|
|
93
|
+
help=(
|
|
94
|
+
"Do not mark this window at all (no tab-title prefix, no border). To keep "
|
|
95
|
+
"the title prefix and only hide the border, use: window-border off"
|
|
96
|
+
),
|
|
93
97
|
)
|
|
94
98
|
launch.add_argument(
|
|
95
99
|
"browser_args",
|
|
@@ -108,6 +112,19 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
108
112
|
sub.add_parser("cleanup", help="Remove stale registry entries and session dirs")
|
|
109
113
|
sub.add_parser("guide", help="Print the bundled agent manual")
|
|
110
114
|
|
|
115
|
+
border = sub.add_parser(
|
|
116
|
+
"window-border",
|
|
117
|
+
help="Show, or persistently turn on/off, the border drawn in marked windows",
|
|
118
|
+
description=(
|
|
119
|
+
"The window marker draws a colored border and a corner badge over the page "
|
|
120
|
+
"of every window it marks. They cover the page's outer edge and top-left "
|
|
121
|
+
"corner. 'off' removes them from every running browser within a second and "
|
|
122
|
+
"keeps them off for later launches, until 'on'. The tab-title prefix is not "
|
|
123
|
+
"affected. With no argument, prints the current setting."
|
|
124
|
+
),
|
|
125
|
+
)
|
|
126
|
+
border.add_argument("state", nargs="?", choices=["on", "off"], help="New setting")
|
|
127
|
+
|
|
111
128
|
help_cmd = sub.add_parser(
|
|
112
129
|
"help", help="Live CDP protocol help from a running instance, or static usage"
|
|
113
130
|
)
|
|
@@ -262,13 +279,27 @@ def _print_json(payload: object) -> None:
|
|
|
262
279
|
print(json.dumps(payload, indent=2))
|
|
263
280
|
|
|
264
281
|
|
|
265
|
-
def
|
|
266
|
-
"""
|
|
267
|
-
|
|
282
|
+
def _browser_args_from_remainder(remainder: list[str] | None) -> list[str]:
|
|
283
|
+
"""Return the verbatim BROWSER_ARGS that follow ``--``, or reject the remainder.
|
|
284
|
+
|
|
285
|
+
``launch`` takes no positional arguments. argparse.REMAINDER starts
|
|
286
|
+
collecting at the first bare token and swallows every option after it, so
|
|
287
|
+
``bt launch e2e-01 --headless`` would silently hand ``e2e-01 --headless``
|
|
288
|
+
to Chrome: Chrome opens ``http://e2e-01/`` and runs headless while
|
|
289
|
+
browser-tools believes the launch is headed (spawning the supervisor,
|
|
290
|
+
marking the window). A remainder that does not start with ``--`` is
|
|
291
|
+
therefore a usage error, not browser args.
|
|
292
|
+
"""
|
|
293
|
+
if not remainder:
|
|
268
294
|
return []
|
|
269
|
-
if
|
|
270
|
-
return
|
|
271
|
-
|
|
295
|
+
if remainder[0] == "--":
|
|
296
|
+
return remainder[1:]
|
|
297
|
+
raise PassthroughUsageError(
|
|
298
|
+
f"launch takes no positional arguments (got {remainder[0]!r}); instance "
|
|
299
|
+
f"names are assigned by the registry; use --profile NAME to bind a named "
|
|
300
|
+
f"profile. Flags for the browser itself go after '--', e.g. "
|
|
301
|
+
f"bt launch --headless -- --proxy-server=host:port"
|
|
302
|
+
)
|
|
272
303
|
|
|
273
304
|
|
|
274
305
|
def _run(args: argparse.Namespace) -> int:
|
|
@@ -284,7 +315,7 @@ def _run(args: argparse.Namespace) -> int:
|
|
|
284
315
|
port=args.port,
|
|
285
316
|
fingerprint=args.fingerprint,
|
|
286
317
|
window_border=not args.no_window_border,
|
|
287
|
-
browser_args=
|
|
318
|
+
browser_args=_browser_args_from_remainder(args.browser_args),
|
|
288
319
|
registry_path=registry_path,
|
|
289
320
|
)
|
|
290
321
|
_print_json(
|
|
@@ -322,6 +353,18 @@ def _run(args: argparse.Namespace) -> int:
|
|
|
322
353
|
print(lifecycle.guide_text())
|
|
323
354
|
return EXIT_OK
|
|
324
355
|
|
|
356
|
+
if args.command == "window-border":
|
|
357
|
+
if args.state is not None:
|
|
358
|
+
user_settings.set_window_border(args.state == user_settings.ON)
|
|
359
|
+
enabled = user_settings.window_border_enabled()
|
|
360
|
+
_print_json(
|
|
361
|
+
{
|
|
362
|
+
"window_border": user_settings.ON if enabled else user_settings.OFF,
|
|
363
|
+
"settings_path": str(user_settings.settings_path()),
|
|
364
|
+
}
|
|
365
|
+
)
|
|
366
|
+
return EXIT_OK
|
|
367
|
+
|
|
325
368
|
if args.command == "help":
|
|
326
369
|
instance, query = passthrough.resolve_help_args(args.args, registry_path=registry_path)
|
|
327
370
|
passthrough.run_help(instance, query, registry_path=registry_path)
|
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
# `binary` parameter was added to launch_browser so the CLI front can resolve
|
|
8
8
|
# the --channel policy flag to a Chrome binary before launch, and (#36) a
|
|
9
9
|
# `user_data_dir` parameter so the CLI front can bind a persistent per-profile
|
|
10
|
-
# user-data-dir instead of the throwaway session dir.
|
|
11
|
-
#
|
|
12
|
-
#
|
|
10
|
+
# user-data-dir instead of the throwaway session dir. A headed launch starts
|
|
11
|
+
# with no window (--no-startup-window) and opens its first window in the
|
|
12
|
+
# background over CDP, so the launch never takes the user's focus (see
|
|
13
|
+
# _open_first_window). Intra-package imports are rewritten to
|
|
14
|
+
# browser_tools.core. Otherwise unchanged from chrome-agent v0.5.7. See RFC-01,
|
|
15
|
+
# section "Vendoring rules".
|
|
13
16
|
|
|
14
17
|
"""Browser launch and session management.
|
|
15
18
|
|
|
@@ -167,6 +170,8 @@ async def launch_browser(
|
|
|
167
170
|
]
|
|
168
171
|
if headless:
|
|
169
172
|
args.append("--headless=new")
|
|
173
|
+
else:
|
|
174
|
+
args.append("--no-startup-window")
|
|
170
175
|
if extra_args:
|
|
171
176
|
args.extend(extra_args)
|
|
172
177
|
|
|
@@ -214,6 +219,19 @@ async def launch_browser(
|
|
|
214
219
|
process.kill()
|
|
215
220
|
raise TimeoutError("Browser did not start within 30 seconds")
|
|
216
221
|
|
|
222
|
+
if not headless:
|
|
223
|
+
try:
|
|
224
|
+
await _open_first_window(port=port)
|
|
225
|
+
except BaseException as exc:
|
|
226
|
+
# Nothing is registered yet, so a browser left running here would be
|
|
227
|
+
# an orphan no verb can see or stop. BaseException, not Exception: a
|
|
228
|
+
# launch cancelled while this awaits (Ctrl-C, a cancelled task)
|
|
229
|
+
# leaves the same orphan, and CancelledError is not an Exception.
|
|
230
|
+
process.kill()
|
|
231
|
+
if isinstance(exc, asyncio.CancelledError):
|
|
232
|
+
raise
|
|
233
|
+
raise RuntimeError(f"Browser started but its first window did not open: {exc}") from exc
|
|
234
|
+
|
|
217
235
|
# Phase 6: Pin to desktop (Linux/X11, best-effort)
|
|
218
236
|
if pin_to_desktop and not headless:
|
|
219
237
|
await _move_to_launching_desktop(pid=process.pid)
|
|
@@ -236,12 +254,13 @@ async def launch_browser(
|
|
|
236
254
|
# detached process -- it must survive the caller exiting (fire-and-forget
|
|
237
255
|
# launch model) -- that holds a CDP connection and, when the browser/window
|
|
238
256
|
# closes, retires the instance from the registry (and removes its session
|
|
239
|
-
# dir). While the browser is alive it also
|
|
257
|
+
# dir). While the browser is alive it also marks the window (tab title
|
|
258
|
+
# prefix), unless:
|
|
240
259
|
# - --no-window-border (window_border is False), or
|
|
241
|
-
# - a fingerprint profile is active: the
|
|
242
|
-
#
|
|
243
|
-
#
|
|
244
|
-
#
|
|
260
|
+
# - a fingerprint profile is active: the title prefix is page-observable
|
|
261
|
+
# (a modified document.title), and bot-defended sites -- exactly where
|
|
262
|
+
# fingerprinting is used -- are where title-diffing detectors live. See
|
|
263
|
+
# the detection audit.
|
|
245
264
|
# Headless launches get no supervisor (no window to close or mark); their
|
|
246
265
|
# registry entries are reclaimed by the launch-time prune above / cleanup.
|
|
247
266
|
if not headless:
|
|
@@ -256,6 +275,24 @@ async def launch_browser(
|
|
|
256
275
|
return instance_info
|
|
257
276
|
|
|
258
277
|
|
|
278
|
+
async def _open_first_window(*, port: int) -> None:
|
|
279
|
+
"""Open the browser's first window in the background.
|
|
280
|
+
|
|
281
|
+
Chrome started normally opens a window and makes itself the active app,
|
|
282
|
+
which takes keyboard focus and the window manager's focus from whatever
|
|
283
|
+
the user is doing (measured on macOS; ``open -g`` does not prevent it).
|
|
284
|
+
A browser started with ``--no-startup-window`` opens nothing, and a window
|
|
285
|
+
created over CDP with ``background`` set leaves focus where it is.
|
|
286
|
+
"""
|
|
287
|
+
from .cdp_client import CDPClient, get_ws_url
|
|
288
|
+
|
|
289
|
+
async with CDPClient(ws_url=get_ws_url(port=port, target_type="browser")) as cdp:
|
|
290
|
+
await cdp.send(
|
|
291
|
+
method="Target.createTarget",
|
|
292
|
+
params={"url": "about:blank", "newWindow": True, "background": True},
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
|
|
259
296
|
def cleanup_sessions(registry_path: str | None = None) -> list[str]:
|
|
260
297
|
"""Remove stale instances and their session directories.
|
|
261
298
|
|