cmdop 0.1.20__tar.gz → 0.1.22__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 (213) hide show
  1. {cmdop-0.1.20 → cmdop-0.1.22}/PKG-INFO +70 -41
  2. {cmdop-0.1.20 → cmdop-0.1.22}/README.md +69 -40
  3. {cmdop-0.1.20 → cmdop-0.1.22}/pyproject.toml +1 -1
  4. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/__init__.py +1 -1
  5. cmdop-0.1.22/src/cmdop/_generated/rpc_messages/browser_pb2.py +133 -0
  6. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/browser_pb2.pyi +4 -2
  7. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/client.py +2 -8
  8. cmdop-0.1.22/src/cmdop/services/browser/__init__.py +59 -0
  9. cmdop-0.1.22/src/cmdop/services/browser/capabilities/__init__.py +15 -0
  10. cmdop-0.1.22/src/cmdop/services/browser/capabilities/_base.py +28 -0
  11. cmdop-0.1.22/src/cmdop/services/browser/capabilities/_helpers.py +16 -0
  12. cmdop-0.1.22/src/cmdop/services/browser/capabilities/dom.py +76 -0
  13. cmdop-0.1.22/src/cmdop/services/browser/capabilities/fetch.py +46 -0
  14. cmdop-0.1.22/src/cmdop/services/browser/capabilities/input.py +49 -0
  15. cmdop-0.1.22/src/cmdop/services/browser/capabilities/scroll.py +147 -0
  16. cmdop-0.1.22/src/cmdop/services/browser/capabilities/timing.py +66 -0
  17. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/browser/js/__init__.py +6 -4
  18. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/browser/js/interaction.py +34 -0
  19. cmdop-0.1.22/src/cmdop/services/browser/service/__init__.py +5 -0
  20. cmdop-0.1.22/src/cmdop/services/browser/service/aio.py +30 -0
  21. cmdop-0.1.20/src/cmdop/services/browser/sync/service.py → cmdop-0.1.22/src/cmdop/services/browser/service/sync.py +9 -4
  22. cmdop-0.1.22/src/cmdop/services/browser/session.py +166 -0
  23. cmdop-0.1.20/src/cmdop/_generated/rpc_messages/browser_pb2.py +0 -133
  24. cmdop-0.1.20/src/cmdop/services/browser/__init__.py +0 -46
  25. cmdop-0.1.20/src/cmdop/services/browser/aio/__init__.py +0 -6
  26. cmdop-0.1.20/src/cmdop/services/browser/aio/service.py +0 -415
  27. cmdop-0.1.20/src/cmdop/services/browser/aio/session.py +0 -358
  28. cmdop-0.1.20/src/cmdop/services/browser/base/__init__.py +0 -6
  29. cmdop-0.1.20/src/cmdop/services/browser/base/session.py +0 -124
  30. cmdop-0.1.20/src/cmdop/services/browser/sync/__init__.py +0 -6
  31. cmdop-0.1.20/src/cmdop/services/browser/sync/session.py +0 -580
  32. {cmdop-0.1.20 → cmdop-0.1.22}/.gitignore +0 -0
  33. {cmdop-0.1.20 → cmdop-0.1.22}/LICENSE +0 -0
  34. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/__init__.py +0 -0
  35. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/agent_messages_pb2.py +0 -0
  36. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/agent_messages_pb2.pyi +0 -0
  37. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/agent_messages_pb2_grpc.py +0 -0
  38. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/common_types_pb2.py +0 -0
  39. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/common_types_pb2.pyi +0 -0
  40. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/common_types_pb2_grpc.py +0 -0
  41. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/control_messages_pb2.py +0 -0
  42. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/control_messages_pb2.pyi +0 -0
  43. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/control_messages_pb2_grpc.py +0 -0
  44. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/__init__.py +0 -0
  45. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/archive_pb2.py +0 -0
  46. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/archive_pb2.pyi +0 -0
  47. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/archive_pb2_grpc.py +0 -0
  48. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/changes_pb2.py +0 -0
  49. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/changes_pb2.pyi +0 -0
  50. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/changes_pb2_grpc.py +0 -0
  51. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/common_pb2.py +0 -0
  52. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/common_pb2.pyi +0 -0
  53. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/common_pb2_grpc.py +0 -0
  54. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/directory_pb2.py +0 -0
  55. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/directory_pb2.pyi +0 -0
  56. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/directory_pb2_grpc.py +0 -0
  57. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/file_crud_pb2.py +0 -0
  58. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/file_crud_pb2.pyi +0 -0
  59. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/file_crud_pb2_grpc.py +0 -0
  60. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/hls_pb2.py +0 -0
  61. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/hls_pb2.pyi +0 -0
  62. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/hls_pb2_grpc.py +0 -0
  63. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/requests_pb2.py +0 -0
  64. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/requests_pb2.pyi +0 -0
  65. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/requests_pb2_grpc.py +0 -0
  66. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/search_pb2.py +0 -0
  67. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/search_pb2.pyi +0 -0
  68. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/search_pb2_grpc.py +0 -0
  69. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/transfer_pb2.py +0 -0
  70. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/transfer_pb2.pyi +0 -0
  71. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations/transfer_pb2_grpc.py +0 -0
  72. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations_pb2.py +0 -0
  73. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations_pb2.pyi +0 -0
  74. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_operations_pb2_grpc.py +0 -0
  75. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/__init__.py +0 -0
  76. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/archive_pb2.py +0 -0
  77. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/archive_pb2.pyi +0 -0
  78. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/archive_pb2_grpc.py +0 -0
  79. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/directory_pb2.py +0 -0
  80. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/directory_pb2.pyi +0 -0
  81. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/directory_pb2_grpc.py +0 -0
  82. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/file_crud_pb2.py +0 -0
  83. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/file_crud_pb2.pyi +0 -0
  84. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/file_crud_pb2_grpc.py +0 -0
  85. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/hls_pb2.py +0 -0
  86. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/hls_pb2.pyi +0 -0
  87. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/hls_pb2_grpc.py +0 -0
  88. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/search_pb2.py +0 -0
  89. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/search_pb2.pyi +0 -0
  90. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc/search_pb2_grpc.py +0 -0
  91. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc_pb2.py +0 -0
  92. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc_pb2.pyi +0 -0
  93. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/file_rpc_pb2_grpc.py +0 -0
  94. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/message_pool.py +0 -0
  95. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/py.typed +0 -0
  96. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/__init__.py +0 -0
  97. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/agent_pb2.py +0 -0
  98. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/agent_pb2.pyi +0 -0
  99. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/agent_pb2_grpc.py +0 -0
  100. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/browser_pb2_grpc.py +0 -0
  101. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/device_pb2.py +0 -0
  102. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/device_pb2.pyi +0 -0
  103. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/device_pb2_grpc.py +0 -0
  104. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/extract_pb2.py +0 -0
  105. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/extract_pb2.pyi +0 -0
  106. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/extract_pb2_grpc.py +0 -0
  107. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/health_pb2.py +0 -0
  108. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/health_pb2.pyi +0 -0
  109. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/health_pb2_grpc.py +0 -0
  110. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/history_pb2.py +0 -0
  111. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/history_pb2.pyi +0 -0
  112. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/history_pb2_grpc.py +0 -0
  113. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/lifecycle_pb2.py +0 -0
  114. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/lifecycle_pb2.pyi +0 -0
  115. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/lifecycle_pb2_grpc.py +0 -0
  116. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/push_pb2.py +0 -0
  117. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/push_pb2.pyi +0 -0
  118. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/push_pb2_grpc.py +0 -0
  119. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/session_pb2.py +0 -0
  120. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/session_pb2.pyi +0 -0
  121. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/session_pb2_grpc.py +0 -0
  122. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/terminal_pb2.py +0 -0
  123. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/terminal_pb2.pyi +0 -0
  124. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages/terminal_pb2_grpc.py +0 -0
  125. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages_pb2.py +0 -0
  126. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages_pb2.pyi +0 -0
  127. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/rpc_messages_pb2_grpc.py +0 -0
  128. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/service_pb2.py +0 -0
  129. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/service_pb2.pyi +0 -0
  130. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/service_pb2_grpc.py +0 -0
  131. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/tunnel_pb2.py +0 -0
  132. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/tunnel_pb2.pyi +0 -0
  133. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/_generated/tunnel_pb2_grpc.py +0 -0
  134. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/__init__.py +0 -0
  135. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/__init__.py +0 -0
  136. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/__init__.py +0 -0
  137. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/client.py +0 -0
  138. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/enums.py +0 -0
  139. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/logger.py +0 -0
  140. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/machines__api__machine_sharing/__init__.py +0 -0
  141. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/machines__api__machine_sharing/client.py +0 -0
  142. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/machines__api__machine_sharing/models.py +0 -0
  143. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/machines__api__machine_sharing/sync_client.py +0 -0
  144. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/machines__api__machines/__init__.py +0 -0
  145. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/machines__api__machines/client.py +0 -0
  146. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/machines__api__machines/models.py +0 -0
  147. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/machines__api__machines/sync_client.py +0 -0
  148. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/retry.py +0 -0
  149. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/schema.json +0 -0
  150. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/machines/sync_client.py +0 -0
  151. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/__init__.py +0 -0
  152. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/client.py +0 -0
  153. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/enums.py +0 -0
  154. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/logger.py +0 -0
  155. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/retry.py +0 -0
  156. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/schema.json +0 -0
  157. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/sync_client.py +0 -0
  158. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/system__api__oauth/__init__.py +0 -0
  159. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/system__api__oauth/client.py +0 -0
  160. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/system__api__oauth/models.py +0 -0
  161. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/system__api__oauth/sync_client.py +0 -0
  162. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/system__api__system/__init__.py +0 -0
  163. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/system__api__system/client.py +0 -0
  164. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/system__api__system/models.py +0 -0
  165. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/system/system__api__system/sync_client.py +0 -0
  166. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/__init__.py +0 -0
  167. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/client.py +0 -0
  168. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/enums.py +0 -0
  169. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/logger.py +0 -0
  170. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/retry.py +0 -0
  171. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/schema.json +0 -0
  172. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/sync_client.py +0 -0
  173. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/__init__.py +0 -0
  174. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/client.py +0 -0
  175. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/models.py +0 -0
  176. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/sync_client.py +0 -0
  177. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/config.py +0 -0
  178. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/discovery.py +0 -0
  179. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/exceptions.py +0 -0
  180. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/helpers/__init__.py +0 -0
  181. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/helpers/cleaner.py +0 -0
  182. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/helpers/formatting.py +0 -0
  183. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/logging.py +0 -0
  184. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/models/__init__.py +0 -0
  185. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/models/agent.py +0 -0
  186. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/models/base.py +0 -0
  187. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/models/config.py +0 -0
  188. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/models/extract.py +0 -0
  189. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/models/files.py +0 -0
  190. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/models/terminal.py +0 -0
  191. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/py.typed +0 -0
  192. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/__init__.py +0 -0
  193. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/agent.py +0 -0
  194. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/base.py +0 -0
  195. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/browser/js/core.py +0 -0
  196. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/browser/js/fetch.py +0 -0
  197. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/browser/js/scroll.py +0 -0
  198. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/browser/models.py +0 -0
  199. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/browser/parsing.py +0 -0
  200. /cmdop-0.1.20/src/cmdop/services/browser/base/service.py → /cmdop-0.1.22/src/cmdop/services/browser/service/_helpers.py +0 -0
  201. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/extract.py +0 -0
  202. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/files.py +0 -0
  203. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/services/terminal.py +0 -0
  204. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/streaming/__init__.py +0 -0
  205. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/streaming/base.py +0 -0
  206. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/streaming/handlers.py +0 -0
  207. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/streaming/terminal.py +0 -0
  208. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/transport/__init__.py +0 -0
  209. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/transport/auth.py +0 -0
  210. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/transport/base.py +0 -0
  211. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/transport/discovery.py +0 -0
  212. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/transport/local.py +0 -0
  213. {cmdop-0.1.20 → cmdop-0.1.22}/src/cmdop/transport/remote.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmdop
3
- Version: 0.1.20
3
+ Version: 0.1.22
4
4
  Summary: Python SDK for CMDOP agent interaction
5
5
  Project-URL: Homepage, https://cmdop.com
6
6
  Project-URL: Documentation, https://cmdop.com
@@ -145,71 +145,100 @@ health: Health = result.output # Typed!
145
145
 
146
146
  ## Browser
147
147
 
148
+ Capability-based API for browser automation.
149
+
148
150
  ```python
149
- with client.browser.create_session() as b:
150
- b.navigate("https://shop.com/products")
151
- b.close_modal() # Close popups
151
+ with client.browser.create_session() as s:
152
+ s.navigate("https://shop.com/products")
153
+ s.dom.close_modal() # Close popups
152
154
 
153
155
  # BeautifulSoup parsing
154
- soup = b.soup() # SoupWrapper with chainable API
156
+ soup = s.dom.soup() # SoupWrapper with chainable API
155
157
  for item in soup.select(".product"):
156
158
  title = item.select_one("h2").text()
157
159
  price = item.attr("data-price")
158
160
 
159
161
  # Scrolling with random delays
160
162
  for _ in range(10):
161
- soup = b.soup(".listings")
162
- # ... parse ...
163
- b.scroll("down", 700)
164
- b.wait_random(0.8, 1.5) # Random delay
163
+ soup = s.dom.soup(".listings")
164
+ s.scroll.js("down", 700)
165
+ s.timing.random(0.8, 1.5)
165
166
 
166
- # Click with cursor movement (human-like)
167
- b.click("button.buy", move_cursor=True) # Moves cursor before clicking
167
+ # Click with cursor movement
168
+ s.click("button.buy", move_cursor=True)
168
169
 
169
170
  # Click all "See more" buttons
170
- b.click_all_by_text("See more")
171
+ s.input.click_all("See more")
171
172
 
172
- # Native mouse operations
173
- b.mouse_move(500, 300) # Smooth cursor movement
174
- b.hover(".tooltip-trigger") # Hover to reveal tooltip
173
+ # Mouse operations
174
+ s.input.mouse_move(500, 300)
175
+ s.input.hover(".tooltip-trigger")
175
176
 
176
177
  # JS fetch (bypass CORS, inherit cookies)
177
- data = b.fetch_json("https://api.site.com/v1/items")
178
+ data = s.fetch.json("/api/items")
178
179
  ```
179
180
 
181
+ ### Core Methods (on session)
182
+
180
183
  | Method | Description |
181
184
  |--------|-------------|
182
185
  | `navigate(url)` | Go to URL |
183
- | `click(selector, move_cursor)` | Click element (optionally move cursor first) |
184
- | `click_all_by_text(text, role)` | Click all matching elements |
186
+ | `click(selector, move_cursor)` | Click element |
185
187
  | `type(selector, text)` | Type text |
186
- | `wait_for(selector, ms)` | Wait for element |
187
- | `wait_seconds(n)` | Sleep |
188
- | `wait_random(min, max)` | Random sleep |
189
- | `extract(selector, attr)` | Get text/attr |
190
- | `get_html(selector)` | Get HTML |
191
- | `soup(selector)` | → SoupWrapper |
192
- | `parse_html(html)` | → BeautifulSoup |
193
- | `fetch_json(url)` | JS fetch → dict |
194
- | `fetch_all(urls)` | Parallel fetch |
195
- | `execute_js(code)` | Run async JS |
188
+ | `wait_for(selector)` | Wait for element |
189
+ | `execute_script(js)` | Run JavaScript |
196
190
  | `screenshot()` | PNG bytes |
197
- | `scroll(dir, amount, ...)` | Native scroll page |
198
- | `scroll_to(selector)` | Scroll element into view |
199
- | `get_scroll_info()` | Position + page size |
200
- | `get_page_info()` | Comprehensive page info |
201
- | `mouse_move(x, y, steps)` | Move cursor to coordinates |
202
- | `hover(selector)` | Hover over element |
191
+ | `get_state()` | URL + title |
192
+ | `get_page_info()` | Full page info |
193
+ | `get/set_cookies()` | Cookie management |
194
+
195
+ ### Capabilities
196
+
197
+ **`session.scroll`** - Scrolling
198
+ | Method | Description |
199
+ |--------|-------------|
200
+ | `js(dir, amount)` | JS scroll (works on complex sites) |
201
+ | `native(dir, amount)` | Browser API scroll |
202
+ | `to_bottom()` | Scroll to page bottom |
203
+ | `to_element(selector)` | Scroll element into view |
204
+ | `info()` | Get scroll position |
205
+ | `infinite(extract_fn)` | Smart infinite scroll with extraction |
206
+
207
+ **`session.input`** - Input operations
208
+ | Method | Description |
209
+ |--------|-------------|
210
+ | `click_js(selector)` | JS click (reliable) |
211
+ | `click_all(text, role)` | Click all matching elements |
212
+ | `key(key, selector)` | Press keyboard key |
213
+ | `hover(selector)` | Hover over element (native) |
214
+ | `hover_js(selector)` | Hover via JS |
215
+ | `mouse_move(x, y)` | Move cursor to coordinates |
216
+
217
+ **`session.timing`** - Delays
218
+ | Method | Description |
219
+ |--------|-------------|
220
+ | `wait(ms)` | Wait milliseconds |
221
+ | `seconds(n)` | Wait seconds |
222
+ | `random(min, max)` | Random delay |
223
+ | `timeout(fn, sec, cleanup)` | Run with timeout |
224
+
225
+ **`session.dom`** - DOM operations
226
+ | Method | Description |
227
+ |--------|-------------|
228
+ | `html(selector)` | Get HTML |
229
+ | `text(selector)` | Get text content |
230
+ | `soup(selector)` | → SoupWrapper |
231
+ | `parse(html)` | → BeautifulSoup |
232
+ | `extract(selector, attr)` | Get text/attr list |
203
233
  | `select(selector, value)` | Dropdown select |
204
234
  | `close_modal()` | Close dialogs |
205
- | `press_key(key, selector)` | Press keyboard key |
206
- | `get/set_cookies()` | Cookie management |
207
235
 
208
- **scroll() parameters:**
209
- - `direction`: "up", "down", "left", "right"
210
- - `amount`: pixels to scroll
211
- - `smooth`: animate scroll (default True)
212
- - `selector`: scroll element into view (alternative to direction/amount)
236
+ **`session.fetch`** - HTTP from browser context
237
+ | Method | Description |
238
+ |--------|-------------|
239
+ | `json(url)` | Fetch JSON |
240
+ | `all(requests)` | Parallel fetch |
241
+ | `execute(method, url, ...)` | Custom request |
213
242
 
214
243
  ## SDKBaseModel
215
244
 
@@ -104,71 +104,100 @@ health: Health = result.output # Typed!
104
104
 
105
105
  ## Browser
106
106
 
107
+ Capability-based API for browser automation.
108
+
107
109
  ```python
108
- with client.browser.create_session() as b:
109
- b.navigate("https://shop.com/products")
110
- b.close_modal() # Close popups
110
+ with client.browser.create_session() as s:
111
+ s.navigate("https://shop.com/products")
112
+ s.dom.close_modal() # Close popups
111
113
 
112
114
  # BeautifulSoup parsing
113
- soup = b.soup() # SoupWrapper with chainable API
115
+ soup = s.dom.soup() # SoupWrapper with chainable API
114
116
  for item in soup.select(".product"):
115
117
  title = item.select_one("h2").text()
116
118
  price = item.attr("data-price")
117
119
 
118
120
  # Scrolling with random delays
119
121
  for _ in range(10):
120
- soup = b.soup(".listings")
121
- # ... parse ...
122
- b.scroll("down", 700)
123
- b.wait_random(0.8, 1.5) # Random delay
122
+ soup = s.dom.soup(".listings")
123
+ s.scroll.js("down", 700)
124
+ s.timing.random(0.8, 1.5)
124
125
 
125
- # Click with cursor movement (human-like)
126
- b.click("button.buy", move_cursor=True) # Moves cursor before clicking
126
+ # Click with cursor movement
127
+ s.click("button.buy", move_cursor=True)
127
128
 
128
129
  # Click all "See more" buttons
129
- b.click_all_by_text("See more")
130
+ s.input.click_all("See more")
130
131
 
131
- # Native mouse operations
132
- b.mouse_move(500, 300) # Smooth cursor movement
133
- b.hover(".tooltip-trigger") # Hover to reveal tooltip
132
+ # Mouse operations
133
+ s.input.mouse_move(500, 300)
134
+ s.input.hover(".tooltip-trigger")
134
135
 
135
136
  # JS fetch (bypass CORS, inherit cookies)
136
- data = b.fetch_json("https://api.site.com/v1/items")
137
+ data = s.fetch.json("/api/items")
137
138
  ```
138
139
 
140
+ ### Core Methods (on session)
141
+
139
142
  | Method | Description |
140
143
  |--------|-------------|
141
144
  | `navigate(url)` | Go to URL |
142
- | `click(selector, move_cursor)` | Click element (optionally move cursor first) |
143
- | `click_all_by_text(text, role)` | Click all matching elements |
145
+ | `click(selector, move_cursor)` | Click element |
144
146
  | `type(selector, text)` | Type text |
145
- | `wait_for(selector, ms)` | Wait for element |
146
- | `wait_seconds(n)` | Sleep |
147
- | `wait_random(min, max)` | Random sleep |
148
- | `extract(selector, attr)` | Get text/attr |
149
- | `get_html(selector)` | Get HTML |
150
- | `soup(selector)` | → SoupWrapper |
151
- | `parse_html(html)` | → BeautifulSoup |
152
- | `fetch_json(url)` | JS fetch → dict |
153
- | `fetch_all(urls)` | Parallel fetch |
154
- | `execute_js(code)` | Run async JS |
147
+ | `wait_for(selector)` | Wait for element |
148
+ | `execute_script(js)` | Run JavaScript |
155
149
  | `screenshot()` | PNG bytes |
156
- | `scroll(dir, amount, ...)` | Native scroll page |
157
- | `scroll_to(selector)` | Scroll element into view |
158
- | `get_scroll_info()` | Position + page size |
159
- | `get_page_info()` | Comprehensive page info |
160
- | `mouse_move(x, y, steps)` | Move cursor to coordinates |
161
- | `hover(selector)` | Hover over element |
150
+ | `get_state()` | URL + title |
151
+ | `get_page_info()` | Full page info |
152
+ | `get/set_cookies()` | Cookie management |
153
+
154
+ ### Capabilities
155
+
156
+ **`session.scroll`** - Scrolling
157
+ | Method | Description |
158
+ |--------|-------------|
159
+ | `js(dir, amount)` | JS scroll (works on complex sites) |
160
+ | `native(dir, amount)` | Browser API scroll |
161
+ | `to_bottom()` | Scroll to page bottom |
162
+ | `to_element(selector)` | Scroll element into view |
163
+ | `info()` | Get scroll position |
164
+ | `infinite(extract_fn)` | Smart infinite scroll with extraction |
165
+
166
+ **`session.input`** - Input operations
167
+ | Method | Description |
168
+ |--------|-------------|
169
+ | `click_js(selector)` | JS click (reliable) |
170
+ | `click_all(text, role)` | Click all matching elements |
171
+ | `key(key, selector)` | Press keyboard key |
172
+ | `hover(selector)` | Hover over element (native) |
173
+ | `hover_js(selector)` | Hover via JS |
174
+ | `mouse_move(x, y)` | Move cursor to coordinates |
175
+
176
+ **`session.timing`** - Delays
177
+ | Method | Description |
178
+ |--------|-------------|
179
+ | `wait(ms)` | Wait milliseconds |
180
+ | `seconds(n)` | Wait seconds |
181
+ | `random(min, max)` | Random delay |
182
+ | `timeout(fn, sec, cleanup)` | Run with timeout |
183
+
184
+ **`session.dom`** - DOM operations
185
+ | Method | Description |
186
+ |--------|-------------|
187
+ | `html(selector)` | Get HTML |
188
+ | `text(selector)` | Get text content |
189
+ | `soup(selector)` | → SoupWrapper |
190
+ | `parse(html)` | → BeautifulSoup |
191
+ | `extract(selector, attr)` | Get text/attr list |
162
192
  | `select(selector, value)` | Dropdown select |
163
193
  | `close_modal()` | Close dialogs |
164
- | `press_key(key, selector)` | Press keyboard key |
165
- | `get/set_cookies()` | Cookie management |
166
194
 
167
- **scroll() parameters:**
168
- - `direction`: "up", "down", "left", "right"
169
- - `amount`: pixels to scroll
170
- - `smooth`: animate scroll (default True)
171
- - `selector`: scroll element into view (alternative to direction/amount)
195
+ **`session.fetch`** - HTTP from browser context
196
+ | Method | Description |
197
+ |--------|-------------|
198
+ | `json(url)` | Fetch JSON |
199
+ | `all(requests)` | Parallel fetch |
200
+ | `execute(method, url, ...)` | Custom request |
172
201
 
173
202
  ## SDKBaseModel
174
203
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cmdop"
3
- version = "0.1.20"
3
+ version = "0.1.22"
4
4
  description = "Python SDK for CMDOP agent interaction"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -124,7 +124,7 @@ from cmdop.logging import (
124
124
  get_log_dir,
125
125
  )
126
126
 
127
- __version__ = "0.1.20"
127
+ __version__ = "0.1.22"
128
128
 
129
129
  __all__ = [
130
130
  # Version
@@ -0,0 +1,133 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: rpc_messages/browser.proto
5
+ # Protobuf Python Version: 6.31.1
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 6,
15
+ 31,
16
+ 1,
17
+ '',
18
+ 'rpc_messages/browser.proto'
19
+ )
20
+ # @@protoc_insertion_point(imports)
21
+
22
+ _sym_db = _symbol_database.Default()
23
+
24
+
25
+
26
+
27
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1arpc_messages/browser.proto\x12\x08terminal\"\x9b\x01\n\x1b\x42rowserCreateSessionRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x10\n\x08provider\x18\x02 \x01(\t\x12\x12\n\nprofile_id\x18\x03 \x01(\t\x12\x11\n\tstart_url\x18\x04 \x01(\t\x12\x10\n\x08headless\x18\x05 \x01(\x08\x12\r\n\x05width\x18\x06 \x01(\x05\x12\x0e\n\x06height\x18\x07 \x01(\x05\"Z\n\x1c\x42rowserCreateSessionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"L\n\x1a\x42rowserCloseSessionRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\"=\n\x1b\x42rowserCloseSessionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"i\n\x16\x42rowserNavigateRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x12\n\ntimeout_ms\x18\x04 \x01(\x05\"L\n\x17\x42rowserNavigateResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x11\n\tfinal_url\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"\x80\x01\n\x13\x42rowserClickRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x12\n\ntimeout_ms\x18\x04 \x01(\x05\x12\x13\n\x0bmove_cursor\x18\x05 \x01(\x08\"6\n\x14\x42rowserClickResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\x8d\x01\n\x12\x42rowserTypeRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x0c\n\x04text\x18\x04 \x01(\t\x12\x12\n\nhuman_like\x18\x05 \x01(\x08\x12\x13\n\x0b\x63lear_first\x18\x06 \x01(\x08\"5\n\x13\x42rowserTypeResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"j\n\x12\x42rowserWaitRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x12\n\ntimeout_ms\x18\x04 \x01(\x05\"D\n\x13\x42rowserWaitResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x66ound\x18\x02 \x01(\x08\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"{\n\x15\x42rowserExtractRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x11\n\tattribute\x18\x04 \x01(\t\x12\r\n\x05limit\x18\x05 \x01(\x05\"W\n\x16\x42rowserExtractResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06values\x18\x02 \x03(\t\x12\r\n\x05\x63ount\x18\x03 \x01(\x05\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"\x7f\n\x1a\x42rowserExtractRegexRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0f\n\x07pattern\x18\x03 \x01(\t\x12\x11\n\tfrom_html\x18\x04 \x01(\x08\x12\r\n\x05limit\x18\x05 \x01(\x05\"]\n\x1b\x42rowserExtractRegexResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07matches\x18\x02 \x03(\t\x12\r\n\x05\x63ount\x18\x03 \x01(\x05\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"Y\n\x15\x42rowserGetHTMLRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\"F\n\x16\x42rowserGetHTMLResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0c\n\x04html\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"Y\n\x15\x42rowserGetTextRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\"F\n\x16\x42rowserGetTextResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0c\n\x04text\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"]\n\x1b\x42rowserExecuteScriptRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0e\n\x06script\x18\x03 \x01(\t\"N\n\x1c\x42rowserExecuteScriptResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0e\n\x06result\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"~\n\x18\x42rowserScreenshotRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x11\n\tfull_page\x18\x03 \x01(\x08\x12\x0e\n\x06\x66ormat\x18\x04 \x01(\t\x12\x0f\n\x07quality\x18\x05 \x01(\x05\"I\n\x19\x42rowserScreenshotResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"H\n\x16\x42rowserGetStateRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\"U\n\x17\x42rowserGetStateResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\r\n\x05title\x18\x03 \x01(\t\x12\r\n\x05\x65rror\x18\x04 \x01(\t\"K\n\x19\x42rowserGetPageInfoRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\"\xbb\x03\n\x1a\x42rowserGetPageInfoResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\r\n\x05title\x18\x04 \x01(\t\x12\x13\n\x0bpage_height\x18\x05 \x01(\x05\x12\x17\n\x0fviewport_height\x18\x06 \x01(\x05\x12\x16\n\x0eviewport_width\x18\x07 \x01(\x05\x12\x10\n\x08scroll_x\x18\x08 \x01(\x05\x12\x10\n\x08scroll_y\x18\t \x01(\x05\x12\x0e\n\x06\x61t_top\x18\n \x01(\x08\x12\x11\n\tat_bottom\x18\x0b \x01(\x08\x12\x14\n\x0cload_time_ms\x18\x0c \x01(\x05\x12\x15\n\rcookies_count\x18\r \x01(\x05\x12\x10\n\x08is_https\x18\x0e \x01(\x08\x12\x13\n\x0bhas_iframes\x18\x0f \x01(\x08\x12\x15\n\rdom_nodes_raw\x18\x10 \x01(\x05\x12\x19\n\x11\x64om_nodes_cleaned\x18\x11 \x01(\x05\x12\x17\n\x0ftokens_estimate\x18\x12 \x01(\x05\x12\x1b\n\x13\x63loudflare_detected\x18\x13 \x01(\x08\x12\x18\n\x10\x63\x61ptcha_detected\x18\x14 \x01(\x08\"\x91\x01\n\rBrowserCookie\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\x12\x0e\n\x06\x64omain\x18\x03 \x01(\t\x12\x0c\n\x04path\x18\x04 \x01(\t\x12\x0e\n\x06secure\x18\x05 \x01(\x08\x12\x11\n\thttp_only\x18\x06 \x01(\x08\x12\x11\n\tsame_site\x18\x07 \x01(\t\x12\x0f\n\x07\x65xpires\x18\x08 \x01(\x03\"t\n\x18\x42rowserSetCookiesRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12(\n\x07\x63ookies\x18\x03 \x03(\x0b\x32\x17.terminal.BrowserCookie\";\n\x19\x42rowserSetCookiesResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"Z\n\x18\x42rowserGetCookiesRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0e\n\x06\x64omain\x18\x03 \x01(\t\"e\n\x19\x42rowserGetCookiesResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12(\n\x07\x63ookies\x18\x02 \x03(\x0b\x32\x17.terminal.BrowserCookie\x12\r\n\x05\x65rror\x18\x03 \x01(\t\"n\n\x17\x42rowserMouseMoveRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\t\n\x01x\x18\x03 \x01(\x05\x12\t\n\x01y\x18\x04 \x01(\x05\x12\r\n\x05steps\x18\x05 \x01(\x05\":\n\x18\x42rowserMouseMoveResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"k\n\x13\x42rowserHoverRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x10\n\x08selector\x18\x03 \x01(\t\x12\x12\n\ntimeout_ms\x18\x04 \x01(\x05\"6\n\x14\x42rowserHoverResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\x9e\x01\n\x14\x42rowserScrollRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x11\n\tdirection\x18\x03 \x01(\t\x12\x0e\n\x06\x61mount\x18\x04 \x01(\x05\x12\x10\n\x08selector\x18\x05 \x01(\t\x12\x11\n\tcontainer\x18\x06 \x01(\t\x12\x0e\n\x06smooth\x18\x07 \x01(\x08\"\xb1\x01\n\x15\x42rowserScrollResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x10\n\x08scroll_x\x18\x02 \x01(\x05\x12\x10\n\x08scroll_y\x18\x03 \x01(\x05\x12\x13\n\x0bscrolled_by\x18\x04 \x01(\x05\x12\x13\n\x0bpage_height\x18\x05 \x01(\x05\x12\x17\n\x0fviewport_height\x18\x06 \x01(\x05\x12\x11\n\tat_bottom\x18\x07 \x01(\x08\x12\r\n\x05\x65rror\x18\x08 \x01(\t\"\xd5\x01\n\x1f\x42rowserValidateSelectorsRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0c\n\x04item\x18\x03 \x01(\t\x12\x45\n\x06\x66ields\x18\x04 \x03(\x0b\x32\x35.terminal.BrowserValidateSelectorsRequest.FieldsEntry\x1a-\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xd2\x02\n BrowserValidateSelectorsResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05valid\x18\x02 \x01(\x08\x12\x46\n\x06\x63ounts\x18\x03 \x03(\x0b\x32\x36.terminal.BrowserValidateSelectorsResponse.CountsEntry\x12H\n\x07samples\x18\x04 \x03(\x0b\x32\x37.terminal.BrowserValidateSelectorsResponse.SamplesEntry\x12\x0e\n\x06\x65rrors\x18\x05 \x03(\t\x12\r\n\x05\x65rror\x18\x06 \x01(\t\x1a-\n\x0b\x43ountsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a.\n\x0cSamplesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"}\n\x19\x42rowserExtractDataRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x1a\n\x12\x62rowser_session_id\x18\x02 \x01(\t\x12\x0c\n\x04item\x18\x03 \x01(\t\x12\x13\n\x0b\x66ields_json\x18\x04 \x01(\t\x12\r\n\x05limit\x18\x05 \x01(\x05\"_\n\x1a\x42rowserExtractDataResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\nitems_json\x18\x02 \x01(\t\x12\r\n\x05\x63ount\x18\x03 \x01(\x05\x12\r\n\x05\x65rror\x18\x04 \x01(\tB\x10Z\x0eterminal/protob\x06proto3')
28
+
29
+ _globals = globals()
30
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'rpc_messages.browser_pb2', _globals)
32
+ if not _descriptor._USE_C_DESCRIPTORS:
33
+ _globals['DESCRIPTOR']._loaded_options = None
34
+ _globals['DESCRIPTOR']._serialized_options = b'Z\016terminal/proto'
35
+ _globals['_BROWSERVALIDATESELECTORSREQUEST_FIELDSENTRY']._loaded_options = None
36
+ _globals['_BROWSERVALIDATESELECTORSREQUEST_FIELDSENTRY']._serialized_options = b'8\001'
37
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE_COUNTSENTRY']._loaded_options = None
38
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE_COUNTSENTRY']._serialized_options = b'8\001'
39
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE_SAMPLESENTRY']._loaded_options = None
40
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE_SAMPLESENTRY']._serialized_options = b'8\001'
41
+ _globals['_BROWSERCREATESESSIONREQUEST']._serialized_start=41
42
+ _globals['_BROWSERCREATESESSIONREQUEST']._serialized_end=196
43
+ _globals['_BROWSERCREATESESSIONRESPONSE']._serialized_start=198
44
+ _globals['_BROWSERCREATESESSIONRESPONSE']._serialized_end=288
45
+ _globals['_BROWSERCLOSESESSIONREQUEST']._serialized_start=290
46
+ _globals['_BROWSERCLOSESESSIONREQUEST']._serialized_end=366
47
+ _globals['_BROWSERCLOSESESSIONRESPONSE']._serialized_start=368
48
+ _globals['_BROWSERCLOSESESSIONRESPONSE']._serialized_end=429
49
+ _globals['_BROWSERNAVIGATEREQUEST']._serialized_start=431
50
+ _globals['_BROWSERNAVIGATEREQUEST']._serialized_end=536
51
+ _globals['_BROWSERNAVIGATERESPONSE']._serialized_start=538
52
+ _globals['_BROWSERNAVIGATERESPONSE']._serialized_end=614
53
+ _globals['_BROWSERCLICKREQUEST']._serialized_start=617
54
+ _globals['_BROWSERCLICKREQUEST']._serialized_end=745
55
+ _globals['_BROWSERCLICKRESPONSE']._serialized_start=747
56
+ _globals['_BROWSERCLICKRESPONSE']._serialized_end=801
57
+ _globals['_BROWSERTYPEREQUEST']._serialized_start=804
58
+ _globals['_BROWSERTYPEREQUEST']._serialized_end=945
59
+ _globals['_BROWSERTYPERESPONSE']._serialized_start=947
60
+ _globals['_BROWSERTYPERESPONSE']._serialized_end=1000
61
+ _globals['_BROWSERWAITREQUEST']._serialized_start=1002
62
+ _globals['_BROWSERWAITREQUEST']._serialized_end=1108
63
+ _globals['_BROWSERWAITRESPONSE']._serialized_start=1110
64
+ _globals['_BROWSERWAITRESPONSE']._serialized_end=1178
65
+ _globals['_BROWSEREXTRACTREQUEST']._serialized_start=1180
66
+ _globals['_BROWSEREXTRACTREQUEST']._serialized_end=1303
67
+ _globals['_BROWSEREXTRACTRESPONSE']._serialized_start=1305
68
+ _globals['_BROWSEREXTRACTRESPONSE']._serialized_end=1392
69
+ _globals['_BROWSEREXTRACTREGEXREQUEST']._serialized_start=1394
70
+ _globals['_BROWSEREXTRACTREGEXREQUEST']._serialized_end=1521
71
+ _globals['_BROWSEREXTRACTREGEXRESPONSE']._serialized_start=1523
72
+ _globals['_BROWSEREXTRACTREGEXRESPONSE']._serialized_end=1616
73
+ _globals['_BROWSERGETHTMLREQUEST']._serialized_start=1618
74
+ _globals['_BROWSERGETHTMLREQUEST']._serialized_end=1707
75
+ _globals['_BROWSERGETHTMLRESPONSE']._serialized_start=1709
76
+ _globals['_BROWSERGETHTMLRESPONSE']._serialized_end=1779
77
+ _globals['_BROWSERGETTEXTREQUEST']._serialized_start=1781
78
+ _globals['_BROWSERGETTEXTREQUEST']._serialized_end=1870
79
+ _globals['_BROWSERGETTEXTRESPONSE']._serialized_start=1872
80
+ _globals['_BROWSERGETTEXTRESPONSE']._serialized_end=1942
81
+ _globals['_BROWSEREXECUTESCRIPTREQUEST']._serialized_start=1944
82
+ _globals['_BROWSEREXECUTESCRIPTREQUEST']._serialized_end=2037
83
+ _globals['_BROWSEREXECUTESCRIPTRESPONSE']._serialized_start=2039
84
+ _globals['_BROWSEREXECUTESCRIPTRESPONSE']._serialized_end=2117
85
+ _globals['_BROWSERSCREENSHOTREQUEST']._serialized_start=2119
86
+ _globals['_BROWSERSCREENSHOTREQUEST']._serialized_end=2245
87
+ _globals['_BROWSERSCREENSHOTRESPONSE']._serialized_start=2247
88
+ _globals['_BROWSERSCREENSHOTRESPONSE']._serialized_end=2320
89
+ _globals['_BROWSERGETSTATEREQUEST']._serialized_start=2322
90
+ _globals['_BROWSERGETSTATEREQUEST']._serialized_end=2394
91
+ _globals['_BROWSERGETSTATERESPONSE']._serialized_start=2396
92
+ _globals['_BROWSERGETSTATERESPONSE']._serialized_end=2481
93
+ _globals['_BROWSERGETPAGEINFOREQUEST']._serialized_start=2483
94
+ _globals['_BROWSERGETPAGEINFOREQUEST']._serialized_end=2558
95
+ _globals['_BROWSERGETPAGEINFORESPONSE']._serialized_start=2561
96
+ _globals['_BROWSERGETPAGEINFORESPONSE']._serialized_end=3004
97
+ _globals['_BROWSERCOOKIE']._serialized_start=3007
98
+ _globals['_BROWSERCOOKIE']._serialized_end=3152
99
+ _globals['_BROWSERSETCOOKIESREQUEST']._serialized_start=3154
100
+ _globals['_BROWSERSETCOOKIESREQUEST']._serialized_end=3270
101
+ _globals['_BROWSERSETCOOKIESRESPONSE']._serialized_start=3272
102
+ _globals['_BROWSERSETCOOKIESRESPONSE']._serialized_end=3331
103
+ _globals['_BROWSERGETCOOKIESREQUEST']._serialized_start=3333
104
+ _globals['_BROWSERGETCOOKIESREQUEST']._serialized_end=3423
105
+ _globals['_BROWSERGETCOOKIESRESPONSE']._serialized_start=3425
106
+ _globals['_BROWSERGETCOOKIESRESPONSE']._serialized_end=3526
107
+ _globals['_BROWSERMOUSEMOVEREQUEST']._serialized_start=3528
108
+ _globals['_BROWSERMOUSEMOVEREQUEST']._serialized_end=3638
109
+ _globals['_BROWSERMOUSEMOVERESPONSE']._serialized_start=3640
110
+ _globals['_BROWSERMOUSEMOVERESPONSE']._serialized_end=3698
111
+ _globals['_BROWSERHOVERREQUEST']._serialized_start=3700
112
+ _globals['_BROWSERHOVERREQUEST']._serialized_end=3807
113
+ _globals['_BROWSERHOVERRESPONSE']._serialized_start=3809
114
+ _globals['_BROWSERHOVERRESPONSE']._serialized_end=3863
115
+ _globals['_BROWSERSCROLLREQUEST']._serialized_start=3866
116
+ _globals['_BROWSERSCROLLREQUEST']._serialized_end=4024
117
+ _globals['_BROWSERSCROLLRESPONSE']._serialized_start=4027
118
+ _globals['_BROWSERSCROLLRESPONSE']._serialized_end=4204
119
+ _globals['_BROWSERVALIDATESELECTORSREQUEST']._serialized_start=4207
120
+ _globals['_BROWSERVALIDATESELECTORSREQUEST']._serialized_end=4420
121
+ _globals['_BROWSERVALIDATESELECTORSREQUEST_FIELDSENTRY']._serialized_start=4375
122
+ _globals['_BROWSERVALIDATESELECTORSREQUEST_FIELDSENTRY']._serialized_end=4420
123
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE']._serialized_start=4423
124
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE']._serialized_end=4761
125
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE_COUNTSENTRY']._serialized_start=4668
126
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE_COUNTSENTRY']._serialized_end=4713
127
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE_SAMPLESENTRY']._serialized_start=4715
128
+ _globals['_BROWSERVALIDATESELECTORSRESPONSE_SAMPLESENTRY']._serialized_end=4761
129
+ _globals['_BROWSEREXTRACTDATAREQUEST']._serialized_start=4763
130
+ _globals['_BROWSEREXTRACTDATAREQUEST']._serialized_end=4888
131
+ _globals['_BROWSEREXTRACTDATARESPONSE']._serialized_start=4890
132
+ _globals['_BROWSEREXTRACTDATARESPONSE']._serialized_end=4985
133
+ # @@protoc_insertion_point(module_scope)
@@ -73,16 +73,18 @@ class BrowserNavigateResponse(_message.Message):
73
73
  def __init__(self, success: bool = ..., final_url: _Optional[str] = ..., error: _Optional[str] = ...) -> None: ...
74
74
 
75
75
  class BrowserClickRequest(_message.Message):
76
- __slots__ = ("session_id", "browser_session_id", "selector", "timeout_ms")
76
+ __slots__ = ("session_id", "browser_session_id", "selector", "timeout_ms", "move_cursor")
77
77
  SESSION_ID_FIELD_NUMBER: _ClassVar[int]
78
78
  BROWSER_SESSION_ID_FIELD_NUMBER: _ClassVar[int]
79
79
  SELECTOR_FIELD_NUMBER: _ClassVar[int]
80
80
  TIMEOUT_MS_FIELD_NUMBER: _ClassVar[int]
81
+ MOVE_CURSOR_FIELD_NUMBER: _ClassVar[int]
81
82
  session_id: str
82
83
  browser_session_id: str
83
84
  selector: str
84
85
  timeout_ms: int
85
- def __init__(self, session_id: _Optional[str] = ..., browser_session_id: _Optional[str] = ..., selector: _Optional[str] = ..., timeout_ms: _Optional[int] = ...) -> None: ...
86
+ move_cursor: bool
87
+ def __init__(self, session_id: _Optional[str] = ..., browser_session_id: _Optional[str] = ..., selector: _Optional[str] = ..., timeout_ms: _Optional[int] = ..., move_cursor: bool = ...) -> None: ...
86
88
 
87
89
  class BrowserClickResponse(_message.Message):
88
90
  __slots__ = ("success", "error")
@@ -439,15 +439,9 @@ class AsyncCMDOPClient:
439
439
  @property
440
440
  def browser(self) -> AsyncBrowserService:
441
441
  """
442
- Async browser service for direct programmatic control.
442
+ Async browser service (stub - not implemented).
443
443
 
444
- Provides: create_session, navigate, click, type, extract, etc.
445
-
446
- Example:
447
- >>> async with client.browser.create_session() as session:
448
- ... await session.navigate("https://google.com")
449
- ... await session.type("input[name='q']", "Python")
450
- ... results = await session.extract(".result-title")
444
+ Use sync CMDOPClient.browser instead.
451
445
  """
452
446
  if self._browser is None:
453
447
  self._browser = AsyncBrowserService(self._transport)
@@ -0,0 +1,59 @@
1
+ """Browser SDK with capability-based API.
2
+
3
+ Usage:
4
+ from cmdop.services.browser import BrowserSession
5
+
6
+ with service.create_session() as session:
7
+ session.navigate("https://example.com")
8
+
9
+ # Capabilities
10
+ session.scroll.js("down", 500)
11
+ session.scroll.to_bottom()
12
+
13
+ session.input.click_js(".button")
14
+ session.input.key("Escape")
15
+
16
+ session.timing.wait(1000)
17
+
18
+ soup = session.dom.soup()
19
+ data = session.fetch.json("/api/data")
20
+ """
21
+
22
+ from .session import BrowserSession
23
+ from .service.sync import BrowserService
24
+ from .service.aio import AsyncBrowserService
25
+ from .models import (
26
+ BrowserCookie,
27
+ BrowserState,
28
+ PageInfo,
29
+ ScrollResult,
30
+ ScrollInfo,
31
+ InfiniteScrollResult,
32
+ )
33
+ from .capabilities import (
34
+ ScrollCapability,
35
+ InputCapability,
36
+ TimingCapability,
37
+ DOMCapability,
38
+ FetchCapability,
39
+ )
40
+
41
+ __all__ = [
42
+ # Session & Service
43
+ "BrowserSession",
44
+ "BrowserService",
45
+ "AsyncBrowserService",
46
+ # Models
47
+ "BrowserCookie",
48
+ "BrowserState",
49
+ "PageInfo",
50
+ "ScrollResult",
51
+ "ScrollInfo",
52
+ "InfiniteScrollResult",
53
+ # Capabilities
54
+ "ScrollCapability",
55
+ "InputCapability",
56
+ "TimingCapability",
57
+ "DOMCapability",
58
+ "FetchCapability",
59
+ ]
@@ -0,0 +1,15 @@
1
+ """Browser capabilities."""
2
+
3
+ from .scroll import ScrollCapability
4
+ from .input import InputCapability
5
+ from .timing import TimingCapability
6
+ from .dom import DOMCapability
7
+ from .fetch import FetchCapability
8
+
9
+ __all__ = [
10
+ "ScrollCapability",
11
+ "InputCapability",
12
+ "TimingCapability",
13
+ "DOMCapability",
14
+ "FetchCapability",
15
+ ]
@@ -0,0 +1,28 @@
1
+ """Base capability class."""
2
+
3
+ from __future__ import annotations
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ if TYPE_CHECKING:
7
+ from ..session import BrowserSession
8
+
9
+
10
+ class BaseCapability:
11
+ """Base class for all capabilities.
12
+
13
+ Capabilities group related browser operations and delegate
14
+ actual execution to the session.
15
+ """
16
+
17
+ __slots__ = ("_s",)
18
+
19
+ def __init__(self, session: "BrowserSession") -> None:
20
+ self._s = session
21
+
22
+ def _js(self, script: str) -> str:
23
+ """Execute JS via session."""
24
+ return self._s.execute_script(script)
25
+
26
+ def _call(self, method: str, *args: Any, **kwargs: Any) -> Any:
27
+ """Call service method via session."""
28
+ return self._s._call_service(method, *args, **kwargs)
@@ -0,0 +1,16 @@
1
+ """Shared parsing helpers for capabilities."""
2
+
3
+ from typing import Any
4
+ from cmdop.services.browser.js import parse_json_result
5
+
6
+
7
+ def to_dict(raw: str) -> dict[str, Any]:
8
+ """Parse JS result to dict, default empty."""
9
+ result = parse_json_result(raw)
10
+ return result if isinstance(result, dict) else {}
11
+
12
+
13
+ def to_list(raw: str) -> list[Any]:
14
+ """Parse JS result to list, default empty."""
15
+ result = parse_json_result(raw)
16
+ return result if isinstance(result, list) else []