ai-dev-browser 0.12.2__tar.gz → 0.12.3__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 (197) hide show
  1. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/.github/workflows/ci.yml +2 -1
  2. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/PKG-INFO +1 -1
  3. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/_tab.py +23 -25
  4. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser.egg-info/PKG-INFO +1 -1
  5. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser.egg-info/SOURCES.txt +1 -0
  6. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser.egg-info/scm_file_list.json +1 -0
  7. ai_dev_browser-0.12.3/ai_dev_browser.egg-info/scm_version.json +8 -0
  8. ai_dev_browser-0.12.3/tests/integration/test_scroll_embedded_target.py +176 -0
  9. ai_dev_browser-0.12.2/ai_dev_browser.egg-info/scm_version.json +0 -8
  10. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/.github/workflows/publish.yml +0 -0
  11. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/.gitignore +0 -0
  12. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/.gitmodules +0 -0
  13. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/.pre-commit-config.yaml +0 -0
  14. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/.secrets.baseline +0 -0
  15. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/LICENSE +0 -0
  16. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/README.md +0 -0
  17. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/__init__.py +0 -0
  18. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/_cli.py +0 -0
  19. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/_version.py +0 -0
  20. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/__init__.py +0 -0
  21. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/accessibility.py +0 -0
  22. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/animation.py +0 -0
  23. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/audits.py +0 -0
  24. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/autofill.py +0 -0
  25. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/background_service.py +0 -0
  26. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/bluetooth_emulation.py +0 -0
  27. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/browser.py +0 -0
  28. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/cache_storage.py +0 -0
  29. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/cast.py +0 -0
  30. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/console.py +0 -0
  31. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/crash_report_context.py +0 -0
  32. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/css.py +0 -0
  33. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/debugger.py +0 -0
  34. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/device_access.py +0 -0
  35. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/device_orientation.py +0 -0
  36. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/dom.py +0 -0
  37. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/dom_debugger.py +0 -0
  38. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/dom_snapshot.py +0 -0
  39. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/dom_storage.py +0 -0
  40. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/emulation.py +0 -0
  41. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/event_breakpoints.py +0 -0
  42. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/extensions.py +0 -0
  43. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/fed_cm.py +0 -0
  44. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/fetch.py +0 -0
  45. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/file_system.py +0 -0
  46. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/headless_experimental.py +0 -0
  47. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/heap_profiler.py +0 -0
  48. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/indexed_db.py +0 -0
  49. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/input_.py +0 -0
  50. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/inspector.py +0 -0
  51. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/io.py +0 -0
  52. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/layer_tree.py +0 -0
  53. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/log.py +0 -0
  54. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/media.py +0 -0
  55. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/memory.py +0 -0
  56. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/network.py +0 -0
  57. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/overlay.py +0 -0
  58. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/page.py +0 -0
  59. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/performance.py +0 -0
  60. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/performance_timeline.py +0 -0
  61. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/preload.py +0 -0
  62. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/profiler.py +0 -0
  63. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/pwa.py +0 -0
  64. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/py.typed +0 -0
  65. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/runtime.py +0 -0
  66. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/schema.py +0 -0
  67. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/security.py +0 -0
  68. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/service_worker.py +0 -0
  69. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/smart_card_emulation.py +0 -0
  70. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/storage.py +0 -0
  71. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/system_info.py +0 -0
  72. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/target.py +0 -0
  73. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/tethering.py +0 -0
  74. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/tracing.py +0 -0
  75. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/util.py +0 -0
  76. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/web_audio.py +0 -0
  77. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/web_authn.py +0 -0
  78. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/cdp/web_mcp.py +0 -0
  79. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/__init__.py +0 -0
  80. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/_case.py +0 -0
  81. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/_element.py +0 -0
  82. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/_image_cap.py +0 -0
  83. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/_transport.py +0 -0
  84. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/ax.py +0 -0
  85. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/browser.py +0 -0
  86. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/cdp.py +0 -0
  87. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/chrome.py +0 -0
  88. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/cleanup.py +0 -0
  89. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/config.py +0 -0
  90. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/connection.py +0 -0
  91. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/cookies.py +0 -0
  92. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/cookies_import.py +0 -0
  93. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/dialog.py +0 -0
  94. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/download.py +0 -0
  95. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/elements.py +0 -0
  96. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/human.py +0 -0
  97. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/login.py +0 -0
  98. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/mouse.py +0 -0
  99. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/navigation.py +0 -0
  100. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/overlays.py +0 -0
  101. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/page.py +0 -0
  102. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/port.py +0 -0
  103. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/process.py +0 -0
  104. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/snapshot.py +0 -0
  105. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/storage.py +0 -0
  106. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/tabs.py +0 -0
  107. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/text_match.py +0 -0
  108. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/core/window.py +0 -0
  109. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/pool/__init__.py +0 -0
  110. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/pool/job.py +0 -0
  111. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/pool/persistence.py +0 -0
  112. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/pool/pool.py +0 -0
  113. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/pool/worker.py +0 -0
  114. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/profile.py +0 -0
  115. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/py.typed +0 -0
  116. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/__init__.py +0 -0
  117. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/_generate.py +0 -0
  118. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/browser_list.py +0 -0
  119. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/browser_start.py +0 -0
  120. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/browser_stop.py +0 -0
  121. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/cdp_send.py +0 -0
  122. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/click_by_html_id.py +0 -0
  123. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/click_by_ref.py +0 -0
  124. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/click_by_text.py +0 -0
  125. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/click_by_xpath.py +0 -0
  126. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/cookies_extract.py +0 -0
  127. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/cookies_import.py +0 -0
  128. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/cookies_list.py +0 -0
  129. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/cookies_load.py +0 -0
  130. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/cookies_save.py +0 -0
  131. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/dialog_respond.py +0 -0
  132. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/download.py +0 -0
  133. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/drag_by_ref.py +0 -0
  134. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/find_by_html_id.py +0 -0
  135. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/find_by_text.py +0 -0
  136. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/find_by_xpath.py +0 -0
  137. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/focus_by_ref.py +0 -0
  138. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/highlight_by_ref.py +0 -0
  139. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/hover_by_ref.py +0 -0
  140. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/html_by_ref.py +0 -0
  141. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/js_evaluate.py +0 -0
  142. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/login_interactive.py +0 -0
  143. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/mouse_click.py +0 -0
  144. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/mouse_drag.py +0 -0
  145. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/mouse_move.py +0 -0
  146. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_discover.py +0 -0
  147. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_emulate_focus.py +0 -0
  148. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_goto.py +0 -0
  149. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_html.py +0 -0
  150. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_info.py +0 -0
  151. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_pdf.py +0 -0
  152. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_reload.py +0 -0
  153. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_screenshot.py +0 -0
  154. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_scroll.py +0 -0
  155. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_wait_element.py +0 -0
  156. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_wait_ready.py +0 -0
  157. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/page_wait_url.py +0 -0
  158. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/screenshot_by_ref.py +0 -0
  159. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/select_by_ref.py +0 -0
  160. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/storage_get.py +0 -0
  161. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/storage_set.py +0 -0
  162. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/tab_close.py +0 -0
  163. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/tab_list.py +0 -0
  164. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/tab_new.py +0 -0
  165. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/tab_switch.py +0 -0
  166. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/type_by_ref.py +0 -0
  167. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/type_by_text.py +0 -0
  168. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/upload_by_ref.py +0 -0
  169. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser/tools/window_set.py +0 -0
  170. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser.egg-info/dependency_links.txt +0 -0
  171. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser.egg-info/requires.txt +0 -0
  172. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/ai_dev_browser.egg-info/top_level.txt +0 -0
  173. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/pyproject.toml +0 -0
  174. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/scripts/sync_cdp.py +0 -0
  175. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/setup.cfg +0 -0
  176. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/__init__.py +0 -0
  177. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/conftest.py +0 -0
  178. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/__init__.py +0 -0
  179. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/scenarios_workspace.json +0 -0
  180. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_ci_integration.py +0 -0
  181. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_cli_unicode_help.py +0 -0
  182. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_cookies_extract_windows.py +0 -0
  183. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_cookies_import.py +0 -0
  184. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_dialog_respond.py +0 -0
  185. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_find_and_interact_workflows.py +0 -0
  186. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_image_cap.py +0 -0
  187. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_locator_workflows.py +0 -0
  188. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_multi_profile_pool.py +0 -0
  189. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_page_reload.py +0 -0
  190. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_port_detection.py +0 -0
  191. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_startup_timeout.py +0 -0
  192. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_timeout_and_retry.py +0 -0
  193. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/integration/test_workspace_workflows.py +0 -0
  194. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/unit/test_case.py +0 -0
  195. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/unit/test_cli_param_type.py +0 -0
  196. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/tests/unit/test_no_acronym_rot.py +0 -0
  197. {ai_dev_browser-0.12.2 → ai_dev_browser-0.12.3}/uv.lock +0 -0
@@ -71,7 +71,8 @@ jobs:
71
71
  tests/integration/test_ci_integration.py \
72
72
  tests/integration/test_cookies_extract_windows.py \
73
73
  tests/integration/test_cli_unicode_help.py \
74
- tests/integration/test_image_cap.py
74
+ tests/integration/test_image_cap.py \
75
+ tests/integration/test_scroll_embedded_target.py
75
76
 
76
77
  # ─────────────────────────────────────────────────────────────────────
77
78
  # CI-integration dogfood: prove the documented "consumer's CI" recipe
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ai-dev-browser
3
- Version: 0.12.2
3
+ Version: 0.12.3
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
@@ -493,36 +493,34 @@ class Tab:
493
493
  # Scroll
494
494
  # =========================================================================
495
495
 
496
+ async def _scroll_by_viewport_percent(self, percent: float) -> None:
497
+ """Scroll by `percent` of viewport height (positive = down,
498
+ negative = up). Reads viewport height AND performs the scroll
499
+ in a single `Runtime.evaluate` call — no CDP Browser or
500
+ Input.synthesizeScrollGesture calls involved.
501
+
502
+ The previous implementation used `Browser.getWindowForTarget`
503
+ (browser-domain) to fetch bounds, then
504
+ `Input.synthesizeScrollGesture` for a smooth scroll. Both are
505
+ Chrome-specific CDP methods that embedded targets (Electron,
506
+ CEF, packaged Chromium apps exposing CDP via
507
+ `--remote-debugging-port`) may not implement — attaching
508
+ would 32601 the whole scroll path even though basic JS
509
+ `window.scrollBy` works fine. `Runtime.evaluate` is
510
+ universally supported, so we lean on that instead. Loses the
511
+ gesture-like smoothness, but agent scroll doesn't need
512
+ animation — the scroll event still fires so lazy-load and
513
+ scroll-listeners still trigger.
514
+ """
515
+ await self.evaluate(f"window.scrollBy(0, window.innerHeight * {percent / 100})")
516
+
496
517
  async def scroll_down(self, amount: int = 25):
497
518
  """Scroll down by percentage of viewport height."""
498
- _window_id, bounds = await self.get_window()
499
- await self.send(
500
- cdp_input.synthesize_scroll_gesture(
501
- x=0,
502
- y=0,
503
- y_distance=-(bounds.height * (amount / 100)),
504
- y_overscroll=0,
505
- x_overscroll=0,
506
- prevent_fling=True,
507
- repeat_delay_ms=0,
508
- speed=7777,
509
- )
510
- )
519
+ await self._scroll_by_viewport_percent(amount)
511
520
 
512
521
  async def scroll_up(self, amount: int = 25):
513
522
  """Scroll up by percentage of viewport height."""
514
- _window_id, bounds = await self.get_window()
515
- await self.send(
516
- cdp_input.synthesize_scroll_gesture(
517
- x=0,
518
- y=0,
519
- y_distance=(bounds.height * (amount / 100)),
520
- x_overscroll=0,
521
- prevent_fling=True,
522
- repeat_delay_ms=0,
523
- speed=7777,
524
- )
525
- )
523
+ await self._scroll_by_viewport_percent(-amount)
526
524
 
527
525
  # =========================================================================
528
526
  # Navigation
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ai-dev-browser
3
- Version: 0.12.2
3
+ Version: 0.12.3
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
@@ -185,6 +185,7 @@ tests/integration/test_locator_workflows.py
185
185
  tests/integration/test_multi_profile_pool.py
186
186
  tests/integration/test_page_reload.py
187
187
  tests/integration/test_port_detection.py
188
+ tests/integration/test_scroll_embedded_target.py
188
189
  tests/integration/test_startup_timeout.py
189
190
  tests/integration/test_timeout_and_retry.py
190
191
  tests/integration/test_workspace_workflows.py
@@ -175,6 +175,7 @@
175
175
  "tests/integration/test_cookies_import.py",
176
176
  "tests/integration/test_multi_profile_pool.py",
177
177
  "tests/integration/test_port_detection.py",
178
+ "tests/integration/test_scroll_embedded_target.py",
178
179
  "tests/integration/test_startup_timeout.py",
179
180
  "tests/integration/test_image_cap.py",
180
181
  "tests/integration/test_locator_workflows.py",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.12.3",
3
+ "distance": 0,
4
+ "node": "g6e1cbbb77386634b38bff6c05be9e0a8663622f0",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-07-02"
8
+ }
@@ -0,0 +1,176 @@
1
+ """Regression: page_scroll must work on embedded CDP targets that
2
+ don't implement Chrome's `Browser` domain (Electron / CEF / packaged
3
+ Chromium apps exposing CDP via `--remote-debugging-port`).
4
+
5
+ Pre-fix, `page_scroll(direction="down")` walked:
6
+ page_scroll → tab.scroll_down → tab.get_window (Browser.getWindowForTarget)
7
+
8
+ That CDP method is Chrome-browser-specific; embedded targets return
9
+ `-32601 Method not found` and the whole scroll path aborts. Reported
10
+ by a downstream integrator attaching to a packaged Electron app.
11
+
12
+ Fix (in `_tab.py`): rewrite `scroll_down` / `scroll_up` to use
13
+ `Runtime.evaluate` with `window.scrollBy(0, window.innerHeight * pct)`.
14
+ Runtime is universally supported. Bounds lookup and gesture
15
+ synthesis (Browser + Input.synthesizeScrollGesture) removed from the
16
+ scroll path entirely.
17
+
18
+ Tests below verify BOTH sides of the contract:
19
+ 1. Positive — scroll_down actually scrolls a real Chrome fixture
20
+ (proves the JS-based rewrite works).
21
+ 2. Negative — scroll_down succeeds even if `tab.get_window` is
22
+ patched to raise (proves the code path no longer depends on
23
+ the Browser-domain call that fails on Electron).
24
+
25
+ The negative test is the load-bearing one: without it, a future
26
+ "cleanup" that reintroduces `get_window()` in the scroll path would
27
+ silently re-break Electron users and CI wouldn't notice (regular
28
+ Chrome has getWindowForTarget so the code would appear to work).
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import base64
34
+ import contextlib
35
+ import os
36
+
37
+ import pytest
38
+
39
+ from ai_dev_browser.core import page_goto, page_scroll
40
+ from ai_dev_browser.core.browser import browser_start, browser_stop
41
+ from ai_dev_browser.core.connection import connect_browser, get_active_tab
42
+
43
+ SKIP_INTEGRATION = os.environ.get("SKIP_INTEGRATION", "").lower() in (
44
+ "1",
45
+ "true",
46
+ "yes",
47
+ )
48
+
49
+
50
+ @pytest.fixture(autouse=True)
51
+ def _integration_guard():
52
+ if SKIP_INTEGRATION:
53
+ pytest.skip("SKIP_INTEGRATION is set")
54
+
55
+
56
+ @pytest.fixture
57
+ async def tab():
58
+ """Headless Chrome loaded with a tall data:URL so scrollY has
59
+ room to change. Deliberately >5x viewport so a 25% scroll is a
60
+ detectable delta."""
61
+ result = browser_start(headless=True, temp=True, reuse="none")
62
+ assert "error" not in result, f"browser_start failed: {result}"
63
+ port = result["port"]
64
+ browser_client = None
65
+ try:
66
+ browser_client = await connect_browser(port=port)
67
+ the_tab = await get_active_tab(browser_client)
68
+ html = (
69
+ "<html><body style='margin:0'>"
70
+ + "".join(
71
+ f"<div style='height:200px;background:hsl({i * 37 % 360},60%,50%);"
72
+ f"color:white;padding:20px;font-size:22px'>Row {i}</div>"
73
+ for i in range(30)
74
+ )
75
+ + "</body></html>"
76
+ )
77
+ data_url = "data:text/html;base64," + base64.b64encode(html.encode()).decode()
78
+ await page_goto(the_tab, data_url)
79
+ yield the_tab
80
+ finally:
81
+ if browser_client is not None:
82
+ with contextlib.suppress(Exception):
83
+ await browser_client.close()
84
+ with contextlib.suppress(Exception):
85
+ browser_stop(port=port)
86
+
87
+
88
+ async def _get_scroll_y(tab) -> float:
89
+ """Read window.scrollY through the same Runtime.evaluate channel
90
+ the fix uses — deep-serialization deserialization of a numeric
91
+ RemoteObject varies, so pull via .value from the eval envelope."""
92
+ result = await tab.evaluate("window.scrollY", return_by_value=True)
93
+ return float(result if result is not None else 0)
94
+
95
+
96
+ async def test_page_scroll_down_actually_scrolls(tab):
97
+ """Positive: real headless Chrome + tall fixture → scroll_down
98
+ must observably move window.scrollY forward. Baseline that proves
99
+ the JS-based rewrite works at all before we go asserting Electron
100
+ compat."""
101
+ before = await _get_scroll_y(tab)
102
+ assert before == 0, f"fixture should start at scrollY=0, got {before}"
103
+
104
+ ok = await page_scroll(tab, direction="down", amount=50)
105
+ assert ok is True
106
+
107
+ after = await _get_scroll_y(tab)
108
+ assert after > before, (
109
+ f"scroll_down(50%) did not move scrollY: before={before}, after={after}"
110
+ )
111
+
112
+
113
+ async def test_page_scroll_up_after_down_reverses(tab):
114
+ """Positive: scroll_up unwinds a prior scroll_down. Two-step
115
+ verifies the sign convention (positive percent = down / content
116
+ moves up) is preserved after the rewrite — a reversed sign would
117
+ slip past 'did it scroll?' asserts."""
118
+ await page_scroll(tab, direction="down", amount=50)
119
+ peak = await _get_scroll_y(tab)
120
+ assert peak > 0
121
+
122
+ await page_scroll(tab, direction="up", amount=50)
123
+ after_up = await _get_scroll_y(tab)
124
+ assert after_up < peak, (
125
+ f"scroll_up did not reduce scrollY: peak={peak}, after_up={after_up}"
126
+ )
127
+
128
+
129
+ async def test_page_scroll_survives_broken_get_window(tab, monkeypatch):
130
+ """Regression pin: even if `tab.get_window` is completely broken —
131
+ the exact failure mode Electron / embedded targets exhibit —
132
+ page_scroll must still work. The rewrite guarantees this by never
133
+ calling get_window() from the scroll path.
134
+
135
+ If a future edit reintroduces `get_window()` into scroll_down or
136
+ a helper it calls, this test will fail on ProtocolException before
137
+ the scroll runs. That's the whole point — Electron users would
138
+ otherwise be silently broken again because regular Chrome CI
139
+ always has getWindowForTarget so the code would look green."""
140
+
141
+ async def _boom():
142
+ raise RuntimeError(
143
+ "Browser.getWindowForTarget wasn't found — simulated Electron target"
144
+ )
145
+
146
+ monkeypatch.setattr(tab, "get_window", _boom)
147
+
148
+ before = await _get_scroll_y(tab)
149
+ ok = await page_scroll(tab, direction="down", amount=50)
150
+ assert ok is True
151
+
152
+ after = await _get_scroll_y(tab)
153
+ assert after > before, (
154
+ f"scroll_down with get_window broken failed to scroll: "
155
+ f"before={before}, after={after}"
156
+ )
157
+
158
+
159
+ async def test_page_scroll_to_bottom_survives_broken_get_window(tab, monkeypatch):
160
+ """The other two page_scroll branches (to_bottom / to_top) already
161
+ used tab.evaluate, so they should already work on embedded
162
+ targets. This test pins that assumption so a future refactor
163
+ doesn't route them through get_window()."""
164
+
165
+ async def _boom():
166
+ raise RuntimeError("simulated Electron: Browser domain unavailable")
167
+
168
+ monkeypatch.setattr(tab, "get_window", _boom)
169
+
170
+ ok = await page_scroll(tab, to_bottom=True)
171
+ assert ok is True
172
+
173
+ after = await _get_scroll_y(tab)
174
+ assert after > 500, (
175
+ f"to_bottom should scroll a 6000px page substantially; got scrollY={after}"
176
+ )
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.12.2",
3
- "distance": 0,
4
- "node": "g6ef249945f324f1963fe8c9513bbf6acd6f022cd",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-07-01"
8
- }
File without changes
File without changes