cmdop 0.1.13__tar.gz → 0.1.16__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 (196) hide show
  1. {cmdop-0.1.13 → cmdop-0.1.16}/PKG-INFO +263 -113
  2. {cmdop-0.1.13 → cmdop-0.1.16}/README.md +259 -111
  3. {cmdop-0.1.13 → cmdop-0.1.16}/pyproject.toml +6 -2
  4. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/__init__.py +16 -1
  5. cmdop-0.1.16/src/cmdop/helpers/__init__.py +9 -0
  6. cmdop-0.1.16/src/cmdop/helpers/cleaner.py +53 -0
  7. cmdop-0.1.16/src/cmdop/helpers/formatting.py +15 -0
  8. cmdop-0.1.16/src/cmdop/logging.py +252 -0
  9. cmdop-0.1.16/src/cmdop/services/browser/__init__.py +44 -0
  10. cmdop-0.1.16/src/cmdop/services/browser/aio/__init__.py +6 -0
  11. cmdop-0.1.16/src/cmdop/services/browser/aio/service.py +323 -0
  12. cmdop-0.1.16/src/cmdop/services/browser/aio/session.py +171 -0
  13. cmdop-0.1.16/src/cmdop/services/browser/base/__init__.py +6 -0
  14. cmdop-0.1.16/src/cmdop/services/browser/base/service.py +62 -0
  15. cmdop-0.1.16/src/cmdop/services/browser/base/session.py +72 -0
  16. cmdop-0.1.16/src/cmdop/services/browser/js.py +109 -0
  17. cmdop-0.1.16/src/cmdop/services/browser/models.py +50 -0
  18. cmdop-0.1.16/src/cmdop/services/browser/sync/__init__.py +6 -0
  19. cmdop-0.1.16/src/cmdop/services/browser/sync/service.py +313 -0
  20. cmdop-0.1.16/src/cmdop/services/browser/sync/session.py +171 -0
  21. cmdop-0.1.13/src/cmdop/services/browser.py +0 -1185
  22. {cmdop-0.1.13 → cmdop-0.1.16}/.gitignore +0 -0
  23. {cmdop-0.1.13 → cmdop-0.1.16}/LICENSE +0 -0
  24. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/__init__.py +0 -0
  25. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/agent_messages_pb2.py +0 -0
  26. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/agent_messages_pb2.pyi +0 -0
  27. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/agent_messages_pb2_grpc.py +0 -0
  28. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/common_types_pb2.py +0 -0
  29. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/common_types_pb2.pyi +0 -0
  30. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/common_types_pb2_grpc.py +0 -0
  31. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/control_messages_pb2.py +0 -0
  32. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/control_messages_pb2.pyi +0 -0
  33. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/control_messages_pb2_grpc.py +0 -0
  34. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/__init__.py +0 -0
  35. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/archive_pb2.py +0 -0
  36. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/archive_pb2.pyi +0 -0
  37. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/archive_pb2_grpc.py +0 -0
  38. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/changes_pb2.py +0 -0
  39. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/changes_pb2.pyi +0 -0
  40. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/changes_pb2_grpc.py +0 -0
  41. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/common_pb2.py +0 -0
  42. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/common_pb2.pyi +0 -0
  43. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/common_pb2_grpc.py +0 -0
  44. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/directory_pb2.py +0 -0
  45. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/directory_pb2.pyi +0 -0
  46. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/directory_pb2_grpc.py +0 -0
  47. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/file_crud_pb2.py +0 -0
  48. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/file_crud_pb2.pyi +0 -0
  49. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/file_crud_pb2_grpc.py +0 -0
  50. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/hls_pb2.py +0 -0
  51. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/hls_pb2.pyi +0 -0
  52. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/hls_pb2_grpc.py +0 -0
  53. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/requests_pb2.py +0 -0
  54. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/requests_pb2.pyi +0 -0
  55. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/requests_pb2_grpc.py +0 -0
  56. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/search_pb2.py +0 -0
  57. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/search_pb2.pyi +0 -0
  58. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/search_pb2_grpc.py +0 -0
  59. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/transfer_pb2.py +0 -0
  60. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/transfer_pb2.pyi +0 -0
  61. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations/transfer_pb2_grpc.py +0 -0
  62. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations_pb2.py +0 -0
  63. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations_pb2.pyi +0 -0
  64. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_operations_pb2_grpc.py +0 -0
  65. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/__init__.py +0 -0
  66. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/archive_pb2.py +0 -0
  67. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/archive_pb2.pyi +0 -0
  68. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/archive_pb2_grpc.py +0 -0
  69. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/directory_pb2.py +0 -0
  70. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/directory_pb2.pyi +0 -0
  71. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/directory_pb2_grpc.py +0 -0
  72. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/file_crud_pb2.py +0 -0
  73. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/file_crud_pb2.pyi +0 -0
  74. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/file_crud_pb2_grpc.py +0 -0
  75. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/hls_pb2.py +0 -0
  76. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/hls_pb2.pyi +0 -0
  77. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/hls_pb2_grpc.py +0 -0
  78. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/search_pb2.py +0 -0
  79. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/search_pb2.pyi +0 -0
  80. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc/search_pb2_grpc.py +0 -0
  81. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc_pb2.py +0 -0
  82. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc_pb2.pyi +0 -0
  83. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/file_rpc_pb2_grpc.py +0 -0
  84. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/message_pool.py +0 -0
  85. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/py.typed +0 -0
  86. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/__init__.py +0 -0
  87. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/agent_pb2.py +0 -0
  88. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/agent_pb2.pyi +0 -0
  89. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/agent_pb2_grpc.py +0 -0
  90. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/browser_pb2.py +0 -0
  91. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/browser_pb2.pyi +0 -0
  92. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/browser_pb2_grpc.py +0 -0
  93. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/device_pb2.py +0 -0
  94. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/device_pb2.pyi +0 -0
  95. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/device_pb2_grpc.py +0 -0
  96. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/extract_pb2.py +0 -0
  97. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/extract_pb2.pyi +0 -0
  98. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/extract_pb2_grpc.py +0 -0
  99. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/health_pb2.py +0 -0
  100. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/health_pb2.pyi +0 -0
  101. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/health_pb2_grpc.py +0 -0
  102. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/history_pb2.py +0 -0
  103. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/history_pb2.pyi +0 -0
  104. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/history_pb2_grpc.py +0 -0
  105. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/lifecycle_pb2.py +0 -0
  106. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/lifecycle_pb2.pyi +0 -0
  107. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/lifecycle_pb2_grpc.py +0 -0
  108. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/push_pb2.py +0 -0
  109. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/push_pb2.pyi +0 -0
  110. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/push_pb2_grpc.py +0 -0
  111. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/session_pb2.py +0 -0
  112. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/session_pb2.pyi +0 -0
  113. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/session_pb2_grpc.py +0 -0
  114. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/terminal_pb2.py +0 -0
  115. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/terminal_pb2.pyi +0 -0
  116. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages/terminal_pb2_grpc.py +0 -0
  117. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages_pb2.py +0 -0
  118. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages_pb2.pyi +0 -0
  119. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/rpc_messages_pb2_grpc.py +0 -0
  120. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/service_pb2.py +0 -0
  121. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/service_pb2.pyi +0 -0
  122. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/service_pb2_grpc.py +0 -0
  123. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/tunnel_pb2.py +0 -0
  124. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/tunnel_pb2.pyi +0 -0
  125. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/_generated/tunnel_pb2_grpc.py +0 -0
  126. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/__init__.py +0 -0
  127. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/__init__.py +0 -0
  128. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/__init__.py +0 -0
  129. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/client.py +0 -0
  130. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/enums.py +0 -0
  131. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/logger.py +0 -0
  132. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/machines__api__machine_sharing/__init__.py +0 -0
  133. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/machines__api__machine_sharing/client.py +0 -0
  134. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/machines__api__machine_sharing/models.py +0 -0
  135. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/machines__api__machine_sharing/sync_client.py +0 -0
  136. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/machines__api__machines/__init__.py +0 -0
  137. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/machines__api__machines/client.py +0 -0
  138. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/machines__api__machines/models.py +0 -0
  139. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/machines__api__machines/sync_client.py +0 -0
  140. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/retry.py +0 -0
  141. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/schema.json +0 -0
  142. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/machines/sync_client.py +0 -0
  143. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/__init__.py +0 -0
  144. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/client.py +0 -0
  145. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/enums.py +0 -0
  146. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/logger.py +0 -0
  147. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/retry.py +0 -0
  148. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/schema.json +0 -0
  149. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/sync_client.py +0 -0
  150. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/system__api__oauth/__init__.py +0 -0
  151. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/system__api__oauth/client.py +0 -0
  152. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/system__api__oauth/models.py +0 -0
  153. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/system__api__oauth/sync_client.py +0 -0
  154. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/system__api__system/__init__.py +0 -0
  155. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/system__api__system/client.py +0 -0
  156. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/system__api__system/models.py +0 -0
  157. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/system/system__api__system/sync_client.py +0 -0
  158. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/__init__.py +0 -0
  159. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/client.py +0 -0
  160. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/enums.py +0 -0
  161. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/logger.py +0 -0
  162. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/retry.py +0 -0
  163. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/schema.json +0 -0
  164. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/sync_client.py +0 -0
  165. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/__init__.py +0 -0
  166. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/client.py +0 -0
  167. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/models.py +0 -0
  168. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/api/generated/workspaces/workspaces__api__workspaces/sync_client.py +0 -0
  169. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/client.py +0 -0
  170. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/config.py +0 -0
  171. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/discovery.py +0 -0
  172. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/exceptions.py +0 -0
  173. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/models/__init__.py +0 -0
  174. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/models/agent.py +0 -0
  175. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/models/base.py +0 -0
  176. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/models/config.py +0 -0
  177. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/models/extract.py +0 -0
  178. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/models/files.py +0 -0
  179. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/models/terminal.py +0 -0
  180. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/py.typed +0 -0
  181. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/services/__init__.py +0 -0
  182. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/services/agent.py +0 -0
  183. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/services/base.py +0 -0
  184. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/services/extract.py +0 -0
  185. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/services/files.py +0 -0
  186. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/services/terminal.py +0 -0
  187. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/streaming/__init__.py +0 -0
  188. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/streaming/base.py +0 -0
  189. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/streaming/handlers.py +0 -0
  190. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/streaming/terminal.py +0 -0
  191. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/transport/__init__.py +0 -0
  192. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/transport/auth.py +0 -0
  193. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/transport/base.py +0 -0
  194. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/transport/discovery.py +0 -0
  195. {cmdop-0.1.13 → cmdop-0.1.16}/src/cmdop/transport/local.py +0 -0
  196. {cmdop-0.1.13 → cmdop-0.1.16}/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.13
3
+ Version: 0.1.16
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
@@ -8,7 +8,7 @@ Project-URL: Repository, https://github.com/markolofsen/cmdop-client
8
8
  Author: CMDOP Team
9
9
  License: MIT
10
10
  License-File: LICENSE
11
- Keywords: agent,automation,cmdop,grpc,terminal
11
+ Keywords: agent,automation,cmdop,terminal
12
12
  Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
@@ -24,6 +24,8 @@ Requires-Dist: httpx>=0.27.0
24
24
  Requires-Dist: protobuf>=4.25.0
25
25
  Requires-Dist: pydantic-settings>=2.0.0
26
26
  Requires-Dist: pydantic>=2.5.0
27
+ Requires-Dist: rich>=13.0.0
28
+ Requires-Dist: toon-python>=0.1.2
27
29
  Provides-Extra: dev
28
30
  Requires-Dist: grpcio-tools>=1.60.0; extra == 'dev'
29
31
  Requires-Dist: mypy>=1.8.0; extra == 'dev'
@@ -63,37 +65,70 @@ Agent connects out. Your code connects to relay. Done.
63
65
 
64
66
  ---
65
67
 
66
- ## What You Get
68
+ ## Install
69
+
70
+ ```bash
71
+ pip install cmdop
72
+ ```
73
+
74
+ ```python
75
+ from cmdop import CMDOPClient, AsyncCMDOPClient
76
+
77
+ # Remote (via cloud relay)
78
+ with CMDOPClient.remote(api_key="cmd_xxx") as client:
79
+ client.files.list("/home")
80
+
81
+ # Local (direct IPC)
82
+ with CMDOPClient.local() as client:
83
+ client.terminal.execute("ls -la")
84
+
85
+ # Async
86
+ async with AsyncCMDOPClient.remote(api_key="cmd_xxx") as client:
87
+ await client.files.read("/etc/hostname")
88
+ ```
89
+
90
+ ---
91
+
92
+ # Part 1: Remote Control
93
+
94
+ ## Terminal
67
95
 
68
- **Terminal:**
69
96
  ```python
70
97
  session = server.terminal.create()
71
98
  server.terminal.send_input(session.session_id, "kubectl get pods\n")
72
99
  output = server.terminal.get_history(session.session_id)
73
100
  ```
74
101
 
75
- **Files:**
102
+ | Method | Description |
103
+ |--------|-------------|
104
+ | `create(shell)` | Start session |
105
+ | `send_input(id, data)` | Send commands |
106
+ | `get_history(id)` | Get output |
107
+ | `resize(id, cols, rows)` | Resize |
108
+ | `send_signal(id, signal)` | SIGINT/SIGTERM |
109
+ | `close(id)` | End session |
110
+
111
+ ## Files
112
+
76
113
  ```python
77
114
  server.files.list("/var/log")
78
115
  server.files.read("/etc/nginx/nginx.conf")
79
116
  server.files.write("/tmp/config.json", b'{"key": "value"}')
80
117
  ```
81
118
 
82
- **Browser scrape without Selenium/Playwright bullshit:**
83
- ```python
84
- with server.browser.create_session() as browser:
85
- browser.navigate("https://shop.com/products")
119
+ | Method | Description |
120
+ |--------|-------------|
121
+ | `list(path)` | List dir |
122
+ | `read(path)` | Read file |
123
+ | `write(path, content)` | Write file |
124
+ | `delete(path)` | Delete |
125
+ | `copy(src, dst)` | Copy |
126
+ | `move(src, dst)` | Move |
127
+ | `mkdir(path)` | Create dir |
128
+ | `info(path)` | Metadata |
86
129
 
87
- # One call → structured data
88
- products = browser.extract_data(
89
- ".product-card",
90
- '{"name": "h2", "price": ".price", "url": {"selector": "a", "attr": "href"}}',
91
- limit=100
92
- )["items"]
93
- # → [{"name": "iPhone", "price": "$999", "url": "/p/123"}, ...]
94
- ```
130
+ ## Agent
95
131
 
96
- **AI Agent — typed responses:**
97
132
  ```python
98
133
  from pydantic import BaseModel
99
134
 
@@ -106,11 +141,15 @@ result = server.agent.run("Check server health", output_schema=Health)
106
141
  health: Health = result.output # Typed!
107
142
  ```
108
143
 
109
- ---
144
+ | Method | Description |
145
+ |--------|-------------|
146
+ | `run(prompt, output_schema)` | Run agent, get typed result |
147
+
148
+ Types: `chat`, `terminal`, `command`, `router`, `planner`
110
149
 
111
- ## Real World
150
+ ## Real World Examples
112
151
 
113
- **AI Agent + Typed Output:**
152
+ **Deploy with typed result:**
114
153
  ```python
115
154
  class DeployResult(BaseModel):
116
155
  success: bool
@@ -125,7 +164,7 @@ if not result.output.success:
125
164
  rollback(result.output.errors)
126
165
  ```
127
166
 
128
- **Fleet Update (1000 devices):**
167
+ **Fleet update (1000 devices):**
129
168
  ```python
130
169
  async def update_fleet(keys: list[str], config: bytes):
131
170
  async with asyncio.TaskGroup() as tg:
@@ -138,7 +177,7 @@ async def update_one(key: str, config: bytes):
138
177
  await dev.terminal.execute("systemctl restart app")
139
178
  ```
140
179
 
141
- **Debug Customer Machine:**
180
+ **Debug customer machine:**
142
181
  ```python
143
182
  with CMDOPClient.remote(api_key=customer_key) as m:
144
183
  m.terminal.send_input(sid, "ps aux\n")
@@ -146,75 +185,60 @@ with CMDOPClient.remote(api_key=customer_key) as m:
146
185
  m.terminal.send_input(sid, "df -h\n")
147
186
  ```
148
187
 
149
- **Scrape Products:**
150
- ```python
151
- class Product(SDKBaseModel):
152
- __base_url__ = "https://amazon.com"
153
- title: str = ""
154
- price: int = 0 # "$1,299" → 1299
155
- url: str = "" # "/dp/..." → "https://amazon.com/dp/..."
156
-
157
- with client.browser.create_session(headless=True) as b:
158
- b.navigate("https://amazon.com/s?k=laptop")
159
- raw = b.extract_data(".s-result-item", '{"title": "h2", "price": ".a-price-whole", "url": {"selector": "a", "attr": "href"}}', limit=50)
160
- products = Product.from_list(raw["items"]) # clean + dedupe + filter
161
- ```
162
-
163
188
  ---
164
189
 
165
- ## Install
166
-
167
- ```bash
168
- pip install cmdop
169
- ```
190
+ # Part 2: Web Parsing
170
191
 
171
- ## Usage
192
+ ## Browser
172
193
 
194
+ **DOM extraction:**
173
195
  ```python
174
- from cmdop import CMDOPClient, AsyncCMDOPClient
175
-
176
- # Remote (via cloud relay)
177
- with CMDOPClient.remote(api_key="cmd_xxx") as client:
178
- client.files.list("/home")
179
-
180
- # Local (direct IPC)
181
- with CMDOPClient.local() as client:
182
- client.terminal.execute("ls -la")
196
+ with server.browser.create_session() as b:
197
+ b.navigate("https://shop.com/products")
183
198
 
184
- # Async
185
- async with AsyncCMDOPClient.remote(api_key="cmd_xxx") as client:
186
- await client.files.read("/etc/hostname")
199
+ products = b.extract_data(
200
+ ".product-card",
201
+ '{"name": "h2", "price": ".price", "url": {"selector": "a", "attr": "href"}}',
202
+ limit=100
203
+ )["items"]
204
+ # → [{"name": "iPhone", "price": "$999", "url": "/p/123"}, ...]
187
205
  ```
188
206
 
189
- ---
190
-
191
- ## API
192
-
193
- ### Terminal
194
-
195
- | Method | Description |
196
- |--------|-------------|
197
- | `create(shell)` | Start session |
198
- | `send_input(id, data)` | Send commands |
199
- | `get_history(id)` | Get output |
200
- | `resize(id, cols, rows)` | Resize |
201
- | `send_signal(id, signal)` | SIGINT/SIGTERM |
202
- | `close(id)` | End session |
207
+ **JS fetch injection (bypass CORS):**
208
+ ```python
209
+ with client.browser.create_session() as b:
210
+ b.navigate("https://site.com") # Get cookies/session
211
+
212
+ # Single API call
213
+ data = b.fetch_json("https://api.site.com/v1/items")
214
+
215
+ # Parallel fetch with headers and credentials
216
+ results = b.fetch_all(
217
+ urls={
218
+ "users": "https://api.site.com/v1/users",
219
+ "orders": "https://api.site.com/v1/orders",
220
+ },
221
+ headers={"Accept": "application/json"},
222
+ credentials=True, # Include cookies
223
+ )
224
+ # → {"users": {"data": [...], "error": None}, "orders": {"data": [...], "error": None}}
225
+ ```
203
226
 
204
- ### Files
227
+ **Custom JS execution:**
228
+ ```python
229
+ with client.browser.create_session() as b:
230
+ b.navigate("https://site.com")
205
231
 
206
- | Method | Description |
207
- |--------|-------------|
208
- | `list(path)` | List dir |
209
- | `read(path)` | Read file |
210
- | `write(path, content)` | Write file |
211
- | `delete(path)` | Delete |
212
- | `copy(src, dst)` | Copy |
213
- | `move(src, dst)` | Move |
214
- | `mkdir(path)` | Create dir |
215
- | `info(path)` | Metadata |
232
+ # Execute async JS with auto-wrap and JSON parsing
233
+ result = b.execute_js("""
234
+ const resp = await fetch('/api/data');
235
+ return await resp.json();
236
+ """)
237
+ # {"items": [...]}
216
238
 
217
- ### Browser
239
+ # Raw mode (returns JSON string)
240
+ raw = b.execute_js("return document.title", raw=True)
241
+ ```
218
242
 
219
243
  | Method | Description |
220
244
  |--------|-------------|
@@ -226,30 +250,15 @@ async with AsyncCMDOPClient.remote(api_key="cmd_xxx") as client:
226
250
  | `extract(selector, attr)` | Get text/attr |
227
251
  | `extract_regex(pattern)` | Regex matches |
228
252
  | `validate_selectors(item, fields)` | Check selectors |
229
- | `extract_data(item, fields, limit)` | **Bulk extract → list[dict]** |
230
- | `execute_script(js)` | Run JS |
253
+ | `extract_data(item, fields, limit)` | Bulk extract → list[dict] |
254
+ | `fetch_json(url)` | JS fetch → dict |
255
+ | `fetch_all(urls, headers, credentials)` | Parallel fetch → {id: {data, error}} |
256
+ | `execute_js(code, raw)` | Async JS with auto-wrap → dict |
257
+ | `execute_script(js)` | Raw JS → str |
231
258
  | `screenshot()` | PNG |
232
259
  | `get_cookies()` / `set_cookies()` | Cookies |
233
260
 
234
- **Scraping workflow:**
235
- ```python
236
- with client.browser.create_session() as b:
237
- b.navigate("https://cars.com/listings")
238
-
239
- # 1. Validate (fail fast if site changed)
240
- v = b.validate_selectors(".item", {"title": "h2", "price": ".price"})
241
- if not v["valid"]:
242
- raise Exception(v["errors"]) # also has counts, samples
243
-
244
- # 2. Extract
245
- cars = b.extract_data(
246
- ".item",
247
- '{"title": "h2", "price": {"selector": ".price", "regex": "\\\\d+"}}',
248
- limit=200
249
- )["items"]
250
- ```
251
-
252
- ### SDKBaseModel
261
+ ## SDKBaseModel
253
262
 
254
263
  Auto-cleaning Pydantic model for scraped data. No more manual `.strip()`, regex, URL joining.
255
264
 
@@ -257,7 +266,7 @@ Auto-cleaning Pydantic model for scraped data. No more manual `.strip()`, regex,
257
266
  from cmdop import SDKBaseModel
258
267
 
259
268
  class Product(SDKBaseModel):
260
- __base_url__ = "https://shop.com" # for relative URLs
269
+ __base_url__ = "https://shop.com"
261
270
 
262
271
  name: str = "" # " iPhone 15 \n" → "iPhone 15"
263
272
  price: int = 0 # "$1,299.00" → 1299
@@ -268,8 +277,6 @@ class Product(SDKBaseModel):
268
277
  products = Product.from_list(raw["items"])
269
278
  ```
270
279
 
271
- **What it does:**
272
-
273
280
  | Type | Input | Output |
274
281
  |------|-------|--------|
275
282
  | `str` | `" text \n\t "` | `"text"` |
@@ -277,19 +284,162 @@ products = Product.from_list(raw["items"])
277
284
  | `float` | `"4.5 out of 5"` | `4.5` |
278
285
  | `str` (url field) | `"/path"` | `"https://base.com/path"` |
279
286
 
280
- **Usage with extract_data:**
287
+ ## Parsing Examples
288
+
289
+ **Scrape with validation:**
281
290
  ```python
282
- raw = browser.extract_data(".product", fields, limit=100)
283
- products = Product.from_list(raw["items"]) # clean + dedupe by url + filter empty
291
+ with client.browser.create_session() as b:
292
+ b.navigate("https://cars.com/listings")
293
+
294
+ # 1. Validate (fail fast if site changed)
295
+ v = b.validate_selectors(".item", {"title": "h2", "price": ".price"})
296
+ if not v["valid"]:
297
+ raise Exception(v["errors"])
298
+
299
+ # 2. Extract
300
+ cars = b.extract_data(".item", '{"title": "h2", "price": ".price"}', limit=200)["items"]
284
301
  ```
285
302
 
286
- ### Agent
303
+ **Scrape with SDKBaseModel:**
304
+ ```python
305
+ class Product(SDKBaseModel):
306
+ __base_url__ = "https://amazon.com"
307
+ title: str = ""
308
+ price: int = 0 # "$1,299" → 1299
309
+ url: str = "" # "/dp/..." → "https://amazon.com/dp/..."
287
310
 
288
- | Method | Description |
289
- |--------|-------------|
290
- | `run(prompt, output_schema)` | Run agent, get typed result |
311
+ with client.browser.create_session(headless=True) as b:
312
+ b.navigate("https://amazon.com/s?k=laptop")
313
+ raw = b.extract_data(".s-result-item", '{"title": "h2", "price": ".a-price-whole", "url": {"selector": "a", "attr": "href"}}', limit=50)
314
+ products = Product.from_list(raw["items"]) # clean + dedupe + filter
315
+ ```
291
316
 
292
- Types: `chat`, `terminal`, `command`, `router`, `planner`
317
+ **Parallel API fetching:**
318
+ ```python
319
+ with client.browser.create_session() as b:
320
+ b.navigate("https://api.example.com")
321
+
322
+ # Fetch 10 pages in parallel
323
+ urls = {f"page_{i}": f"https://api.example.com/items?page={i}" for i in range(10)}
324
+ results = b.fetch_all(urls)
325
+
326
+ items = []
327
+ for key, res in results.items():
328
+ if res["data"]: # {"data": {...}, "error": None}
329
+ items.extend(res["data"].get("items", []))
330
+ elif res["error"]:
331
+ print(f"{key} failed: {res['error']}")
332
+ ```
333
+
334
+ **JS fetch for protected APIs:**
335
+ ```python
336
+ with client.browser.create_session() as b:
337
+ b.navigate("https://site.com") # Get session cookies
338
+
339
+ # Fetch JSON API (inherits cookies)
340
+ data = b.fetch_json("https://api.site.com/v1/data")
341
+
342
+ # Parallel fetch with custom headers
343
+ results = b.fetch_all(
344
+ urls={
345
+ "inspection": f"https://api.site.com/v1/car/{car_id}/inspection",
346
+ "options": f"https://api.site.com/v1/car/{car_id}/options",
347
+ },
348
+ headers={"Accept": "application/json", "Origin": "https://site.com"},
349
+ credentials=True,
350
+ )
351
+
352
+ inspection = results["inspection"]["data"]
353
+ options = results["options"]["data"]
354
+ ```
355
+
356
+ ---
357
+
358
+ # Part 3: Utilities
359
+
360
+ ## Logging
361
+
362
+ Rich-powered logger with automatic project root detection and file persistence.
363
+
364
+ ```python
365
+ from cmdop import get_logger
366
+
367
+ log = get_logger(__name__)
368
+ log.info("Starting process")
369
+ log.debug("Details: %s", data)
370
+ log.warning("Something seems off")
371
+ log.error("Failed!", exc_info=True) # With traceback
372
+ ```
373
+
374
+ **Features:**
375
+ - Rich console output with colors and timestamps
376
+ - Auto-saves to `logs/` folder in project root
377
+ - Finds project root by `pyproject.toml`, `requirements.txt`, `.git`
378
+ - Daily log rotation by filename
379
+
380
+ **Custom settings:**
381
+ ```python
382
+ from cmdop import get_logger, setup_logging
383
+
384
+ # Set log level
385
+ log = get_logger(__name__, level="DEBUG")
386
+
387
+ # Custom app name for log files
388
+ log = get_logger(__name__, app_name="myparser")
389
+ # → logs/myparser_2024-01-17.log
390
+
391
+ # Disable file logging
392
+ log = get_logger(__name__, log_to_file=False)
393
+ ```
394
+
395
+ **Log file format:**
396
+ ```
397
+ 2024-01-17 14:30:25 | INFO | myapp.parser:42 - Starting process
398
+ 2024-01-17 14:30:26 | ERROR | myapp.parser:58 - Failed to fetch
399
+ ```
400
+
401
+ | Function | Description |
402
+ |----------|-------------|
403
+ | `get_logger(name, level, app_name)` | Get configured logger |
404
+ | `setup_logging(level, log_to_file)` | Configure root logger |
405
+ | `find_project_root()` | Find Python project root |
406
+ | `get_log_dir(app_name)` | Get/create logs directory |
407
+
408
+ ## TOON Format (Token Optimization)
409
+
410
+ Convert JSON to TOON format — saves 30-50% tokens for LLM consumption.
411
+
412
+ ```python
413
+ from cmdop import json_to_toon, JsonCleaner
414
+
415
+ # Simple conversion
416
+ data = {"name": "Alice", "age": 25, "city": "Seoul"}
417
+ toon = json_to_toon(data)
418
+ # → "name: Alice\nage: 25\ncity: Seoul"
419
+
420
+ # With cleaning (removes nulls, empty values, noise keys)
421
+ cleaner = JsonCleaner(noise_keys={"internal_id", "metadata"})
422
+ clean_toon = cleaner.to_toon({
423
+ "name": "BMW X5",
424
+ "price": 50000,
425
+ "internal_id": "abc123", # removed
426
+ "specs": None, # removed
427
+ "options": [], # removed
428
+ })
429
+ # → "name: BMW X5\nprice: 50000"
430
+ ```
431
+
432
+ **JsonCleaner features:**
433
+ - Removes `None` values and empty `[]`, `{}`, `""`
434
+ - Simplifies `{"code": "1", "title": "Good"}` → `"Good"`
435
+ - Custom noise keys per domain
436
+
437
+ | Function | Description |
438
+ |----------|-------------|
439
+ | `json_to_toon(data)` | Convert dict/list to TOON string |
440
+ | `JsonCleaner(noise_keys)` | Cleaner with custom noise keys |
441
+ | `cleaner.compact(data)` | Clean without converting |
442
+ | `cleaner.to_toon(data)` | Clean + convert to TOON |
293
443
 
294
444
  ---
295
445