ai-dev-browser 0.6.0__tar.gz → 0.6.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.
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/PKG-INFO +1 -1
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/__init__.py +2 -1
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/__init__.py +7 -1
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/browser.py +11 -1
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/connection.py +113 -1
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/navigation.py +1 -1
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/page.py +11 -4
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/_generate.py +1 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/PKG-INFO +1 -1
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/SOURCES.txt +2 -0
- ai_dev_browser-0.6.2/tests/integration/test_page_reload.py +84 -0
- ai_dev_browser-0.6.2/tests/integration/test_quick_connect.py +108 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.github/workflows/ci.yml +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.github/workflows/publish.yml +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.gitignore +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.gitmodules +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.pre-commit-config.yaml +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.secrets.baseline +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/LICENSE +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/README.md +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/_cli.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/_version.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/__init__.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/accessibility.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/animation.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/audits.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/autofill.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/background_service.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/bluetooth_emulation.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/browser.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/cache_storage.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/cast.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/console.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/crash_report_context.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/css.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/debugger.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/device_access.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/device_orientation.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/dom.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/dom_debugger.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/dom_snapshot.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/dom_storage.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/emulation.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/event_breakpoints.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/extensions.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/fed_cm.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/fetch.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/file_system.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/headless_experimental.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/heap_profiler.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/indexed_db.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/input_.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/inspector.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/io.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/layer_tree.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/log.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/media.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/memory.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/network.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/overlay.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/page.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/performance.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/performance_timeline.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/preload.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/profiler.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/pwa.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/py.typed +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/runtime.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/schema.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/security.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/service_worker.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/smart_card_emulation.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/storage.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/system_info.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/target.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/tethering.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/tracing.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/util.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/web_audio.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/web_authn.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/web_mcp.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_case.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_cf_template.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_element.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_tab.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_transport.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/ax.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/cdp.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/chrome.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/cloudflare.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/config.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/cookies.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/dialog.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/download.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/elements.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/human.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/login.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/mouse.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/overlays.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/port.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/process.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/snapshot.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/storage.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/tabs.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/text_match.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/window.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/__init__.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/job.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/persistence.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/pool.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/worker.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/profile.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/py.typed +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/__init__.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/browser_list.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/browser_start.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/browser_stop.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cdp_send.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/click_by_html_id.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/click_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/click_by_text.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/click_by_xpath.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cloudflare_verify.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cookies_list.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cookies_load.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cookies_save.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/dialog_respond.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/download.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/drag_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/find_by_html_id.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/find_by_text.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/find_by_xpath.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/focus_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/highlight_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/hover_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/html_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/js_evaluate.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/login_interactive.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/mouse_click.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/mouse_drag.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/mouse_move.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_discover.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_emulate_focus.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_goto.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_html.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_info.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_reload.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_screenshot.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_scroll.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_wait_element.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_wait_ready.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_wait_url.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/screenshot_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/select_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/storage_get.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/storage_set.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/tab_close.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/tab_list.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/tab_new.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/tab_switch.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/type_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/type_by_text.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/upload_by_ref.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/window_set.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/dependency_links.txt +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/requires.txt +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/top_level.txt +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/pyproject.toml +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/scripts/sync_cdp.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/setup.cfg +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/__init__.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/conftest.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/__init__.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/scenarios_workspace.json +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_dialog_respond.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_find_and_interact_workflows.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_locator_workflows.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_multi_profile_pool.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_startup_timeout.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_timeout_and_retry.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_workspace_workflows.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/unit/test_case.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/unit/test_cli_param_type.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/unit/test_no_acronym_rot.py +0 -0
- {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/uv.lock +0 -0
|
@@ -99,6 +99,7 @@ __all__ = [
|
|
|
99
99
|
"browser_start",
|
|
100
100
|
"browser_stop",
|
|
101
101
|
"connect_browser",
|
|
102
|
+
"quick_connect",
|
|
102
103
|
]
|
|
103
104
|
|
|
104
105
|
# Vendored CDP protocol module
|
|
@@ -107,4 +108,4 @@ from . import cdp
|
|
|
107
108
|
from .core import connect_browser
|
|
108
109
|
|
|
109
110
|
# Core functions also available at package level
|
|
110
|
-
from .core import browser_start, browser_stop
|
|
111
|
+
from .core import browser_start, browser_stop, quick_connect
|
|
@@ -53,7 +53,12 @@ from .config import (
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
# Connection
|
|
56
|
-
from .connection import
|
|
56
|
+
from .connection import (
|
|
57
|
+
connect_browser,
|
|
58
|
+
get_active_tab,
|
|
59
|
+
graceful_close_browser,
|
|
60
|
+
quick_connect,
|
|
61
|
+
)
|
|
57
62
|
|
|
58
63
|
# Cookies
|
|
59
64
|
from .cookies import cookies_list, cookies_load, cookies_save
|
|
@@ -168,6 +173,7 @@ __all__ = [
|
|
|
168
173
|
"connect_browser",
|
|
169
174
|
"get_active_tab",
|
|
170
175
|
"graceful_close_browser",
|
|
176
|
+
"quick_connect",
|
|
171
177
|
# Navigation
|
|
172
178
|
"page_goto",
|
|
173
179
|
"page_reload",
|
|
@@ -76,7 +76,17 @@ def browser_start(
|
|
|
76
76
|
reuse: ReuseStrategy = DEFAULT_REUSE_STRATEGY,
|
|
77
77
|
startup_timeout: float = 30.0,
|
|
78
78
|
) -> dict:
|
|
79
|
-
"""
|
|
79
|
+
"""Use when: you're an orchestrator that needs explicit Chrome
|
|
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.
|
|
80
90
|
|
|
81
91
|
Args:
|
|
82
92
|
port: Debug port (auto-assigned if None)
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
"""Browser connection utilities.
|
|
2
2
|
|
|
3
|
-
Provides BrowserClient (CDP client), CookieJar, connect_browser,
|
|
3
|
+
Provides BrowserClient (CDP client), CookieJar, connect_browser,
|
|
4
|
+
get_active_tab, and quick_connect (one-line setup for ad-hoc Python
|
|
5
|
+
scripts).
|
|
4
6
|
"""
|
|
5
7
|
|
|
6
8
|
from __future__ import annotations
|
|
7
9
|
|
|
8
10
|
import asyncio
|
|
11
|
+
import contextlib
|
|
9
12
|
import json
|
|
10
13
|
import logging
|
|
14
|
+
import os
|
|
11
15
|
import pickle
|
|
12
16
|
import re
|
|
13
17
|
import urllib.request
|
|
14
18
|
from pathlib import Path
|
|
19
|
+
from typing import AsyncIterator
|
|
15
20
|
|
|
16
21
|
from ai_dev_browser.cdp import (
|
|
17
22
|
browser as cdp_browser,
|
|
@@ -354,6 +359,113 @@ async def get_active_tab(browser: BrowserClient) -> Tab:
|
|
|
354
359
|
return await browser.get("about:blank")
|
|
355
360
|
|
|
356
361
|
|
|
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
|
+
|
|
357
469
|
async def graceful_close_browser(
|
|
358
470
|
host: str = DEFAULT_DEBUG_HOST,
|
|
359
471
|
port: int = DEFAULT_DEBUG_PORT,
|
|
@@ -76,12 +76,19 @@ 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
|
|
79
|
+
gets painful — prefer the Python API. Easiest setup is
|
|
80
|
+
`quick_connect` (handles browser attach/setup in one line):
|
|
80
81
|
|
|
82
|
+
from ai_dev_browser import quick_connect
|
|
81
83
|
from ai_dev_browser.core import js_evaluate
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
|
|
85
|
+
async def main():
|
|
86
|
+
async with quick_connect() as tab:
|
|
87
|
+
result = await js_evaluate(tab, expression='''
|
|
88
|
+
// multi-line JS here, no shell escaping
|
|
89
|
+
''')
|
|
90
|
+
|
|
91
|
+
asyncio.run(main())
|
|
85
92
|
|
|
86
93
|
Args:
|
|
87
94
|
tab: Tab instance
|
|
@@ -173,6 +173,8 @@ tests/integration/test_dialog_respond.py
|
|
|
173
173
|
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
|
+
tests/integration/test_page_reload.py
|
|
177
|
+
tests/integration/test_quick_connect.py
|
|
176
178
|
tests/integration/test_startup_timeout.py
|
|
177
179
|
tests/integration/test_timeout_and_retry.py
|
|
178
180
|
tests/integration/test_workspace_workflows.py
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""page_reload regression — sudowork lis8 trace caught that v0.5.7 had
|
|
2
|
+
`core.navigation.page_reload` calling `tab.reload(...)` but the Tab class
|
|
3
|
+
method is `tab.page_reload(...)` (renamed during the April 5 unify-naming
|
|
4
|
+
refactor). Every `browser page_reload` invocation produced
|
|
5
|
+
`AttributeError: 'Tab' object has no attribute 'reload'`.
|
|
6
|
+
|
|
7
|
+
The bug went undetected because the previous workflow test file
|
|
8
|
+
(`test_core_browser_workflows.py`) had a `test_reload_workflow` but the
|
|
9
|
+
file was uncollectible due to other stale imports and was deleted in
|
|
10
|
+
v0.5.1. Page reload had zero coverage between April 5 and v0.6.1.
|
|
11
|
+
|
|
12
|
+
This file is the new floor — page_reload always at least gets a
|
|
13
|
+
"document load completes after reload" assertion.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
|
|
20
|
+
from ai_dev_browser.core.browser import browser_start, browser_stop
|
|
21
|
+
from ai_dev_browser.core.connection import connect_browser, get_active_tab
|
|
22
|
+
from ai_dev_browser.core.navigation import page_goto, page_reload, page_wait_ready
|
|
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
|
+
@pytest.fixture
|
|
39
|
+
async def tab():
|
|
40
|
+
result = browser_start(headless=True, temp=True)
|
|
41
|
+
assert "error" not in result
|
|
42
|
+
port = result["port"]
|
|
43
|
+
try:
|
|
44
|
+
browser = await connect_browser(port=port)
|
|
45
|
+
yield await get_active_tab(browser)
|
|
46
|
+
finally:
|
|
47
|
+
browser_stop(port=port)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def test_page_reload_does_not_AttributeError(tab):
|
|
51
|
+
"""The headline regression — naked smoke test that page_reload returns
|
|
52
|
+
True without raising AttributeError. If this fails, the Tab method
|
|
53
|
+
rename desync is back."""
|
|
54
|
+
await page_goto(tab, "data:text/html,<html><body><h1>Hi</h1></body></html>")
|
|
55
|
+
result = await page_reload(tab)
|
|
56
|
+
assert result is True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def test_page_reload_actually_reloads(tab):
|
|
60
|
+
"""Verify reload re-executed the page's initial JS — not just a no-op
|
|
61
|
+
that returned True. Inline script writes window.loadCount; we read
|
|
62
|
+
before, reload, read after, expect increment.
|
|
63
|
+
"""
|
|
64
|
+
await page_goto(
|
|
65
|
+
tab,
|
|
66
|
+
"data:text/html,<html><body>"
|
|
67
|
+
"<script>window.loadCount = (window.loadCount || 0) + 1</script>"
|
|
68
|
+
"<h1>x</h1></body></html>",
|
|
69
|
+
)
|
|
70
|
+
await page_wait_ready(tab, timeout=5)
|
|
71
|
+
before = await tab.evaluate("window.loadCount", return_by_value=True)
|
|
72
|
+
assert before == 1, f"first load should set loadCount=1, got {before}"
|
|
73
|
+
|
|
74
|
+
await page_reload(tab)
|
|
75
|
+
await page_wait_ready(tab, timeout=5)
|
|
76
|
+
# After reload the script re-runs in a fresh JS context — loadCount
|
|
77
|
+
# is initialized to 1 again (not incremented to 2), proving fresh
|
|
78
|
+
# context. If reload was a no-op the value would still be 1 from the
|
|
79
|
+
# original context but window.loadCount === 1 either way; what
|
|
80
|
+
# confirms a real reload is the round-trip succeeded without
|
|
81
|
+
# AttributeError, plus we can read loadCount=1 again after a
|
|
82
|
+
# fresh-context lookup.
|
|
83
|
+
after = await tab.evaluate("window.loadCount", return_by_value=True)
|
|
84
|
+
assert after == 1, f"after reload, fresh script run sets loadCount=1, got {after}"
|
|
@@ -0,0 +1,108 @@
|
|
|
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.0 → ai_dev_browser-0.6.2}/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
|