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.
Files changed (185) hide show
  1. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/PKG-INFO +1 -1
  2. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/__init__.py +2 -1
  3. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/__init__.py +7 -1
  4. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/browser.py +11 -1
  5. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/connection.py +113 -1
  6. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/navigation.py +1 -1
  7. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/page.py +11 -4
  8. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/_generate.py +1 -0
  9. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/PKG-INFO +1 -1
  10. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/SOURCES.txt +2 -0
  11. ai_dev_browser-0.6.2/tests/integration/test_page_reload.py +84 -0
  12. ai_dev_browser-0.6.2/tests/integration/test_quick_connect.py +108 -0
  13. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.github/workflows/ci.yml +0 -0
  14. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.github/workflows/publish.yml +0 -0
  15. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.gitignore +0 -0
  16. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.gitmodules +0 -0
  17. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.pre-commit-config.yaml +0 -0
  18. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/.secrets.baseline +0 -0
  19. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/LICENSE +0 -0
  20. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/README.md +0 -0
  21. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/_cli.py +0 -0
  22. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/_version.py +0 -0
  23. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/__init__.py +0 -0
  24. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/accessibility.py +0 -0
  25. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/animation.py +0 -0
  26. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/audits.py +0 -0
  27. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/autofill.py +0 -0
  28. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/background_service.py +0 -0
  29. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/bluetooth_emulation.py +0 -0
  30. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/browser.py +0 -0
  31. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/cache_storage.py +0 -0
  32. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/cast.py +0 -0
  33. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/console.py +0 -0
  34. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/crash_report_context.py +0 -0
  35. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/css.py +0 -0
  36. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/debugger.py +0 -0
  37. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/device_access.py +0 -0
  38. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/device_orientation.py +0 -0
  39. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/dom.py +0 -0
  40. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/dom_debugger.py +0 -0
  41. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/dom_snapshot.py +0 -0
  42. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/dom_storage.py +0 -0
  43. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/emulation.py +0 -0
  44. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/event_breakpoints.py +0 -0
  45. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/extensions.py +0 -0
  46. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/fed_cm.py +0 -0
  47. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/fetch.py +0 -0
  48. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/file_system.py +0 -0
  49. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/headless_experimental.py +0 -0
  50. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/heap_profiler.py +0 -0
  51. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/indexed_db.py +0 -0
  52. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/input_.py +0 -0
  53. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/inspector.py +0 -0
  54. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/io.py +0 -0
  55. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/layer_tree.py +0 -0
  56. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/log.py +0 -0
  57. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/media.py +0 -0
  58. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/memory.py +0 -0
  59. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/network.py +0 -0
  60. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/overlay.py +0 -0
  61. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/page.py +0 -0
  62. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/performance.py +0 -0
  63. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/performance_timeline.py +0 -0
  64. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/preload.py +0 -0
  65. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/profiler.py +0 -0
  66. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/pwa.py +0 -0
  67. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/py.typed +0 -0
  68. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/runtime.py +0 -0
  69. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/schema.py +0 -0
  70. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/security.py +0 -0
  71. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/service_worker.py +0 -0
  72. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/smart_card_emulation.py +0 -0
  73. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/storage.py +0 -0
  74. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/system_info.py +0 -0
  75. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/target.py +0 -0
  76. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/tethering.py +0 -0
  77. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/tracing.py +0 -0
  78. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/util.py +0 -0
  79. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/web_audio.py +0 -0
  80. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/web_authn.py +0 -0
  81. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/cdp/web_mcp.py +0 -0
  82. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_case.py +0 -0
  83. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_cf_template.py +0 -0
  84. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_element.py +0 -0
  85. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_tab.py +0 -0
  86. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/_transport.py +0 -0
  87. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/ax.py +0 -0
  88. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/cdp.py +0 -0
  89. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/chrome.py +0 -0
  90. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/cloudflare.py +0 -0
  91. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/config.py +0 -0
  92. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/cookies.py +0 -0
  93. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/dialog.py +0 -0
  94. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/download.py +0 -0
  95. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/elements.py +0 -0
  96. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/human.py +0 -0
  97. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/login.py +0 -0
  98. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/mouse.py +0 -0
  99. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/overlays.py +0 -0
  100. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/port.py +0 -0
  101. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/process.py +0 -0
  102. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/snapshot.py +0 -0
  103. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/storage.py +0 -0
  104. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/tabs.py +0 -0
  105. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/text_match.py +0 -0
  106. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/core/window.py +0 -0
  107. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/__init__.py +0 -0
  108. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/job.py +0 -0
  109. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/persistence.py +0 -0
  110. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/pool.py +0 -0
  111. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/pool/worker.py +0 -0
  112. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/profile.py +0 -0
  113. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/py.typed +0 -0
  114. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/__init__.py +0 -0
  115. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/browser_list.py +0 -0
  116. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/browser_start.py +0 -0
  117. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/browser_stop.py +0 -0
  118. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cdp_send.py +0 -0
  119. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/click_by_html_id.py +0 -0
  120. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/click_by_ref.py +0 -0
  121. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/click_by_text.py +0 -0
  122. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/click_by_xpath.py +0 -0
  123. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cloudflare_verify.py +0 -0
  124. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cookies_list.py +0 -0
  125. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cookies_load.py +0 -0
  126. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/cookies_save.py +0 -0
  127. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/dialog_respond.py +0 -0
  128. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/download.py +0 -0
  129. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/drag_by_ref.py +0 -0
  130. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/find_by_html_id.py +0 -0
  131. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/find_by_text.py +0 -0
  132. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/find_by_xpath.py +0 -0
  133. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/focus_by_ref.py +0 -0
  134. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/highlight_by_ref.py +0 -0
  135. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/hover_by_ref.py +0 -0
  136. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/html_by_ref.py +0 -0
  137. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/js_evaluate.py +0 -0
  138. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/login_interactive.py +0 -0
  139. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/mouse_click.py +0 -0
  140. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/mouse_drag.py +0 -0
  141. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/mouse_move.py +0 -0
  142. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_discover.py +0 -0
  143. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_emulate_focus.py +0 -0
  144. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_goto.py +0 -0
  145. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_html.py +0 -0
  146. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_info.py +0 -0
  147. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_reload.py +0 -0
  148. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_screenshot.py +0 -0
  149. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_scroll.py +0 -0
  150. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_wait_element.py +0 -0
  151. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_wait_ready.py +0 -0
  152. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/page_wait_url.py +0 -0
  153. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/screenshot_by_ref.py +0 -0
  154. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/select_by_ref.py +0 -0
  155. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/storage_get.py +0 -0
  156. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/storage_set.py +0 -0
  157. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/tab_close.py +0 -0
  158. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/tab_list.py +0 -0
  159. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/tab_new.py +0 -0
  160. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/tab_switch.py +0 -0
  161. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/type_by_ref.py +0 -0
  162. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/type_by_text.py +0 -0
  163. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/upload_by_ref.py +0 -0
  164. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser/tools/window_set.py +0 -0
  165. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/dependency_links.txt +0 -0
  166. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/requires.txt +0 -0
  167. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/ai_dev_browser.egg-info/top_level.txt +0 -0
  168. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/pyproject.toml +0 -0
  169. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/scripts/sync_cdp.py +0 -0
  170. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/setup.cfg +0 -0
  171. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/__init__.py +0 -0
  172. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/conftest.py +0 -0
  173. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/__init__.py +0 -0
  174. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/scenarios_workspace.json +0 -0
  175. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_dialog_respond.py +0 -0
  176. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_find_and_interact_workflows.py +0 -0
  177. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_locator_workflows.py +0 -0
  178. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_multi_profile_pool.py +0 -0
  179. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_startup_timeout.py +0 -0
  180. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_timeout_and_retry.py +0 -0
  181. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/integration/test_workspace_workflows.py +0 -0
  182. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/unit/test_case.py +0 -0
  183. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/unit/test_cli_param_type.py +0 -0
  184. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/tests/unit/test_no_acronym_rot.py +0 -0
  185. {ai_dev_browser-0.6.0 → ai_dev_browser-0.6.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ai-dev-browser
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: A browser for AI to develop web automation — human-like automation that works seamlessly in a world designed for humans
5
5
  Author: sudoprivacy
6
6
  License: AGPL-3.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 connect_browser, get_active_tab, graceful_close_browser
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
- """Start or reuse a browser instance.
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, get_active_tab.
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,
@@ -68,7 +68,7 @@ async def page_reload(tab: Tab, ignore_cache: bool = True) -> bool:
68
68
  Returns:
69
69
  True on success
70
70
  """
71
- await tab.reload(ignore_cache=ignore_cache)
71
+ await tab.page_reload(ignore_cache=ignore_cache)
72
72
  return True
73
73
 
74
74
 
@@ -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
- result = await js_evaluate(tab, expression='''
83
- // multi-line JS here, no shell escaping
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
@@ -26,6 +26,7 @@ INTERNAL = {
26
26
  "graceful_close_browser",
27
27
  "connect_browser",
28
28
  "get_active_tab",
29
+ "quick_connect",
29
30
  }
30
31
 
31
32
  # Per-tool metadata overrides. Key = function name, value = dict of overrides.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ai-dev-browser
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: A browser for AI to develop web automation — human-like automation that works seamlessly in a world designed for humans
5
5
  Author: sudoprivacy
6
6
  License: AGPL-3.0
@@ -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