ai-dev-browser 0.6.2__tar.gz → 0.7.1__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.
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/PKG-INFO +1 -1
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/__init__.py +1 -2
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/__init__.py +1 -7
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/browser.py +1 -11
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/connection.py +1 -113
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/page.py +4 -11
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/snapshot.py +2 -2
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/_generate.py +0 -1
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser.egg-info/PKG-INFO +1 -1
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser.egg-info/SOURCES.txt +0 -1
- ai_dev_browser-0.6.2/tests/integration/test_quick_connect.py +0 -108
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/.github/workflows/ci.yml +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/.github/workflows/publish.yml +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/.gitignore +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/.gitmodules +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/.pre-commit-config.yaml +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/.secrets.baseline +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/LICENSE +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/README.md +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/_cli.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/_version.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/__init__.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/accessibility.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/animation.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/audits.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/autofill.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/background_service.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/bluetooth_emulation.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/browser.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/cache_storage.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/cast.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/console.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/crash_report_context.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/css.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/debugger.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/device_access.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/device_orientation.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/dom.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/dom_debugger.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/dom_snapshot.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/dom_storage.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/emulation.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/event_breakpoints.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/extensions.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/fed_cm.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/fetch.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/file_system.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/headless_experimental.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/heap_profiler.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/indexed_db.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/input_.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/inspector.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/io.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/layer_tree.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/log.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/media.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/memory.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/network.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/overlay.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/page.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/performance.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/performance_timeline.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/preload.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/profiler.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/pwa.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/py.typed +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/runtime.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/schema.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/security.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/service_worker.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/smart_card_emulation.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/storage.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/system_info.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/target.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/tethering.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/tracing.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/util.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/web_audio.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/web_authn.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/cdp/web_mcp.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/_case.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/_cf_template.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/_element.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/_tab.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/_transport.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/ax.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/cdp.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/chrome.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/cloudflare.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/config.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/cookies.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/dialog.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/download.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/elements.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/human.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/login.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/mouse.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/navigation.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/overlays.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/port.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/process.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/storage.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/tabs.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/text_match.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/core/window.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/pool/__init__.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/pool/job.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/pool/persistence.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/pool/pool.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/pool/worker.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/profile.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/py.typed +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/__init__.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/browser_list.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/browser_start.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/browser_stop.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/cdp_send.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/click_by_html_id.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/click_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/click_by_text.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/click_by_xpath.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/cloudflare_verify.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/cookies_list.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/cookies_load.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/cookies_save.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/dialog_respond.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/download.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/drag_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/find_by_html_id.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/find_by_text.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/find_by_xpath.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/focus_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/highlight_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/hover_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/html_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/js_evaluate.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/login_interactive.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/mouse_click.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/mouse_drag.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/mouse_move.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_discover.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_emulate_focus.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_goto.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_html.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_info.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_reload.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_screenshot.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_scroll.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_wait_element.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_wait_ready.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/page_wait_url.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/screenshot_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/select_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/storage_get.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/storage_set.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/tab_close.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/tab_list.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/tab_new.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/tab_switch.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/type_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/type_by_text.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/upload_by_ref.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser/tools/window_set.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser.egg-info/dependency_links.txt +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser.egg-info/requires.txt +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/ai_dev_browser.egg-info/top_level.txt +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/pyproject.toml +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/scripts/sync_cdp.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/setup.cfg +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/__init__.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/conftest.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/__init__.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/scenarios_workspace.json +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/test_dialog_respond.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/test_find_and_interact_workflows.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/test_locator_workflows.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/test_multi_profile_pool.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/test_page_reload.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/test_startup_timeout.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/test_timeout_and_retry.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/test_workspace_workflows.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/unit/test_case.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/unit/test_cli_param_type.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/unit/test_no_acronym_rot.py +0 -0
- {ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/uv.lock +0 -0
|
@@ -99,7 +99,6 @@ __all__ = [
|
|
|
99
99
|
"browser_start",
|
|
100
100
|
"browser_stop",
|
|
101
101
|
"connect_browser",
|
|
102
|
-
"quick_connect",
|
|
103
102
|
]
|
|
104
103
|
|
|
105
104
|
# Vendored CDP protocol module
|
|
@@ -108,4 +107,4 @@ from . import cdp
|
|
|
108
107
|
from .core import connect_browser
|
|
109
108
|
|
|
110
109
|
# Core functions also available at package level
|
|
111
|
-
from .core import browser_start, browser_stop
|
|
110
|
+
from .core import browser_start, browser_stop
|
|
@@ -53,12 +53,7 @@ from .config import (
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
# Connection
|
|
56
|
-
from .connection import
|
|
57
|
-
connect_browser,
|
|
58
|
-
get_active_tab,
|
|
59
|
-
graceful_close_browser,
|
|
60
|
-
quick_connect,
|
|
61
|
-
)
|
|
56
|
+
from .connection import connect_browser, get_active_tab, graceful_close_browser
|
|
62
57
|
|
|
63
58
|
# Cookies
|
|
64
59
|
from .cookies import cookies_list, cookies_load, cookies_save
|
|
@@ -173,7 +168,6 @@ __all__ = [
|
|
|
173
168
|
"connect_browser",
|
|
174
169
|
"get_active_tab",
|
|
175
170
|
"graceful_close_browser",
|
|
176
|
-
"quick_connect",
|
|
177
171
|
# Navigation
|
|
178
172
|
"page_goto",
|
|
179
173
|
"page_reload",
|
|
@@ -76,17 +76,7 @@ def browser_start(
|
|
|
76
76
|
reuse: ReuseStrategy = DEFAULT_REUSE_STRATEGY,
|
|
77
77
|
startup_timeout: float = 30.0,
|
|
78
78
|
) -> dict:
|
|
79
|
-
"""
|
|
80
|
-
lifecycle control — managing port assignments, profile-specific
|
|
81
|
-
reuse, knowing the exact PID, calling `browser_stop` later.
|
|
82
|
-
Returns `{port, pid, headless, url, profile, reused, message}`.
|
|
83
|
-
|
|
84
|
-
For ad-hoc Python scripts (`python -c "..."`, a one-off
|
|
85
|
-
`script.py`) that just want a Tab to act on without writing the
|
|
86
|
-
full `browser_start → connect_browser → get_active_tab` ceremony,
|
|
87
|
-
prefer `from ai_dev_browser import quick_connect` — auto-detects
|
|
88
|
-
a running browser (env var → workspace scan), starts one if
|
|
89
|
-
needed, and yields a context-managed Tab in one line.
|
|
79
|
+
"""Start or reuse a browser instance.
|
|
90
80
|
|
|
91
81
|
Args:
|
|
92
82
|
port: Debug port (auto-assigned if None)
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
"""Browser connection utilities.
|
|
2
2
|
|
|
3
|
-
Provides BrowserClient (CDP client), CookieJar, connect_browser,
|
|
4
|
-
get_active_tab, and quick_connect (one-line setup for ad-hoc Python
|
|
5
|
-
scripts).
|
|
3
|
+
Provides BrowserClient (CDP client), CookieJar, connect_browser, get_active_tab.
|
|
6
4
|
"""
|
|
7
5
|
|
|
8
6
|
from __future__ import annotations
|
|
9
7
|
|
|
10
8
|
import asyncio
|
|
11
|
-
import contextlib
|
|
12
9
|
import json
|
|
13
10
|
import logging
|
|
14
|
-
import os
|
|
15
11
|
import pickle
|
|
16
12
|
import re
|
|
17
13
|
import urllib.request
|
|
18
14
|
from pathlib import Path
|
|
19
|
-
from typing import AsyncIterator
|
|
20
15
|
|
|
21
16
|
from ai_dev_browser.cdp import (
|
|
22
17
|
browser as cdp_browser,
|
|
@@ -359,113 +354,6 @@ async def get_active_tab(browser: BrowserClient) -> Tab:
|
|
|
359
354
|
return await browser.get("about:blank")
|
|
360
355
|
|
|
361
356
|
|
|
362
|
-
@contextlib.asynccontextmanager
|
|
363
|
-
async def quick_connect(
|
|
364
|
-
port: int | None = None,
|
|
365
|
-
start_if_needed: bool = True,
|
|
366
|
-
headless: bool = True,
|
|
367
|
-
temp: bool = False,
|
|
368
|
-
profile: str | None = None,
|
|
369
|
-
) -> AsyncIterator[Tab]:
|
|
370
|
-
"""Use when: you're writing an ad-hoc Python script (`python -c "..."`,
|
|
371
|
-
a one-off `script.py`, an exploratory snippet) that needs a Tab to
|
|
372
|
-
act on, and you don't want to write the full
|
|
373
|
-
`browser_start → connect_browser → get_active_tab` setup ceremony.
|
|
374
|
-
Yields a Tab as an async context manager. On exit, closes the CDP
|
|
375
|
-
connection but does NOT stop the underlying Chrome — the next
|
|
376
|
-
script can attach again.
|
|
377
|
-
|
|
378
|
-
Resolution order for which Chrome to attach to:
|
|
379
|
-
1. Explicit `port` arg
|
|
380
|
-
2. `AI_DEV_BROWSER_PORT` env var (orchestrators set this)
|
|
381
|
-
3. workspace scan via `find_workspace_chromes()` (an ai-dev-browser
|
|
382
|
-
Chrome already running for this cwd)
|
|
383
|
-
4. If none of the above and `start_if_needed=True`, call
|
|
384
|
-
`browser_start()` with the headless / temp / profile args
|
|
385
|
-
and attach to the new one.
|
|
386
|
-
|
|
387
|
-
Use `browser_start()` directly when you're an orchestrator that
|
|
388
|
-
needs explicit lifecycle control (managing port assignments,
|
|
389
|
-
profile-specific reuse, explicit stop). `quick_connect` is the
|
|
390
|
-
short path for "I just want a Tab and don't care about the
|
|
391
|
-
bookkeeping."
|
|
392
|
-
|
|
393
|
-
Args:
|
|
394
|
-
port: Specific debug port to attach. None = auto-detect.
|
|
395
|
-
start_if_needed: If no Chrome is found via env/workspace scan,
|
|
396
|
-
spawn one via `browser_start()`. Default True (the script
|
|
397
|
-
"just works"); set False if you want to fail loudly when
|
|
398
|
-
no browser is running.
|
|
399
|
-
headless: Forwarded to `browser_start` if a new Chrome is
|
|
400
|
-
spawned. Default True (matches script-style use).
|
|
401
|
-
temp: Forwarded to `browser_start`. Default False — uses the
|
|
402
|
-
workspace-default profile so the script can reuse session
|
|
403
|
-
state.
|
|
404
|
-
profile: Forwarded to `browser_start` for profile-specific
|
|
405
|
-
isolation. None = workspace default.
|
|
406
|
-
|
|
407
|
-
Yields:
|
|
408
|
-
Tab: ready to use with the rest of the core API
|
|
409
|
-
(`type_by_html_id`, `click_by_text`, `page_screenshot`, etc.).
|
|
410
|
-
|
|
411
|
-
Example:
|
|
412
|
-
from ai_dev_browser import quick_connect
|
|
413
|
-
from ai_dev_browser.core import type_by_html_id, click_by_text
|
|
414
|
-
|
|
415
|
-
async def main():
|
|
416
|
-
async with quick_connect() as tab:
|
|
417
|
-
await type_by_html_id(tab, "user", "alice")
|
|
418
|
-
await click_by_text(tab, "Sign in")
|
|
419
|
-
|
|
420
|
-
asyncio.run(main())
|
|
421
|
-
"""
|
|
422
|
-
# Lazy imports to avoid a hard dependency cycle: connection.py is
|
|
423
|
-
# low-level transport; browser_start lives in browser.py and pulls
|
|
424
|
-
# in launch logic. We only need them when actually starting.
|
|
425
|
-
actual_port = port
|
|
426
|
-
|
|
427
|
-
if actual_port is None:
|
|
428
|
-
env_port = os.environ.get("AI_DEV_BROWSER_PORT")
|
|
429
|
-
if env_port:
|
|
430
|
-
try:
|
|
431
|
-
actual_port = int(env_port)
|
|
432
|
-
except ValueError:
|
|
433
|
-
pass
|
|
434
|
-
|
|
435
|
-
if actual_port is None:
|
|
436
|
-
from .port import find_workspace_chromes
|
|
437
|
-
|
|
438
|
-
for p, _pid in find_workspace_chromes():
|
|
439
|
-
actual_port = p
|
|
440
|
-
break
|
|
441
|
-
|
|
442
|
-
if actual_port is None:
|
|
443
|
-
if not start_if_needed:
|
|
444
|
-
raise RuntimeError(
|
|
445
|
-
"quick_connect: no running ai-dev-browser Chrome found "
|
|
446
|
-
"(checked port arg, AI_DEV_BROWSER_PORT env, workspace "
|
|
447
|
-
"scan) and start_if_needed=False"
|
|
448
|
-
)
|
|
449
|
-
from .browser import browser_start
|
|
450
|
-
|
|
451
|
-
result = browser_start(headless=headless, temp=temp, profile=profile)
|
|
452
|
-
if "error" in result:
|
|
453
|
-
raise RuntimeError(
|
|
454
|
-
f"quick_connect: browser_start failed: {result['error']}"
|
|
455
|
-
)
|
|
456
|
-
actual_port = result["port"]
|
|
457
|
-
|
|
458
|
-
browser = await connect_browser(port=actual_port)
|
|
459
|
-
try:
|
|
460
|
-
tab = await get_active_tab(browser)
|
|
461
|
-
yield tab
|
|
462
|
-
finally:
|
|
463
|
-
# Release the CDP connection so the script's process can exit
|
|
464
|
-
# cleanly; Chrome itself stays alive for the next attach.
|
|
465
|
-
with contextlib.suppress(Exception):
|
|
466
|
-
await browser.close()
|
|
467
|
-
|
|
468
|
-
|
|
469
357
|
async def graceful_close_browser(
|
|
470
358
|
host: str = DEFAULT_DEBUG_HOST,
|
|
471
359
|
port: int = DEFAULT_DEBUG_PORT,
|
|
@@ -76,19 +76,12 @@ async def js_evaluate(tab: Tab, expression: str) -> dict:
|
|
|
76
76
|
`page_discover`)
|
|
77
77
|
|
|
78
78
|
For **multi-line** custom JS the shell quoting in `--expression "..."`
|
|
79
|
-
gets painful — prefer the Python API
|
|
80
|
-
`quick_connect` (handles browser attach/setup in one line):
|
|
79
|
+
gets painful — prefer the Python API:
|
|
81
80
|
|
|
82
|
-
from ai_dev_browser import quick_connect
|
|
83
81
|
from ai_dev_browser.core import js_evaluate
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
result = await js_evaluate(tab, expression='''
|
|
88
|
-
// multi-line JS here, no shell escaping
|
|
89
|
-
''')
|
|
90
|
-
|
|
91
|
-
asyncio.run(main())
|
|
82
|
+
result = await js_evaluate(tab, expression='''
|
|
83
|
+
// multi-line JS here, no shell escaping
|
|
84
|
+
''')
|
|
92
85
|
|
|
93
86
|
Args:
|
|
94
87
|
tab: Tab instance
|
|
@@ -73,7 +73,7 @@ def _format_ax_node(
|
|
|
73
73
|
if (
|
|
74
74
|
interactable_only
|
|
75
75
|
and not is_interactable
|
|
76
|
-
and role not in ("heading", "img", "alert")
|
|
76
|
+
and role not in ("heading", "image", "img", "alert")
|
|
77
77
|
):
|
|
78
78
|
if hasattr(node, "children") and node.children:
|
|
79
79
|
for child in node.children:
|
|
@@ -89,7 +89,7 @@ def _format_ax_node(
|
|
|
89
89
|
return results
|
|
90
90
|
|
|
91
91
|
# Build node info
|
|
92
|
-
if role and (name or is_interactable):
|
|
92
|
+
if role and (name or is_interactable or role == "image"):
|
|
93
93
|
ref_counter[0] += 1
|
|
94
94
|
|
|
95
95
|
# Get node_id first so we can encode it in ref
|
|
@@ -174,7 +174,6 @@ tests/integration/test_find_and_interact_workflows.py
|
|
|
174
174
|
tests/integration/test_locator_workflows.py
|
|
175
175
|
tests/integration/test_multi_profile_pool.py
|
|
176
176
|
tests/integration/test_page_reload.py
|
|
177
|
-
tests/integration/test_quick_connect.py
|
|
178
177
|
tests/integration/test_startup_timeout.py
|
|
179
178
|
tests/integration/test_timeout_and_retry.py
|
|
180
179
|
tests/integration/test_workspace_workflows.py
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
"""quick_connect — one-line ad-hoc Python script setup.
|
|
2
|
-
|
|
3
|
-
Reported by sudowork lis8 trace: LLMs writing combined-CLI scripts via
|
|
4
|
-
shell tool (`python -c "..."`) wasted 4 steps figuring out the
|
|
5
|
-
import + browser_start + connect_browser + get_active_tab boilerplate.
|
|
6
|
-
quick_connect collapses that to one async-context-manager call,
|
|
7
|
-
auto-detecting a running browser or starting one.
|
|
8
|
-
|
|
9
|
-
Resolution order tested here:
|
|
10
|
-
1. Explicit port — attaches to that one
|
|
11
|
-
2. AI_DEV_BROWSER_PORT env var
|
|
12
|
-
3. workspace scan (find_workspace_chromes)
|
|
13
|
-
4. start_if_needed=True falls through to browser_start
|
|
14
|
-
5. start_if_needed=False raises when nothing found
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
import os
|
|
18
|
-
|
|
19
|
-
import pytest
|
|
20
|
-
|
|
21
|
-
from ai_dev_browser import quick_connect
|
|
22
|
-
from ai_dev_browser.core.browser import browser_start, browser_stop
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
SKIP_INTEGRATION = os.environ.get("SKIP_INTEGRATION", "").lower() in (
|
|
26
|
-
"1",
|
|
27
|
-
"true",
|
|
28
|
-
"yes",
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@pytest.fixture(autouse=True)
|
|
33
|
-
def _integration_guard():
|
|
34
|
-
if SKIP_INTEGRATION:
|
|
35
|
-
pytest.skip("SKIP_INTEGRATION is set")
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
async def test_quick_connect_starts_browser_when_none_running(monkeypatch):
|
|
39
|
-
"""End-to-end smoke: no env, no existing browser → quick_connect
|
|
40
|
-
starts one, yields a working Tab, exit closes CDP but leaves Chrome.
|
|
41
|
-
"""
|
|
42
|
-
# Make sure auto-detect can't find anything pre-existing
|
|
43
|
-
monkeypatch.delenv("AI_DEV_BROWSER_PORT", raising=False)
|
|
44
|
-
|
|
45
|
-
# Track the port that gets started so we can clean up after
|
|
46
|
-
started_port: int | None = None
|
|
47
|
-
|
|
48
|
-
async with quick_connect(headless=True, temp=True) as tab:
|
|
49
|
-
# The Tab must actually be usable
|
|
50
|
-
title = await tab.evaluate("document.title")
|
|
51
|
-
assert isinstance(title, str)
|
|
52
|
-
# Capture the port the underlying Chrome bound — used for teardown
|
|
53
|
-
started_port = tab._connection.websocket_url.split(":")[2].split("/")[0]
|
|
54
|
-
started_port = int(started_port)
|
|
55
|
-
|
|
56
|
-
# Chrome should still be alive after exit (quick_connect only releases
|
|
57
|
-
# the CDP connection, doesn't browser_stop)
|
|
58
|
-
try:
|
|
59
|
-
from ai_dev_browser.core.port import is_port_in_use
|
|
60
|
-
|
|
61
|
-
assert is_port_in_use(port=started_port), (
|
|
62
|
-
"quick_connect should leave Chrome alive on exit so the next "
|
|
63
|
-
"script can attach again"
|
|
64
|
-
)
|
|
65
|
-
finally:
|
|
66
|
-
browser_stop(port=started_port)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
async def test_quick_connect_attaches_to_existing_via_port_arg():
|
|
70
|
-
"""Explicit port arg — quick_connect attaches to a Chrome the caller
|
|
71
|
-
already started, doesn't spawn a new one."""
|
|
72
|
-
pre = browser_start(headless=True, temp=True)
|
|
73
|
-
assert "error" not in pre
|
|
74
|
-
port = pre["port"]
|
|
75
|
-
try:
|
|
76
|
-
async with quick_connect(port=port) as tab:
|
|
77
|
-
value = await tab.evaluate("1 + 1", return_by_value=True)
|
|
78
|
-
assert value == 2
|
|
79
|
-
finally:
|
|
80
|
-
browser_stop(port=port)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
async def test_quick_connect_attaches_to_existing_via_env_var(monkeypatch):
|
|
84
|
-
"""AI_DEV_BROWSER_PORT env var — common orchestrator-injected pattern."""
|
|
85
|
-
pre = browser_start(headless=True, temp=True)
|
|
86
|
-
assert "error" not in pre
|
|
87
|
-
port = pre["port"]
|
|
88
|
-
try:
|
|
89
|
-
monkeypatch.setenv("AI_DEV_BROWSER_PORT", str(port))
|
|
90
|
-
async with quick_connect() as tab:
|
|
91
|
-
value = await tab.evaluate("'hello'", return_by_value=True)
|
|
92
|
-
assert value == "hello"
|
|
93
|
-
finally:
|
|
94
|
-
browser_stop(port=port)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
async def test_quick_connect_raises_when_start_if_needed_false_and_nothing_found(
|
|
98
|
-
monkeypatch,
|
|
99
|
-
):
|
|
100
|
-
"""Fail-loud mode: caller wants to attach to existing or fail —
|
|
101
|
-
no surprise browser launch."""
|
|
102
|
-
monkeypatch.delenv("AI_DEV_BROWSER_PORT", raising=False)
|
|
103
|
-
# Stop any running browsers first so workspace scan finds nothing
|
|
104
|
-
browser_stop(stop_all=True)
|
|
105
|
-
|
|
106
|
-
with pytest.raises(RuntimeError, match="no running ai-dev-browser Chrome"):
|
|
107
|
-
async with quick_connect(start_if_needed=False) as _tab:
|
|
108
|
-
pass # pragma: no cover (raises before yield)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
{ai_dev_browser-0.6.2 → ai_dev_browser-0.7.1}/tests/integration/test_find_and_interact_workflows.py
RENAMED
|
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
|